CakePHPでTodoアプリケーション

CakePHP3でTODOアプリを作ってみます

作ったもの: https://github.com/kshiva1126/cakephp3_todo.git

setup

Gitクローンからコンテナの立ち上げまで

$ git clone https://github.com/kshiva1126/cakephp3_docker.git
$ cd cakephp3_docker
$ docker-compose build
$ docker-compose up -d
$ docker-compose exec app composer install

Databaseの設定

config/app.php の下記4項目を修正します

    'Datasources' => [
        'default' => [
            ...
            'host' => 'db',
            'username' => 'user',
            'password' => 'password',
            'database' => 'cake_db',
            ...
        ]
    ]

http://localhost:3000 でページが確認できます

migration

下記コマンドでマイグレーションファイルを生成します

config/Migrations/ に出力されます

bin/cake bake migration CreateTasks name:string d
bin/cake bake migration CreateTasks name:string decription:text done:boolean created modified

ちなみに bin/cake migrations create でも作成できるらしいけど今回はスキップ

<?php
use Migrations\AbstractMigration;

class CreateTasks extends AbstractMigration
{
    public function change()
    {
        $table = $this->table('tasks');
        $table->addColumn('name', 'string', [
            'default' => null,
            'limit' => 255,
            'null' => false,
        ]);
        $table->addColumn('decription', 'text', [
            'default' => null,
            'null' => false,
        ]);
        $table->addColumn('done', 'boolean', [
            'default' => false, // nullからfalseに変更した
            'null' => false,
        ]);
        $table->addColumn('created', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->addColumn('modified', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->create();
    }
}

マイグレートします

bin/cake migrations migrate
mysql> desc tasks;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255) | NO   |     | NULL    |                |
| decription | text         | NO   |     | NULL    |                |
| done       | tinyint(1)   | NO   |     | 0       |                |
| created    | datetime     | NO   |     | NULL    |                |
| modified   | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

マイグレーションファイルにはなかった id は自動的に追加されるようです

bake

CakePHPといえば、 bake ですね!!!

bake にはたくさんのサブコマンドがありますが、今回は all を利用してMVCすべてのスケルトンを生成します

先程作成した tasks を指定します

bin/cake bake all tasks

ここで http://localhost:3000/tasks にアクセスしてみます

tasks_top.png

もうそれっぽい画面が表示されました

左カラムの New Task から追加画面にいけます

tasks_add.png

追加後です

tasks_top_added.png

customize

このまま終了だとかなり味気ないので、ちょっとしたカスタマイズを加えます

現状、Done を 更新するためには編集画面で行うしかありません

tasks_edit.png

これを、TOP画面からでも更新できるようにします

まずViewを編集します

Done を Checkbox で表示させます

参考: https://book.cakephp.org/3/ja/views/helpers/form.html#checkbox-radio-select-options

src/Template/Tasks/index.ctp

<tbody>
    <?php foreach ($tasks as $task): ?>
    <tr>
        <td><?= $this->Number->format($task->id) ?></td>
        <td><?= h($task->name) ?></td>
        <!-- <td><?= h($task->done) ?></td> -->
        <!-- Checkboxで表示させるように修正 -->
        <td><?= $this->Form->checkbox('done', [
            'value' => h($task->done),
            'checked' => h($task->done),
            'data-id' => $this->Number->format($task->id),
            'hiddenField' => false,
        ]) ?></td>
        <td><?= h($task->created) ?></td>
        <td><?= h($task->modified) ?></td>
        .. 省略 ..
</tbody>

jQueryのAjaxを使いたいので、CDNで読み込ませます

src/Template/Layout/default.ctp

<head>
    <?= $this->Html->charset() ?>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        <?= $cakeDescription ?>:
        <?= $this->fetch('title') ?>
    </title>
    .. 省略 ..

    <!-- jQuery読み込み -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>

Done を更新するためにAjaxでPOSTする処理を追加します

src/Template/Tasks/index.ctp

<script>
$(function () {
    const csrfToken = <?= json_encode($this->request->getParam("_csrfToken")) ?>;
    $("input[name='done']").on("change", function (event) {
        const data = {
            id: $(this).data('id'),
            done: $(this).prop('checked') ? 1 : 0,
        };
        $.ajax({
            type: 'POST',
            dataType: "json",
            url: '/tasks/changeDone',
            headers: {
                'X-CSRF-Token': csrfToken
            },
            data,
        })
        .fail(function (err) {
            console.log(err)
        });
    });
});
</script>

Controllerに更新処理を追加します

TasksController に新たに changeDone() メソッドを追加することで /tasks/changeDone でアクセスできるようになります

src/Controller/TasksController

public function changeDone()
{
    // postのみ許可する
    $this->request->allowMethod('post');
    $id = (int) $this->request->getData('id');
    $done = (int) $this->request->getData('done');

    // idに合致するTaskを取得
    $task = $this->Tasks->get($id);
    $task->done = $done;
    $this->Tasks->save($task);

    exit;
}

(CakePHP的にこの書き方で正しいのかはわからない… (特に最後の exit; ))

これでTOP画面からDone の更新が行えるようになりました

参考記事

cakephp3 ブログチュートリアル解説

CAKEPHP3でPhpSpreadsheet使う

CakePHP3環境構築入門 ~初心者がVSCodeでリモート上のCakePHPアプリをステップ実行できるようにするまで。~

CakePHP3でjsonを返すAPIをCakePHPの流儀に従って記述量少なく書きたい人生だった

CakePHP3 で SessionとCookie設定でブラウザ終了後もセッションを継続する方法