Help us understand the problem. What is going on with this article?

CakePHP3で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 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 の更新が行えるようになりました:clap:

kshiva1126
都内でプログラマ3年目として働いています。 業務で使用している言語はPHPとたまにJSです。 勉強の中で気づいたことや共有したいことを書いていこうと思っています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away