PHP
laravel
LaravelDay 1

Laravel5 route, event アノテーション

More than 3 years have passed since last update.

annotationは本体から切り離されて、3rdパーティと変更されました。

アノテーションパッケージ

Laravel5の状況

本題に入る前に現在の状況ですが、
チェックしている方はご存知の通り Laravel5は2015年1月リリースの可能性が高く、
すぐに情報が古くなる場合もあります
また現時点(2014/12/01)ではβ版はありませんが、
開発版をインストールして5の現時点の状態で使用する事が可能です
手軽に使う分にはそこまで大きく変わりませんが、
Laravelパッケージ開発者や、コアを熟知している中級者や上級者の方々は、
4よりもさらに便利に、より拡張し易い方向へと変わっています

それでは、5で追加されたルーティングとイベントのアノテーションを!

Laravel5 install

インストール方法はいくつかありますが、いつもと同じ方法で開発版をインストールする事が出来ます

$ composer create-project laravel/laravel プロジェクト名 --prefer-dist dev-develop

php artisan serveは削除された様なので、簡単に起動させたい場合は

$ php -S 127.0.0.1:8000 -t 'public/'

と、ビルトインサーバを立ち上げるだけです
You have arrived.

実行環境の指定方法が変更されましたので、
プロジェクトルートの .env.sample.envにリネームする等してください
中に記述されているAPP_ENV=localで実行環境を変更する事が出来ます
(もちろんこれまでと同じ方法でも可能です、ソースコードを読んでみてください)

Laravel5 Router

スタンダードなrouter

今まで通りルーティングはroutes.phpに記述していくことができます
インストール時にすぐに動く様にいくつかルーティング記述されています
ファサードでの記述ではなくなりましたが、この辺りは後日誰かが書くはず・・!

app/Http/routes.php
$router->get('/', 'WelcomeController@index');
$router->get('/home', 'HomeController@index');

$routerは\Illuminate\Routing\Routerオブジェクトで特に変わりませんが、
サービスプロバイダで自由に色々実装できる様に拡張されました
app/Providers/RouterServiceProvider.phpがそれです

コントローラーの名前空間はデフォルトで下記の様に記述されています

protected $namespace = 'App\Http\Controllers';

に記述する事で省略して記述できますが、特に使わなくてもかまいません
使わない場合はこれまでのgroupでの指定と同じです

app/Http/routes.php
$router->group(['namespace' => 'App\Http\Controllers'], function($router) {
        $router->get('/', 'WelcomeController@index');
        $router->get('/home', 'HomeController@index');
    }
);

アノテーション利用のrouter

ではアノテーションを利用してルーティングを作ってみます
app/Http/routes.phpに記述したものはコメントアウトしておきます

$ php artisan route:list

何も表示されない事を確認、もし表示されていればcompileされたファイルがあるはずなので、

$ php artisan clear-compiled

またはstorage/framework/compiled.phpを削除します

ルーティングで利用可能なアノテーションは
Illuminate\Routing\Annotations\Annotationsにあります

アノテーション 該当するもの 対象
@Controller $router->controller() クラス
@Resource $router->resource() クラス
@Middleware filter処理等 クラス・メソッド
@Where whenに該当  クラス・メソッド
@Get GET メソッド
@Post POST メソッド
@Put PUT メソッド
@Patch PATCH メソッド
@Delete DELETE メソッド
@Options OPTIONS メソッド

メソッドに記述する例

シンプルなGet, Postなどのを利用してみます

app/Http/Controllers/SampleController.php
namespace App\Http\Controllers;

class SampleController extends Controller
{
    /**
     * @Get("sample")
     * @return string
     */
    public function sample()
    {
        return "sample";
    }
}

sampleメソッドをGETの処理で使う様にアノテーションで指定します
URIは/sampleとなります
それから、先ほどのapp/Providers/RouterServiceProvider.phpに次の様に追加します

app/Providers/RouterServiceProvider.php
    protected $scan = [
        'App\Http\Controllers\SampleController'
    ];

次にControllerのアノテーションをスキャンして、ルーティングを自動で作成します

$ php artisan route:scan

storage/framework/routes.scanned.phpファイルが作成、または元からある方は追記されます

$router->get('sample', [
    'uses' => 'App\Http\Controllers\SampleController@sample',
    'as' => NULL,
    'middleware' => [],
    'where' => [],
    'domain' => NULL,
]);

ブラウザなどからアクセスしてsampleと表示されるか確認してみましょう!
spring frameworkのbeanファイルのルーティング版の様なものですね
なおスキャンをしなくても、
app/Providers/RouterServiceProvider.phpに下記のプロパティを有効にすると
自動で追加される様になります!

protected $scanWhenLocal = true;

他のPost等も基本的には同じです
次にフィルターやルーティングに名前を付けていってみましょう
最初から登録されているフィルター(middleware)は
app/Http/Kernel.phpにあります ここではauthを使ってみる事にします
きっと誰かが詳細書いてくれるはず・・!

    /**
     * @Get("sample", as="sample", middleware={"auth"})
     * @return string
     */
    public function sample()
    {
        return "sample";
    }

再度scanを実行してroute:listで確認してみます
route:list.png
ブラウザからアクセスすると、ログイン画面に遷移されます(用意されていないのでエラー画面のはず)
middlewareとwhenは配列でいくつでも指定できます

    /**
     * @Get("sample/{id}", as="sample", middleware={"auth"}, where={"id": "[0-9]+"})
     * @param $id
     * @return string
     */
    public function sample($id)
    {
        return "sample";
    }

引数を必須として、且つ数字以外は利用できないルーティングの場合はこの様になります
またこれまであったdomainも利用できますので、同じ様に追加するだけで指定が可能です

    /**
     * @Get("sample")
     * @Middleware({"auth"})
     * @param $id
     * @return string
     */
    public function sample($id)
    {
        return "sample";
    }

さらにMiddlewareとWhereは個別に記述する事も可能です

クラスに記述する例

いままでのResourceコントローラーと同様に指定してみます

namespace App\Http\Controllers;

/**
 * @Resource("sample", only={"index"}, names={"index": "index.name"})
 */
class SampleController extends \App\Http\Controllers\Controller
{

    public function index()
    {
        return "sample index";
    }

}

URIが/sampleでそれぞれのメソッドがルーティングに登録されますが、
onlyでindexのみ利用する様に指定し、
nameは指定しない場合はsampleをprefixに自動で付与されますが、
名前を任意で指定しました
さらに@Controllerアノテーションでprefixを付与させたり、
実行するdomainを指定します

/**
 * @Resource("sample", only={"index"}, names={"index": "index.name"})
 * @Controller(prefix="api", domain="app")
 * @Middleware({"auth"})
 */
class SampleController extends \App\Http\Controllers\Controller
{

}

メソッドにもさらに記述して様々なルーティングを作る事が出来ます
他にも色々あり、自分でアノテーションを追加する事も出来ますが、
まだイベントについても書いてないのでまた次回に・・

ルーティングを共存

複数人のチームで開発している場合は、アノテーションだけだと分かり辛い場合もあります
開発者の好みによってアノテーション有無の両方のルーティングを混ぜて使う事が出来ますので
routes.phpを削除しなければならないとか、そういう事はありませんが、
アノテーションを使ったルーティングが優先されます
またこれらのルーティングはroute:cacheでキャッシュする事も出来ますが、
書くと長くなるのでこの辺で・・

Laravel5 event annotation

routerに比べれば遥かにシンプルです
app/Providers/EventServiceProvider.phpにデフォルトのサービスプロバイダーがあります
routerと同じ様にannotationを利用するので、scanで配列を使います
ファイルはどこに作っても構いませんので、簡単なクラスを作ってみます

app/Listener/SampleListener.php
namespace App\listener;

class SampleListener
{

    /**
     * @hears("accessEvent")
     */
    public function access()
    {
        echo "access";
    }
} 

ただ単に文字列を返却するだけのシンプルなeventです
@hearsでイベント名を付けます
それでは同様にscanにクラスを追加するので
app/Providers/EventServiceProvider.php

class EventServiceProvider extends ServiceProvider
{

    protected $scan = [
        "App\Listener\SampleListener"
    ];

}

スキャンコマンドは

$ php artisan event:scan 

です
実行後にevent.scanned.phpに追記されているのを確認します
もちろんrouterと同じ様に自動で追記することもできます

$events->listen(array (
  0 => 'accessEvent',
), 'App\listener\SampleListener@access');

先ほど利用したcontrollerを利用します

namespace App\Http\Controllers;

use Illuminate\Contracts\Events\Dispatcher;

class SampleController extends Controller
{

    /**
     * @Get("sample")
     * @return string
     */
    public function sample(Dispatcher $event)
    {
        $event->fire('accessEvent');
    }
}

折角なのでファサードを使わずにメソッドインジェクションでDispatcherを指定して
fireでイベントを起こします
ブラウザからアクセスすると
accessと表示されているはず!
複数の名前をつける事も出来ますので色々遊ぶ事ができます

    /**
     * @hears({"accessEvent", "sample.event"})
     */
    public function access()
    {
        echo "access";
    }

それぞれの機能については実装されているコードに記載されていますので、
色々試してやりやすい実装方法でルーティングなどを作りましょう!