#FuelPHP 5 分で API を実装するチュートリアル(スクリーンキャストあり)

2013/12/19

FuelPHP Advent Calendar 2013 の 19 日目です。昨日は、@madmamor さんの「FuelPHPとMongoDBとTraceKitでJavaScriptのエラー情報を収集してみる」でした。

API を作る機会が増えていますよね。スマホアプリから叩いたり、Javascript のフレームワークから叩いたりと。

あなたも私も、いきなり誰かに「私、API が叩きたいの♥」と言われるかも知れません。

ということで、いつそうなってもいいように、FuelPHP で API を実装する流れをおさらいしておきましょう。

FuelPHP には Controller_Rest というものが用意されていて、API を作るのがとても簡単なんですよー、とはよく言われるところですが、実際にどれぐらい簡単なのかやってみました。

結果は、FuelPHP のインストールも含めて、4 分 44 秒で実装できました。

以下、詳しく説明します。

前提条件

今回は、下記環境での実装例となります。

  • PHP 5.4(Built-in web server、Short array syntax を使っています)
  • FuelPHP 1.7
  • データベースに mysql を利用
  • mysql の host は localhost、port は 3306、ユーザ、パスワードともに root、データベース名は fuel_dev(FuelPHP インストール時のdevelopment環境でのデフォルト設定です)

では、はじめましょう。

データベースの準備

あらかじめ、fuel_dev という名前のデータベースを作っておきます。

$ echo 'create database fuel_dev' | mysql -u root -proot

FuelPHP のインストール

oilコマンドでさくっと行きましょう。参考)http://fuelphp.com/docs/

$ curl get.fuelphp.com/oil | sh
$ cd Sites/
$ oil create api

できたら、そのディレクトリへ移動。

$ cd api

一応念のため、動くか確認しておきましょう。ビルトインサーバ使います。

$ php -S localhost:8000 -t public

はいこんにちは。

何を作るか

今回は、簡単なメモみたいなのを作りましょう。メモを記録したり、取得したりするだけのもの。

  • http://localhost:8000/memo/write (POST メソッドで)
  • http://localhost:8000/memo/read (GET メソッドで、JSONを返す)

という2つの URL を用意して、それぞれ、メモの投稿と取得をさせたいと思います。

では、進みましょう。

oil generate で model 作成

oil generate でモデル作ります。

$ php oil generate model memo memo:varchar created_at:timestamp updated_at:timestamp --mysql-timestamp --crud --created-at --updated-at

僕の好みで、--crud --mysql-timestamp --created-at --updated-atオプションをつけてます。

    Creating model: /Users/omoon/Documents/api/fuel/app/classes/model/memo.php
    Creating migration: /Users/omoon/Documents/api/fuel/app/migrations/001_create_memos.php

とメッセージが表示されて、model と同時にマイグレーションファイルも作成されていることが分かります。

忘れないうちに、そのまま oil r migrate して、テーブルを作成してしまいましょう。

% php oil r migrate
Performed migrations for app:default:
001_create_memos

route.php の編集

続いて、fuel/app/config/route.php を下記のように編集します。

// fuel/app/config/route.php
return array(
    '_root_'  => 'welcome/index',  // The default route
    '_404_'   => 'welcome/404',    // The main 404 route
    
    'memo/read' => 'memo/read',
    'memo/write' => 'memo/write',
);

これで、

  • http://localhost:8000/memo/write
  • http://localhost:8000/memo/read

この2つのURLへアクセスできるようになります。

oil generate で controller 作成

上記で設定したルーティングに合わせてコントローラを作りましょう。

FuelPHP では、あらかじめ用意されている Controller_Rest を継承して作ります。ここがキモですね。

ここもoil generateでさくっと行きたいところですが、ざっと見た感じでは、Controller_Rest 用のオプションなどがあまり用意されていないようでしたので、ある程度まで作ってちょこっと修正する方針で行きます。

$ php oil generate controller memo write read --extends=Controller_Rest

これで、fuel/app/classes/controller/memo.php に下記のようなファイルができあがりますので、

class Controller_Memo extends Controller_Rest
{

    public function action_read()
    {
        $data["subnav"] = array('read'=> 'active' );
        $this->template->title = 'Memo » Read';
        $this->template->content = View::forge('memo/read', $data);
    }

    public function action_write()
    {
        $data["subnav"] = array('write'=> 'active' );
        $this->template->title = 'Memo » Write';
        $this->template->content = View::forge('memo/write', $data);
    }

}

このように編集します。 

class Controller_Memo extends Controller_Rest
{

    protected $format = 'json';

    public function get_read()
    {
        $memos = Model_Memo::find_all();
        $this->response($memos);
    }

    public function post_write()
    {
        $memo = Input::post('memo');
        Model_Memo::forge(['memo' => $memo])->save();
    }

}

ポイントは、

  • protected $format = 'json'; でデフォルトフォーマットを JSON に
  • public function get_read()readを GET メソッドで受け付けるように
  • public function post_write()writeを POST メソッドで受け付けるように

各メソッドでは、今回は単純にModel_Memo::find_all()で取得、Model_Memo::forge()->save()で保存を行っています。

さ、これでできたはずです。

動作確認

curl コマンドでちゃんと動くか確認します。

POSTで書き込み。

curl http://localhost:8000/memo/write -d "memo=test1"
curl http://localhost:8000/memo/write -d "memo=test2"
curl http://localhost:8000/memo/write -d "memo=test3"

GETで取得。

$ curl http://localhost:8000/memo/read
[{"id":"1","memo":"test1","created_at":"2013-12-19 19:48:08","updated_at":"2013-12-19 19:48:08"},{"id":"2","memo":"test2","created_at":"2013-12-19 19:48:12","updated_at":"2013-12-19 19:48:12"},{"id":"3","memo":"test3","created_at":"2013-12-19 19:48:15","updated_at":"2013-12-19 19:48:15"}]

無事、JSONが返却されました。

最後に

噂通り、FuelPHP での API 実装はとてもお手軽でした。みなさんも一度やってみておくと何かの時にアワアワしなくていいのではないでしょうか。

ところで、ゴリゴリ記事を書いて、必死でスクリーンキャストまで撮って、公開ボタンを押そうとしたまさにその時、@kenji_s さんが、過去に同様のことをなさっていることを発見してしまいました。

決してパクったわけではありません(信じてー)が、もうちょっと過去記事などをしっかり見ておくべきでした。。大変失礼しました。

ただ(言い訳みたいですが)、@kenji_s さんのバージョンは 1.4 で今回は 1.7、また、実装している API や手法も少し異なりますので、実装方法の異なるバージョンとして見ていただければ幸いです。汗。。

明日は、@Altsencturely さんです。

では、また。

LUMIX DMC-GM1 にライカのリストストラップをつけたら超カッコイイんですけど、というはなし

2013/12/12

小さいカメラにネックストラップは嫌だなー、ということで、リストストラップ探してたらいいの見つけた。

P1070679.JPG

ライカのやつ。

P1070476.JPG

ライカ、なんか嬉しいので、もう一回箱。

P1070472.JPG

白いステッチが超かっこいい。なんかモテそう。

P1070681.JPG

カメラも良い。小さいは正義。

P1070479.JPG

めちゃめちゃ良く写る。なんだこれ。

P1070486.JPG

ということで、みなさんも真似するといいと思います。

←カメラ

←ストラップ(Leica Wrist Strap for M & X Vario, Black)

FuelPHP のデータベースマイグレーションを Pagoda Box で使うときの注意

2013/12/03

FuelPHP Advent Calendar 2013 の 3 日目です。昨日は、@kenji_s さんの「FuelPHPの開発環境を20分で構築する(Vagrant編)」でした。`

今日は、FuelPHP の データベースマイグレーションを Pagoda Box で使う時にハマるポイントについて書きたいと思います。テーマがニッチ過ぎて、同じようなことで困っている人が他にもいるのか少し心配ではありますが、気にせず行きたいと思います。

Pagoda Box とは

まず、Pagoda Box ってなんや?というはなしを。

top

Pagoda Box は、LAMP 環境を構築できる PHP 専門の PaaS です。

PHP が使える PaaS はいくつかありますが、Pagoda Box は PHP に特化した PaaS なので、PHP エンジニアにはとてもなじみやすく、僕は結構気に入ってよく使っています。ちなみに、FuelPHP の公式サイトも Pagoda Box 上で動いているようです。

なお、Pagoda Box については、この間発売されたこの本に書きました。みなさん、よければ読んでみてください。

PHPengineer_hyoshi

PHPエンジニア養成読本 〔現場で役立つイマドキ開発ノウハウ満載! 〕 (Software Design plus)

技術評論社
(著)新原 雅司、原田 康生、小山 哲志、田中 久輝、保科 一成、大村 創太郎、増永 玲
(編集)PHPエンジニア養読本編集部

FuelPHP データベースマイグレーションのおさらい

続いて、FuelPHP でのデータベースマイグレーションの手順を簡単におさらいしておきましょう。

公式サイトの説明は、http://fuelphp.com/docs/general/migrations.html ですね。

oil generate model

$ oil generate model xxx で model クラスと、マイグレーション用のクラスが一気に作られます。僕は好みで、--crud を使うことが多いです(というかcrud しか使いません)。

% php oil generate model post id:int name:varchar message:text created_at:datetime --crud --mysql-timestamp
    Creating model: /Users/omoon/Documents/www/speak_on_fuelphp/fuel/app/classes/model/post.php
    Creating migration: /Users/omoon/Documents/www/speak_on_fuelphp/fuel/app/migrations/001_create_posts.php

で、つくられるmodelクラス。

// fuel/app/classes/model/post.php
class Model_Post extends \Model_Crud
{
    protected static $_properties = array(
        'id',
        'name',
        'message',
        'created_at'
    );
    protected static $_mysql_timestamp = true;
    protected static $_table_name = 'posts';
}

つくられるマイグレーションクラス

// fuel/app/migrations/001_create_posts.php
namespace Fuel\Migrations;
class Create_posts
{
    public function up()
    {
        \DBUtil::create_table('posts', array(
            'id' => array('constraint' => 11, 'type' => 'int'),
            'name' => array('constraint' => 255, 'type' => 'varchar'),
            'message' => array('type' => 'text'),
            'created_at' => array('type' => 'datetime'),

        ), array('id'));
    }
    public function down()
    {
        \DBUtil::drop_table('posts');
    }
}

oil r migrate

で、$ oil r migrateで該当テーブルがデータベースに作成されます。この際、

  • データベース上に migration というテーブル
  • fuel/app/config/FUEL_ENV/migrations.php というファイル(FUEL_ENV は環境)

が作成され、マイグレーションの状況を管理するしくみになっています。

なにが問題なのか

このしくみを使って、Pagoda Box へアプリケーションをデプロイしたタイミングでデータベースの初期化まで一気にやってしまいたいのですが、以下の問題がありうまくいかないということがわかりました。

  • $ oil r migration 実行時に fuel/config/production/migrations.php ファイルが生成されるので、fuel/config/production/ を writable にする必要がある
  • Pagoda Box では、writable ディレクトリは、ソースコードレポジトリとは別に、ネットワーク上にマウントされる
  • そのため、同じディレクトリにあるデータベースへの接続ファイル fuel/config/production/db.php が消える
  • データベースへの接続ができなくなる

解決方法

  • fuel/app/config/pagoda/db.phpに別ファイルで Pagoda Box 甩設定ファイルを用意しておく
  • before_deploy フックで、fuel/app/config/pagoda/db.php ファイルをfuel/app/config/production/ 配下へコピーする

という作戦で解決です。

参考までに Boxfile 例。

global:
  env:
    - FUEL_ENV: production
db1:
  type: mysql
  name: speak
web1:
  shared_writable_dirs:
    - /fuel/app/cache
    - /fuel/app/logs
    - /fuel/app/tmp
    - /fuel/app/config/production # <- migrations.php が作られるためwritableに
  document_root: public
  php_version: 5.4.14
  php_date_timezone: "Asia/Tokyo"
  php_extensions:
    - pdo_mysql
    - zip
  after_build:
    - "curl -s http://getcomposer.org/installer | php"
    - "php composer.phar install"
  before_deploy:
    # production とは別のディレクトリにおいておいた db.php をコピー
    - "cp fuel/app/config/pagoda/db.php fuel/app/config/production/db.php"
    - "php oil r migrate"

fuel/app/config/pagoda.db.php はこうなります。

return array(
    'default' => array(
        'connection'  => array(
            'dsn'        => 'mysql:host='.$_SERVER['DB1_HOST'].';port='.$_SERVER['DB1_PORT'].';dbname='.$_SERVER['DB1_NAME'],
            'username'   => $_SERVER['DB1_USER'],
            'password'   => $_SERVER['DB1_PASS'],
        ),
    ),
);

これで、$ git push pagoda で一気にアプリケーションのデプロイからデータベースの初期化までできるようになります。

それでは、また。

明日は、mikakane さんです。