2017年5月17日水曜日

CakePHP3の開発手順

Index

Summary

CakePHP3 で、新規Webアプリケーションを作成する際の、基本的な手順を示します。

前提

Visual Studio Code でCakePHP3開発環境を構築する
Visual Studio Code に拡張機能をインストールする

本記事では、データベースに SQLite3 を使用します。
また、プロジェクトフォルダを、$ROOT$ と表記します。

作業の流れ

CakePHP3 は、bake で簡単にアプリに必要なファイルをジェネレートできますが、前提として、データベースのテーブルが存在する必要があります。そのため、まずはデータベースから作成していきます。

データベースの作成

プロジェクトフォルダ直下に、SQLite3 のデータベースファイルを格納するフォルダを作成します。本記事では、フォルダ名を「db」としています。

コマンドプロンプトで、以下コマンドを実行します。

$ROOT$> cd db
$ROOT$\db> sqlite3 mydata.sqlite3
$ROOT$\db> sqlite3 test_mydata.sqlite3

これで、データベースの作成は完了です。
test_ を付けたデータベースは、テスト用です。

データベース接続情報の設定

app.php で、データベース接続情報を設定します。デフォルトでは、MySQLに接続する設定が記述されているので、SQLite3に接続する様に変更します。

config\app.php
    'Datasources' => [
        'default' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Sqlite',
            'persistent' => false,
            'username' => '',
            'password' => '',
            'database' => ROOT . DS . 'db' . DS . 'mydata.sqlite3',
            'encoding' => 'utf8',
            'cacheMetadata' => true,
        ],
        'test' => [
            'className' => 'Cake\Database\Connection',
            'driver' => 'Cake\Database\Driver\Sqlite',
            'persistent' => false,
            'username' => '',
            'password' => '',
            'database' => ROOT . DS . 'db' . DS . 'test_mydata.sqlite3',
            'encoding' => 'utf8',
            'cacheMetadata' => true,
        ],
    ],

組み込みのアプリケーションサーバを起動し、

$ROOT$> bin\cake server

http://localhost:8765 を表示してみましょう。
設定がうまくいっていれば、Database 欄が「CakePHP is able to connect to the database.」となっているはずです。

Migration

データベースが出来上がったので、テーブルを作成していきます。
テーブル作成やカラム追加は、Migration プラグインで管理することにします。

本家のサイトで、分かり易く解説されているので、
Migration 自体の説明は割愛します。

https://book.cakephp.org/3.0/ja/migrations.html
http://docs.phinx.org/en/latest/migrations.html

試しに、id, name カラムを持つ depts テーブルを作成してみます。
プライマリキー id は、何も指定しなくても自動的に付与されます。

$ROOT$> bin\cake bake migration CreateDepts name:string

これで、config\Migrations フォルダ配下に、マイグレーションファイルが作成されます。以下、自動生成されたマイグレーションファイルの中身です。

config\Migrations\20170516085210_CreateDepts
<?php
use Migrations\AbstractMigration;

class CreateDepts extends AbstractMigration
{
    public function change()
    {
        $table = $this->table('depts');
        $table->addColumn('name', 'string', [
            'default' => null,
            'limit' => 255,
            'null' => false,
        ]);
        $table->create();
    }
}

必要に応じて、limit などを編集してください。

他のテーブルやインデックスなど、必要なマイグレーションファイルをすべて作成したら、以下のコマンドで、マイグレーションを実行します。

$ROOT$> bin\cake migrations migrate

これで、テーブルが作成されます。

-c test オプションを付けて、テスト用データベースにもマイグレーションを適用しておきます。

$ROOT$> bin\cake migrations migrate -c test

bake で、MVC関連のファイルを生成する

前節で作成した depts テーブルに関するMVC関連のプログラム一式を、bake で自動生成します。

$ROOT$> bin\cake bake all depts

これで、モデル・テンプレート・コントローラ、およびユニットテストが作成されます。http://localhost:8765/depts で、自動生成されたアプリの動作を確認してみましょう。depts テーブルのレコード一覧画面が表示され、新規登録・変更・削除がちゃんと動きますね。素晴らしいです。

ちなみに、bake には all 以外にも指定できる引数が色々あります。例えば、model を指定すれば、モデルのみが作成されます。bake で使える引数の全量は、以下で確認することが出来ます。

$ROOT$> bin/cake bake

本格的に開発する

ここまでで、基本的な動作をするアプリケーションを作成できました。あとは、自動生成されたプログラムを修正していっても良いのですが、本格的に開発するためには、以下の様なことをやっていきます。

view や stored procedure の Migration
CakePHP3(というよりも Phinx)の Migration は、テーブル作成・削除、カラム追加・削除、インデックス作成・削除に対応していますが、ビューやストアドプロシージャの作成・削除には対応していません。repeatable migrations のアイデアなど検討されている様ですが、現状では up() に execute を書いて、生の SQL を発行するしか手がなさそうです。view に対して bake したかったりするので、運用を明確にする必要があります。
自動生成クラスと、拡張クラスの分離
変更開発でテーブルにカラム追加するなど、bake を再実行する(焼き直す)ことがあります。このとき、自動生成クラス自体に修正を入れていると bake で上書きされてしまうので、直接修正するのではなく、クラスを継承して処理を拡張する様にします。
テンプレートのカスタマイズ
bake は、テンプレートを使ってクラスを自動生成しているため、テンプレートをカスタマイズすることで、簡単に自動生成されるクラスの内容を変更できます。CakePHP3 が推奨するカスタマイズ方法があるので、それに従って、プロジェクトにフィットした bake を作りこんでいきます。

view の Migration

まず、マイグレーションファイルを作成します。

$ROOT$> bin\cake migrations create UpViewMembers

マイグレーション名のプレフィックスは、Create や Add を避けて、Up としてみます。そうすると、中身が空のマイグレーションファイルが作成されます。

up() メソッドに、view を作成する DDL を記述します。
また、down() メソッドには、view を削除する DDL を記述します。
(ロールバック時のため)

この部分、SQLite3 固有の記述となるため、MySQL など他のデータベースにマイグレーションする際は、記述を見直す必要があります。

config\Migrations\20170517065415_up_view_members.php
<?php

use Phinx\Migration\AbstractMigration;

class UpViewMembers extends AbstractMigration
{
    public function up()
    {
        $count = $this->execute(
            'create view view_members as
            select m.id, m.name, d.name as dept_name, m.participation_date
            from members m inner join depts d on m.dept_id = d.id;'
        );
    }

    public function down()
    {
        $count = $this->execute('drop view view_members;');
    }
}

※ members テーブルは、予め作成しているものとします。

これで、マイグレーションすると view が作成されます。

$ROOT$> bin\cake migrations migrate

SQLite3 で確認してみましょう。

$ROOT$> cd db
$ROOT$db> sqlite3 mydata.sqlite3
sqlite> .tables
depts         members       phinxlog      view_members

view_members が、作成されています。

ロールバックすると、どうなるか試してみます。

bin\cake migrations rollback -t 20170517045439

-t 20170517045439 で、view を作成する直前のマイグレーションID まで戻しています。(マイグレーションファイルの ‘_’ アンダースコアより前のタイムスタンプ部分が、マイグレーションIDです)

SQLite3 で確認してみましょう。

sqlite> .tables
depts         members       phinxlog

消えてますね。

注意が必要なのは、view を変更するときのマイグレーションファイルです。

  • UP() : drop してから create
  • down() : drop してから、前の状態で create

といった感じにしてあげないと駄目ですね。これは、「前の状態で create」という部分などが DRY じゃないので、DDL を外出しにして管理する何かしらの仕組みを構築すべきですね。

ということで、Migrations を拡張するプラグインを開発してみました。

CakePHP3 で Bake を拡張してみる

あとは、マイグレーションファイルはプルリクで運用し辛いところがありそうです。まあ、スキーマ変更はそれほど頻繁に起きないでしょうから、マイグレーション管理されていることのほうがメリットが大きいと思います。(stored procedure を多用するプロジェクトだと、少し運用を考えなければならないかも知れません・・・)

0 件のコメント:

コメントを投稿