add to hatena hatena.comment (4) add to del.icio.us (0) add to livedoor.clip (1) add to Yahoo!Bookmark (0) Total: 5

CakePHP Tips:ドラッグ&ドロップでデータを並び替える

マスターのメンテナンス機能やCMS系の機能を開発する際に、データの並びをユーザーが自由に設定できるようにしたいという要件はよくあります。

CakePHPとprototype.jsを使えば、ドラッグ&ドロップでデータの並びを設定することが簡単に実装できます。

今回のサンプルはこちらで確認できます。

id, name(果物名), position(position) の3カラムのfuruitsテーブルのデータを並び替えています。

方針

CakePHPではAjaxヘルパにドラッグ&ドロップのメソッドが用意されていますが、普通にjavascriptを書いたほうが簡単に実装できますので、今回はあえて自前で実装していきます。

処理の概要としては、以下のような感じです。

1.レイアウト:headタグ内でprototype.js、scriptaculous.jsを読み込む
2.ビュー:並び替えの対象用のコンテナのdivを設定
3.ビュー:データをループし、コンテナ内に表示情報と配列型のHIDDENでidを設置
4.ビュー:javascriptでドラッグ&ドロップが可能なSotableクラスにコンテナを指定
5.コントローラー:POSTされたデータは 並び順=>id となっているので、ループしながらsaveFieldメソッドで並び順を保存

ソースコード:コントローラー (controllers/fruits_controller.php)

PHP:
  1. <?php
  2. class FruitsController extends AppController
  3. {
  4.  var $name = 'Fruits';
  5.  var $uses = array('Fruit');
  6.  
  7.  function index() {
  8.   $this->pageTitle = 'ドラッグ&ドロップで並び替えできます';
  9.   $M = $this->Fruit;
  10.   $data = $M->findAll(NULL, NULL, "{$M->name}.position, {$M->name}.id desc");
  11.   $this->set('data', $data);
  12.  }
  13.  
  14.  function change_position() {
  15.   $M = $this->Fruit;
  16.   $position_id =&amp; $this->params['form']['position_id'];
  17.   if(!empty($position_id)) {
  18.    foreach($position_id as $position => $id){
  19.      $M->id = $id;
  20.      $M->saveField('position', $position);
  21.    }
  22.    $this->Session->setFlash('並び替えの設定を保存しました。','display_info');
  23.   }
  24.   $this->redirect("/{$this->viewPath}/index/");
  25.  }
  26.  
  27. }
  28. ?>

[point]
・データは$_POST['position_id']に配列(並び => id)で渡される

・saveFieldメソッドでpositionを更新する

ソースコード:ビュー (views/fruits/index.thtml)

PHP:
  1. <form action="<?php echo $html->url('/fruits/change_position/') ?>" method="post" name="myForm">
  2. <div id="position_box">
  3. <?php foreach($data as $i => $_data): ?>
  4.   <div style="cursor:move; margin-bottom:3px; border:solid 1px gray; background-color:white">
  5.    <div style="padding:3px;"><?php echo $i+1 ?><?php echo $_data['Fruit']['name'] ?></div>
  6.    <input type="hidden" name="position_id[]" value="<?php echo $_data['Fruit']['id'] ?>">
  7.   </div>
  8.  <?php endforeach; ?>
  9.  <center style="margin:5px">
  10.   <input type="submit" value="並び替えを保存する">
  11.  </center>
  12. </div>
  13. </form>
  14. <script type="text/javascript"><!--
  15. document.observe('dom:loaded', function(){
  16.  Sortable.create('position_box', {tag: 'div'});
  17. });
  18. //--></script>

[point]
・position_boxというdivコンテナを作成

・各レコード内にposition_id[]というid値を含んだHIDDENを設置

・javascript Sortableクラスにposition_boxコンテナを指定

※prototype.jsとscriptaculous.js?load=effects,dragdropはレイアウトで事前に読み込んでおくか、ビューの先頭でscriptタグを使って読み込ませる

HTML:
  1. <script type="text/javascript" src="/js/prototype/prototype.js"></script>
  2.  
  3. <script type="text/javascript" src="/js/prototype/scriptaculous.js?load=effects,dragdrop"></script>

ソースコード:モデル (models/fruit.php)

PHP:
  1. <?php
  2. class Fruit extends AppModel
  3. {
  4.  var $name = 'Fruit';
  5.  var $useTable = 'fruits';
  6. }
  7. ?>

テーブルSQL

SQL:
  1. CREATE TABLE IF NOT EXISTS `fruits` (
  2.   `id` bigint(20) NOT NULL AUTO_INCREMENT,
  3.   `name` varchar(100) NOT NULL DEFAULT '',
  4.   `position` bigint(20) NOT NULL DEFAULT 99999,
  5.   PRIMARY KEY  (`id`)
  6. ) ENGINE=MyISAM;
  7. INSERT INTO `fruits` (`id`, `name`, `position`) VALUES
  8. (1, 'オレンジ', 99999),
  9. (2, 'リンゴ', 99999),
  10. (3, 'バナナ', 99999),
  11. (4, 'パイナップル', 99999),
  12. (5, 'マンゴー', 99999),
  13. (6, 'ぶどう', 99999),
  14. (7, 'グレープフルーツ', 99999),
  15. (8, 'レモン', 99999);

関連するその他の記事

Comments

Leave a Reply