Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

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 : 作成したライブラリを設置できる。

処理の流れ詳細

  • URLとしてのエントリポイント呼び出し(app/webroot/index.php)
  • dispatcherの呼び出し。使用するControllerを決定する。
    • dispatcherのパスは cake/dispatcher.php
  • Controllerのメソッドであるアクションを実行。アクションからModelを経由してDBにアクセスし、データを取得。
    • 例 /user/list/5 というリクエストURIだとしたら UserControllerクラスのlistメソッドが呼び出される。
  • Controllerは取得した結果を整形し、Viewにデータを渡して表示。

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設定ファイルをコピーして、書き換える

app/config# sudo cp database.php.default database.php

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>
アクセスして閲覧できる事を確認

http://localhost/cake/members

サンプルプログラムの設定は以上です。