はとのーと

エジソンノート(アイデア、思い付き、メモ)として使っています。誰かの役に立つかもしれないので公開しています。

BEAR.Sundayについてのメモ

BEAR.Sundayを理解するためのリンクなど。

目次:

公式

スライド

Qiita Advent Calendar

"○○Module"

「○○Module」は「○○をRay.Diでインジェクトできるようにする」ためのモジュールと理解するとよい。

例:

  • Ray.AuraSqlModule: Aura.Sqlをインジェクトできるようにする
  • Ray.AuraRouterModule: Aura.Routerをインジェクトできるようにする
  • Madapaja.TwigModule: Twigをインジェクトできるようにする
  • Bear.QiqModule: Qiqをインジェクトできるようにする

データベース関連

Database Modules

↓以下が\右を含む→ Aura.Sql Ray.AuraSqlModule Aura.SqlQuery
Ray.QueryModule
Ray.MediaQuery
Ray.AuraSqlModule

Aura.〜 はアプリケーション開発で使える様々なツールのパッケージ。 Aura for PHP : About

Ray.〜 はBEAR.Sunday開発者の郡山さんが作成されているパッケージ。

Aura.Sql

Aura.Sql/README.md at 5.x · auraphp/Aura.Sql · GitHub

PHPのPDOを拡張したデータベースライブラリ。

PDOを拡張したExtendedPdoは以下の特徴を持つ。

  • 必要な時にデータベースに自動的に接続する (遅延接続)
  • quote() で配列をクオートしてSQLの "IN" 節で使えるようにする
  • perform() でハッシュで指定された引数をバインドして実行できる (prepare() 不要)

BEAR.Sunday公式の説明ページ: データベース | BEAR.Sunday

Ray.AuraSqlModule

Ray.AuraSqlModule/README.md at 1.x · ray-di/Ray.AuraSqlModule · GitHub

Aura.SqlをRay.DIでインジェクトするためのモジュール。 Aura.Sql, Ray.QueryModule, Ray.MediaQueryのためのDB接続情報を管理する。

Ray.QueryModule & Ray.MediaQuery

Ray.MediaQueryはRay.QueryModuleと同等の機能をRay.DIでインジェクトするためのモジュール。 ただしRay.QueryModuleとRay.MediaQueryの間には直接の包含関係は無い。

ドメイン層からインフラ層の実装に依存するのではなく、その逆、ドメイン層のインターフェイスにインフラ層の実装を合わせる事を特定の状況下でより効率的に行うためのパッケージがこのRay.MediaQueryです。

ドメインはインフラ層の実装や仕様に対して無知に、自由にインターフェイスを設計します。

(『ドメインとインフラ層のDIPRay.MediaQuery - Qiita )

Ray.QueryModule

Ray.QueryModule/README.ja.md at 1.x

以下が含まれる。

  • SqlQueryModule - SQLを実行可能な関数オブジェクトにする
  • WebQueryModule - URIを実行可能な関数オブジェクトにする
  • PhpQueryModule - 汎用のストレージアクセスを実行可能な関数オブジェクトにする

SQLファイルやWeb APIの設定をするだけで関数オブジェクトが作成される。 関数オブジェクト内部のコードを書く必要はない。

Ray.QueryModuleを単体で使うときは接続設定をRay.AuraSqlModuleでやる。 参照: BEAR.SundayとSQLと - Qiita

Ray.MediaQuery

Ray.MediaQuery/README.ja.md at 1.x

Ray.QueryModule相当の機能を含む。

Ray.MediaQueryを使うとクエリーからの戻り値をハッシュではなくエンティティとして受け取れる (Ray.QueryModuleにはこの機能は無い)。

AOP

公式ドキュメント: AOP | BEAR.Sunday

Ray.AopはPHPでどのようにAOPを実現しているのか? — A Day in Serenity (Reloaded) — PHP, CodeIgniter, FuelPHP, Linux or something

コンテントネゴシエーション

公式ドキュメント: コンテントネゴシエーション | BEAR.Sunday

同じリソースをHTML形式やJSON形式といった複数の形式で返すための仕組み。

BEAR.Acceptを使い、全体適用か部分適用を選んで使う。

  • 全体適用: クライアントが指定する形式でリソースを返す
  • 部分適用: リソースごとに返す形式を指定する

PageリソースをHTML形式で返すためにコンテキストを'html-app'にすると、既定ですべてのPageリソースがHTMLで返されるようになり、対応するテンプレートが必要になる。 BEAR.Acceptの部分適用を使うと一部のリソースをHTML以外で返すことができるようになり、テンプレートが不要になる。

コンテキストが'html-app'のとき、部分適用では以下のようにメソッドごとに@Producesで返す形式を指定できる。

<?php

    /**
     * @return static
     *
     * @Produces({"text/html"})
     * */
    public function onGet(): static
    {
        ...
    }

    /**
     * @return static
     *
     * @Produces({"application/json"})
     * */
    public function onPost(string $name, string $status): static
    {
        ...
    }

上記のコードではGETメソッドではHTML形式で、POSTメソッドではJSON形式で結果を返す。 (HTML形式が既定なので、GETメソッドの方は@Produces行が無くてもよい。)

HAL & ALPS

BEAR.SundayはHALとALPSをサポートしている。

参考リンク:

HAL (Hypertext Application Language)

The Hypertext Application Language

HALはリソース間ハイパーリンクについての一貫性のある簡潔な書式。

リソース表現(JSON)に以下のものを含むことでハイパーリンクを表現する。

  • _links - リンク
  • _embedded - 含まれるリソース

BEAR.SundayでHAL形式の表現を返すにはコンテキストに hal を指定し、@Embedアノテーションでリソースを埋め込む。

ALPS (Application-Level Profile Semantics)

alps.io

ALPSはリソースのフィールドの意味や型、遷移の属性を表現する。

BEAR.Sundayでは Fake コンテキストを作成し、FakeJSONを @JsonSchema で読み込ませることで偽のデータを返すFakeサーバを立ち上げたり(サーバが完成する前にクライアントを作成することができる)、渡される値を自動バリデートすることができる。

雑多な調査

参考資料:

URIをリソースにマップする処理

URIをリソースにマップしているのは BEAR\Resource\AppAdapterget メソッド。

<?php

public function get(AbstractUri $uri): ResourceObject
{
    if (substr($uri->path, -1) === '/') {  // --- (1)
        $uri->path .= 'index';
    }

    $path = str_replace('-', '', ucwords($uri->path, '/-'));  // --- (2)
    /** @var ''|class-string $class */
    $class = sprintf('%s\Resource\%s', $this->namespace, str_replace('/', '\\', ucwords($uri->scheme) . $path));  // --- (3)
    try {
        $instance = $this->injector->getInstance($class);  // --- (4)
        assert($instance instanceof ResourceObject);
    } catch (Unbound $e) {
        throw $this->getNotFound($uri, $e, $class);
    }

    return $instance;
}
  1. URIの最後が / だったら index を追加
  2. URI/- で区切り、単語の先頭を大文字にする
  3. リソースクラスのファイルパスに変換
  4. リソースをインスタンス
コンテキストをURIスキームにマップする処理

コンテキストが http 以外の場合: BEAR\Package\Context\ApiModule

<?php

    protected function configure(): void
    {
        $this->bind()->annotatedWith(DefaultSchemeHost::class)->toInstance('app://self');
        $this->bind()->annotatedWith(ContextScheme::class)->toInstance('app://self');
    }

コンテキストが http の場合: BEAR\Sunday\Provide\Router\RouterModule

<?php

    protected function configure(): void
    {
        $this->bind(RouterInterface::class)->to(WebRouter::class);
        $this->bind()->annotatedWith(DefaultSchemeHost::class)->toInstance('page://self');
    }

ここで設定した DefaultSchemeHost が、たとえば BEAR\Package\Provide\Router\WebRouter などで

<?php

    /**
     * @DefaultSchemeHost("schemeHost")
     */
    #[DefaultSchemeHost('schemeHost')]
    public function __construct(string $schemeHost, HttpMethodParamsInterface $httpMethodParams)
    {

このように $schemeHost にバインドされて使われている。

DockerfileでAPCuを有効にする

DockerのAlpine LinuxコンテナでAPCu(APCキャッシュ)を有効にする時はDockerfileに次の記述を入れる。

# install packages for apcu
RUN apk --update --no-cache add autoconf g++ make && \
    pecl install apcu && \
    echo -e "extension=apcu.so\napcu.enabled=1\napc.enable_cli=1" > ${PHP_INI_DIR}/conf.d/apcu.ini