Yii 2.0 入門 – インストールからコード生成ツールGiiの使い方、ルーティング設定まで

PHPのMVCフレームワークの中では、Githubリポジトリのスターの数がLaravel, CodeIgniter, Symfonyに次いでくらい多いのに、国内では書籍でも紹介されることがないマイナーなフレームワークYii。
最近2.0がリリースされてモダンになったらしいので、雰囲気を掴むためにプロジェクトのセットアップからScaffoldingツール GiiによるCRUDコードの生成を試してみました。

Yiiの特徴としては、まずOracleにやMongoDBなど他のフレームワークでは対応していないDBまでサポートしていることがあります。
SQLServerは最近どのフレームワークでも対応してきましたが、Oracleでちゃんと動くのはYiiとSymfonyくらいではないでしょうか。

また、これからフレームワークを選定するならLaravelとの比較になると思いますが、LaravelはフロントエンドにAngularJSやReactJSなどのSPAフレームワークと組み合わせて使うことを考慮しているのに対して、どちらかというとYiiは昔ながらのMVCフレームワークでシンプルです。
また、Scaffoldingツール Giiが便利で、ささっとDBのフロントアプリを立ち上げたいとかに向いてそうです。

インストール

Vagrantを利用して環境を構築してみます。
Ubuntu 14.04のVagrant boxにLAMPをインストールし、Yii 2.0のプロジェクトを生成、動作を確認するところまでまず解説していきます。

Vagrant環境のセットアップ

プロジェクト用ディレクトリyii2-helloを作成して、Ubuntu 14.04のVagrant環境を用意

$ mkdir yii2-hello && cd yii2-hello
$ vagrant init ubuntu/trusty64

“Yii 2.0 入門 – インストールからコード生成ツールGiiの使い方、ルーティング設定まで” の続きを読む

Laravel homesteadを利用したLaravel 5 ローカル開発環境の構築

Laravelは、フロントエンドのビルドツールLaravel ElixrがGulpタスクであるためPHPの他にNode環境が必要になったりと、ひととおり開発環境を揃えるのが若干面倒だったりします。
そこで、Laravelには、ローカル開発用のVagrant box Laravel Homestead が用意されています。

この記事では、Homesteadを利用したLaravel5の開発環境の構築手順を試してみたのでまとめてみました。

前提条件としてVirtualboxとVagrantはインストール済みとして解説します。
boxはVirtualboxとVMWare プロバイダ用がありますが、ここではVirtualboxを利用します。

HomesteadのVagrant boxを追加

vagrant boxコマンドでhomestead boxを追加します。

$ vagrant box add laravel/homestead
==> box: Loading metadata for box 'laravel/homestead'
    box: URL: https://atlas.hashicorp.com/laravel/homestead
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) virtualbox
2) vmware_desktop

Enter your choice: 1
==> box: Adding box 'laravel/homestead' (v0.4.1) for provider: virtualbox
    box: Downloading: https://atlas.hashicorp.com/laravel/boxes/homestead/versions/0.4.1/providers/virtualbox.box
==> box: Successfully added box 'laravel/homestead' (v0.4.1) for 'virtualbox'!

virtualboxを選択します。

Homesteadのインストール

ユーザのホームディレクトリにHomesteadをインストールします。
Homesteadには、Vagrantfileと初期設定のためのシェルのみが含まれます。

以下のコマンドを実行してHomesteadをセットアップします。

$ ~
$ git clone https://github.com/laravel/homestead.git Homestead
$ cd Homestead/
$ bash init.sh
Homestead initialized!

クローンして、init.shを実行すると設定を含む~/.homesteadディレクトリが作成されます。
“Laravel homesteadを利用したLaravel 5 ローカル開発環境の構築” の続きを読む

MAMPのPHPにoci8およびpdo_ociをインストールするには

以下のQiitaの記事を参考にMAMPのPHPからOracleに接続できるようにしてみました。
MacOSX – Macにoci8をインストールする – Qiita
oracle – yumで入れたPHPにoci8とpdo_ociを入れる – Qiita
Setting up MAMP, PEAR, PECL, and PHPUnit on Lion. – Taylor Otwell

MAMPは、インストールにOracleへの接続関数oci_connectPDOからのOracle接続は含まれていません。
Oracleへの接続を有効にするには、以下の拡張ライブラリを追加する必要があります。

  • oci_connectはoci8.so
  • PDOによる接続にはpdo_oci

拡張ライブラリはPECLかソースコンパイルで追加することができます。
また、ライブラリのコンパイルにはOracle Instant Clientが必要です。

以下、Oracle Instant Clientの準備から各拡張ライブラリのインストール、Apache起動時に環境変数を追加する設定まで解説します。

“MAMPのPHPにoci8およびpdo_ociをインストールするには” の続きを読む

Laravel ExcelでPHPExcelを利用するには

PHPExcelをLaravelで利用する場合はサービスプロバイダー Laravel Excel が使えます。

HP: http://www.maatwebsite.nl/laravel-excel/
Githu: https://github.com/Maatwebsite/Laravel-Excel

Laravel Excelのセットアップ

composer.jsonのrequireにパッケージを追加
[text title=”composer.json” hightlight=”3″]
"require": {
"laravel/framework": "4.2.*",
"maatwebsite/excel": "1.*"
},
[/text]
Composerを更新する
[bash gutter=”false”]
$ php composer.phar update
[/bash]
or
[bash gutter=”false”]
$ composer update
[/bash]
“Laravel ExcelでPHPExcelを利用するには” の続きを読む

LaravelをApacheのサブディレクトリ(Alias)にインストールするには

公式フォーラムに書いてありました。
[SOLVED] Apache Alias (subfolder) and .htaccess (Page 1) / Laravel 4.x Help / Laravel Forums

物理ディレクトリ /var/www/hellolaravel/ にlaravelのプロジェクトを配置した場合のhttpd.confと.htaccessの設定は以下の用になります。

[text title=”https.conf”]
Alias /hellolaravel "/var/www/hellolaravel/public/"

<Directory "/var/www/hellolaravel/public/">
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Order allow,deny
Allow from all
</Directory>
[/text]

.htaccessはRewriteBaseを追加します。
[text title=”hellolaravel/public/.htaccess” highlight=”9, 11″]
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>

RewriteEngine On

# Redirect Trailing Slashes…
RewriteRule ^(.*)/$ /hellolaravel/$1 [L,R=301]

RewriteBase /hellolaravel

# Handle Front Controller…
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
[/text]
最後のSlashを削除するRewriteRule(“# Redirect Trailing Slashes…”の箇所)を残す場合は、”/helloralavel”を追加しておきます(9行目)。

以上の設定で、http://hostname/helloraravel/でアクセスできるようになります。

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できました。

Facebook PHPをComposerで利用するには

Facebook SDK for PHP(Github: facebook/facebook-php-sdk) を利用してFacebookアプリを作成する最小限の手順

アプリ用ディレクトリ作成

$ mkdir hellofacebooksdk
$ cd hellofacebooksdk

facebook/php-sdkを指定したcomporser.jsonを作成

$ vim composer.json
{
  "require" : {
    "facebook/php-sdk" : "*";
  }
}

Comporserのパッケージインストール用コマンドcomposer.pharをダウンロードして、パッケージのインストールを実行

$ curl -s http://getcomposer.org/installer | php
$ php composer.phar install

vendorディレクトリ以下にcomposerとインストールしたfacebookパッケージが展開される。

以下、GithubのREADME.mdを貼付けた動作確認用サンプル(examples/example.phpを短くしたもの)

<?php
require 'vendor/autoload.php';

$facebook = new Facebook(array(
        'appId'  => '0123456789',
        'secret' => 'abcdefghijklmn',
));

// Get User ID
$user = $facebook->getUser();

if ($user) {
  try {
    // Proceed knowing you have a logged in user who's authenticated.
    $user_profile = $facebook->api('/me');
  } catch (FacebookApiException $e) {
    error_log($e);
    $user = null;
  }
}

if ($user) {
  $logoutUrl = $facebook->getLogoutUrl();
} else {
  $loginUrl = $facebook->getLoginUrl();
}
?>
<!doctype html>
<html>
  <head>
    <title>Hello Facebook PHP SDK</title>
  </head>
  <body>
    <h1>Hello Facebook PHP SDK</h1>

    <div>
    <?php if ($user): ?>
        <a href="<?php echo $logoutUrl; ?>">ログアウト</a>
    <?php else: ?>
        <a href="<?php echo $loginUrl; ?>">Facebookログイン</a>
    <?php endif ?>
    </div>

    <?php if ($user): ?>
    <p>
        <img src="https://graph.facebook.com/<?php echo $user; ?>/picture">
        <?php echo $user_profile['name'] ?>でログインしました。
    </p>
    <?php endif ?>
  </body>
</html>

参照: Facebook PHP SDK with Composer

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