Laravel5でアノテーションを追加してみよう(中級者以上向け)

Posted: 2014-12-22 00:12 |  laravel 

Laravel Advent Calendar 2014 には書いていない、全く初心者向けではないものを紹介!
中身の仕組みを理解している中級者以上向けです

Laravel5でルーティングとイベントにアノテーションが追加されたので、
折角なので独自のアノテーションを足してみようというヤツです
アノテーションは使わない人は全く使わないと思います
β版にすらなっていないですが、弄り倒しましょう
イベントも併用して紹介です

@PreDestroy追加してみる

ルーティングアノテーションとは別のものを追加してみましょー
@PreDestroyはjavaでおなじみのアノテーションで、
コントローラーのafterfilterのタイミングで実行される様に組み合わせれば近い事が出来るはず・・!

コントローラー実行時のイベントの流れはだいたい
前後にキャッシュ等のイベントがありますが、
router.before
router.matched
router.after

の流れになっています(今のところ)
実装の流れは、router.afterを起点にアノテーションを取得して実行させます

まずは適当にアノテーションを実装します
詳しくはdoctrine/annotations を参考にどうぞ!
 

namespace App\Annotations;

/**
 * @Annotation
 * @package App\Annotations
 */
class PreDestroy
{

    /**
     * @return string
     */
    public function action()
    {
        echo 'predestroy';
    }
}

Illuminate\Routing\Annotations\Annotations\Annotation を継承してみても良いでしょう!
サンプルなのでエコーするだけの処理です
実際にはキャッシュ操作だったり、クッキー関連や、レスポンス変更したり、
afterを利用する場面はそこそこあると思います
次にアノテーションを利用できる様にする為のクラスを実装します
 

namespace App\Annotations;

use ReflectionMethod;
use Symfony\Component\Finder\Finder;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\SimpleAnnotationReader;

/**
 * Class RegisterAnnotation
 * @package App\Annotations
 */
class RegisterAnnotation
{

    public function __construct()
    {
        $this->register();
    }

    /**
     * @return void
     */
    protected function register()
    {
        foreach (Finder::create()->files()->in(__DIR__) as $file) {
            AnnotationRegistry::registerFile($file->getRealPath());
        }
    }

    /**
     * @param $name
     * @return array
     */
    public function resolver($name)
    {
        list($controller, $method) = explode('@', $name);
        $reflectionMethod = new ReflectionMethod($controller, $method);
        return $this->getReader()->getMethodAnnotations($reflectionMethod);
    }

    /**
     * Get an annotation reader instance.
     * @return \Doctrine\Common\Annotations\SimpleAnnotationReader
     */
    protected function getReader()
    {
        with($reader = new SimpleAnnotationReader)->addNamespace('App\Annotations');
        return $reader;
    }

}
アノテーションのクラスをファイルスキャンで登録して、取得できる様にします
この辺はフレームワークの実装処理を読むか、doctrine/annotationsを参考にして下さい
あとはサービスプロバイダーです
namespace App\Providers;

use Illuminate\Routing\Route;
use Illuminate\Support\ServiceProvider;
use App\Annotations\RegisterAnnotation;

/**
 * Class RequestServiceProvider
 * @package App\Providers
 */
class RequestServiceProvider extends ServiceProvider
{

    public function register()
    {

    }

    public function boot()
    {
        $this->app['events']->listen('router.matched', function ($route) {

            $this->app['events']->listen('router.after', function() use ($route){
                $this->annotationResolver($route);
            });
        });

    }

    /**
     * @param Route $route
     */
    protected function annotationResolver(Route $route)
    {
        $action = $route->getAction();
        $annotations = (new RegisterAnnotation())->resolver($action['controller']);
        if(count($annotations)) {
            foreach ($annotations as $annotation) {
                $annotation->action();
            }
        }
    }

}
この例では route.matched で実行されるコントローラー/メソッドを取得して、
afterで該当のメソッドのアノテーションを取得し、あれば実行する様になってます
忘れずにapp.phpに追加します
    'providers' => [

        /*
         * Application Service Providers...
         */
        'App\Providers\AppServiceProvider',
        'App\Providers\EventServiceProvider',
        'App\Providers\RouteServiceProvider',
        'App\Providers\ConsoleServiceProvider',
        'App\Providers\RequestServiceProvider',
あとはコントローラーに記述します
namespace App\Http\Controllers;

/**
 * Class HomeController
 * @package App\Http\Controllers
 */
class HomeController extends Controller
{

    /**
     * @Get("/", as="home.index")
     * @PreDestroy
     * @return \Illuminate\View\View
     */
    public function index()
    {
        return view('home.index');
    }
}
こんな感じでアノテーション自体を追加して実装する事が出来ました
@PostConstruct でformRequest実行する様に作ってたんですけど、
あんまり意味なかったので、止めて比較的意味ありそうなものを紹介しました



 

about ytake

執筆に参加しています


Laravel お役立ち情報

share



このエントリーをはてなブックマークに追加

Categories

laravel 45

DTM 0

music 0

PHP全般 31

0

JAPAN 1

WORLD 1

javascript 4

RDBMS 1

NoSQL 1

NewSQL 1

Recent Posts

Ad

comments powered by Disqus

GitHub

Social Links

Author


クリエイティブ・コモンズ・ライセンス
Yuuki Takezawa 作『Ytake Blog』はクリエイティブ・コモンズ 表示 - 非営利 4.0 国際 ライセンス で提供されています。

© ytake/comnect All Rights Reserved. 2014