ブログチュートリアル Part.1

CakePHP4のブログチュートリアルを進める。 book.cakephp.org

インストール

Composerでローカルにインストールする。

composer self-update && composer create-project --prefer-dist cakephp/app:4.* blog

初期設定

tmpとlogsディレクトリのパーミッションを変更する。

chown -R www-data tmp
chown -R www-data logs

データベースの設定を行う。今回はSQLiteを使用する。 Aritclesテーブルを作成するために下記SQLを実行。

sqlite> CREATE TABLE articles (
   ...>     id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
   ...>     title VARCHAR(50),
   ...>     body TEXT,
   ...>     created DATETIME DEFAULT NULL,
   ...>     modified DATETIME DEFAULT NULL
   ...> );
sqlite>
sqlite> ;

config/app.php にデータベースの設定を追加する。

<?php
'Datasources' => [
    'default' => [
        'driver' => Sqlite::class,
        'database' => ROOT . DS . 'db',
    ],
]

Article モデルの作成

モデルクラスを作成します。 モデルクラスは、データベースと直接やりとりを行う場所で、基本的なCRUD操作の役割を担います。

下記コマンドでArticlesTable モデルを作成する。

bin/cake bake model Articles

Articles コントローラーの作成

コントローラーを作成します。 コントローラーは、処理対象を操作するロジック全てが発生する場所で、モデルクラスに命令を与えるのもコントローラーの役割です。

下記コマンドでArticlesController クラスを作成する。

bin/cake bake controller Articles

Article ビューの作成

ビューを作成します。 ビューは、クライアントへ表示する画面の構成を担います。 コントローラーからセットされたビュー変数で画面をレンダリングします。

下記コマンドでArticle ビューを作成する。

bin/cake bake template all Articles

データのバリデーション

デフォルトのバリデーションロジックを ArticlesTable クラスに実装します。

<?php
namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\Validation\Validator;

class ArticlesTable extends Table
{
    public function initialize(array $config): void
    {
        $this->addBehavior('Timestamp');
    }

    public function validationDefault(Validator $validator): Validator
    {
        $validator
            ->notEmptyString('title')
            ->requirePresence('title', 'create')
            ->notEmptyString('body')
            ->requirePresence('body', 'create');

        return $validator;
    }
}

ルーティング

config/routes.php を修正し、トップ画面にArticlesのindexページを表示するように修正します。

<?php
$builder->connect('/', ['controller' => 'Articles', 'action' => 'index']);

ツリーカテゴリーの作成

投稿記事をカテゴリ作成のために Tree behavior を使用します。

Migrations プラグイン

migrations プラグイン をインストールするため、下記コマンドを実行します。

composer require cakephp/migrations:~1.0

articles テーブルを作成するマイグレーションファイルを作成します。 下記コマンドでマイグレーションファイルを生成します。

bin/cake bake migration CreateArticles title:string body:text category_id:integer created modified

次に、categories テーブルのマイグレーションファイルを作成します。 下記コマンドでマイグレーションファイルを生成します。

bin/cake bake migration CreateCategories parent_id:integer lft:integer[10] rght:integer[10] name:string[100] description:string created modified

最後に、マイグレーションコマンドを実行し、データベース内にテーブルを作成します。

bin/cake migrations migrate

テーブルの編集

Articles と Categories テーブルとを結びつけるため、ArticlesTable に下記のようにアソシエーションの設定を追加します。

<?php
$this->addBehavior('Timestamp');
// Just add the belongsTo relation with CategoriesTable
$this->belongsTo('Categories', [
    'foreignKey' => 'category_id',
]);

Categories のスケルトンコードを作成する

bake コマンドで、Categoriesのコードを作成します。

bin/cake bake model Categories
bin/cake bake controller Categories
bin/cake bake template Categories

templateのカテゴリのオプションの修正を行います。

<?php
echo $this->Form->control('parent_id', [
    'options' => $parentCategories,
    'empty' => 'No parent category'
]);

CategoriesController.php のindexアクションを編集して、ツリーでカテゴリーを並べ替えるために moveUp() および moveDown() メソッドを追加する。

<?php
class CategoriesController extends AppController
{
    public function index()
    {
        $categories = $this->Categories->find()
            ->order(['lft' => 'ASC'])
            ->all();
        $this->set(compact('categories'));
        $this->viewBuilder()->setOption('serialize', ['categories']);
    }

    public function moveUp($id = null)
    {
        $this->request->allowMethod(['post', 'put']);
        $category = $this->Categories->get($id);
        if ($this->Categories->moveUp($category)) {
            $this->Flash->success('The category has been moved Up.');
        } else {
            $this->Flash->error('The category could not be moved up. Please, try again.');
        }
        return $this->redirect($this->referer(['action' => 'index']));
    }

    public function moveDown($id = null)
    {
        $this->request->allowMethod(['post', 'put']);
        $category = $this->Categories->get($id);
        if ($this->Categories->moveDown($category)) {
            $this->Flash->success('The category has been moved down.');
        } else {
            $this->Flash->error('The category could not be moved down. Please, try again.');
        }
        return $this->redirect($this->referer(['action' => 'index']));
    }
}

templates/Categories/index.php を下記のように変更する。

<?php
<div class="actions large-2 medium-3 columns">
    <h3><?= __('Actions') ?></h3>
    <ul class="side-nav">
        <li><?= $this->Html->link(__('New Category'), ['action' => 'add']) ?></li>
    </ul>
</div>
<div class="categories index large-10 medium-9 columns">
    <table cellpadding="0" cellspacing="0">
    <thead>
        <tr>
            <th>Id</th>
            <th>Parent Id</th>
            <th>Lft</th>
            <th>Rght</th>
            <th>Name</th>
            <th>Description</th>
            <th>Created</th>
            <th class="actions"><?= __('Actions') ?></th>
        </tr>
    </thead>
    <tbody>
    <?php foreach ($categories as $category): ?>
        <tr>
            <td><?= $category->id ?></td>
            <td><?= $category->parent_id ?></td>
            <td><?= $category->lft ?></td>
            <td><?= $category->rght ?></td>
            <td><?= h($category->name) ?></td>
            <td><?= h($category->description) ?></td>
            <td><?= h($category->created) ?></td>
            <td class="actions">
                <?= $this->Html->link(__('View'), ['action' => 'view', $category->id]) ?>
                <?= $this->Html->link(__('Edit'), ['action' => 'edit', $category->id]) ?>
                <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $category->id], ['confirm' => __('Are you sure you want to delete # {0}?', $category->id)]) ?>
                <?= $this->Form->postLink(__('Move down'), ['action' => 'moveDown', $category->id], ['confirm' => __('Are you sure you want to move down # {0}?', $category->id)]) ?>
                <?= $this->Form->postLink(__('Move up'), ['action' => 'moveUp', $category->id], ['confirm' => __('Are you sure you want to move up # {0}?', $category->id)]) ?>
            </td>
        </tr>
    <?php endforeach; ?>
    </tbody>
    </table>
</div>

こちらで、/yoursite/categories/add へアクセスすることで、カテゴリー一覧に遷移することでできる。