5分で分かるCakePHPの基礎
PHPのFWを比較することを試みようと思っている。PHPの4大FWと言われる、CakePHP,Symphoney,Zend,Codeigniterは少しずつ勉強を進めよう。まずは軽量かつ覚えやすいというCakePHPについて記述する。※コードの追跡を行ったのはCakePHP version1.3.9。現時点での最新Version。
特徴や規則
- RoRの影響を受けて作られている。2006年頃から存在し、PHP4でも使える。
- MVC(Model View Controller)。Viewを純粋なPHPでかける。
- 習得が比較的楽。
- ViewHelperが利用可能。ViewHelperで自動的に出力をsanitize。
- Action/FilterChainをサポート。
- Validatorサポート。
- 関数の短縮表記。
- 簡単な処理の流れを説明すると、entrypointからDispatcherが呼び出すControllerを決定し、ControllerはModelとデータのやり取りをして取得結果を整形してViewに渡す という構成。
- ファイル名の設定にはアンダースコア、クラス名の設定にはキャメル記法を用いる。(例)my_sample_class.phpというファイル名にMySampleClassというクラスを定義する事ができる。
- ファイルやDBの命名規則が厳格。
- Controllerクラスの中でメソッド名の接頭辞としてアンダースコアを付けるとURLからはアクセス不可能なメソッドとして扱う事ができる。
- Modelクラスの定義もキャメル記法。呼び出されるdbのテーブル名はアンダースコア表記。名前は複数形とする。
- 呼び出し方は http://Cakeのパス/コントローラ/メソッド(アクション)/パラメータ。内部のrewrite処理によりapp/webroot/index.phpが起動されコントローラ、メソッド、パラメータを解釈。
- キャッシュ機構も備えている。(apc,memcache,xcache)。Viewのキャッシュも可能。
Directory Tree
主要なフォルダ構成は次の通り
- app : 作成したアプリケーションを設置する場所
- config: DB接続やbootstrap、coreの設定ファイルを入れる
- controllers : controllerとcomponentを入れる
- libs : ファーストパーティ用のライブラリ
- locale : 国際化のための文字ファイル
- models : models,behaviors,datasourcesを入れる
- plugins : pluginパッケージを入れる
- tests : testケースのコードを入れる
- tmp : ログ、セッション情報、データの一時保存場所
- vendors : サードパーティ用のライブラリ
- views : 表示用のファイルを設置
- webroot : アプリケーションのエントリポイントなどのドキュメントルート
- cake : coreライブラリ。中身の変更は禁止。
- vendors : 作成したライブラリを設置できる。
処理の流れ詳細
entrypoint
entrypointのphpは以下の処理を行っている。
- filepathは- entrypointはapp/webroot/index.php
- 各必要定数のdefineとbootstrapファイルのinclude。
- dispatcherの呼び出し、dispatch処理。
<?php ----- 略 if (!defined('DS')) { define('DS', DIRECTORY_SEPARATOR); } /** * These defines should only be edited if you have cake installed in * a directory layout other than the way it is distributed. * When using custom settings be sure to use the DS and do not add a trailing DS . */ /** * The full path to the directory which holds "app", WITHOUT a trailing DS. * */ if (!defined('ROOT')) { define('ROOT', dirname(dirname(dirname(__FILE__)))); } ----- 略 if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } if (isset($_GET['url']) && $_GET['url'] === 'favicon.ico') { return; } else { $Dispatcher = new Dispatcher(); $Dispatcher->dispatch(); }
bootstrap
- 定数の設定
- エラーの種類の設定
- 各種ファイルのrequire
<?php if (!defined('PHP5')) { define('PHP5', (PHP_VERSION >= 5)); } if (!defined('E_DEPRECATED')) { define('E_DEPRECATED', 8192); } error_reporting(E_ALL & ~E_DEPRECATED); require CORE_PATH . 'cake' . DS . 'basics.php'; $TIME_START = getMicrotime(); require CORE_PATH . 'cake' . DS . 'config' . DS . 'paths.php'; require LIBS . 'object.php'; require LIBS . 'inflector.php'; require LIBS . 'configure.php'; require LIBS . 'set.php'; require LIBS . 'cache.php'; Configure::getInstance(); require CAKE . 'dispatcher.php';
dispatcher
dispatcherは以下の処理を行う。
- URL、parameterの特定。
- 呼び出すcontrollerの特定。
<?php if (is_array($url)) { $url = $this->__extractParams($url, $additionalParams); } else { if ($url) { $_GET['url'] = $url; } $url = $this->getUrl(); $this->params = array_merge($this->parseParams($url), $additionalParams); } $this->here = $this->base . '/' . $url; if ($this->asset($url) || $this->cached($url)) { return; } $controller =& $this->__getController();
- action、メソッドの特定。
- controllerにデータを設定。
<?php $controller->base = $this->base; $controller->here = $this->here; $controller->webroot = $this->webroot; $controller->plugin = isset($this->params['plugin']) ? $this->params['plugin'] : null; $controller->params =& $this->params; $controller->action =& $this->params['action']; $controller->passedArgs = array_merge($this->params['pass'], $this->params['named']);
- invokeメソッド内部でcontroller処理の起動
- controllerの初期化。
- controllerの呼び出し、実行。
- viewのrender。
- controllerのshutdown処理を行う。
- viewの表示。
<?php $controller->constructClasses(); $controller->startupProcess(); $output = call_user_func_array(array(&$controller, $params['action']), $params['pass']); -------略 if ($controller->autoRender) { $controller->output = $controller->render(); } elseif (empty($controller->output)) { $controller->output = $output; } $controller->shutdownProcess(); if (isset($params['return'])) { return $controller->output; } echo($controller->output);
サンプルプログラム設置
- DBの定義。
- Controller,Model,Viewの設置。
DBの定義
DB設定ファイルをコピーして、書き換える
login,password,databaseなどを書き換え。
<?php class DATABASE_CONFIG { var $default = array( 'driver' => 'mysql', 'persistent' => false, 'host' => 'localhost', 'login' => 'user', 'password' => '', 'database' => 'todo', 'prefix' => '', );DBのschema作成SQLは次の通り。Modelの名前の複数形として定義する。
CREATE TABLE `members` ( `id` int(11) unsigned NOT NULL auto_increment, `name` varchar(255) NOT NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL, PRIMARY KEY (`id`), KEY `created` (`created`), KEY `modified` (`modified`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 | INSERT INTO `members` (`name`, `created`, `modified`) VALUES ('yahoo', '2011-08-20 00:00:00', '2011-08-21 01:00:00'), ('google', '2011-08-21 02:00:00', '2011-08-21 02:00:00'), ('facebook', '2011-08-21 05:00:00', '2011-08-21 05:00:00');controllerの定義
- app/controllers/members_controller.phpとして定義。
- classは必ずAppControllerを継承する。
- 利用Model、アクションを定義。var $uses = array('Member'); $this->set('members', $this->Task->findAll(null, null, 'Member.created ASC'));
- Viewに渡すデータを設定。
<?php // app/controllers/members_controller.php class MembersController extends AppController { var $name = 'Members'; var $uses = array('Member'); function index() { $this->set('members', $this->Member->findAll(null, null, 'Member.created ASC')); } }Modelの定義
<?php // app/model/member.php class Member extends AppModel { var $name = 'Member'; }Viewの定義
- controllerでsetにより渡されてきたmembersを展開できる。
- hという関数はcake/basics.phpに登録されているhtmlspecialcharsを行う短縮関数。
<table> <tr> <th>Id</th> <th>登録内容</th> <th>作成日</th> </tr> <?php foreach ($members as $member) { ?> <tr> <td><?php echo h($member['Member']['id']) ?></td> <td><?php echo h($member['Member']['name']) ?></td> <td><?php echo h($member['Member']['created']) ?></td> </tr> <?php } ?> </table>