読者です 読者をやめる 読者になる 読者になる

PHP関西勉強会でYii2-alphaを試しました

「えー、会場の時間の関係でこの後の人は発表時間2分でお願いします」

という消化不良だったので、Yii2を試した感想を書きます。

http://www.yiiframework.com/news/76/yii-2-0-alpha-is-released/

12月のアタマで、Yii2がようやくアルファ版になりました。パブリックプレビューからずいぶん経ちましたね。あと残るはNoSQLのActiveRecordを作っていろいろ仕上げに入るということで、待ち遠しいきょうこの頃、PHP勉強会で「やり残したことをもくもくしよう」というわけで、どこまで進んだのかをじっさいに見てみました。

まず、プロジェクト作成が Composer で簡単にできるようになっていました。

$ php composer.phar create-project --stability=dev yiisoft/yii2-app-basic testapp

単純な構成のアプリケーションはこれ一発で初期化できます。testappというプロジェクトフォルダができて、要るものが全部入っています。設定などの基本構成もほとんど済んでいます。--stability=dev は安定版がリリース されればなくなるでしょう。

で、いきなりPHPのビルトインサーバで動かすと...

$ php -S localhost:8081 -t web

f:id:tanakahisateru:20131222011602p:plain

いきなりBootstrapじゃん! しかも3がベース。

こんなかっこいい画面が出来上がった状態で始まります。最初から問い合わせフォームとログインフォームが付いているのも健在です。

Yii-Bootstrap チュートリアル - tips - ドキュメント - yiijan.org | Yii日本ユーザグループ

ここもう要らないですね。せっせとBootstrapを入れるためにがんばっていたアレをしなくて済むようになるのは大助かりです。

デフォルトのプロジェクト構造も変わりました。

├── assets
├── commands
├── config
├── controllers
├── models
├── runtime
├── tests
├── vendor
├── views
└── web

protected の中身が出てきた感じです。通常の公開フォルダ web がコードの中にいます。もちろんこれは基本形というだけで、yii2-app-basic 以外にも advanced みたいなマルチサイト向けの構成もあります。で、このプロジェクトのルートが名前空間\app になります。ビューも静的ファイルも上に名前空間のルートがある感じなので、アプリケーションが綺麗にパッケージになってる感じがありますね。

注目すべきは画面の下の方にあるデバッグバーです。Symfonyにあるアレです。リクエストごとの状態やログを見られる機能。面白いのはPHPのバージョン番号が書いてあるところ。

f:id:tanakahisateru:20131222013830p:plain

クリックするとアレがそのまんま!!

f:id:tanakahisateru:20131222013915p:plain

phpinfo(); exit; だけやるアクションをいちいち書かなくてもいいんですよ。わかってらっしゃる。

f:id:tanakahisateru:20131222014310p:plain

Giiも乗りました。GiiはWebブラウザでコード生成できるツールです。

モデルとCRUDを作ってみます。モデルはこれまでと全く同じ感じで作れました。CRUD名前空間をフルに指定する必要がありました。リリースまでにもうちょっと補完が効くようになるんだろうな。

f:id:tanakahisateru:20131222014752p:plain

f:id:tanakahisateru:20131222014804p:plain

レイアウトは main.php 一択になり、2カラムレイアウト用のアクションのメニューはない感じになっています。Yiiの1のときの2カラムレイアウトとアクションメニューって、レスポンシブでモバイルファーストにするとき標準とするにはちょっと邪魔で、自分は外して使っていたんですが、それが基本になったということで、個人的には嬉しい仕様です。

そうそうレスポンシブといえば、Bootstrap3ベースなので何もしなくてもこのぐらいできてます。本当に自動で作ってまだ何もしてないサイトですよ。

f:id:tanakahisateru:20131222015324p:plain

ログインの認証のカスタマイズもわかりやすくなっていました。Yii 1 ではこういうコンポーネントを実装しました。

<?php
class UserIdentity extends CUserIdentity
{
    public function authenticate()
    {
        // ここを書き換えてDBアクセスによる認証など自由に書く
    }
}

Yii 2 はこうです。

<?php
namespace app\models;

use yii\web\IdentityInterface;

class User extends Model implements IdentityInterface
{
    // IdentityInterface を実装する
}

こういう形の User という名前の モデルmodels に置いてあります。それをこう。

<?php
namespace app\models;

use yii\db\ActiveRecord;
use yii\web\IdentityInterface;

class User extends ActiveRecord implements IdentityInterface
{
    public static function tableName()
    {
        return 'user';
    }

    public static function findIdentity($id)
    {
        return self::find($id);
    }

    public static function findByUsername($username)
    {
        return self::find()->where(
            'username=:name', [ ':name'=>$username ]
        )->one();
    }
    // あとは初期実装のまま
}

Model を ActiveRecord にして、必須であるテーブル名とその検索方法を書いたぐらい。

これまでは DB 上でアカウント情報を表すARなモデルを作って、それを CUserIdentity が使うという形で、まあそれでも何でもできたんですが、Yii 2 ではもっと簡単に、モデルとして見えるところにユーザが最初から定義されていて、それをARにするならどうぞ、というわかりやすい感じになっています。

で、ここでもうひとつ驚きがありますね。->model() がなくてクラス自体がリポジトリになってますね。Rails感が増しました。また、findByAttributes()find() + CDbCriteria のどっち使うかがなくなり、引数なしの find() の戻り値がクエリビルダになるからみんな使え、という仕様になりました。

対比してわかりやすいよう Yii1 のコード例を3つ:

User::model()->findAllByAttributes(array(
    'username'=>$username,
));
User::model()->find('username=:name', array(
    ':name' => $username,
));
$criteria = new CDbCriteria();
$criteria->addCondition('username=:name');
$criteria->params = array(
    ':name' => $username,
);
User::model()->find($criteria);

どれ使えと... というのがひとつの様式に統合された感じです。

で、どの形でフェッチするのか、つまり、ARとしてoneか、ARの配列としてallか、単一の値をscalarか、というのを普通に書くというのも、例には出してないですが、CDbCommandの方法との一貫性につながっています。

まああと、PHP5.4以上なので普通にショートアレイが使われていますね。コンパクトでいい感じです。

コントローラまわりの改善。不自然さはなくなっていて、依存関係的に正しい感じになっていると感じました。Yii1は、アクションのアクセス制限の仕組みの根本は付け替え可能なフィルタ機能なのに、なぜかコントローラの抽象にaccessRulesなんてメソッドが最初からある、なんていう、現実的だけどちょっと変な進化をしてきた痕跡がありましたが、そこらへんたぶんだいぶ整理されてます。

ビューも、ビューファイルでいう $this が実はコントローラのことだった、なんてことはなく、yii\web\Viewインスタンスになっています。これまで可能だった、ビューヘルパーとしてコントローラにメソッドを追加、なんていう変な作り方はできなくなっています。

あと、これ大きいなと思うのが、エンティティとフォームを兼用しているあのARモデルですが、フォームっぽさがCRUD用途のみという感じになるように、Giiが生成するようになったことです。検索フォームなどDBの列とは別のプロパティが必要な種類のフォームは、エンティティのCRUDをやるためのモデルから外れて、検索だけやるフォームとしてARではない単独のフォームモデルに分離されるようになりました。

これ教育上とてもいいことだと思います。追加機能のためのフィールドをどんどんひとつのモデルに付け足して混在させていく作りって、モデル駆動の人にしてみたら、中心とするモデル実装の汚染なんですよね。でもプログラマーは、お手本コードに search() なんていう特殊なものを同じところに書いてあるなら、それ真似するでしょ。結果、どんどんひとつのモデルにフィールドとメソッドが増え、太っていきます。ファットモデル。Yii2の初期コードは、それをしないお手本になっている気がしました。(それでいてフォームバリデーションを最低限必要なぶんだけ同じ所に持っているモデルというのは、素早いプロトタイピングをやるのにすごく便利です)

Yii経験者じゃないと何のことかわからないと思いますが、とにかくYii2はよくできています。速さと便利さのためにいくらか犠牲になっていた、正しい方法への誘導というフレームワークの意義を、可能な限り取り戻そうという意図が感じられました。数年後、PHP界の正しいRailsとして選択の余地なしという評価をもらえるものになっていると思います。たぶんね。