Help us understand the problem. What is going on with this article?

BEARでインターセプターを実装する時の覚え書き(アノテーション、マッチャー)

BEARのAOP をよく使っています。この記事はBEARでインターセプターを実装するときの私の覚え書きです。

カスタムアノテーションを作るべきとき

  • 「単にアプリケーションの設定値を束縛したい」という用途であれば、必ずしもカスタムアノテーションを用意する必要はない。その用途ならばビルトインアノテーションの @Named 1 が簡易的で便利。
  • 基本的にはカスタムアノテーションクラスを作成することを検討。

モジュールとカスタムアノテーション

  • 必要に応じてモジュールの分割を行う(独立した機能モジュールでのインターセプター、カスタムアノテーションの設計)。
  • 例: 認可のアノテーション Accessible を作成したい場合
<?php
namespace MyVendor\MyPackage\Security\Module;

//  (`AppModule` に直接束縛を書くのではなく、) 
// セキュリティを扱う独立した機能として `SecurityModule` を作成、
// その中で認可機能を束縛。
class SecurityModule extends AbstractModule
{
    public function configure()
    {
        $this->bindInterceptor(
            $this->matcher->subclassesOf(ResourceObject::class),
            $this->matcher->annotatedWith(Accessible::class),
            [AccessibleInterceptor::class]
        );
    }
}
use MyVendor\MyPackage\Security\Module\Accessible;

// `SecurityModule` のアノテーションを利用
/**
 * @Accessible("administrator")
 */
public function onGet(string $articleId)
{
    // ...
}

マッチャー(Matcher)

  • モジュールの束縛で適切に対象を指定(インターセプタークラス内で実行対象をチェックしているとしても明示的に設定)
  • 必要に応じてカスタムマッチャー 2 を作成

リソースのHTTPメソッドをインターセプトしたい場合の実装例

// リソースのメソッドのためのカスタムマッチャー
class IsHttpMethodMatcher extends EqualsToMatcher
{
    public function __construct()
    {
        parent::__construct([
            'onGet',
            'onPost',
            'onPut',
            'onPatch',
            'onDelete',
            'onHead',
        ]);
    }
}
// 上記 `IsHttpMethodMatcher` のスーパークラス。
// 同一かどうかのカスタムマッチャー。
use Ray\Aop\AbstractMatcher;

class EqualsToMatcher extends AbstractMatcher
{
    /**
     * @var array
     */
    private $values;

    /**
     * @param string|array $values
     */
    public function __construct($values)
    {
        parent::__construct();

        $this->values = (array) $values;
    }

    /**
     * {@inheritdoc}
     */
    public function matchesClass(\ReflectionClass $class, array $arguments)
    {
        return in_array(strtolower($class->getName()), array_map('strtolower', $this->values));
    }

    /**
     * {@inheritdoc}
     */
    public function matchesMethod(\ReflectionMethod $method, array $arguments)
    {
        return in_array(strtolower($method->getShortName()), array_map('strtolower', $this->values));
    }
}
// モジュールでの束縛
$this->bindInterceptor(
    $this->matcher->subclassesOf(ResourceObject::class),
    new IsHttpMethodMatcher(),
    [FooInterceptor::class]
);

上記は、@iteman さんによるプライベートプロジェクトのコードを一部改変したものです。下記パッケージにしてあります。

※リソースのインターセプターの用途としては自分のドメインに合ったフレームワークを作りたいときを想定しています。BEARは標準セットで使うこともできますが、拡張に対して開かれているので自分のドメインにあったフレームワークを作っていくアプローチを採ることも可能です。

インターセプターとサービスの協調

  • インターセプターに複雑な仕事をさせる場合はサービスの利用を検討
  • サービスにバリエーションの考慮が不要な場合はサービスを直接 アンターゲット束縛 3 してインターセプターへインジェクト
インターセプター --- depends ---> サービス
  • フレームワークとサービスの境界を設計 (扱う情報の正規化はサービスに引き渡す前に済ませる)

まとめ

BEARでインターセプターを実装する時のトピックを挙げて、リソースをインターセプトしたい場合の実装例も記しました。適切なアノテーション、適切なマッチャーを使うことは良いプラクティスだと思います。


  1.  @Named (名前束縛) : Ray.Di のビルトインアノテーションで 名前 を指定して束縛します 

  2.  カスタムマッチャーの作成手順についてはBEARマニュアル参照 

  3.  アンターゲット束縛:コンクリートクラスの束縛ができます(Ray.Di マニュアル参照) 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした