API開発に便利なPHPフレームワーク(3) – FuelPHP –

連載1回目ではPHPフレームワークの中でも人気があるLaravel、2回目では作成したアプリケーションの実行速度が爆速になるPhalconをご紹介しました。

PHPでAPIを作成する際、フレームワークを使って実装していくのがもはや一般的かと思いますが、色んなフレームワークを使ってみた結果思うことは、フレームワーク選びに正解はないのかなという事です。


フレームワーク毎に作者の思想やベストプラクティスが詰まっているはずなので、それを好むか、または受け入れられるかと言ったところが選択する上で重要です。

今回は使いやすさと実行速度のバランスが取れた、FuelPHPというフレームワークをご紹介したいと思います。

目次

  1. とにかくバランスが取れたフレームワーク……だが
  2. FuelPHPの導入方法
  3. APIを作ってみる
  4. 強力なoilコマンド
  5. データベースへの接続
  6. まとめ

とにかくバランスが取れたフレームワーク……だが

FuelPHPの特長として挙げられるのは以下のとおり。

  • クラスファイルをネームスペースベース、ディレクトリベースのどちらでも扱える作り(プロジェクト単位では統一する必要がありますが)
  • ユーザーが利用するアプリケーションと、管理側のアプリケーションを単一のプロジェクト内でドキュメントルートを分割できる
  • モデルやプレゼンターなどの使い回しが可能なモジュール構造
  • フルスタックフレームワークと呼べるほど機能が大盛りではないけれど、マイクロフレームワークと言うほど足りない訳でもない、絶妙な加減が実現した実行速度

クラスファイルをネームスペースベース、ディレクトリベースのどちらでも扱える作り(プロジェクト単位では統一する必要がありますが)、ユーザーが利用するアプリケーションと、管理側のアプリケーションを単一のプロジェクト内でドキュメントルートを分割できる上、モデルやプレゼンターなどの使い回しが可能なモジュール構造、フルスタックフレームワークと呼べるほど機能が大盛りではないけれど、マイクロフレームワークと言うほど足りない訳でもない、絶妙な加減が実現した実行速度。

私はこのフレームワークで幾つもAPIサーバーを作ってきましたので、このフレームワークの良さを伝えることは簡単ですが、おすすめ度でいうと、10段階で6、良くて7と言ったところです。


FuelPHPの最大の弱点はプログラムではなく現在の開発状況で、最新安定版は1.8で最終更新日が2017年1月。この記事を書いている時点で既に1年以上が経過しています。また、次期バージョンの1.9と2.0の開発ですが、こちらは細かいコミットですが、少しずつ進んではいますが、開発が長期化していて開発版を意味する「DEV」が取れる気配がないのも非常に残念なところです。

ただ、現状の1.8でも速度的に問題もないですし、これと言った大きな不具合に当たったこともなく、何よりPHP7系への対応ができているので、当面は1.8を使っていて大丈夫だと思います。

公式ドキュメントの日本語化がかなり進んでおり、充実しています。
困った時は公式ドキュメントを読むと大抵のことは解決してしまうでしょう。

FuelPHPの導入方法

FuelPHPの導入は非常に簡単です。
git cloneでソースを入手した後、composer updateコマンドでその他のコンポーネントを導入します。

【bash】

# ソースコードを保存するパスへ移動
cd /path/to/fuel
# git cloneでソースコードを入手
git clone git://github.com/fuel/fuel.git .
# 同梱のcomposerを最新版にアップデート
php composer.phar self-update
# composerを使って依存するモジュールをインストール
php composer.phar update --prefer-dist
# ログやキャッシュなどのファイルを保存するディレクトリに書き込み権限を付ける
php oil refine install

以上で動かせる状態になります。

APIを作ってみる

接続元のIPアドレスを返す単純なAPIを作ってみたいと思います。
FuelPHPでは、API開発が簡単に進められる、RESTコントローラーを持っていますので、コントローラーはこれを使ってみます。

【php】

// fuel/app/classes/controller/ip.php
<?php
class Controller_Ip extends Controller_Rest
{
    public function action_check()
    {
        return $this->response(Input::ip());
    }
}

ローカルの開発環境なら、「http://localhost/ip/check」というURLでアクセスすれば、PCのIPアドレスが表示されると思います。

RESTコントローラのいいところは、$this->response()メソッドの引数に配列をセットすると、好みのフォーマットに変換してくれるといったお手軽さにあります。

【php】

// fuel/app/classes/controller/ip.php
<?php
class Controller_Ip extends Controller_Rest
{
    public function action_server()
    {
        return $this->response(Input::server());
    }
}

上記のようなaction_server()メソッドを追加し、さっきと同じように、「http://localhost/ip/server.json」というURLでアクセスすれば、Input::server()メソッドの結果がJSON形式で出力されます。
Input::server()は、FuelPHP内で$_SERVER変数にアクセスするために用意されたメソッドで、引数を指定しなければ、$_SERVER変数の中身が全て出力されます。

http://localhost/ip/server.jsonというURLは、拡張子にjsonの指定をしているため、JSONデータで返ってきますが、指定をしなければ注意書きも出力されます。拡張子の指定なしでもJSONが出力されるようにするには、コントローラーファイルでそれを指定すればいいだけです。

【php】

<?php
class Controller_Ip extends Controller_Rest
{
    // この行を追加
    public $format = 'json';
    public function action_server()
    {
        return $this->response(Input::server());
    }
}

強力なoilコマンド

FuelPHPには、コンソールで利用できるoilというコマンドが用意されています。
機能がたくさんあるのでここで全てを紹介することはできませんが、コントローラーやモデルの雛形作成やマイグレーション操作、ユニットテストの実行、対話型のPHPコンソールの起動など便利なものが揃っています。

特にモデルの作成は、マイグレーションも同時に作成できるので積極的に使っていきたい機能と言えます。

ここでは、モデルを作成するoilコマンドを紹介します。
ブログの記事データを格納するテーブルを想定したモデルの作成になります。

【bash】

php oil g model article id:int:unsigned[true]
title:varchar[64] category:int:null[true]
user_id:int:unsigned[true] body:text published_at:datetime

上記のコマンドを流すと、以下のモデルファイルとマイグレーションファイルが作成されます。

【php】

// fuel/app/classes/model/article.php
<?php
class Model_Article extends \Orm\Model
{
    protected static $_properties = array(
        'id',
        'title',
        'category',
        'user_id',
        'body',
        'published_at',
        'created_at',
        'updated_at',
    );
    protected static $_observers = array(
        'Orm\Observer_CreatedAt' => array(
        'events' => array('before_insert'),
        'mysql_timestamp' => false,
    ),
        'Orm\Observer_UpdatedAt' => array(
            'events' => array('before_update'),
            'mysql_timestamp' => false,
        ),
    );
    protected static $_table_name = 'articles';
}

【php】

// fuel/app/migrations/001_create_articles.php
<?php
namespace Fuel\Migrations;
class Create_articles
{
    public function up()
    {
        \DBUtil::create_table('articles', array(
            'id' => array('constraint' => 11, 'type' => 'int', 'unsigned' => true),
            'title' => array('constraint' => 64, 'type' => 'varchar'),
            'category' => array('constraint' => 11, 'type' => 'int', 'null' => true),
            'user_id' => array('constraint' => 11, 'type' => 'int', 'unsigned' => true),
            'body' => array('type' => 'text'),
            'published_at' => array('type' => 'datetime'),
            'created_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),
            'updated_at' => array('constraint' => 11, 'type' => 'int', 'null' => true),
        ), array('id'));
    }
    public function down()
    {
        \DBUtil::drop_table('articles');
    }
}

マイグレーションファイルは適用されていない状態なので、以下のコマンドで適用します。

【bash】

php oil r migrate

ストレスなく「oil g model」コマンド使うためのポイントを幾つか挙げてみます。

  • IDなどunsigned Integer型で定義したいカラムは、明示的にunsigned[true]を付ける必要がある
  • null[true]の指定がない場合は必須になる(例の場合ではtitleカラムやbodyカラム)
  • 自動的に作成日時を格納するcreated_atカラムと最終更新日時を格納するupdated_atカラムが追加される(不要の場合は「––no-timestamp」オプションを追加)
  • 上記のコマンドを実行すると、時刻関連のデータはタイムスタンプをinteger型で格納するため、Datetime型で格納したい場合は「––mysql-timestamp」オプションを追加する

特に4番目は好みが非常に分かれる部分ですので、注意が必要です。

データベースへの接続

データベースとのやりとりは、モデルを利用して行います。
先ほど作成したarticlesテーブルを使って、データの保存を試してみます。

【php】

// モデルの作成
$article = Model_Article::forge();
// オブジェクトのプロパティとして設定
$article->title = 'FuelPHP入門';
$article->user_id = 1;
$article->body = '...';
$article->published_at = date('Y-m-d H:i:s');
// 配列としてアクセスすることもできる
$article['title'] = 'FuelPHP入門';
$article['user_id'] = 1;
$article['body'] = '...';
$article['published_at'] = date('Y-m-d H:i:s');
// forge()メソッド時の引数として一括指定することもできる
$article = Model_Article::forge(array(
    'title' => 'FuelPHP入門',
    'user_id' => 1,
    'body' => '...',
    'published_at' => date('Y-m-d H:i:s'),
));
// 保存(INSERT文によるデータ登録)
$article->save();
// データの参照(id=1のデータを取得)
$article = Model_Article::find(1);
$article->title = 'FuelPHP入門 下準備編';
// 保存(UPDATE文によるデータ更新)
$article->save();

モデルの使い方は直感的にわかりやすく、扱いやすい印象です。
SQLでいうところのJOIN処理に対応したモデルの階層構造を持ち、関連したテーブルのデータを大元のモデルから一括で保存・削除するカスケード処理なども用意されています。

トランザクションも利用でき(PDOを利用している場合のみ)、FuelPHPの流儀に則ってデータベースが定義されていれば、細かい設定なしにJOINしたデータを取得することもできますので、APIの仕様を検討している段階からFuelPHPの利用を考えている場合は、データベースの設計もFuelPHPに寄せてしまうと開発も速くなるのではないでしょうか。

まとめ

開発の速度に燃料(Fuel)を、ということでFuelPHPをご紹介しました。
特にRESTコントローラーはAPIのために作られたコントローラーですので、ぜひ利用していきたいクラスです。

oilコマンドは公式ドキュメントではCoreクラスやORMと同列にメニューが存在するくらい高機能なコマンドです。

今回はモデルの作成をご紹介しましたが、oilコマンドからはリファインと呼ばれる、タスクのバックグラウンド処理が実行できますので、cronなどに登録する定期処理などの実行にうってつけです。

タスクには、既存のDBからモデルを作成する、「oil g model」コマンドの逆の処理を行う便利な機能もあります。

モデルでは、forge()メソッドでモデルを作成し、データを新規登録する処理を見ていただきました。
save()メソッドは、データが登録されているかどうかで、保存方法を自動的に切り替えてくれるメソッドです。
文脈によって処理の方法を考える必要がないので便利ですね。

大規模開発となってくると、コントローラーやモデルが肥大化してくるため、ビジネスロジックを切り出すなどの対応をしていかないとチーム開発は厳しくなってくると思いますが、スピード感が必要な開発や、中小規模な開発などでは、フレームワークには手を加えず使っていっても対応できるのではないでしょうか。
View周りが少し貧弱なので、RESTコントローラーを使ったAPI開発には特にオススメです。

熟れるまでに時間も掛からず、処理速度でもPHPフレームワークの中では速い部類に属する、FuelPHPでのAPI開発を試していただけると幸いです。

次回、API開発に便利なPHPフレームワーク(4)では、安定して人気があるフレームワーク「Symfony」をご紹介します。

  1. API開発に便利なPHPフレームワーク(1)- Laravel –
  2. API開発に便利なPHPフレームワーク(2)- Phalcon –
  3. API開発に便利なPHPフレームワーク(3)- FuelPHP –
  4. API開発に便利なPHPフレームワーク(4)- Symfony –
  5. API開発に便利なPHPフレームワーク(5)- CakePHP –
  6. API開発に便利なPHPフレームワークを比較 超主観的にランキングしてみた