CakePHP2で表のカラムの順番を入れ替えるボタンの作り方

## きっかけ
演習でファイルがダウンロードできるサイトを作っていて、そのカテゴリーを管理するサイトで矢印↑↓をクリックすると前後の順番を入れ替えられるようにしたかったです。どのように作ったか記しておきます。

![カテゴリ管理画面イメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1802093/9b0f7363-c92e-5dd8-44c4-65296197cc08.png)

## 手順
1, Controllerに更新するデータのidを渡す
2, 並び替え用の数値を書き換え
3, データベースに書き換えたデータを保存

## データベース
order_numberは表示順を表わします。表示順を入れ替えて更新することで並び替えできるようにします。
| id | category_name | order_number |
|:-----------|:------------|------------:|
| 1       | カテゴリー1        | 1         |
| 2     | カテゴリー2      | 2       |
| 3      | 社内文書        | 3        |
| 4      | 基本        | 4       |

## 並び替え入れ替え矢印の部分のビュー画面
```CakePHP2:index.ctp
<table>
    <tr>
        <th>カテゴリー名</th>
        <th>並び替え</th>
        <th>登録テンプレート数</th>
        <th>操作</th>
    </tr>
    <tr>
        <?php foreach ((array) $categories as $category) { ?>
    <tr>
        <td><?php echo $category['Category']['category_name'] ?></td>
        <td>
            <?php echo $this->Form->create('Category');
            echo $this->Form->input('id');
            $id = $category['Category']['id'];
            $order_number = $category['Category']['order_number'];
            //表示順が最小ではないとき、↑を表示
            if ($order_number != $min) {
                echo $this->Form->submit(__('↑'), array('name' => 'up'));
            }
            //hiddenでidをControllerに渡す
            echo $this->Form->hidden('id', ['value' => $id]);
            echo $this->Form->end(); ?>

            <?php echo $this->Form->create('Category');
            echo $this->Form->input('id');
            //表示順が最大ではないとき、↓を表示
            if ($order_number != $max) {
                echo $this->Form->submit(__('↓'), array('name' => 'down'));
            }
            echo $this->Form->hidden('id', ['value' => $id]);
            echo $this->Form->end(); ?>
        </td>
~省略~
    </tr>
<?php } ?>
</table>
```
## Controllerの処理
まずクリックされたカラムのidを受け取ります。
```CakePHP2:CategoriesController.php
public function index()
{
　if ($this->request->is(array('post', 'put'))) {
　　if ($this->Category->save($this->request->data)) {
　　　$id = $this->request->data['Category']['id'];
```
得たidで検索してそのカラムのorder_number(表示順)とカテゴリー名を得ます。
ボタンクリックされた行の表示
```
$options = array(
　'conditions' => array(
　'Category.id' => $id
　)
);
$data = $this->Category->find('first', $options);
// ボタンクリックされた行のorder_number
$clicked = $data['Category']['order_number'];
// ボタンクリックされた行のcategory_name
$clicked_name = $data['Category']['category_name'];
```
矢印が↑だった場合、
入れ替え先のデータを得ます。表示順が１つ上のものです。
その検索条件は表示順がクリックされたものより小さく、降順（大きい順）に並べたときの一番目のもの、と表せます。
```
if (isset($this->request->data['up'])) {
// 入れ替え先のデータ
　$options2 = array(
　　'conditions' => array(
　　'Category.order_number <'=> $clicked
  ),
    'order' => array('Category.order_number desc'),
    'limit' => 1
    );
//入れ替え先のデータを得る
$data2 = $this->Category->find('first', $options2);
```
あとは
・ボタンクリックされたデータ
・入れ替え先のデータ
のorder_number(表示順)を入れ替えます。
```
// 1つ前の入れ替え先のidを$id2に代入
$id2 = $data2['Category']['id'];
// 入れ替え先のorder_number
$replace = $data2['Category']['order_number'];
// 入れ替え先のcategory_name
$replace_name = $data2['Category']['category_name'];
// $updateにクリックされたid,入れ替え先のorder_numberを入れる
if (isset($replace)) {
　$update = array(
　　'Category' => array(
　　'id' => $id,
　　'order_number' => $replace
　　)
　);
}
// $updateにクリックされたid,入れ替え先のorder_numberを入れる
if (isset($replace)) {
    $update = array(
        'Category' => array(
        'id' => $id,
        'order_number' => $replace
        )
    );
}
// $update2に入れ替え先のid,クリックされた行のorder_numberを入れる
if (isset($id2)) {
    $update2 = array(
        'Category' => array(
        'id' => $id2,
        'order_number' => $clicked
    )
    );
}
```
入れ替えたデータを保存します。
```
$this->Category->save($update);
$this->Category->save($update2);
```
また、↓ボタンの場合、入れ替え先のデータの検索条件はこのようにしました。
あとの操作は↑と同じような感じです。
```
} else if (isset($this->request->data['down'])) {
//入れ替え先のデータ
    $options3 = array(
        'conditions' => array(
        'Category.order_number >' => $clicked
        ),
    'order' => array('Category.order_number asc'),
    'limit' => 1
```
また、↑の表示順がページでそれぞれ一番上の時は↑、一番下の時は↓を表示しないようにしたいので、
はじめにorder_number(表示順)の最大値と最小値を得るようにしました。
```
public function index()
    {
        $max = $this->Category->find('first', array(
                    'fields' => array('Max(Category.order_number) as order_number_max')
                ));

        $min = $this->Category->find('first', array(
                    'fields' => array('Min(Category.order_number) as order_number_min')
                ));
                $max_order_number = $max[0]['order_number_max'];
                $min_order_number = $min[0]['order_number_min'];
```

## おわりに
もっとスッキリまとまった書き方があると思うのですが、
どのように考えて記述したか記録しておくために書きました。
これからに役立てていきたいです。