ギジュログ

FlashとかPHPとかiOSとかJavaとか。関東でフリーランスやってる人の気まぐれな技術録。

CakePHP3 もくもく会 #2 に参加してきました

色々と改善されていると噂の CakePHP 3 をもくもく勉強する会その2にお邪魔してきました。
CakePHP 3.0.0 もくもく会(勉強会) #2 - Co-Edo CakePHP | Doorkeeper
そこでやったことをメモ。

今回の目標

という感じのながれになりました。

環境構築

Co-Edo の田中さんが Vagrantfile を用意してくれていました。(素敵!)ので、それを利用させていただくことに。
Vagrantfile の内容はこちら
コマンドとしては下記のような感じで

# まず VirtualBox の GuestTool を更新するプラグインをいれておく
$ vagrant plugin install vagrant-vbguest
# vagrant を実行する適当なフォルダを作る
$ mkdir -p work/vagrant/cakephp3
$ cd work/vagrant/cakephp3
# 上記のソースファイルをもってくる
$ git clone https://github.com/monsat/vagrant-lamp-sample.git
$ git checkout -b cakephp3 origin/cakephp3
# Vagrantfile あるディレクトリで Vagrant 起動
$ cd vagrant-lamp-sample/vagrant
$ vagrant up

少し時間はかかりますが、これで環境構築は終わりです。うまくいけば http://192.168.33.40/ にアクセスすると下記のようなCakeのページが表示されます。
f:id:katsuren:20140308121725p:plain,w900
DebugKit が入っていないよって警告に関してもグリーンにすることはできますが、Plugin 自体は今動かないようなので今のところ必要ありません。
うまくいかない場合はVMをいったん破壊して起動し直すといいかもしれないです。自分はダウンロードまわりでうまくいかないことが何回かあったのでとりあえずVM削除/起動を繰り返しました。

# うまくいかなかった場合
$ vagrant halt
$ vagrant destroy
y
# もし composer でファイルをダウンロードしてた場合はそれも削除しておく
$ rm -rf ../composer.lock ../app
$ vagrant up




ディレクトリ構成確認

まずはチュートリアルを始める前に、ディレクトリ構成を眺めます。上記の vagrant で起動した場合、vagrant フォルダと同階層の app フォルダがプロジェクト一式になります。
大きな変更点があったところだけざっとピックアップしてみます。早速プロジェクト直下から。

$ tree app -L 1 -d
app
├── App
├── Plugin
├── Test
├── tmp
├── vendor
└── webroot

こんな感じになってます。この時点で色々違います。ちなみに、2 はこんな感じでした。

$ tree cakephp -L 1 -d
cakephp
├── app
├── lib
├── plugins
└── vendors

フォルダ名が大文字になったり、app 内にあった tmp や webroot、Test がプロジェクトフォルダ直下にきてますね。ちなみに、lib フォルダは削除され、vendor の中に cakephp ライブラリとして配置されるようになったようです。

App 内はこんなかんじでした

$ tree App -L 1 -d
App
├── Config
├── Console
├── Controller
├── Lib
├── Locale
├── Model
├── Template
└── View

Template フォルダが増えてます。これ、どうやら View の考え方が変わっていて、今まで View にいれていたテンプレートファイルはこちらで管理するようになったようです。View フォルダは、Helper などのクラスを管理するようになったみたいです。

Config 内も見てみます。

$ tree -L 1 Config/
Config/
├── Schema
├── acl.ini.php
├── acl.php
├── app.default.php
├── app.php
├── bootstrap.php
├── paths.php
└── routes.php

database.php はなくなり、app.php の中で管理するようになったようです。
また、paths.php が新しく追加されました。この中には 2 まで APP とか TMP とか、CakePHPフレームワーク内で定義されていたものがここに移されたようです。独自のビジネスロジックなどをフォルダにまとめて管理する場合に便利そうです。

最後に Model 内を見てみます。

$ tree Model -L 1 -d
Model
├── Behavior
├── Datasource
├── Entity
└── Table

Table と Entity が増えてます。どうやら 3 からは DB とのやりとりをするのは Table、Entity というものが担当するようです。
Table クラスが従来の Model っぽい使い方で、そこから取得したデータは配列ではなく Entity というクラスになって返ってきます。



ブログチュートリアル

CakePHP のドキュメントには、チュートリアルとしてブログを作成する内容のものがあります。3 のバージョンの内容もボチボチ反映されてきていますが、まだそれでは動かなかったりするのでハマりつつその内容を実行してくことに。ドキュメントまわりは下記のものを参考にしました。基本的には 3 の books(英語版)をベースに、API をみつつやっていきました。
CakePHP3 のドキュメント
CakePHP3 の API リファレンス
(すでに CakePHP 3 でブログチュートリアルをやっていらっしゃる方がいました!)
まだ本プレビューでは bake は動かないようなので、自力で全部書いていきます。
成果物は github にあげました。
katsuren/cake3-blog · GitHub


前準備

DB にテーブルを用意しておきます。いつものSQLです。

> CREATE DATABASE cake3_blog DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
> use cake3_blog;
> 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());

設定ファイルは Config/app.php で、"Datasources" という項目名になっているので、それを書き換えます。項目名以外はほとんど変わっていないので、今までどおりな感じです。

<?php

'Datasources' => [
	'default' => [
		'className' => 'Cake\Database\Connection',
		'driver' => 'Cake\Database\Driver\Mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'your_user_name',  // 設定したユーザー名をいれる
		'password' => 'your_secret',  // 設定したパスワード
		'database' => 'cake3_blog',   // 作成したDB名
		'prefix' => false,
		'encoding' => 'utf8',
	],

	/**
	 * The test connection is used during the test suite.
	 */
	'test' => [
		'className' => 'Cake\Database\Connection'
		'driver' => 'Cake\Database\Driver\Mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'my_app',
		'password' => 'secret',
		'database' => 'test_myapp',
		'prefix' => false,
		'encoding' => 'utf8',
	],
],

モデルを作成

前準備で作ったテーブルにアクセスするモデルを作成します。とはいっても、今回は Model クラスではなく、Table クラスと Entity クラスを作ることになります。
まずは Table

# App/Model/Table/PostsTable.php
<?php
namespace App\Model\Table;

use Cake\ORM\Table;

class PostsTable extends Table {
}

そしてEntity

# App/Model/Entity/post.php
<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;

class Post extends Entity {
}

とりあえずこれで動くようになります。特筆すべきは、App がなくなったこと。2 系までは利用するクラスを

App::uses('Model', 'Model');

みたいな感じで登録していました。今回は use 文を使うようになっているようです。そのため、2系のプラグインは軒並みアウトですね。それぞれ Table と Entity を継承するので、Cake\ORM\Table と Cake\ORM\Entity を利用宣言します。
また、名前空間を利用するようになっています。とりあえずフォルダ構成と同じ名前空間を指定してあげています。


コントローラー、ビューの作成

では、今作成したモデルから一覧を表示するコントローラー/ビューを作成してみます。

# App/Controller/PostsController.php
<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\ORM\TableRegistry;

class PostsController extends AppController {
	public function index() {
		$posts = TableRegistry::get('Posts');
		$this->set('posts', $posts->find('all'));
	}
}

コントローラー自体はまだほとんど変わっていませんが、モデルの利用方法が変わっています。いままでは uses プロパティに利用するモデルを記述してモデルを呼び出していました。今回からは TableRegistry というクラスから Table クラスのインスタンスを生成するようです。

<!-- App/Template/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->id; ?></td>
		<td><?php echo $post->title; ?></td>
		<td><?php echo $post->created->format('Y-m-d H:i:s'); ?></td>
	</tr>
	<?php endforeach; ?>
	<?php unset($post); ?>
</table>

ビューもCTPがそのまま使えます。ここでは Entity の解説をします。
Table から find した結果は Entity の配列として返ってきます。
Entity は、テーブルを作成したときのフィールド名がそのままプロパティとして扱えるので、上記のようにそのまま id, title, created を取得できるようになっています。フィールドの定義が DateTime なので、php でも String ではなく DateTime オブジェクトとして取得されます。

ここまでの内容は、http://192.168.33.40/posts/index で確認することができるようになっています。


ちょっと長くなったので、続きはまたあとで

続き書きました
CakePHP3 もくもく会 #2 に参加してきました 続き - ギジュログ