入門

CakePHPフレームワークはアプリケーションの堅牢な基礎を提供します。 これは最初のユーザのリクエスト全てから最後のWEBページのレンダリングまで、全面的に取り扱います。 またフレームワークがMVCの原則に従うことから、アプリケーションのほとんどの側面に於いてカスタマイズ・拡張が簡単にできるようになります。

このフレームワークはファイル名からデータベースのテーブル名まで、基礎的な組織構造も提供し、アプリケーション全体を矛盾無く論理的に保ちます。 この概念は単純ですが強力です。 規約に従うことで、どこに何があるのか、それらがどのように組織化されているのかを、いつも確実に把握できるのです。

CakePHPを体験し学ぶ最良の方法は腰を据えて何かを作ることです。 手始めに、単純なブログアプリケーションを構築します。

ブログチュートリアル

Cakeをさっそく使ってみましょう。 このチュートリアルを読んでいるのは、Cakeの動作に関してさらに学びたいと思っているからだと思います。 私たちは、生産性を高め、コーディングがさらに楽しいものになることを目指しています。 コードを調べているうちに、きっとあなたもそのことに気が付くでしょう。

このチュートリアルでは、シンプルなブログアプリケーションを作成します。 Cakeを取得してインストールし、データベースの設定を行い、ブログの投稿記事の一覧表示(list)、追加(add)、編集(edit)、削除(delete)などのアプリケーションロジックを作成します。

必要なもの:

  1. 動作しているWebサーバ。 Apacheを使っているという前提で書いてありますが、他の種類のサーバを使用する場合でも、ほぼ同じにいけるはずです。 サーバの設定を少し変える必要があるかもしれませんが、たいていの人は、そのままの設定でCakeを動作させることが可能です。 PHP 5.2.8以上が動作していることを確認してください。
  2. データベースサーバ。 このチュートリアルでMySQLを使用します。 データベースを作成できる程度のSQLの知識が必要です。 その先はCakeが面倒をみてくれます。 MySQLを使用するので、PHPで pdo_mysql が有効になっていることを確認してください。
  3. PHPの基本的な知識。 オブジェクト指向プログラミングに慣れていれば非常に有利ですが、手続き型に慣れているという人でも心配する必要はありません。
  4. 最後に、MVCプログラミングに関する基本的な知識が必要です。 概要については、 MVC(Model-View-Controller)を理解する を見てください。 半ページぐらいの説明ですので、心配はご無用です。

それでは、はじめましょう!

Cakeのダウンロード

まずは、最新のCakeのコードをダウンロードしてきましょう。

最新のCakeをダウンロードするには、GitHubにあるCakePHPプロジェクトを見てみましょう: https://github.com/cakephp/cakephp/tags そして、2.0の最新リリースをダウンロードします。

または、 git を使ってレポジトリをcloneすることもできます。 git clone git://github.com/cakephp/cakephp.git

どちらにしても、ダウンロードしたコードをDocumentRoot内に配置してください。 そうすると、ディレクトリは次のようになります:

/path_to_document_root
    /app
    /lib
    /plugins
    /vendors
    .htaccess
    index.php
    README

Cakeのディレクトリ構造について少し学んでおきましょう: CakePHPのフォルダ構造 のセクションをチェックしてください。

ブログデータベースの作成

次に、ブログで使用する基礎的なデータベースをセットアップしましょう。 データベースをまだ作成していないのであれば、このチュートリアル用に好きな名前で空のデータベースを作成しておいてください。 このページでは、投稿記事を保存するためのテーブルをひとつ作成します。 次のSQLをデータベースで実行してください。:

/* まず、postsテーブルを作成します: */
CREATE TABLE posts (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50),
    body TEXT,
    created DATETIME DEFAULT NULL,
    modified DATETIME DEFAULT NULL
);

/* それから、テスト用に記事をいくつか入れておきます: */
INSERT INTO posts (title,body,created)
    VALUES ('タイトル', 'これは、記事の本文です。', NOW());
INSERT INTO posts (title,body,created)
    VALUES ('またタイトル', 'そこに本文が続きます。', NOW());
INSERT INTO posts (title,body,created)
    VALUES ('タイトルの逆襲', 'こりゃ本当にわくわくする!うそ。', NOW());

テーブル名とフィールド名は適当に選んだわけではありません。 Cakeのデータベース命名規約とクラスの命名規約に従っておくと、(どちらも、 CakePHPの規約 の中で説明されています)たくさんの機能を自由に使うことができ、設定作業をする必要がなくなります。 Cakeはフレキシブルなので、最悪な従来型のデータベーススキーマにも対応することができますが、規約に従えば、時間を節約することができます。

詳細は、 CakePHPの規約 を参照してください。 簡単に言うと、’posts’というテーブル名にしておけば、自動的にPostモデルが呼び出され、’modified’と’created’というフィールドがあると、自動的にCakeが管理するようになります。

Cakeのデータベース設定

どんどん進みましょう。 データベースがどこにあって、どうやって接続するかをCakeに教えます。 多くの人にとって、設定(configure)をする最初で最後の機会です。

CakePHPのデータベース設定ファイルの元は、 /app/Config/database.php.default の中にあります。 同一ディレクトリ上にこのファイルのコピーを作り、 database.php という名前にしてください。

この設定ファイルの中身は一目瞭然です。 $default 配列の値を自分のセットアップに合わせて変更するだけです。 完全な設定の配列の例は次のようなものになるでしょう:

public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'localhost',
    'port' => '',
    'login' => 'cakeBlog',
    'password' => 'c4k3-rUl3Z',
    'database' => 'cake_blog_tutorial',
    'schema' => '',
    'prefix' => '',
    'encoding' => 'utf8'
);

新しくできた database.php ファイルを保存したら、ブラウザをあけて、Cakeのwelcomeページを開いてください。 データベース接続のファイルがある、そしてデータベースに接続できる、というメッセージが表示されるはずです。

ノート

PDOとpdo_mysqlがphp.iniで有効になっている必要があることを覚えておいてください。

追加の設定

設定できる項目があと三つあります。 たいていの開発者はこれらの詳細なリストも仕上げますが、このチュートリアルに必要不可欠、というわけではありません。 ひとつは、セキュリティハッシュ用のカスタム文字列(「salt」ともいう)です。 二つ目は、独自の番号(「seed」ともいう)を暗号化用に定義するということです。 三つ目は、CakePHPが、 tmp フォルダに書き込めるようにすることです。

セキュリティ用のsaltは、ハッシュの生成に用いられます。 /app/Config/core.php の187行目を編集し、デフォルトのsalt値を変更してください。 すぐに推測できるような値でなければ、何であってもかまいません。:

/**
 * A random string used in security hashing methods.
 */
Configure::write('Security.salt', 'pl345e-P45s_7h3*S@l7!');

サイファシード(cipher seed)は暗号化・復号化のための文字列です。 シード値を /app/Config/core.php の192行目を編集してデフォルト値から変えてください。 すぐに推測できるような値でなければ、何であってもかまいません。:

/**
 * A random numeric string (digits only) used to encrypt/decrypt strings.
 */
Configure::write('Security.cipherSeed', '7485712659625147843639846751');

最後の作業は、 app/tmp ディレクトリをWebで書き込めるようにすることです。 いちばん良い方法は、Webサーバのユーザ名を調べて、(<?php echo `whoami`; ?>) app/tmp ディレクトリの所有権をそのユーザにすることです。 この最後の(*nixでの)コマンドは次のようなものです:

$ chown -R www-data app/tmp

何かの理由でCakePHPがそのディレクトリに書き込めない場合、警告が表示されます。 (運用モードでは表示されません。)

mod_rewriteについて

新しいユーザはmod_rewriteでつまずくことがよくあります。 例えばCakePHPのwelcomeページが少しおかしくなったりします(画像が表示されない、CSSが効いていない)。 これはおそらく、システム上のmod_rewriteが機能していないということです。 以下のいずれかの項目を参照して、URLリライティングが有効になるように設定してください。

はじめてのCakePHPアプリケーションを構築しはじめるには、続けて ブログチュートリアル - レイヤーの追加 を見てください。

ブログチュートリアル - レイヤーの追加

Postモデルの作成

モデルクラスは、CakePHPアプリケーションの基本中の基本(bread and butter)です。 CakePHPのモデルを作成することで、データベースとやりとりできるようになり、表示(view)、追加(add)、編集(edit)、削除(delete)といった操作に必要な土台を手に入れることになります。

CakePHPのモデルクラスのファイルは、 /app/Model の中にあり、今回は、 /app/Model/Post.php というファイルを作って保存します。 ファイルの中身全体は次のようになります:

class Post extends AppModel {
}

命名規約は、CakePHPでは非常に大切です。 モデルをPostという名前にすることで、CakePHPは自動的に、このモデルはPostsControllerで使用されるのだろう、と考えます。 また、 posts という名前のデータベーステーブルと結びつけられます。

ノート

もし一致するファイルが/app/Modelに見つけられなければ、CakePHPは動的にモデルオブジェクトを生成します。 これはまた、不意に間違ったファイル名(例えば、post.phpやposts.php)をつけると、CakePHPはどんな設定も認識できず、代わりにデフォルトのものを使うことになるということも意味します。

テーブルの接頭辞(prefix)や、コールバック、バリデーションといったモデルの詳細については、マニュアルの モデル の章を参照してください。

Postsコントローラの作成

次に、投稿記事(posts)に対するコントローラを作成します。 コントローラとは、投稿記事とやりとりするためのビジネスロジックが入るところです。 簡単に言うと、それは幾つかのモデルとやりとりし、投稿記事に関連する作業を行う場所です。 この新しいコントローラは、 PostsController.php という名前で、 /app/Controller ディレクトリの中に配置します。 基本的なコントローラは次のようになります:

class PostsController extends AppController {
    public $helpers = array('Html', 'Form');
}

では、コントローラにひとつのアクションを追加してみましょう。 アクションは、アプリケーションの中のひとつの関数か、インターフェイスをあらわしています。 例えば、ユーザが www.example.com/posts/index(www.example.com/posts/と同じです) をリクエストした場合、投稿記事の一覧が表示されると期待するでしょう。 このアクションのコードは次のようになります:

class PostsController extends AppController {
    public $helpers = array('Html', 'Form');

    public function index() {
        $this->set('posts', $this->Post->find('all'));
    }
}

PostsControllerの中に index() という関数を定義することによって、ユーザは、www.example.com/posts/indexというリクエストで、そのロジックにアクセスできるようになります。 同様に、 foobar() という関数を定義すると、ユーザは、www.example.com/posts/foobarでアクセスできるようになります。

警告

あるURLにさせたいために、コントローラ名とアクション名をそれに合わせて独自に命名したくなるかもしれませんが、その誘惑に抵抗してください。 CakePHPの規約(コントローラは複数形、など)に従って、読みやすく、理解しやすいアクション名を付けるようにしましょう。 あとで、「routes」という機能を使って、URLとコードを結びつけることができます。

アクションの中にあるひとつの指令が、 set() を使って、コントローラからビュー(次に作成します)にデータを渡しています。 この行は、Postモデルの find('all') メソッドから返ってきた値で、「posts」というビューの変数を設定します。 Postモデルは自動的に $this->Post として呼び出せるようになります。 これは、Cakeの命名規約に従っているからです。

Cakeのコントローラに関する詳細は、 コントローラ の章をチェックしてください。

Postビューの作成

現在、モデルにはデータが入り、コントローラにはアプリケーションロジックと流れが定義されています。 今度は、作成したindexアクション用のビューを作成しましょう。

Cakeのビュー(view)は、アプリケーションのレイアウト(layout)の内側にはめこまれる、データ表示用の断片部品です。 たいていのアプリケーションでは、PHPのコードが含まれるHTMLになりますが、XML、CSV、バイナリのデータにもなりえます。

レイアウト(Layout)は、ビューを囲む表示用のコードで、独自に定義したり、切り替えたりすることも可能ですが、今のところは、デフォルト(default)のものを使用することにしましょう。

一つ前のセクションの set() メソッドによって、ビューから「posts」変数が使えるように割り当てたのを覚えていますか。 ビューに渡されたデータは次のようなものになっています:

// print_r($posts) の出力:

Array
(
    [0] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [title] => タイトル
                    [body] => これは、記事の本文です。
                    [created] => 2008-02-13 18:34:55
                    [modified] =>
                )
        )
    [1] => Array
        (
            [Post] => Array
                (
                    [id] => 2
                    [title] => またタイトル
                    [body] => そこに本文が続きます。
                    [created] => 2008-02-13 18:34:56
                    [modified] =>
                )
        )
    [2] => Array
        (
            [Post] => Array
                (
                    [id] => 3
                    [title] => タイトルの逆襲
                    [body] => こりゃ本当にわくわくする!うそ。
                    [created] => 2008-02-13 18:34:57
                    [modified] =>
                )
        )
)

Cakeのビューファイルは、 /app/View の中の、コントローラ名に対応するフォルダの中に保存されています(この場合は、「Posts」というフォルダを作成します)。 この投稿記事データをテーブル表示するには、ビューのコードは次のようなものにできます

<!-- File: /app/View/Posts/index.ctp -->

<h1>Blog posts</h1>
<table>
    <tr>
        <th>Id</th>
        <th>Title</th>
        <th>Created</th>
    </tr>

    <!-- ここから、$posts配列をループして、投稿記事の情報を表示 -->

    <?php foreach ($posts as $post): ?>
    <tr>
        <td><?php echo $post['Post']['id']; ?></td>
        <td>
            <?php echo $this->Html->link($post['Post']['title'],
array('controller' => 'posts', 'action' => 'view', $post['Post']['id'])); ?>
        </td>
        <td><?php echo $post['Post']['created']; ?></td>
    </tr>
    <?php endforeach; ?>
    <?php unset($post); ?>
</table>

シンプルですよね。

$this->Html というオブジェクトを使っていることに気づいたかもしれません。 これは、CakePHPの HtmlHelper クラスのインスタンスです。 CakePHPには一連のビューヘルパーがあり、リンクの作成、フォームの出力、JavaScript、Ajaxなどをすぐに使えます。 使い方の詳細については、 ヘルパー を参照してください。 ここで重要なのは、 link() メソッドが、指定されたタイトル(最初のパラメータ)とURL(二つ目のパラメータ)でHTMLリンクを生成する、ということです。

Cake内でURLを指定する場合、配列フォーマットの使用が推奨されます。 これはルーティングの章で詳しく説明されます。 URLに配列フォーマットを用いることによって、CakePHPのリバースルーティング機能を活用することができます。 また、/コントローラ/アクション/パラメータ1/パラメータ2という形のアプリケーションの基本パスに対する相対パスを単に書くこともできます。

この時点で、ブラウザから http://www.example.com/posts/index を開いてみてください。 タイトルと投稿内容のテーブル一覧がまとめられているビューが表示されるはずです。

ビューの中のリンク(投稿記事のタイトルから/posts/view/some_idというURLへのリンク)をクリックすると、CakePHPは、そのアクションはまだ定義されていません、という表示を出します。 もしそういう表示が出ない場合には、何かおかしくなってしまったか、もうすでにあなたがその定義作業をしてしまったから(仕事がハヤイ!)か、のどちらかです。 そうでないなら、これからPostsControllerの中に作ってみましょう:

class PostsController extends AppController {
    public $helpers = array('Html', 'Form');

    public function index() {
         $this->set('posts', $this->Post->find('all'));
    }

    public function view($id = null) {
        if (!$id) {
            throw new NotFoundException(__('Invalid post'));
        }

        $post = $this->Post->findById($id);
        if (!$post) {
            throw new NotFoundException(__('Invalid post'));
        }
        $this->set('post', $post);
    }
}

set() の呼び出しはもう知っていますね。 find('all') の代わりに、 findById() を使っていることに注目してください。 今回は、ひとつの投稿記事の情報しか必要としないからです。

ビューのアクションが、ひとつのパラメータを取っていることに注意してください。 それは、これから表示する投稿記事のID番号です。 このパラメータは、リクエストされたURLを通して渡されます。 ユーザが、 /posts/view/3 とリクエストすると、「3」という値が $id として渡されます。

ユーザーが実在するレコードにアクセスすることを保証するために少しだけエラーチェックを行います。 もしユーザが /posts/view とリクエストしたら、 NotFoundException を送出し CakePHPのErrorHandlerに処理が引き継がれます。 また、ユーザーが存在するレコードにアクセスしたことを確認するために同様のチェックを実行します。

では、新しい「view」アクション用のビューを作って、 /app/View/Posts/view.ctp というファイルで保存しましょう。

<!-- File: /app/View/Posts/view.ctp -->

<h1><?php echo h($post['Post']['title']); ?></h1>

<p><small>Created: <?php echo $post['Post']['created']; ?></small></p>

<p><?php echo h($post['Post']['body']); ?></p>

/posts/index の中にあるリンクをクリックしたり、手動で、 /posts/view/1 にアクセスしたりして、動作することを確認してください。

記事の追加

データベースを読み、記事を表示できるようになりました。 今度は、新しい投稿ができるようにしてみましょう。

まず、PostsControllerの中に、 add() アクションを作ります:

class PostsController extends AppController {
    public $helpers = array('Html', 'Form', 'Session');
    public $components = array('Session');

    public function index() {
        $this->set('posts', $this->Post->find('all'));
    }

    public function view($id) {
        if (!$id) {
            throw new NotFoundException(__('Invalid post'));
        }

        $post = $this->Post->findById($id);
        if (!$post) {
            throw new NotFoundException(__('Invalid post'));
        }
        $this->set('post', $post);
    }

    public function add() {
        if ($this->request->is('post')) {
            $this->Post->create();
            if ($this->Post->save($this->request->data)) {
                $this->Session->setFlash(__('Your post has been saved.'));
                return $this->redirect(array('action' => 'index'));
            }
            $this->Session->setFlash(__('Unable to add your post.'));
        }
    }
}

ノート

SessionComponentとSessionHelperを、使うコントローラで読み込む必要があります。 必要不可欠なら、AppControllerで読み込むようにしてください。

add() アクションの動作は次のとおりです: もし、リクエストのHTTPメソッドがPOSTなら、Postモデルを使ってデータの保存を試みます。 何らかの理由で保存できなかった場合には、単にビューを表示します。 この時に、ユーザバリデーションエラーやその他の警告が表示されることになります。

すべてのCakePHPのリクエストは CakeRequest オブジェクトに格納されており、$this->request でアクセスできます。リクエストオブジェクトには、受信したリクエストに関するいろんな情報が含まれているので、アプリケーションのフローの制御に利用できます。今回は、リクエストがHTTP POSTかどうかの確認に CakeRequest::is() メソッドを使用しています。

ユーザがフォームを使ってデータをPOSTした場合、その情報は、 $this->request->data の中に入ってきます。 pr()debug() を使うと、内容を画面に表示させて、確認することができます。

SessionComponentの SessionComponent::setFlash() メソッドを使ってセッション変数にメッセージをセットすることによって、リダイレクト後のページでこれを表示します。 レイアウトでは SessionHelper::flash を用いて、メッセージを表示し、対応するセッション変数を削除します。 コントローラの Controller::redirect 関数は別のURLにリダイレクトを行います。 array('action' => 'index') パラメータは/posts、つまりpostsコントローラのindexアクションを表すURLに解釈されます。 多くのCakeの関数で指定できるURLのフォーマットについては、 APIRouter::url() 関数を参考にすることができます。

save() メソッドを呼ぶと、バリデーションエラーがチェックされ、もしエラーがある場合には保存動作を中止します。 これらのエラーがどのように扱われるのかは次のセクションで見てみましょう。

データのバリデーション

Cakeはフォームの入力バリデーションの退屈さを取り除くのに大いに役立ちます。 みんな、延々と続くフォームとそのバリデーションルーチンのコーディングは好まないでしょう。 CakePHPを使うと、その作業を簡単、高速に片付けることができます。

バリデーションの機能を活用するためには、ビューの中でCakeのFormHelperを使う必要があります。 FormHelper はデフォルトで、すべてのビューの中で $this->Form としてアクセスできるようになっています。

addのビューは次のようなものになります:

<!-- File: /app/View/Posts/add.ctp -->

<h1>Add Post</h1>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('title');
echo $this->Form->input('body', array('rows' => '3'));
echo $this->Form->end('Save Post');
?>

ここで、FormHelperを使って、HTMLフォームの開始タグを生成しています。 $this->Form->create() が生成したHTMLは次のようになります:

<form id="PostAddForm" method="post" action="/posts/add">

create() にパラメータを渡さないで呼ぶと、現在のコントローラのadd()アクション(または id がフォームデータに含まれる場合 edit() アクション)に、POSTで送るフォームを構築している、と解釈されます。

$this->Form->input() メソッドは、同名のフォーム要素を作成するのに使われています。 最初のパラメータは、どのフィールドに対応しているのかをCakePHPに教えます。 2番目のパラメータは、様々なオプションの配列を指定することができます。 - この例では、textareaの列の数を指定しています。 ここには少しばかりの内観的な手法とオートマジックが使われています。 input() は、指定されたモデルのフィールドに基づいて、異なるフォーム要素を出力します。

$this->Form->end() の呼び出しで、submitボタンとフォームの終了部分が出力されます。 end() の最初のパラメータとして文字列が指定してある場合、FormHelperは、それに合わせてsubmitボタンに名前をつけ、終了フォームタグも出力します。 ヘルパーの詳細に関しては、 ヘルパー を参照してください。

さて少し戻って、 /app/View/Posts/index.ctp のビューで「Add Post」というリンクを新しく表示するように編集しましょう。 <table> の前に、以下の行を追加してください:

<?php echo $this->Html->link(
    'Add Post',
    array('controller' => 'posts', 'action' => 'add')
); ?>

バリデーション要件について、どうやってCakePHPに指示するのだろう、と思ったかもしれません。 バリデーションのルールは、モデルの中で定義することができます。 Postモデルを見直して、幾つか修正してみましょう:

class Post extends AppModel {
    public $validate = array(
        'title' => array(
            'rule' => 'notEmpty'
        ),
        'body' => array(
            'rule' => 'notEmpty'
        )
    );
}

$validate 配列を使って、 save() メソッドが呼ばれた時に、どうやってバリデートするかをCakePHPに教えます。 ここでは、本文とタイトルのフィールドが、空ではいけない、ということを設定しています。 CakePHPのバリデーションエンジンは強力で、組み込みのルールがいろいろあります (クレジットカード番号、Emailアドレス、などなど)。 また柔軟に、独自ルールを作って設定することもできます。 この設定に関する詳細は、 /models/data-validation を参照してください。

バリデーションルールを書き込んだので、アプリケーションを動作させて、タイトルと本文を空にしたまま、記事を投稿してみてください。 FormHelper::input() メソッドを使ってフォーム要素を作成したので、バリデーションエラーのメッセージが自動的に表示されます。

投稿記事の編集

それではさっそく投稿記事の編集ができるように作業をしましょう。 もうCakePHPプロのあなたは、パターンを見つけ出したでしょうか。 アクションをつくり、それからビューを作る、というパターンです。 PostsControllerの edit() アクションはこんな形になります:

public function edit($id = null) {
    if (!$id) {
        throw new NotFoundException(__('Invalid post'));
    }

    $post = $this->Post->findById($id);
    if (!$post) {
        throw new NotFoundException(__('Invalid post'));
    }

    if ($this->request->is(array('post', 'put'))) {
        $this->Post->id = $id;
        if ($this->Post->save($this->request->data)) {
            $this->Session->setFlash(__('Your post has been updated.'));
            return $this->redirect(array('action' => 'index'));
        }
        $this->Session->setFlash(__('Unable to update your post.'));
    }

    if (!$this->request->data) {
        $this->request->data = $post;
    }
}

このアクションではまず、ユーザが実在するレコードにアクセスしようとしていることを確認します。 もし $id パラメータが渡されてないか、ポストが存在しない場合、 NotFoundException を送出してCakePHPのErrorHandlerに処理を委ねます。

次に、リクエストがPOSTかPUTであるかをチェックします。 もしリクエストがPOSTかPUTなら、POSTデータでレコードを更新したり、バリデーションエラーを表示したりします。

もし $this->request->data が空っぽだったら、取得していたポストレコードをそのままセットしておきます。

editビューは以下のようになるでしょう:

<!-- File: /app/View/Posts/edit.ctp -->

<h1>Edit Post</h1>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('title');
echo $this->Form->input('body', array('rows' => '3'));
echo $this->Form->input('id', array('type' => 'hidden'));
echo $this->Form->end('Save Post');
?>

(値が入力されている場合、)このビューは、編集フォームを出力します。 必要であれば、バリデーションのエラーメッセージも表示します。

ひとつ注意: CakePHPは、「id」フィールドがデータ配列の中に存在している場合は、モデルを編集しているのだと判断します。 もし、「id」がなければ、(addのビューを復習してください) save() が呼び出された時、Cakeは新しいモデルの挿入だと判断します。

これで、特定の記事をアップデートするためのリンクをindexビューに付けることができます:

<!-- File: /app/View/Posts/index.ctp  (編集リンクを追加済み) -->

<h1>Blog posts</h1>
<p><?php echo $this->Html->link("Add Post", array('action' => 'add')); ?></p>
<table>
    <tr>
        <th>Id</th>
        <th>Title</th>
        <th>Action</th>
        <th>Created</th>
    </tr>

<!-- $post配列をループして、投稿記事の情報を表示 -->

<?php foreach ($posts as $post): ?>
    <tr>
        <td><?php echo $post['Post']['id']; ?></td>
        <td>
            <?php echo $this->Html->link($post['Post']['title'], array('action' => 'view', $post['Post']['id'])); ?>
        </td>
        <td>
            <?php echo $this->Html->link('Edit', array('action' => 'edit', $post['Post']['id'])); ?>
        </td>
        <td>
            <?php echo $post['Post']['created']; ?>
        </td>
    </tr>
<?php endforeach; ?>

</table>

投稿記事の削除

次に、ユーザが投稿記事を削除できるようにする機能を作りましょう。 PostsControllerの delete() アクションを作るところから始めます:

public function delete($id) {
    if ($this->request->is('get')) {
        throw new MethodNotAllowedException();
    }

    if ($this->Post->delete($id)) {
        $this->Session->setFlash(__('The post with id: %s has been deleted.', h($id)));
        return $this->redirect(array('action' => 'index'));
    }
}

このロジックは、$idで指定された記事を削除し、 $this->Session->setFlash() を使って、ユーザに確認メッセージを表示し、それから /posts にリダイレクトします。 ユーザーがGETリクエストを用いて削除を試みようとすると、例外を投げます。 捕捉されない例外はCakePHPの例外ハンドラーによって捕まえられ、気の利いたエラーページが表示されます。 多くの組み込み 例外(Exception) があり、アプリケーションが生成することを必要とするであろう様々なHTTPエラーを指し示すのに使われます。

ロジックを実行してリダイレクトするので、このアクションにはビューがありません。 しかし、indexビューにリンクを付けて、投稿を削除するようにできるでしょう:

<!-- File: /app/View/Posts/index.ctp -->

<h1>Blog posts</h1>
<p><?php echo $this->Html->link('Add Post', array('action' => 'add')); ?></p>
<table>
    <tr>
        <th>Id</th>
        <th>Title</th>
        <th>Actions</th>
        <th>Created</th>
    </tr>

<!-- ここで$posts配列をループして、投稿情報を表示 -->

    <?php foreach ($posts as $post): ?>
    <tr>
        <td><?php echo $post['Post']['id']; ?></td>
        <td>
            <?php echo $this->Html->link($post['Post']['title'], array('action' => 'view', $post['Post']['id']));?>
        </td>
        <td>
            <?php echo $this->Form->postLink(
                'Delete',
                array('action' => 'delete', $post['Post']['id']),
                array('confirm' => 'Are you sure?'));
            ?>
            <?php echo $this->Html->link('Edit', array('action' => 'edit', $post['Post']['id'])); ?>
        </td>
        <td>
            <?php echo $post['Post']['created']; ?>
        </td>
    </tr>
    <?php endforeach; ?>

</table>

postLink() を使うと、投稿記事の削除を行うPOSTリクエストをするためのJavascriptを使うリンクが生成されます。 WEBクローラーが不意にコンテンツ全てを削除できてしまうので、GETリクエストを用いたコンテンツの削除を許可することは危険です。

ノート

このビューコードはFormHelperを使い、削除する前に、JavaScriptによる確認ダイアログでユーザに確認します。

ルーティング(Routes)

CakePHPのデフォルトのルーティングの動作で十分だという人もいます。 しかし、ユーザフレンドリで一般の検索エンジンに対応できるような操作に関心のある開発者であれば、CakePHPの中で、URLがどのように特定の関数の呼び出しにマップされるのかを理解したいと思うはずです。 このチュートリアルでは、routesを簡単に変える方法について扱います。

ルーティングテクニックの応用に関する情報は、 routes-configuration を見てください。

今のところ、ユーザがサイト(たとえば、http://www.example.com )を見に来ると、 CakeはPagesControllerに接続し、「home」というビューを表示するようになっています。 ではこれを、ルーティングルールを作成してPostsControllerに行くようにしてみましょう。

Cakeのルーティングは、 /app/Config/routes.php の中にあります。 デフォルトのトップページのルートをコメントアウトするか、削除します。 この行です:

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

この行は、「/」というURLをデフォルトのCakePHPのホームページに接続します。 これを、自分のコントローラに接続させるために、次のような行を追加してください:

Router::connect('/', array('controller' => 'posts', 'action' => 'index'));

これで、「/」でリクエストしてきたユーザを、PostControllerのindex()アクションに接続させることができます。

ノート

CakePHPは「リバースルーティング」も利用します - 上記のルートが定義されている状態で、配列を期待する関数に array('controller' => 'posts', 'action' => 'index') を渡すと、結果のURLは「/」になります。 つまり、URLの指定に常に配列を使うということが良策となります。 これによりルートがURLの行き先を定義する意味を持ち、 リンクが確実に同じ場所を指し示すようになります。

まとめ

この方法に乗っ取ったアプリケーションの作成により、平和、賞賛、愛、お金までもが、あなたが考えうる以上にもたらされるでしょう。 シンプルですよね。 ですが、気をつけてほしいのは、このチュートリアルは、非常に基本的な点しか扱っていない、ということです。 CakePHPには、もっともっと 多くの 機能があります。 シンプルなチュートリアルにするために、それらはここでは扱いませんでした。 マニュアルの残りの部分をガイドとして使い、もっと機能豊かなアプリケーションを作成してください。

基本的なアプリケーションの作成が終わったので、現実世界のアプリを作る準備が整いました。 自分のプロジェクトを始めて、 Cookbook の残りと API を使いましょう。

もし困ったときは、いろんな方法で助けを得ることができます。 情報の探し方 を見てみてください。CakePHPにようこそ!

お勧めの参考文献

CakePHPを学習する人が次に学びたいと思う共通のタスクがいくつかあります:

  1. レイアウト: WEBサイトのレイアウトをカスタマイズする
  2. エレメント ビューのスニペットを読み込んで再利用する
  3. Scaffolding: コードを作成する前のプロトタイピング
  4. Bakeでコード生成 基本的なCRUDコードの生成
  5. シンプルな認証と承認のアプリケーション: ユーザの認証と承認のチュートリアル