2011年11月26日に開催した、CakePHP2.0ハンズオン@札幌の資料をHTMLにしたものを公開します。
解説は現場で行ったため、説明不足の資料になっています。基本的には公式のチュートリアルと同一です。なので、以前の記事とも内容が重複しています。
1. 作業の注意・この資料について
プログラムを保存する場合、文字コードは「UTF-8」にして保存してください。改行コードは何でもいいです(LFのみ推奨)。
ファイル名の大文字小文字は間違えないように入力してください。
この資料は、http://book.cakephp.org/2.0/en/ を元に作成されています。
2. CakePHPのインストール
ダウンロード
http://cakephp.org/から、2.0.3 Stable(現時点での最新バージョン)のパッケージをダウンロードします。解凍し、Apacheが見える場所(htdocs直下など)に展開してください。
ここでは仮に、htdocs/cakeblog/に展開します。
XAMPP(Windows)環境の場合は、 ダウンロードして展開して作られた「cakephp-cakephp-2b55a02」(ファイル名はダウンロードしたバージョンによって違います)というフォルダを、「C:¥xampp¥htdocs」に移動します。その後、「 cakephp-cakephp-2b55a02」を「cakeblog」にリネームします。
MAMP(MacOSX)環境の場合は、ダウンロードして展開して作られた「cakephp-cakephp-2b55a02」(ファイル名はダウンロードしたバージョンによって違います)というフォルダを、「/Application/MAMP/htdocs」(あるいは「 アプリケーション -> MAMP -> htdocs」)に移動します。その後、「 cakephp-cakephp-2b55a02」を「cakeblog」にリネームします。
起動と設定
http://localhost/cakeblog/でアクセスできると思うので、アクセスしてみてください。(環境によっては変わるかもしれません)
エラーがいろいろ出ると思うので、確認していきます。(環境によって出るものと出ないものがあります)
「Please change the value of ‘Security.salt’ in app/Config/core.php to a salt value specific to your application」と出た場合
「app/Config/core.php」を開いて、
Configure::write(’Security.salt’, ‘DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi’);
の行の、よくわからない文字列の部分を、適当なよくわからない文字列に変更してください。(何でもいいです)
「Please change the value of ‘Security.cipherSeed’ in app/Config/core.php to a numeric (digits only) seed value 〜」と出た場合
「app/Config/core.php」を開いて、
Configure::write(’Security.cipherSeed’, ‘76859309657453542496749683645’);
の行の、よくわからない数字の部分を、適当なよくわからない数字に変更してください。
「Your database configuration file is NOT present.」と出た場合
次項で説明します。
「Cake is NOT able to connect to the database.」と出た場合
DBの設定は書けていますが、設定した通りのDBに接続ができません。次項を読みなおしてください。
「Warning: _cake_core_ cache was unable to write ‘cake_dev_ja’ to Apc cache in 〜」と出た場合
APCが無効になっています。APCを有効にするか、apc.soを読み込まないようにしてください。どちらもphp.iniで設定できます。
「Warning: _cake_core_ cache was unable to write ‘cake_dev_ja’ to File cache in 〜」と出た場合
APCは無効ですが、ファイルキャッシュへの書き込みができません。「chmod -R 777 app/tmp」で、いろいろエラーが消えます。
「Warning: /Application/MAMP/htdocs/cakeblog/app/tmp/cache/ is not writable in 〜」と出た場合
「chmod -R 777 app/tmp」で解決します。
「Your tmp directory is NOT writable.」と出た場合
「chmod -R 777 app/tmp」で解決します。
「URL rewriting is not properly configured on your server. 」と出た場合
Apacheでmod_rewriteを有効にしてください。できない場合は、app/Config/core.phpの、
//Configure::write(’App.baseUrl’, env(’SCRIPT_NAME’));
の行を、
Configure::write(’App.baseUrl’, env(’SCRIPT_NAME’));
と変更した上で、今後の説明の「http://localhost/cakeblog/」を、「http://localhost/cakeblog/index.php/」に読み替えてください。
(例:「http://localhost/cakeblog/posts」→「http://localhost/cakeblog/index.php/posts」
3. DBの設定
「app/Config/database.php.default」を、「app/Config/database.php」にリネーム(あるいはコピー)してください。
中のプログラムの、
public $default = array( ‘datasource’ => ‘Database/Mysql’, ‘persistent’ => false, ‘host’ => ‘localhost’, ‘login’ => ‘user’, ‘password’ => ‘password’, ‘database’ => ‘database_name’, ‘prefix’ => ‘’, //’encoding’ => ‘utf8’, );
の部分を、
public $default = array( ‘datasource’ => ‘Database/Mysql’, ‘persistent’ => false, ‘host’ => ‘localhost’, ‘login’ => ‘root’, ‘password’ => ‘’, ‘database’ => ‘cakeblog’, ‘prefix’ => ‘’, ‘encoding’ => ‘utf8’, );
のように変更します。(独自のDB接続設定がある場合は、それに合わせて修正してください)
phpMyAdmin等で、「cakeblog」というデータベースを作成します。phpMyAdminの場合は、「新規データベースを作成する」の箇所に「cakeblog」と入力し、「照合順序」を、「utf8_bin」にして、「作成」を押してください。
その後、以下のSQLを入力します。phpMyAdminの場合は、「cakeblog」のデータベースを選択し、「SQL」タブで、以下を貼りつけて、「実行する」を押します。
CREATE TABLE posts ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, title VARCHAR(50), body TEXT, created DATETIME DEFAULT NULL, modified DATETIME DEFAULT NULL ) Engine=InnoDB; INSERT INTO posts (title,body,created) VALUES (’The title’, ‘This is the post body.’, NOW()); INSERT INTO posts (title,body,created) VALUES (’A title once again’, ‘And the post body follows.’, NOW()); INSERT INTO posts (title,body,created) VALUES (’Title strikes back’, ‘This is really exciting! Not.’, NOW());
4. モデルの作成
app/Model/Post.phpを作成します。
<?php
class Post extends AppModel {
}
5. コントローラーの作成
app/Controller/PostsController.phpを作成します。
<?php class PostsController extends AppController { public $helpers = array (’Html’,’Form’); public function index() { $this->set(’posts’, $this->Post->find(’all’)); } }
6. ビューの作成
app/View/Posts/index.ctpを作成します。
<h1>Blog posts</h1> <table> <tr> <th>Id</th> <th>Title</th> <th>Created</th> </tr> <?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; ?> </table>
7. 詳細画面の作成
app/Controller/PostsController.phpを修正します。
<?php class PostsController extends AppController { public $helpers = array(’Html’, ‘Form’); public function index() { $this->set(’posts’, $this->Post->find(’all’)); } public function view($id = null) { $this->Post->id = $id; $this->set(’post’, $this->Post->read()); } }
app/View/Posts/view.ctpを作成します。
<h1><?php echo $post[’Post’][’title’]?></h1> <p><small>Created: <?php echo $post[’Post’][’created’]?></small></p> <p><?php echo $post[’Post’][’body’]?></p>
8. 新規作成画面の作成
app/Controller/PostsController.phpを修正します。
<?php class PostsController extends AppController { public $components = array(’Session’); public function index() { $this->set(’posts’, $this->Post->find(’all’)); } public function view($id) { $this->Post->id = $id; $this->set(’post’, $this->Post->read()); } public function add() { if ($this->request->is(’post’)) { if ($this->Post->save($this->request->data)) { $this->Session->setFlash(’Your post has been saved.’); $this->redirect(array(’action’ => ‘index’)); } } } }
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’);
app/View/Post/index.ctpの末尾に、addへのリンクを追加します。
<?php echo $this->Html->link(’Add Post’, array(’controller’ => ‘posts’, ‘action’ => ‘add’)); ?>
9. バリデーション
app/Model/Post.phpを修正します。
<?php class Post extends AppModel { public $validate = array( ‘title’ => array( ‘rule’ => ‘notEmpty’ ), ‘body’ => array( ‘rule’ => ‘notEmpty’ ) ); }
10. 編集画面の作成
app/Controller/PostsController.phpに、以下の処理を追加します。
<?php class PostsController extends AppController { ... public function edit($id = null) { $this->Post->id = $id; if ($this->request->is(’get’)) { $this->request->data = $this->Post->read(); } else { if ($this->Post->save($this->request->data)) { $this->Session->setFlash(’Your post has been updated.’); $this->redirect(array(’action’ => ‘index’)); } } } … }
app/View/Posts/edit.ctpを作成します。
<h1>Edit Post</h1> <?php echo $this->Form->create(’Post’, array(’action’ => ‘edit’)); 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’); ?>
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> <?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>
11. 削除機能の作成
app/Controller/PostsController.phpに、以下の処理を追加します。
<?php class PostsController extends AppController { ... public function delete($id) { if (!$this->request->is(’post’)) { throw new MethodNotAllowedException(); } if ($this->Post->delete($id)) { $this->Session->setFlash(’The post with id: ‘ . $id . ‘ has been deleted.’); $this->redirect(array(’action’ => ‘index’)); } } … }
12. ルーティング
ルーティングを変更する場合は、app/Config/routes.phpを編集します。
現在は http://localhost/cakeblog/posts からアクセスしていますが、これを http://localhost/cakeblog/ でアクセスできるようにするには、
Router::connect(’/’, array(’controller’ => ‘posts’, ‘action’ => ‘index’)); //Router::connect(’/’, array(’controller’ => ‘pages’, ‘action’ => ‘display’, ‘home’));
のようにします。
13. 見た目の変更
app/View/Layouts/default.ctpを作成することによって、外観を自由に変更することができます。
以下の内容をサンプルに、自由に書き換えてみましょう。
<!DOCTYPE html> <html> <head> <?php echo $this->Html->charset(); ?> <title> <?php echo $cakeDescription ?>: <?php echo $title_for_layout; ?> </title> <?php echo $this->Html->meta(’icon’); echo $this->Html->css(’cake.generic’); echo $scripts_for_layout; ?> </head> <body> <div id="container"> <div id="header"> <h1>CakePHP 2.0 Sample</h1> </div> <div id="content"> <?php echo $this->Session->flash(); ?> <?php echo $content_for_layout; ?> </div> <div id="footer"> Powered by CakePHP </div> </div> <?php echo $this->element(’sql_dump’); ?> </body> </html>
14. コメント機能
ここまでの実装を元に、コメント機能を作成してみましょう。(時間が余った人向け)
15. 管理画面の作成
CakePHPには、管理画面を簡単に作成できる機能が入っています。
仮に、ユーザーというテーブルがあり、それを管理できる画面を簡単に作ります。
データベースに、以下のSQLを投入します。
CREATE TABLE users ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(255) NOT NULL, password varchar(255) NOT NULL, created datetime DEFAULT NULL, modified datetime DEFAULT NULL, PRIMARY KEY (id) ) Engine=InnoDB;
app/Model/User.phpを作成します。
<?php class User extends AppModel { }
app/Controller/UsersController.phpを作成します。
<?php class UsersController extends AppController { public $scaffold; }
http://localhost/cakeblog/users にアクセスしてみましょう。
16. 認証
一覧・表示以外は、認証が必要にします。
ここでは、先程作成した、Usersモデル及びコントローラーを使用します。
パスワードを暗号化しなければいけないので、自動で保存時に暗号化されるようにします。app/Model/User.phpを変更します。
<?php App::uses(’AuthComponent’, ‘Controller/Component’); class User extends AppModel { // ... public function beforeSave() { if (isset($this->data[$this->alias][’password’])) { $this->data[$this->alias][’password’] = AuthComponent::password($this->data[$this->alias][’password’]); } return true; } // ...
変更したら、http://localhost/cakeblog/usersから、適当にユーザーを作成してみてください。
作成したら、ログインとログアウトができるようにします。
ログイン関係はUsersControllerに追加します。app/Controller/UsersController.phpを編集します。
<?php class UsersController extends AppController { public $scaffold; public $components = array('Session', 'Auth'); public function beforeFilter() { parent::beforeFilter(); $this->Auth->allow('login'); } public function login() { if ($this->request->is('post')) { if ($this->Auth->login()) { $this->redirect($this->Auth->redirect()); } else { $this->Session->setFlash(__('Invalid username or password, try again')); } } } public function logout() { $this->redirect($this->Auth->logout()); } }
ログイン画面が必要なので、app/View/Users/login.ctpを作成します。
<div class="users form"> <?php echo $this->Session->flash('auth'); ?> <?php echo $this->Form->create('User');?> <fieldset> <legend><?php echo __('Please enter your username and password'); ?></legend> <?php echo $this->Form->input('username'); echo $this->Form->input('password'); ?> </fieldset> <?php echo $this->Form->end(__('Login'));?> </div>
これでhttp://localhost/cakeblog/users/loginにアクセスするとログインができるようになります。
ログインできているのかどうかよくわからないので、ブログの投稿・編集・削除は、ログインが必要にします。
app/Controller/PostsController.phpを編集します。
<?php class PostsController extends AppController { public $components = array('Session', 'Auth'); public function beforeFilter() { parent::beforeFilter(); $this->Auth->allow('index', 'view'); } // .....
ついでに、ログインとログアウトのリンクを追加します。app/View/Layouts/default.ctpの適当な場所に、以下を追加します。
<?php if ($login_user_id !== null) { echo "Welcome ".h($login_user_name)." !!<br />"; echo $this->Html->link('Logout', array('controller' => 'users', 'action' => 'logout')); } else { echo $this->Html->link('Login', array('controller' => 'users', 'action' => 'login')); } ?>
このままではエラーになるので、$login_user_idと$login_user_nameが常に入るようにします。app/Controller/AppController.phpを作成します。
<?php class AppController extends Controller { public $components = array('Session', 'Auth'); public function beforeFilter() { parent::beforeFilter(); $this->set('login_user_id', $this->Auth->user('id')); $this->set('login_user_name', $this->Auth->user('username')); } }
ブログの投稿時にユーザーIDを記録するようにします。
まず、postsテーブルにuser_idを追加します。phpMyAdmin等で、以下のSQLを入力してください。
ALTER TABLE posts ADD COLUMN user_id INT(11);
これに合わせて、PostsControllerのaddの際に、user_idを自動入力させます。app/Controller/PostsController.phpを編集します。
<?php // app/Controller/PostsController.php public function add() { if ($this->request->is(’post’)) { $this->request->data[’Post’][’user_id’] = $this->Auth->user(’id’); //Added this line if ($this->Post->save($this->request->data)) { $this->Session->setFlash(’Your post has been saved.’); $this->redirect(array(’action’ => ‘index’)); } } }