CakePHP を学ぶ最も良い方法はなにか作ってみることです。 簡単なコンテンツ管理アプリケーションから作ることを始めましょう。
このチュートリアルは簡単な CMS アプリケーションを作ります。 はじめに CakePHP のインストールを行い、データベースの作成、 そしてアプリケーションを素早く仕上げるための CakePHP が提供するツールを使います。
必要なもの:
データベースサーバー。このチュートリアルでは MySQL サーバーを使います。
データベースを作成するための SQL の知識が必要です。CakePHP は、それを前提としています。
MySQL を使用するとき、 PHP で pdo_mysql
が有効になっていることを確認してください。
基礎的な PHP の知識。
始める前に、最新の PHP バージョンであることを確認してください。
php -v
最低でも PHP 7.4 (CLI) 以上をインストールしてください。 あなたのウェブサーバーの PHP バージョンもまた、 7.4 以上でなければなりません。 そして、コマンドラインインターフェイス (CLI) の PHP バージョンと同じバージョンにしてください。
最も簡単な CakePHP のインストール方法は Composer を使う方法です。Composer は、 ターミナルやコマンドラインプロンプトから CakePHP をインストールのシンプルな方法です。 まだ準備ができていない場合、最初に Composer のダウンロードとインストールが必要です。 cURL がインストールされていたら、次のように実行するのが簡単です。
curl -s https://getcomposer.org/installer | php
もしくは Composer のウェブサイト
から composer.phar
をダウンロードすることができます。
そして、インストールディレクトリーからターミナルに次の行を入力するだけで、現在の作業ディレクトリーの cms ディレクトリーに CakePHP アプリケーションのスケルトンをインストールすることができます。
php composer.phar create-project --prefer-dist cakephp/app:4.* cms
Composer Windows Installer をダウンロードして実行した場合、インストールディレクトリー (例えば、 C:\wamp\www\dev\cakephp3) からターミナルに次の行を入力してください。
composer self-update && composer create-project --prefer-dist cakephp/app:4.* cms
Composer を使うメリットは、 正しいファイルパーミッションの設定や、 config/app.php ファイルの作成などのように、自動的に完全なセットアップをしてくれることです。
CakePHP をインストールする他の方法があります。 Composer を使いたくない場合、 インストール セクションをご覧ください。
CakePHP のダウンロードやインストール方法にかかわらず、いったんセットアップが完了すると、 ディレクトリー構成は次のようになります。
/cms
/bin
/config
/logs
/plugins
/src
/tests
/tmp
/vendor
/webroot
.editorconfig
.gitignore
.htaccess
.travis.yml
composer.json
index.php
phpunit.xml.dist
README.md
CakePHP のディレクトリー構造がどのように働くかを学ぶのにいい機会かもしれません。 CakePHP のフォルダー構成 セクションをご覧ください。
このチュートリアルで迷ったら、 GitHub で完成した結果を見ることができます。
デフォルトホームページを確認することで、インストールが正しいことをざっと確かめることができます。 その前に、開発用サーバーを起動する必要があります。
cd /path/to/our/app
bin/cake server
注釈
Windows では、このコマンドは bin\cake server
(バックスラッシュ) です。
これで、 8765 ポートで PHP のビルトインウェブサーバーが起動します。ウェルカムページを見るために http://localhost:8765 をウェブブラウザーで開いてください。CakePHP がデータベース接続が 可能かどうか以外は、すべての確認事項が緑色のコック帽になるべきです。そうでなければ、PHP 拡張の 追加のインストールやディレクトリーのパーミッション設定が必要かもしれません。
次に、 データベースの構築と最初のモデルの作成 をします。
先ほどは CakePHP をインストールしましたので、 CMS
アプリケーションのためのデータベースをセットアップしましょう。まだセットアップしていない場合、
例えば cake_cms
のように、あなたの好きな名前で、このチュートリアルで使用する空のデータベースを
作成してください。必要なテーブルを作成するために、以下の SQL を実行することができます。
USE cake_cms;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
created DATETIME,
modified DATETIME
);
CREATE TABLE articles (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
slug VARCHAR(191) NOT NULL,
body TEXT,
published BOOLEAN DEFAULT FALSE,
created DATETIME,
modified DATETIME,
UNIQUE KEY (slug),
FOREIGN KEY user_key (user_id) REFERENCES users(id)
) CHARSET=utf8mb4;
CREATE TABLE tags (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(191),
created DATETIME,
modified DATETIME,
UNIQUE KEY (title)
) CHARSET=utf8mb4;
CREATE TABLE articles_tags (
article_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (article_id, tag_id),
FOREIGN KEY tag_key(tag_id) REFERENCES tags(id),
FOREIGN KEY article_key(article_id) REFERENCES articles(id)
);
INSERT INTO users (email, password, created, modified)
VALUES
('[email protected]', 'secret', NOW(), NOW());
INSERT INTO articles (user_id, title, slug, body, published, created, modified)
VALUES
(1, 'First Post', 'first-post', 'This is the first post.', 1, now(), now());
複合主キーを持つ articles_tags
テーブルにお気づきでしょうか。CakePHP は、
ほぼどこでも複合主キーをサポートしているので、追加の id
カラムを必要としない
単純なスキーマを持つことができます。
私たちが使用するテーブルやカラムの名前は恣意的ではありませんでした。CakePHP の 命名規則 を使用することによって、CakePHP がより効果的になり、 フレームワークの設定を避けられます。CakePHP は、ほぼ全てのデータベーススキーマに対応できるくらい 十分に柔軟ですが、CakePHP がデフォルトで提供する規約に従うことで、時間を節約できます。
次に、どこにデータベースあるか、そしてどうやってデータベースに接続するかを CakePHP
に伝えましょう。あなたのセットアップを適用するために config/app.php
ファイルの中の Datasources.default
配列の値を置き換えてください。
完全な設定配列の例は、以下のようになります。
<?php
return [
// 上には他の設定があります
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'cakephp',
'password' => 'AngelF00dC4k3~',
'database' => 'cake_cms',
'encoding' => 'utf8mb4',
'timezone' => 'UTC',
'cacheMetadata' => true,
],
],
// 下には他の設定があります
];
一度 config/app.php ファイルを保存して、 'CakePHP is able to connect to the database' が緑色のコック帽であることを確認してください。
注釈
app フォルダーに config/app_local.php がある場合、 app.php の設定を上書きします。
モデルは、CakePHP アプリケーションの心臓部です。データを読んだり変更することができます。 それらは、データ間のリレーションの構築、データの検証、アプリケーションルールの適用をすることができます。 モデルは、コントローラーアクションとテンプレートを構築するために必要な基礎を構築します。
CakePHP のモデルは Table
と Entity
オブジェクトで構成されています。 Table
オブジェクトは、指定されたテーブルの中に保存されたエンティティーの集合へのアクセスを提供します。
それらは src/Model/Table の中に保存されます。私たちが今から作成するファイルは、
src/Model/Table/ArticlesTable.php に保存されます。完成したファイルは次のようになります。
<?php
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public function initialize(array $config) : void
{
$this->addBehavior('Timestamp');
}
}
このテーブルの created
や modified
カラムを自動的に更新する
Timestamp ビヘイビアーを追加しました。
Table オブジェクトを ArticlesTable
と名付けることで、CakePHP は、命名規則により
articles
テーブルを使用するモデルであると解釈します。また、CakePHP は、
id
カラムがテーブルの主キーであると解釈する規約を使用します。
注釈
もし一致するファイルが src/Model/Table に見つけられなければ、CakePHP は動的に モデルオブジェクトを生成します。これはまた、不意に間違ったファイル名 (例えば、 articlestable.php や ArticleTable.php) をつけると、CakePHP はどの設定も認識できず、 代わりに生成されたモデルを使うことになるということも意味します。
また、Articles のための Entity クラスも作成します。エンティティーは、 データベースの1つのレコードを表し、データに対して行レベルの振る舞いを提供します。 このエンティティーは、 src/Model/Entity/Article.php に保存されます。 完成したファイルは、次のようになります。
<?php
// src/Model/Entity/Article.php
namespace App\Model\Entity;
use Cake\ORM\Entity;
class Article extends Entity
{
protected $_accessible = [
'*' => true,
'id' => false,
'slug' => false,
];
}
エンティティーは、今はとてもスリムです。そして、 一括代入 (Mass Assignment) によって
どのようにプロパティーを変更できるかを制御するプロパティー _accessible
をセットアップしました。
このモデルは、今は動きませんが、次は最初の コントローラーとテンプレート を作成し、このモデルとのやりとりができるようにします。
モデルが作成できたので、記事のコントローラーが必要です。CakePHP のコントローラーは、 レスポンスを準備するために、HTTP リクエストを処理し、モデルのメソッドに含まれるビジネスロジックを 実行します。この新しいコントローラーは src/Controller ディレクトリーの中で ArticlesController.php と呼ばれるファイルに記述します。 基本的なコントローラーの外観は次の通りです。
<?php
// src/Controller/ArticlesController.php
namespace App\Controller;
class ArticlesController extends AppController
{
}
それでは、コントローラーにアクションを追加しましょう。アクションは、ルートに接続させる
コントローラーのメソッドです。例えば、ユーザーが www.example.com/articles/index
(www.example.com/articles と同じ) をリクエストした場合、CakePHP は、
ArticlesController
の index
メソッドを呼びます。このメソッドは、モデル層に問い合わせ、
ビューでテンプレートを描画してレスポンスを準備する必要があります。そのアクションのコードは、
次のようになります。
<?php
// src/Controller/ArticlesController.php
namespace App\Controller;
class ArticlesController extends AppController
{
public function index()
{
$this->loadComponent('Paginator');
$articles = $this->Paginator->paginate($this->Articles->find());
$this->set(compact('articles'));
}
}
ArticlesController
の index()
メソッドを定義することで、ユーザーは、
www.example.com/articles/index をリクエストすることで、そこにあるロジックに
アクセスできるようになります。同様に、 foobar()
というメソッドを定義した場合、
ユーザーはそのメソッドに www.example.com/articles/foobar で、アクセスできます。
特定の URL を取得できるように、コントローラーとアクションの名前を付けたいという
誘惑に駆られるかもしれません。その誘惑に抗ってください。代わりに、 CakePHP の規約
にしたがって、読みやすく意味のあるアクション名を作成してください。そうすれば
ルーティング を使って、あなたが望む URL を、
あなたが作成したアクションに接続することができます。
このコントローラーのアクションはとてもシンプルです。
これは、命名規則によって自動的にロードされる Articles モデルを使用して、
データベースからページ分けされた記事を取得します。次に (これからすぐに作成する)
テンプレートの中に記事を渡すために set()
を使用します。CakePHP は、
コントローラーのアクションが完了した後、自動的にテンプレートを描画します。
モデルからデータを取得し、ビューのコンテキストを準備するコントローラーを持っていますので、 index アクションのビューテンプレートを作成しましょう。
CakePHP のビューテンプレートは、アプリケーションのレイアウト内に挿入される表示用の PHP コードです。 ここで HTML が作成されますが、 View は JSON、CSV、または PDF などのバイナリファイルの生成もできます。
レイアウトは、ビューを囲む表示用のコードです。レイアウトファイルは、 ヘッダー・フッター・ナビゲーション要素のような一般的なサイトの要素が含まれます。 アプリケーションは、複数のレイアウトを持つことができ、それらを切り替えることができますが、 今回はデフォルトのレイアウトを使用しましょう。
CakePHP のテンプレートファイルは、 templates の中で 対応するコントローラーの名前をつけたフォルダーの中に保存されます。 今回の場合、 'Articles' という名前のフォルダーを作成する必要があります。 あなたのアプリケーションに以下のコードを追加してください。
<!-- File: templates/Articles/index.php -->
<h1>記事一覧</h1>
<table>
<tr>
<th>タイトル</th>
<th>作成日時</th>
</tr>
<!-- ここで、$articles クエリーオブジェクトを繰り返して、記事の情報を出力します -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
前のセクションでは、 set()
を使って 'articles' 変数をビューに割り当てました。
ビューに渡された変数は、上記のコードの中で使用したローカル変数として、
ビューテンプレートの中で利用できます。
$this->Html
というオブジェクトを使っていることにお気づきでしょうか。
これは、 CakePHP の HtmlHelper のインスタンスです。
CakePHP には、リンク、フォーム、ページ制御ボタンの作成などのタスクを簡単に行うための
一連のビューヘルパーが付属しています。 ヘルパー について、
その章で詳しく学べますが、ここで重要なことは、 link()
メソッドは、
与えられたリンクテキスト(第1パラメーター) と URL (第2パラメーター) を元に
HTML リンクを生成することです。
CakePHP で URL を指定する際、配列や 名前付きルート が 推奨されます。これらの構文で、CakePHP が提供するリバースルーティング機能を 活用することができます。
この時点で、ブラウザーで http://localhost:8765/articles/index を 見ることができるはずです。記事のタイトルとテーブルのリストで正しくフォーマットされた リストビューが表示されます。
記事一覧の 'view' リンクの一つをクリックした際、アクションが実装されてないという エラーページが表示されるはずです。今から、それを修正しましょう。
// 既存の src/Controller/ArticlesController.php ファイルに追加
public function view($slug = null)
{
$article = $this->Articles->findBySlug($slug)->firstOrFail();
$this->set(compact('article'));
}
これはシンプルなアクションですが、いくつかの強力な CakePHP 機能を使用しています。
動的なファインダー である findBySlug()
を使用することにより
アクションを開始します。このメソッドは、与えられたスラグによって記事を検索する基本的なクエリーを
作成することができます。その時、最初のレコードを取得するか NotFoundException
を投げるか
のいずれかをする firstOrFail()
を使います。
このアクションは $slug
パラメーターを持ちますが、そのパラメーターはどこから来るのでしょう?
ユーザーが /articles/view/first-post
をリクエストした際、 値 'first-post' が
CakePHP のルーティングとディスパッチレイヤーで $slug
に渡されます。
新しいアクションを保存してブラウザーをリロードすると、別の CakePHP エラーページが表示され、
view テンプレートが見つからないことがわかります。それを修正しましょう。
新しい 'view' アクションのビューを作成し、 templates/Articles/view.php に置きましょう。
<!-- File: templates/Articles/view.php -->
<h1><?= h($article->title) ?></h1>
<p><?= h($article->body) ?></p>
<p><small>作成日時: <?= $article->created->format(DATE_RFC850) ?></small></p>
<p><?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?></p>
/articles/index
のリンクを使うことによって、動作することを確認できますし、
/articles/view/slug-name
のような URL にアクセスすることによって手動で記事を
リクエストすることを確認できます。
基本的な読み込みビューを作成できたので、新しい記事を作成できるようにする必要があります。
まず、 ArticlesController
に add()
アクションを作成してください。
コントローラーは次のようになります。
// src/Controller/ArticlesController.php
namespace App\Controller;
use App\Controller\AppController;
class ArticlesController extends AppController
{
public function initialize(): void
{
parent::initialize();
$this->loadComponent('Paginator');
$this->loadComponent('Flash'); // FlashComponent をインクルード
}
public function index()
{
$articles = $this->Paginator->paginate($this->Articles->find());
$this->set(compact('articles'));
}
public function view($slug)
{
$article = $this->Articles->findBySlug($slug)->firstOrFail();
$this->set(compact('article'));
}
public function add()
{
$article = $this->Articles->newEmptyEntity();
if ($this->request->is('post')) {
$article = $this->Articles->patchEntity($article, $this->request->getData());
// user_id の決め打ちは一時的なもので、あとで認証を構築する際に削除されます。
$article->user_id = 1;
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to add your article.'));
}
$this->set('article', $article);
}
}
注釈
フラッシュ コンポーネントを、使用するコントローラーに含める
必要があります。また、 AppController
に含めてもよいでしょう。
こちらがこの add()
アクションの行うことです。
リクエストの HTTP メソッドが POST だった場合、Articles モデルを使用してデータを保存しようとします。
なんらかの理由で保存しなかった場合、ただビューを描画します。これは、ユーザーバリデーションエラーや その他の警告を表示する機会を与えてくれます。
全ての CakePHP のリクエストは、 $this->request
を使用してアクセス可能なリクエストオブジェクトを
含みます。リクエストオブジェクトは、今受信したリクエストに関する情報を含みます。リクエストが HTTP POST
リクエストであることを確認するために Cake\Http\ServerRequest::is()
メソッドを
使用します。
POST データは、 $this->request->getData()
で利用可能です。それがどのような内容かを
知りたい場合に pr()
関数や debug()
関数を使って出力することができます。
データを保存するために、まず POST データを Article エンティティーに 「変換 (marshal)」します。
エンティティーは、以前作成した ArticlesTable を使用して永続化されます。
新しい記事を保存した後、セッションにメッセージをセットするために FlashComponent の
success()
メソッドを使用します。 success
メソッドは PHP の
マジックメソッド機能
を使用して提供されます。フラッシュメッセージは、リダイレクトした後の次のページ上で表示されます。
レイアウトの中に、フラッシュメッセージを表示し、対応するセッション変数をクリアする
<?= $this->Flash->render() ?>
があります。最後に、保存が完了した後、
Cake\Controller\Controller::redirect
を使ってユーザーを記事一覧に戻します。
パラメーター ['action' => 'index']
は、例えば ArticlesController
の index
アクションの場合、 URL /articles
に変換します。 API の
Cake\Routing\Router::url()
関数を参照すると、様々な CakePHP 関数の URL を
指定できる書式を見ることができます。
こちらが add ビューテンプレートです。
<!-- File: templates/Articles/add.php -->
<h1>記事の追加</h1>
<?php
echo $this->Form->create($article);
// 今はユーザーを直接記述
echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => 1]);
echo $this->Form->control('title');
echo $this->Form->control('body', ['rows' => '3']);
echo $this->Form->button(__('Save Article'));
echo $this->Form->end();
?>
FormHelper を使うと、 HTML フォームの開始タグを生成できます。
こちらが $this->Form->create()
が生成する HTML です。
<form method="post" action="/articles/add">
URL オプションなしで create()
を呼び出したので、 FormHelper
は、フォームを
現在のアクションに戻したいと仮定します。
$this->Form->control()
メソッドは、同じ名前のフォーム要素を作成するために使われます。
1番目のパラメーターは、どのフィールドに対応するかを CakePHP に伝えます。そして、2番目の
パラメーターは、さまざまなオプションを指定できます。上記の場合、テキストエリアの行数などです。
ここではちょっとした内部情報の確認 (introspection) と規約の使用があります。
control()
は、指定されたモデルフィールドにもとづいて異なるフォーム要素を出力し、
語形変化 (inflection) を使ってラベルを生成します。オプションを使用して、
フォームコントロールのラベル、入力、または、その他の要素をカスタマイズすることができます。
$this->Form->end()
の呼び出しでフォームを閉じます。
さて、 templates/Articles/index.php ビューを更新して、新しい
「記事の追加」リンクを追加しましょう。 <table>
の前に以下の行を追加してください。
<?= $this->Html->link('記事の追加', ['action' => 'add']) ?>
記事を今保存すると、スラグ属性は、作成されておらず、カラムは NOT NULL
なので保存に失敗します。
スラグの値は、通常、URL セーフなバージョンの記事タイトルです。スラグを作成するために ORM の
beforeSave() コールバック が使用できます。
<?php
// src/Model/Table/ArticlesTable.php の中で
namespace App\Model\Table;
use Cake\ORM\Table;
// Text クラス
use Cake\Utility\Text;
// EventInterface クラス
use Cake\Event\EventInterface;
// 次のメソッドを追加してください。
public function beforeSave(EventInterface $event, $entity, $options)
{
if ($entity->isNew() && !$entity->slug) {
$sluggedTitle = Text::slug($entity->title);
// スラグをスキーマで定義されている最大長に調整
$entity->slug = substr($sluggedTitle, 0, 191);
}
}
このコードはシンプルで、重複したスラグを考慮していません。しかし、後でそれを修正します。
今のアプリケーションは、記事を保存できますが編集はできません。今から修正しましょう。
ArticlesController
に次のアクションを追加してください。
// src/Controller/ArticlesController.php の中で
// 次のメソッドを追加してください。
public function edit($slug)
{
$article = $this->Articles->findBySlug($slug)->firstOrFail();
if ($this->request->is(['post', 'put'])) {
$this->Articles->patchEntity($article, $this->request->getData());
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been updated.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to update your article.'));
}
$this->set('article', $article);
}
このアクションは、まずユーザーが既存のレコードにアクセスすることを確保します。
$slug
パラメーターの中に渡されなかったり、記事が存在しなかった場合、
NotFoundException
が投げられ、 CakePHP の ErrorHandler が、適切なエラーページを
描画します。
次に、このアクションはリクエストが POST または PUT いずれかのリクエストかどうかをチェックします。
そうであれば、POST/PUT データを元に、 patchEntity()
メソッドを使って
article エンティティーを更新します。最後に、 save()
を呼び出して、
適切なフラッシュメッセージを設定し、リダイレクトするか検証エラーを表示します。
edit テンプレートは次のようになります。
<!-- File: templates/Articles/edit.php -->
<h1>記事の編集</h1>
<?php
echo $this->Form->create($article);
echo $this->Form->control('user_id', ['type' => 'hidden']);
echo $this->Form->control('title');
echo $this->Form->control('body', ['rows' => '3']);
echo $this->Form->button(__('Save Article'));
echo $this->Form->end();
?>
このテンプレートは、編集フォーム(値が入力された状態)に加えて、 必要な検証エラーメッセージを出力します。
特定の記事を編集するためのリンクで index ビューを更新できるようになりました。
<!-- File: templates/Articles/index.php (編集リンク付き) -->
<h1>記事一覧</h1>
<p><?= $this->Html->link("記事の追加", ['action' => 'add']) ?></p>
<table>
<tr>
<th>タイトル</th>
<th>作成日時</th>
<th>操作</th>
</tr>
<!-- ここで、$articles クエリーオブジェクトを繰り返して、記事情報を出力します -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Html->link('編集', ['action' => 'edit', $article->slug]) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
この時点まで、記事は入力検証が行われていませんでした。 バリデーター を使って修正しましょう。
// src/Model/Table/ArticlesTable.php
// この use 文を名前空間宣言のすぐ下に追加して、
// Validator クラスをインポートします。
use Cake\Validation\Validator;
// 次のメソッドを追加してください。
public function validationDefault(Validator $validator): Validator
{
$validator
->notEmptyString('title')
->minLength('title', 10)
->maxLength('title', 255)
->notEmptyString('body')
->minLength('body', 10);
return $validator;
}
validationDefault()
メソッドは、 save()
メソッドが呼ばれる際のデータの検証方法を
CakePHP に伝えます。ここでは、title フィールドと body フィールドの両方が空であってはならず、
長さに制約があることを指定しました。
CakePHP の検証エンジンは強力で柔軟性があります。メールアドレス、IP アドレスなどのようにタスクに 頻繁に使用されるルール一式を提供し、独自の検証ルールを追加する柔軟性を提供します。 その設定の詳細については、 バリデーション のドキュメントを確認してください。
さて、検証ルールが整いましたので、
それがどのように動くかを見るためにアプリを使って空のタイトルや本文で記事を追加してみてください。
FormHelper の Cake\View\Helper\FormHelper::control()
メソッドを使用して、
フォーム要素を作成しているので、検証エラーメッセージが自動的に表示されます。
次に、ユーザーが記事を削除する方法を作ってみましょう。
ArticlesController
の中の delete()
アクションから始めましょう。
// src/Controller/ArticlesController.php
// 次のメソッドを追加してください。
public function delete($slug)
{
$this->request->allowMethod(['post', 'delete']);
$article = $this->Articles->findBySlug($slug)->firstOrFail();
if ($this->Articles->delete($article)) {
$this->Flash->success(__('The {0} article has been deleted.', $article->title));
return $this->redirect(['action' => 'index']);
}
}
このロジックは $slug
で指定された記事を削除し、 $this->Flash->success()
を使って
/articles
にリダイレクトした後に確認メッセージを表示します。
ユーザーが GET リクエストを使って記事を削除しようとすると、 allowMethod()
は例外をスローします。
キャッチされない例外は CakePHP の例外ハンドラによって捕捉され、素晴らしいエラーページが表示されます。
アプリケーションで生成する必要のあるさまざまな HTTP エラーを示すために使用できる組み込みの
例外 が多数あります。
警告
ウェブクローラーが誤ってすべてのコンテンツを削除する可能性があるため、
GET リクエストを使用してコンテンツを削除することは とても 危険です。
それでコントローラーの中で allowMethod()
を使ったのです。
私たちはロジックを実行して、別のアクションにリダイレクトしているだけなので、 このアクションにはテンプレートはありません。ユーザーが記事を削除できるリンク付きに index テンプレートを更新するといいでしょう。
<!-- File: templates/Articles/index.php (削除リンク付き) -->
<h1>記事一覧</h1>
<p><?= $this->Html->link("記事の追加", ['action' => 'add']) ?></p>
<table>
<tr>
<th>タイトル</th>
<th>作成日時</th>
<th>操作</th>
</tr>
<!-- ここで、$articles クエリーオブジェクトを繰り返して、記事情報を出力します -->
<?php foreach ($articles as $article): ?>
<tr>
<td>
<?= $this->Html->link($article->title, ['action' => 'view', $article->slug]) ?>
</td>
<td>
<?= $article->created->format(DATE_RFC850) ?>
</td>
<td>
<?= $this->Html->link('編集', ['action' => 'edit', $article->slug]) ?>
<?= $this->Form->postLink(
'削除',
['action' => 'delete', $article->slug],
['confirm' => 'よろしいですか?'])
?>
</td>
</tr>
<?php endforeach; ?>
</table>
postLink()
を使用すると、
JavaScript を使用して記事を削除する POST リクエストを行うリンクが作成されます。
注釈
また、このビューコードは FormHelper
を使って記事を削除しようとする前に
JavaScript の確認ダイアログを表示します。
基本的な記事管理のセットアップの後は、 タグとユーザーテーブルの基本的な操作 を作成します。