SlideShare a Scribd company logo
LaravelAspectで関心の分離
KenjiroKubota
2017/07/08
Profile
Kenjiro Kubota
istyle.inc
 PHP, HHVM/Hack, Javascript 
DTPDesigner
WebDesigner
FrontEnginner
WebApplicationEngiiner﴾now﴿
関心の分離とは
関心の分離(かんしんのぶんり、英語: separation of concerns、SoC)とは、ソフトウェア工
学において、プログラムを機能面において可能な限り重複がない、複数の機構に明確に分割
することをいう。ここでいう「関心﴾関心事﴿」とは、プログラムのある機能や振る舞い、目的
のことである。﴾Wikipedia﴿
Aspect﴾AOP﴿とは
アスペクト指向プログラミング(アスペクトしこうプログラミング、Aspect Oriented
Programming、AOP)は、オブジェクト指向ではうまく分離できない特徴(クラス間を横断
﴾cross‐cutting﴿ するような機能)を「アスペクト」とみなし、アスペクト記述言語をもちいて
分離して記述することでプログラムに柔軟性をもたせようとする試み。アスペクトの例とし
ては、データ転送帯域の制限や例外の処理などがある。Java にアスペクト指向的要素を追加
したAspectJ が実験的に実装されている。﴾Wikipedia﴿
横断的関心事を解決する手段
代表的なケースはロギング、トランザクション、キャッシュなどが挙げられます
Laravelで利用する際はRay.Aopを用いている以下のライブラリがオススメ(宣伝)
ytake/laravel‐aspect
利用ケース ロギング
普通はこんな感じ
public function get($id)
{
    Log::info($id);
    $this‐>logger‐>info($id);
}
Logファサードを使ったり、コンストラクトインジェクションしたloggerを使ったり...
LaravelAspectを使うと
use YtakeLaravelAspectAnnotationLoggable;
class AspectLoggable
{
    /**
     * @Loggable
     * @param null $id
     * @return null
     */
    public function normalLog($id = null)
    {
        return $id;
    }
}
利用ケース トランザクション
普通はこんな感じ?
public function save(array $params)
{
    DB::beginTransaction();
    try {
        $result = $this‐>eloquent‐>save($params);
        DB::commit();
        return $result;
    } catch(Exception $e) {
        DB::rollback();
        Log::error($e‐>getMessage());
        throw $e;
    }
}
LaravelAspectなら
use YtakeLaravelAspectAnnotationTransactional;
/**
 * @Transactional("master")
 * @LogExceptions
 */
public function save(array $params)
{
    return $this‐>eloquent‐>save($params);
}
アノテーションで関心の分離ができる
他にもデフォルトで便利なアノテーションが用意されてます
詳しくはライブラリのREADEMEを見てください。
LaravelAspectに用意されてるアノテーションも便利なんですが
自分たちのアプリに合わせた独自のアノテーションを作り
たいですよね?
サンプルケース
最終ログイン日時の記録
まずはLaravelAspectを導入
$ composer require ‐‐no‐update ytake/laravel‐aspect && composer update
Provider登録
 config/app.php 
'providers' => [
    // added AspectServiceProvider 
    YtakeLaravelAspectAspectServiceProvider::class,
    // added Artisan Command
    YtakeLaravelAspectConsoleServiceProvider::class,
]
設定ファイルとかModulesをアプリケーションにコピー
$ php artisan ytake:aspect‐module‐publish
$ php artisan vendor:publish
こんな感じで追加されます
laravel
  ‐ app
    ‐ Modules
      ‐ CacheableModule.php
      ‐ CacheEvictModule.php
      ‐ CachePutModule.php
      ‐ TransactionalModule.php
      ‐ LoggableModule.php
      ‐ LogExceptionsModule.php
      ‐ PostConstructModule.php
      ‐ RetryOnFailureModule.php
      
  ‐ config
    ‐ ytake‐laravel‐aop.php
独自アノテーションの定義
use DoctrineCommonAnnotationsAnnotation;
/**
 * @Annotation
 * @Target("METHOD")
 * Class LastLoginTime
 */
class LastLoginTime extends Annotation
{
    //
}
アスペクト利用時は以下の様になる
‐>  @LastLoginTime() 
インターセプターの定義
※ アノテーションが実行されるときの挙動を定義
use RayAopMethodInvocation;
use RayAopMethodInterceptor;
use YtakeLaravelAspectAnnotationAnnotationReaderTrait;
class LastLoginTimeInterceptor implements MethodInterceptor
{
    use AnnotationReaderTrait;
    
    /**
     * @param MethodInvocation $invocation
     * @return object
     */
    public function invoke(MethodInvocation $invocation)
    {
      // before
        $result = $invocation‐>proceed();
        // after
        $user = $result‐>getUser();
        $lastLoginTime = app()‐>make(AppServiceLastLoginTime::class);
        if (!$lastLoginTime‐>update($user)) {
            throw new ErrorException("Failed Update Last Login Time");
        }
        return $result;
    }
}
// before
$result = $invocation‐>proceed();
// after
beforeはアノテーションを記述したメソッドが実行される前に実行される。
afterはメソッド実行されたあとに実行される
$resultにはそのメソッドの返り値が入ります。
ポイントカットの定義
※ 特定のアノテーションが実行されるときに起動されるインターセプターを定義
class LastLoginTimePointCut extends CommonPointCut implements PointCutable
{
    /** @var string */
    protected $annotation = AppAnnotationLastLoginTime::class;
    
    /**
     * @param Container $app
     * @return RayAopPointcut
     */
    public function configure(Container $app)
    {
        $this‐>setInterceptor(new LastLoginTimeInterceptor);
        return $this‐>withAnnotatedAnyInterceptor();
    }
}
モジュールの追加
※ アノテーションが利用されるクラスを定義する
use AppAspectPointCutLastLoginTimePointCut;
use YtakeLaravelAspectModulesAspectModule;
class LastLoginTimeModule extends AspectModule
{
    /** @var array */
    protected $classes = [
        AppHttpControllerLoginController::class,
    ];
    
    /**
     * @return LastLoginTimePointCut
     */
    public function registerPointCut()
    {
        return new LastLoginTimePointCut;
    }
}
最後にModulesを以下に登録してあげればOK
 config/ytake‐laravel‐aop.php 
        'modules' => [
            ...
            // append modules
            AppModulesLastLoginTimeModule::class,
        ],
まとめ
LaravelAspectをとりあえず導入するだけでも楽々AOPが実現できる
拡張もできるので独自の要件にも対応できる
関心を分離することでいちクラスの責務を追求できるようになります
単一責任の原則
thanks :﴿

More Related Content

ODP
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
PPTX
つぶやきGLSLのススメ
PPTX
わかりづらいS3クロスアカウントアクセス許可に立ち向かおう
PPTX
RLSを用いたマルチテナント実装 for Django
PDF
[Cloud OnAir] Google Cloud における RDBMS の運用パターン 2020年11月19日 放送
PDF
AWSとReactで始めるShopifyアプリ開発
PDF
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
PDF
実践 NestJS
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
つぶやきGLSLのススメ
わかりづらいS3クロスアカウントアクセス許可に立ち向かおう
RLSを用いたマルチテナント実装 for Django
[Cloud OnAir] Google Cloud における RDBMS の運用パターン 2020年11月19日 放送
AWSとReactで始めるShopifyアプリ開発
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
実践 NestJS

What's hot (20)

PDF
OpenID Connect 入門 〜コンシューマーにおけるID連携のトレンド〜
PDF
俺が考えた最強のID連携デザインパターン
PPTX
Apache Avro vs Protocol Buffers
PDF
BigQuery で 150万円 使ったときの話
PDF
ソーシャルゲームのためのデータベース設計
PDF
Doma SQLテンプレートのしくみ
PDF
Laravelの認証について
PPTX
ここがつらいよ、Hyperledger Fabricの商用適用(Blockchain GIG #4発表資料)
PPTX
IDaaS を利用すべき理由とエンジニアがおさえておくべきポイント (2021年1月14日)
PDF
なぜOpenID Connectが必要となったのか、その歴史的背景
PDF
[GKE & Spanner 勉強会] Cloud Spanner の技術概要
PPTX
NGINXでの認可について考える
PDF
DynamoDB設計のちょっとした技
PPTX
OpenVRやOpenXRの基本的なことを調べてみた
PDF
中・大規模でLaravelを導入するTips
PDF
Python におけるドメイン駆動設計(戦術面)の勘どころ
PDF
Google Cloud Dataflow を理解する - #bq_sushi
PDF
M04_失敗しないための Azure Virtual Desktop 設計ガイド
PDF
OAuth 2.0 Web Messaging Response Mode - OpenID Summit Tokyo 2015
PDF
ピクサー USD 入門 新たなコンテンツパイプラインを構築する
OpenID Connect 入門 〜コンシューマーにおけるID連携のトレンド〜
俺が考えた最強のID連携デザインパターン
Apache Avro vs Protocol Buffers
BigQuery で 150万円 使ったときの話
ソーシャルゲームのためのデータベース設計
Doma SQLテンプレートのしくみ
Laravelの認証について
ここがつらいよ、Hyperledger Fabricの商用適用(Blockchain GIG #4発表資料)
IDaaS を利用すべき理由とエンジニアがおさえておくべきポイント (2021年1月14日)
なぜOpenID Connectが必要となったのか、その歴史的背景
[GKE & Spanner 勉強会] Cloud Spanner の技術概要
NGINXでの認可について考える
DynamoDB設計のちょっとした技
OpenVRやOpenXRの基本的なことを調べてみた
中・大規模でLaravelを導入するTips
Python におけるドメイン駆動設計(戦術面)の勘どころ
Google Cloud Dataflow を理解する - #bq_sushi
M04_失敗しないための Azure Virtual Desktop 設計ガイド
OAuth 2.0 Web Messaging Response Mode - OpenID Summit Tokyo 2015
ピクサー USD 入門 新たなコンテンツパイプラインを構築する
Ad

More from Kenjiro Kubota (19)

PDF
いまどき(これから)のPHP開発
PDF
アイスタイル特設サイトにおけるVue.js導入事例(再演)
PDF
gRPC入門
PDF
アイスタイル特設サイトにおけるVue.jsの導入事例
PDF
Akkaとは。アクターモデル とは。
PDF
フロントエンドエンジニアが知るべきFirebaseの世界
PDF
PHP,Go,Elasticsearchによる、@cosmeを5倍速くする取り組み
PDF
カメラを利用したアプリを作って約1000人で遊んだ話
PDF
FirebaseとNuxtでLPを作って見た
PDF
introducing vue-wait-component
PDF
HHVM/Hackを本番投入した話
PDF
HackのAsyncCurlで死んだ話
PDF
LaravelでAPI定義を管理する
PDF
2017: A CSS Design Odyssey
PDF
Introducing hhvm hack-async
PDF
Responsableを使ったadr実装
PDF
土日でLineみたいなチャット作ってきた!
PDF
Viewを活用して複雑化と戦う
PDF
Laravelでfacadeを使わない開発
いまどき(これから)のPHP開発
アイスタイル特設サイトにおけるVue.js導入事例(再演)
gRPC入門
アイスタイル特設サイトにおけるVue.jsの導入事例
Akkaとは。アクターモデル とは。
フロントエンドエンジニアが知るべきFirebaseの世界
PHP,Go,Elasticsearchによる、@cosmeを5倍速くする取り組み
カメラを利用したアプリを作って約1000人で遊んだ話
FirebaseとNuxtでLPを作って見た
introducing vue-wait-component
HHVM/Hackを本番投入した話
HackのAsyncCurlで死んだ話
LaravelでAPI定義を管理する
2017: A CSS Design Odyssey
Introducing hhvm hack-async
Responsableを使ったadr実装
土日でLineみたいなチャット作ってきた!
Viewを活用して複雑化と戦う
Laravelでfacadeを使わない開発
Ad

Laravel aspectで関心の分離