FuelPHPアプリをCapistrano3でデプロイ – Capistrano環境構築編

前回の記事「FuelPHPアプリをCapistrano3でデプロイ – Chef環境構築編」で準備した環境に、Capistrano3でFuelPHPをデプロイする手順をまとめる

FuelPHPは、Coreをsubmoduleのままにしている場合は、git submoduleに対応させる必要がある
ComposerによるPHPパッケージの追加はCapistrano::Composerプラグインを利用する

公式のREADMEに従ってプロジェクトを作した後に、FuelPHP固有の設定を追加していく

ssh-keyをbitbucketに登録

PCからの直接デプロイする場合は、すでにリポジトリにローカルの公開キーを登録済みと思われるが、登録していない場合は、
ssh-keyを生成してbitbucketに登録」あたりを参考に、公開キーをBitbucketに登録しておく

Capistranoのインストール

まずは、プロジェクト用ディレクトリを作成

$ mkdir fuelphp-cap

Gemfileを作成

# Gemfile
source 'https://rubygems.org'

gem 'capistrano', '~>; 3.4.0'

bundle installを実行
PCからの実行を考えるとローカルインストールしておきたいので--pathをつけている

$ bundle install --path vendor/bundle

“FuelPHPアプリをCapistrano3でデプロイ – Capistrano環境構築編” の続きを読む

FuelPHPアプリをCapistrano3でデプロイ – Chef環境構築編

Ubuntu 14.04上にFuelPHPアプリをCapistrano3でデプロイする環境をChefでセットアップした手順のまとめ

MySQLは、DB専用サーバーを立てることを前提に、WebアプリケーションサーバーとしてApache + mod_phpな環境をChefで構築していく
また、Capistranoに合わせたApacheの設定もChefで記述する

Chefの実行およびCapistoranoによるデプロイは、踏み台を使わずPC Macからすべて実行可能な環境を作る

Chef開発環境セットアップ

Chef DevKITのインストール

Chefは、現在開発キットが提供されておりRuby gemでのインストールは不要になっている
Chef Development KITのサイトに行くとプラットフォームごとのインストーラーを入手できる
https://downloads.chef.io/chef-dk/
開発キットには、chefおよび以下の周辺ツールがオールインワンで含まれている

  • Berkshelf 3.0
  • Test Kitchen
  • Foodcritic

Knife soloのインストール

PCからChefを実行するためにはKnife soloが必要になる
ChefDKのgemに追加する

$ /opt/chefdk/embedded/bin/gem install knife-solo

“FuelPHPアプリをCapistrano3でデプロイ – Chef環境構築編” の続きを読む

FuelPHPでTwilioアプリを作成してみた

Railsを使って実装している、Twilio Dosにあるチュートリアル Appointment Reminder と同じアプリケーションをFuelPHPで実装してみます。

TwilioのAPIを呼び出すライブラリは、Twilio APIライブラリ – PHP, C#, Python, Java, RubyのPHPのところにも載っている Fuel-Twilio というFuelPHPパッケージを利用します。
Github: fuel-packages/fuel-twilio

FuelPHPプロジェクトを作成した後、まずは、fuel-twilioパッケージをセットアップしていきます。

[Download ZIP]からパッケージを落として fuel/packages にコピーします。
[bash gutter=”false”]
$ mv ~/Downloads/fuel-twilio-master.zip fuel/packages/
$ cd fuel/packages
$ unzip fuel-twilio-master.zip
$ mv fuel-twilio-master fuel-twilio
[/bash]

always_loadにfuel-twilioパッケージを指定
[php title=”fuel/app/config/config.php” firstline=”260″]
‘always_load’ => array(

‘packages’ => array(
//’orm’,
‘fuel-twilio’,
),

),
[/php]

次に、fuel/packages/fuel-twilio/config/twilio.php を fuel/app/configにコピーしてアクセスキーなどを設定します。
[bash gutter=”false”]
$ cp fuel/packages/fuel-twilio/config/twilio.php fuel/app/config/
[/bash]
[php title=”fuel/app/config/twilio.php”]
‘account_sid’ => ‘XXXXX’,
‘auth_token’ => ‘YYYYY’,
‘from’ => ‘+815011112222’,
[/php]
ACCOUNT SIDとAUTH TOKENは、Twilioのダッシュボードで確認できます。
fromには、発信元の電話番号を指定します。

補足:
fuel-twilioはTwilioへのhttpリクエストにPHP cURLを使います。
インストールされていない場合は、インストールしておきます。
UbuntuなどAPT利用時のコマンド
[bash gutter=”false”]
$ sudo apt-get install php5-curl
$ sudo service apache2 reload
[/bash]

fuel-twilioパッケージのセットアップは以上です。

以降、Appointment Reminderを実装して行きます。

homeコントローラを作成して、必要なアクションを追加します。
[bash gutter=”false”]
$ oil g controller home index makecall reminder directions goodbye
Creating view: /path/to/fuel/app/views/template.php
Creating view: /path/to/fuel/app/views/home/index.php
Creating view: /path/to/fuel/app/views/home/makecall.php
Creating view: /path/to/fuel/app/views/home/reminder.php
Creating view: /path/to/fuel/app/views/home/directions.php
Creating view: /path/to/fuel/app/views/home/goodbye.php
Creating controller: /path/to/fuel/app/classes/controller/home.php
[/bash]
Viewが必要なのはindexだけなので、それ以外のビューは削除しておきます。
[bash gutter=”false”]
$ rm fuel/app/views/home/makecall.php
$ rm fuel/app/views/home/reminder.php
$ rm fuel/app/views/home/directions.php
$ rm fuel/app/views/home/goodbye.php
[/bash]

Twilioからのリクエストの応答は、Twilio::twimlを利用してXMLを生成するので、Controller_Restを継承したコントローラに分けることはせずController_Homeですべて実装しています。

ルートへのアクセスをすべてHomeControllerのアクションにルーティングします。
[php title=”fuel/app/config/routes.php”]
<?php
return array(
‘_root_’ => ‘home/index’, // The default route
‘(:segment)’ => ‘home/$1’,
);
[/php]
参照: やや高度なルーティング – FuelPHP Documentation

次に、各アクションを実装していきます。

1. index ページ

Appointment Reminderのhowtos/appointmentreminder/index.html.erbをFuelPHPのindex.phpに実装します。
Flashメッセージは、template.phpのコードを利用できるので省略します。
[php title=”fuel/app/views/home/index.php”]
<h1>Twilio phone reminder demo</h1>
<h3>Enter your phone number to receive an automated reminder</h3>
<?php echo Form::open(array(‘action’ => ‘makecall’)) ?>
<?php echo Form::input(‘number’); ?>
<?php echo Form::submit(‘Call me!’); ?>
<?php echo Form::close(); ?>
[/php]
homeコントローラのindexアクションはそのまま利用します。

2. makecall アクション

元のサンプルのhowtos/appointmentreminder/appointmentreminder_controller.rbのmakecallアクションをFuelPHPのhomeコントローラのmakecallアクションとして実装します。
[php title=”fuel/app/classes/controller/home.php” firstline=”13″ highlight=”24,25,26,27,28″]
public function action_makecall()
{
if (!Input::post(‘number’))
{
Session::set_flash(‘error’, ‘Invalid phone number’);
Response::redirect(‘/’);
}

$call = Twilio\Twilio::request(‘MakeCall’);
try
{
$response = $call->create(array(
‘To’ => Input::post(‘number’),
‘From’ => ‘+815011112222’,
‘Url’ => Uri::create(Uri::base(false). "reminder"),
));

if ($response->status !== ‘queued’)
{
Session::set_flash(‘error’, $response->message);
Response::redirect(‘/’);
}
}
catch (Exception $e)
{
Session::set_flash(‘error’, $e->getMessage());
Response::redirect(‘/’);
}

Session::set_flash(‘success’, ‘Calling ‘.Input::post(‘number’).’…’);
Response::redirect(‘/’);
}
[/php]
ハイライト箇所がTwilioから電話をかけるコードです。
他はエラーハンドリングになります。

3. reminderアクション

howtos/appointmentreminder/appointmentreminder_controller.rbのreminderアクション
howtos/appointmentreminder/reminder.xml.builderビュー
をFuelPHP homeコントローラのreminderアクションに実装します。
[php title=”fuel/app/classes/controller/home.php” firstline=”46″]
public function action_reminder()
{
$question = new Twilio\Twilio_Twiml();
$question->say(‘こんにちはこの電話はTwilioから発信しています。明日の午前9時からアポイントメントがあります。’, array(‘language’ => ‘ja-jp’));
$question->say(‘このメニューを繰り返す場合は1を、順路を聞く場合は2を、終了する場合は3をプッシュしてください。’, array(‘language’ => ‘ja-jp’));
$twiml = Twilio\Twilio::twiml();
$twiml->gather(
$question,
array(
‘action’ => Uri::create(Uri::base(false). "directions"),
‘method’ => ‘GET’,
‘numDigits’ => 1,
)
);

$response = Response::forge($twiml->render());
$response->set_header(‘Content-type’, ‘text/xml; charset=utf-8’);
return $twiml->render();
}
[/php]
元のサンプルではレスポンスのXMLをビューで構築していますが、fuel-twilioにはTwilio\Twilio_Twimlクラスが用意されているので、アクション内で応答を構築して返しています。
メッセージは、日本語にしています。日本語の場合は、Sayの属性languageja-jpを指定します。
Gatherの使い方は、Grabbing key presses during a call を参考にしました。

4. directionsアクション

howtos/appointmentreminder/appointmentreminder_controller.rbのdirectionsアクションとhowtos/appointmentreminder/directions.xml.builderをhomeコントローラのdirectionsアクションに実装します。

[php title=”fuel/app/classes/controller/home.php” firstline=”66″]
public function action_directions()
{
if (Input::get(‘Digits’) == 3)
{
Response::redirect(‘goodbye’);
}

else if (Input::get(‘Digits’) == 1)
{
Response::redirect(‘reminder’);
}

$twiml = new Twilio\Twilio_Twiml();
$twiml->say(‘アポイントメントは通り近くの建物で行われます。’, array(‘language’ => ‘ja-jp’));
$twiml->redirect(Uri::create(Uri::base(false). "reminder"));

$response = Response::forge($twiml->render());
$response->set_header(‘Content-type’, ‘text/xml; charset=utf-8’);
return $response;
}
[/php]

5. goodbyeアクション

goodbyeは元記事には載ってせんが以下のように実装しました。
[php title=”fuel/app/classes/controller/home.php” firstline=”87″]
public function action_goodbye()
{
$twiml = new Twilio\Twilio_Twiml();
$twiml->say(‘さようなら。’, array(‘language’ => ‘ja-jp’));

$response = Response::forge($twiml->render());
$response->set_header(‘Content-type’, ‘text/xml; charset=utf-8’);
return $response;
}
[/php]

以上で、Railsのチュートリアル Appointment Reminder と同じ動作のアプリケーションをFuelPHPできました。

FuelPHP でコマンド実行タスクを実装する

FuelPHPで、バッチ実行用のコマンドを実装するには、タスク を利用できます。

コントローラをバッチ実行に兼用するCodeIgniterから比べると、この辺りは後継のFuelPHPの方が使いやすくなっています。
また、FuelPHPのタスクは非常にシンプルな仕組みなので、ちょっとモデルの実装を確認するときなどにも割と重宝するときもあります(すべてにテストがかければいいんですけど。。)。

サンプルのタスクが、あるので実行してみます。

$ oil r robots

                    "KILL ALL HUMANS!"
                      _____     /
                     /_____\
                ____[\*---*/]____
               /\ #\ \_____/ /# /\
              /  \# \_.---._/ #/  \
             /   /|\  |   |  /|\   \
            /___/ | | |   | | | \___\
            |  |  | | |---| | |  |  |
            |__|  \_| |_#_| |_/  |__|
            //\\  <\ _//^\\_ />  //\\
            \||/  |\//// \\\\/|  \||/
                  |   |   |   |
                  |---|   |---|
                  |---|   |---|
                  |   |   |   |
                  |___|   |___|
                  /   \   /   \
                 |_____| |_____|
                 |HHHHH| |HHHHH|

アスキーアートのロボットが表示されます。”KILL ALL HUMANS!”。。。w

タスクの実行は、oilコマンドにクラス名を指定します。
(つまり migrate などは fuel/core/tasks に含まれるタスクになっています)

タスククラスの書き方は fuel/app/tasks ディレクトリに、namespace “Fuel\Tasks” を指定したクラスを定義します。
処理は、タスククラスのインスタンスメソッドに実装します。

// fuel/app/tasks/greeting.php
namespace Fuel\Tasks;

class Greeting
{

    public function run($message = 'Hey', $name = "Guys")
    {
        echo $message." ".$name."!\n";
    }

    public function goodMorning($name = "Guys")
    {
        echo $this->run("Good morning", $name);
    }
}

この例では、run メソッドと goodMornig というメソッドを実装しています。

また、Oilコマンドに、タスクの生成コマンドも用意されています。
タスク – Generate – Oil パッケージ – FuelPHP ドキュメント
このタスクを生成する場合は以下のようにoilコマンドを実行します。

$ oil g task greeting goodMorning
        Preparing task method [GoodMorning]
    Creating tasks: /path/fuel/app/tasks/greeting.php

タスクの実行は、タスク名のみだと run メソッドが実行されます。
一方、run 以外の名前のメソッドを実行するには”:”に続けてメソッド名を指定します。
また、このタスクの run メソッドには引数が2つありますが、引数はタスク名に続けて空白区切りで指定します。

$ oil r Greeting
Hey Guys!
$ oil r Greeting "Good night" John!
Good night John!!
$ oil r Greeting:goodMorning
Good morning Guys!
$ oil r Greeting:goodMorning Bob
Good morning Bob!

補足になりますが、タスクの中でモデルを呼び出す場合は、タスクのネームスペースが “Fuel\Tasks” に指定されているので、グローバルから指定する必要があります。
例えば、Greetingのロジックをモデルに移した場合。

<?php
// fuel/app/classes/model/greeting.php
class Model_Greeting
{
    public static function hey($message = 'Hey', $name = "Guys")
    {
        echo $message." ".$name."!\n";
    }
}
// fuel/app/tasks/greeting.php
namespace Fuel\Tasks;

class Greeting
{

    public function run($message = 'Hey', $name = "Guys")
    {
        \Model_Greeting::hey($message, $name);
    }
}
$ oil r Greeting
Hey Guys!

FuelPHP Admin scaffoldingの使い方

FuelPHPには、マスター管理対象となるモデルの管理画面を自動生成するOilコマンド、Admin Scaffolding
がデフォルトで含まれています。

会社のモデルの管理画面を作成したときの手順です。

コードと名前だけをもつ会社マスター用のモデルを作成して、マイグレーションを実行

$ oil g admin company code:string name:string 
    Creating controller: /path/to/project/fuel/app/classes/controller/base.php
    Creating controller: /path/to/project/fuel/app/classes/controller/admin.php
    Creating views: /path/to/project/fuel/app/views/admin/template.php
    Creating views: /path/to/project/fuel/app/views/admin/dashboard.php
    Creating views: /path/to/project/fuel/app/views/admin/login.php
    Creating migration: /path/to/project/fuel/app/migrations/001_create_companies.php
    Creating model: /path/to/project/fuel/app/classes/model/company.php
    Creating controller: /path/to/project/fuel/app/classes/controller/admin/company.php
    Creating view: /path/to/project/fuel/app/views/admin/company/index.php
    Creating view: /path/to/project/fuel/app/views/admin/company/view.php
    Creating view: /path/to/project/fuel/app/views/admin/company/create.php
    Creating view: /path/to/project/fuel/app/views/admin/company/edit.php
    Creating view: /path/to/project/fuel/app/views/admin/company/_form.php
$ oil r migrate

管理画面にアクセス可能かどうかは Auth パッケージの User の所属グループによって判断されます。

Authパッケージを有効にします。

// app/config/config.php
    'always_load'  => array(
        // ...
        'packages'  => array(
            'orm',
            'auth',
        ),
        // ...
        'config'  => array('auth'),
        // ...
    ),

Authドライバーは Ormauth を指定しました。

 $ cp fuel/packages/auth/config/auth.php fuel/app/config/
// fuel/app/config/auth.php
return array(
    'driver' => 'Ormauth',
    'verify_multiple_logins' => false,
    'salt' => 'xxxxxxx',
    'iterations' => 10000,
);

Authパッケージ用のテーブルをデータベースに追加します。

$ oil r migrate --packages=auth
Performed migrations for package:auth:
001_auth_create_usertables
002_auth_create_grouptables
003_auth_create_roletables
004_auth_create_permissiontables
005_auth_create_authdefaults
006_auth_add_authactions
007_auth_add_permissionsfilter
008_auth_create_providers
009_auth_create_oauth2tables
010_auth_fix_jointables

管理画面にアクセスするユーザは、”Super Admins”のAuth_Groupに所属している必要があります。
追加された Controller_Admin をみると before で管理者かどうかをチェックしているのがわかります。

// fuel/app/classes/controller/admin.php
class Controller_Admin extends Controller_Base
{
    // ...
    public function before()
    {
        parent::before();

        if (Request::active()->controller !== 'Controller_Admin' or ! in_array(Request::active()->action, array('login', 'logout')))
        {
            if (Auth::check())
            {
                $admin_group_id = Config::get('auth.driver', 'Simpleauth') == 'Ormauth' ? 6 : 100;
                if ( ! Auth::member($admin_group_id))
                {
                    Session::set_flash('error', e('You don\'t have access to the admin panel'));
                    Response::redirect('/');
                }
            }
            else
            {
                Response::redirect('admin/login');
            }
        }
    }

Ormoauthの場合は、id=6 のグループが管理者グループとしてデータベースに登録されています。
ユーザーにグループを設定する画面はないので、データベースを直に修正して管理者を設定します。

とりあえず、Authパッケージのマイグレーションで追加される admin@example.org / admin ユーザーでログインすると、/admin 以下に管理画面が作成されています。

admin_scaffolding

参考:
FuelPHP での「管理パネル」チュートリアル – A Day in Serenity @ kenjis
Build an Admin Panel with the Fuel PHP Framework – Tuts+ Code Tutorial

FuelPHP モデルに独自に実装したObserverを追加するには

公式ドキュメントの 独自のオブザーバーを書く で説明されていますが、改めてメモ。

// fuel/app/classes/observer/something.php
class Observer_Something extends Orm\Observer
{

    public function after_insert(Orm\Model $model)
    {
        \Log::info('Succesfully created new object of class '.get_class($model));
    }
}

これを Postモデルに適用する場合

<?php
//fuel/app/classes/model/post.php
use Orm\Model;

class Model_Post extends Model
{
    // ...
    protected static $_observers = array(
        'Orm\Observer_CreatedAt' =>; array(
            'events' =>; array('before_insert'),
            'mysql_timestamp' =>; false,
        ),
        'Orm\Observer_UpdatedAt' =>; array(
            'events' =>; array('before_save'),
            'mysql_timestamp' =>; false,
        ),
        'Observer_Somthing' =>; array(
            'events' =>; array('after_insert'),
        ),
    );
    // ...
}

Windows Azure WebサイトでFuelPHPアプリを動かす

  1. WEBサイトを作成します。

新規Webサイトの作成

  1. Webサイトの作成-ウィザード1 – 名前とリージョンとデータベースにMySQLを選択

FuelPHP-Azure-2

  1. Webサイトの作成-ウィザード2 – データベースの確認

FuelPHP-Azure-3

  1. Webサイトの作成-ウィザード3 – リポジトリの選択

FuelPHP-Azure-4

  1. Bitbucketとの接続を許可します

FuelPHP-Azure-5

  1. リポジトリを選択します
    今回はbitbucketのリポジトリを利用しました。

FuelPHP-Azure-6

チェックボタンをクリックするとWebサイトの作成が始まります。

  1. 新しいWebサイトが追加されました

FuelPHP-Azure-7

  1. デプロイを確認
    fuelblogを選択し[デプロイ]タブを開くと、gitからcloneされたことを確認できます。

FuelPHP-Azure-8

デプロイはされていますが、まだデータベースの設定やmigrationはされていないので動きません。

  1. データベースの設定
    データベースのホスト名、データベース名、接続ユーザの情報は[構成]タブの[接続文字列]で確認できます。

FuelPHP-Azure-9
接続情報を db.php に指定します。

<?php
// fuel/app/config/production/db.php
/**
 * The production database settings. These get merged with the global settings.
 */
return array(
    'default' => array(
        'connection'  => array(
            'dsn'        => 'mysql:host=ja-cdbr-azure-east-a.cloudapp.net;dbname=fuelphpAC9JPSbeW',
            'username'   => 'b075b5148a0559',
            'password'   => 'f4f0edcd',
        ),
    ),
);

編集した db.php はコミットしておきます。

  1. production環境に設定する
    [構成]タブの[アプリケーション設定]に FUEL_ENV を追加します。

FuelPHP-Azure-10

  1. デプロイスクリプトの準備
    デプロイ時に、Composer updateとマイグレーションを実行するように設定します。

deploymentscriptの作成するために、Winsows Azure SDKを http://www.windowsazure.com/ja-jp/downloads/ からPHP / Mac のインストール を選択してダウンロードし、インストールします。
以下のコマンドでスクリプトを生成します。

$ azure site deploymentscript --php
info:    Executing command site deploymentscript
info:    Generating deployment script for Web Site
info:    Generated deployment script files
info:    site deploymentscript command OK

以下の2つのファイルができます

  • .deployment
  • deploy.sh

deploy.shの最後にComporserとマイグレーションの処理を記述します。

...
echo Running Composer.
cd $DEPLOYMENT_TARGET
"D:\Program Files (x86)\PHP\v5.4\php.exe" composer.phar update --prefer-dist -v

echo Running FuelPHP migration.
"D:\Program Files (x86)\PHP\v5.4\php.exe" oil refine migrate
cd $DEPLOYMENT_SOURCE

echo "Finished successfully."

oilの実行は、FUEL_ENV=productionを指定しなくても、[アプリケーション設定]が適用されます。

git add してpushします。

$ git add .deployment deploy.sh
$ git commit -m "deployment script"
$ git push origin master

新たにデプロイが実行されます。

FuelPHP-Azure-11

[Running deployment command…]のログを表示してみるとComposer updateとマイグレーションが正しく実行されたことが確認できます。

Command: bash deploy.sh

Handling Basic Web Site deployment.

KuduSync.NET from: 'D:\home\site\repository' to: 'D:\home\site\wwwroot'

Copying file: 'fuel\app\config\development\db.php'

Running Composer.

Loading composer repositories with package information

Updating dependencies (including require-dev)

  - Installing psr/log (dev-master a78d650)

    Downloading: connection...    Downloading: 0%               Downloading: 15%    Downloading: 30%    Downloading: 45%    Downloading: 60%    Downloading: 75%    Downloading: 100%

    Extracting archive

  - Installing monolog/monolog (1.5.0)

    Downloading: connection...    Downloading: 100%         

    Extracting archive

  - Installing fuelphp/upload (2.0.1)

    Downloading: connection...    Downloading: 100%         

    Extracting archive

monolog/monolog suggests installing mlehner/gelf-php (Allow sending log messages to a GrayLog2 server)

monolog/monolog suggests installing raven/raven (Allow sending log messages to a Sentry server)

monolog/monolog suggests installing doctrine/couchdb (Allow sending log messages to a CouchDB server)

monolog/monolog suggests installing ext-amqp (Allow sending log messages to an AMQP server (1.0+ required))

monolog/monolog suggests installing ext-mongo (Allow sending log messages to a MongoDB server)

Writing lock file

Generating autoload files

Running FuelPHP migration.

Performed migrations for app:default:

001_create_posts

Finished successfully.
  1. 動作確認
    動いた。

FuelPHP-Azure-12

  1. publicフォルダをルートディレクトリに設定する
    上記の動作確認は、http://fuelblog.azurewebsites.net/public/posts にアクセスしていたので、publicディレクトリをルートディレクトリとして指定し直します。
    プロジェクト直下に、以下のWeb.configを作成して、pushするとpublicなしでアクセスできるようになります。
<?xml version="1.0" encoding="utf-8"?>
<!-- Web.config -->
<!--
  For more information on how to configure your ASP.NET application, please visit
  [url=http://go.microsoft.com/fwlink/?LinkId=169433]http://go.microsoft.com/fwlink/?LinkId=169433[/url]
  -->
<configuration>
  <system.diagnostics>
   <trace>
      <listeners>
        <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics">
          <filter type="" />
        </add>
      </listeners>
    </trace>
  </system.diagnostics>
  <appSettings>
    <add key="EMULATED" value="true" />
  </appSettings>
  <system.webServer>
      <httpErrors errorMode="Detailed"/>
      <defaultDocument>
      <files>
        <clear />
        <add value="index.php" />
        <add value="index.htm" />
        <add value="index.html" />
      </files>
    </defaultDocument>
      <rewrite>
          <rules>
            <rule name="Redir Subdir" stopProcessing="false">
                <match url="(.*)" ignoreCase="false" />
                <conditions>
                    <add input="{URL}" pattern="^/public" ignoreCase="false" negate="true" />
                </conditions>
                <action type="Rewrite" url="/public/{R:1}" appendQueryString="true" />
            </rule>
            <rule name="RegleFichierPublic" stopProcessing="true">
                <match url="^\/public\/(.*)$" ignoreCase="false" />
                <conditions>
                    <add input="{URL}" pattern="^/public" ignoreCase="false" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
                </conditions>
                <action type="Rewrite" url="/public/index.php/{R:1}" appendQueryString="true" />
            </rule>
          </rules>
      </rewrite>
  </system.webServer>
</configuration>

補足

SDKのアンインストール手順メモ。

This package will install the Windows Azure SDK into /usr/local/bin/azure/

To use the command line interface after installation, type `azure` in the Terminal.

To uninstall, type `azure-uninstall` in the Terminal.

.gitmodulesは、Windowsのパス区切り文字に置き換えなくても動く。

submodule updateが失敗する(かなり頻発)が、そのときは何回か再試行または同期しなおすと正常実行される。
FuelPHP関連のsubmoduleは、FuelPHP自体をアップデートするとき以外はsubmoduleを外しておいた方が良さそう。
git submoduleの解除方法

参考

PHP and MySQL on Windows Azure: Getting Started and Deploying with Git – site point
Azure Web site で FuelPHP を動かして migration までやってみた
無料で使えるWindows Azure Webサイトの新モードを試す
[IIS][Azure]Configure FuelPHP – FuelPHP Forums
Getting started on Windows Azure with PHP on Mac OS. (youtube)

FuelPHPでユニークバリデーションを追加する

FuelPHPは、標準ではユニークチェック用のバリデーションルールが用意されていないので、ユニークチェックをしたい場合は独自のバリデーションを拡張する必要があります。

公式ドキュメントの Validation クラスを拡張する に独自バリデーションの追加方法が記載されていますが、この例がちょうどユニークチェックの追加方法になっています。

以下のコードは、ドキュメントの例に、idの比較を含めて編集時にも対応していました。

// fuel/app/classes/myvalidation.php
<?php
class MyValidation
{
    // 静的メソッドであることに注意する
    public static function _validation_unique($val, $options)
    {
        list($table, $field) = explode('.', $options);

        $id = Validation::active()->input('id');

        $result = DB::select("LOWER (\"$field\")")
        ->where($field, '=', Str::lower($val))
        ->where('id', '!=', $id) // 編集時には、同じレコードを外してチェック
        ->from($table)->execute();

        Validation::active()->set_message('unique', '「:label 」はユニークです。「:value」は既に登録されています。');

        return ! ($result->count() > 0);
    }
 }

モデルへの適用

// fuel/app/classes/model/user.php
<?php
class Model_User extends \Orm\Model
{
    ...
    public static function validate($factory)
    {
        $val = Validation::forge($factory);
        $val->add_callable('MyValidation');
        $val->add_field('screen_name', 'screen_name', 'required|max_length[255]')
            ->add_rule('unique', 'users.code');
        return $val;
    }
    ...
}

また、idは、postパラメータに含める必要があるため編集フォームに含めます。

// fuel/app/views/user/_form.php
<?php echo Form::hidden('id', Input::post('id', isset($user) ? $user->id : '')); ?>

ここは、ちょっと気持ちが悪い。しかし、他にいい方法が思いつかない。

FuelPHP oil generate migrationによるマイグレーション作成

FuelPHPのマイグレーションの使い方について、主にoilコマンドによるマイグレーション生成の仕方についてまとめている

Magic Migrationのルールについては、fuel/packages/oil/classes/generate/generate.phpmigrationメソッド、fuel/packages/oil/classes/generate/migration/actions.phpを見ると詳細が分かる

oil generateコマンドの使い方

テーブルの作成とフィールド定義

テーブルの作成はモデルの作成と同時に実行するのが便利
ビューも必要ならscaffoldを使う

$ php oil generate model Comment post_id:integer message:string
    Creating model: /Applications/MAMP/htdocs/appointments/fuel/app/classes/model/comment.php
    Creating migration: /Applications/MAMP/htdocs/appointments/fuel/app/migrations/012_create_comments.php

テーブル作成のマイグレーションのみを生成する場合は
create_{テーブル名}のようにマイグレーション名を指定する

$ php oil generate migration create_comments post_id:integer message:string

“FuelPHP oil generate migrationによるマイグレーション作成” の続きを読む

FuelPHP – 環境ごとにログの出力レベルを変える

FuelPHPでは、config直下と同じ設定が環境ごとの設定にある場合上書きされます(参照:環境と設定)。
なので、例えば development でのみ log_threshold を info にしたいときは、config/development に config.php を作成して、以下を記述すれば適用されます。
[php title=”fuel/app/config/development/config.php”]
return array(
‘log_threshold’ => Fuel::L_INFO,
);
[/php]