Skip to content

Latest commit

 

History

History
323 lines (250 loc) · 8.32 KB

README.ja.md

File metadata and controls

323 lines (250 loc) · 8.32 KB

Ray.QueryModule

codecov Type Coverage Continuous Integration

English

概要

Ray.QueryModuleはデータベースなど外部メディアへの問い合わせを、インジェクトされる関数オブジェクトで行うようにします。

  • SqlQueryModuleはDB用です。SQLファイルをそのSQLを実行する単純な関数オブジェクトに変換します。
  • WebQueryModuleはWeb API用です。URIをそのURIにWebレクエストする単純な関数オブジェクトに変換します。
  • PhpQueryModuleは汎用のモジュールです。静的な変換では提供できないストレージアクセスをPHPの関数オブジェクトとして提供します。

モチベーション

  • コードにドメイン層(利用コード)とインフラストラクチャ層(インジェクトされる関数)の明確な境界を持たせることが出来ます。
  • 実行オブジェクトは自動で生成されるので実行のための手続きコードを記述する必要がありません。
  • 利用コードは外部メディアの実態に無関心なので、ストレージを後で変更することができます。平行開発やスタブ化が容易です。

インストール

Composerインストール

$ composer require ray/query-module

Moduleインストール

use Ray\Di\AbstractModule;
use Ray\Query\SqlQueryModule;

class AppModule extends AbstractModule
{
    protected function configure()
    {
        // SqlQueryModule インストール
        $this->install(new SqlQueryModule($sqlDir));

        // WebQueryModuleインストール
        $webQueryConfig = [
            'post_todo' => ['POST', 'https://httpbin.org/todo'],
            'get_todo' => ['GET', 'https://httpbin.org/todo']
        ];
        $guzzleConfig = [];
        $this->install(new WebQueryModule($webQueryConfig, $guzzleConfig));
        
        // ISO8601 DateTimeフォーマット
        $this->>install(new Iso8601FormatModule(['created_at', 'updated_at']);
    }
}

SQLファイル

$sqlDir/todo_insert.sql

INSERT INTO todo (id, title) VALUES (:id, :title)

$sqlDir/todo_item_by_id.sql

SELECT * FROM todo WHERE id = :id

利用

SQLを実行オブジェクトに

SqlQueryModuleをインストールするとSQLのファイル名によって束縛されたSQL実行関数がインジェクトされます。 例えば以下の例なら、todo_insert.sqlファイルが$createTodoの実行オブジェクトに変換されインジェクトされます

class Todo
{
    /**
     * @var callable
     */
    private $createTodo;
    
    /**
     * @var callable
     */
    private $todo;
    
    /**
     * @Named("createTodo=todo_insert, todo=todo_item_by_id")
     */
    public function __construct(
        callable $createTodo,
        callable $todo
    ){
        $this->createTodo = $createTodo;
        $this->todo = $todo;
    }
    
    public function get(string $uuid)
    {
        return ($this->todo)(['id' => $uuid]);
    }

    public function create(string $uuid, string $title)
    {
        ($this->createTodo)([
            'id' => $uuid,
            'title' => $title
        ]);
    }
}

単一行と複数行

得られる値が単一行(Row)複数行(Rowのリスト)に応じてRowInterfaceRowListInterfaceを指定することができます。

use Ray\Query\RowInterface;

class Todo
{
    /**
     * @Named("todo_item_by_id")
     */
    public function __construct(RowInterface $todo)
    {
        $this->todo = $todo;
    }
    
    public function get(string $uuid)
    {
        $todo = ($this->todo)(['id' => $uuid]); // 単一行
    }
}
use Ray\Query\RowListInterface;

class Todos
{
    /**
     * @Named("todos")
     */
    public function __construct(RowListInterface $todos)
    {
        $this->todos = $todos;
    }
    
    public function get(string $uuid)
    {
        $todos = ($this->todos)(); // 複数行
    }
}

メソッドをオーバーライド

@Queryでメソッド全体をSQLの実行に置き換えることができます。

class Foo
{
    /**
     * @Query(id="todo_item_by_id")
     */
    public function get(string $id)
    {
    }
}

メソッド引数とSQLのバインドする変数名が違う時はtemplated=trueを指定するとuri_templateと同じように変数名を変えることができます。

class FooTempalted
{
    /**
     * @Query(id="todo_item_by_id?id={a}", templated=true)
     */
    public function get(string $a)
    {
    }
}

単一行の時はtype='row'を指定します。

class FooRow
{
    /**
     * @Query(id="ticket_item_by_id", type="row")
     */
    public function onGet(string $id) : ResourceObject
    {
    }
}

SELETした結果が無い場合にはcode 404が返ります。

URIを実行オブジェクトに

WebQueryModuleは設定で束縛したURIをWebアクセスする実行関数がインジェクトされます。 例えば以下の例なら、https://httpbin.org/todoPOSTリクエストする$createTodoの実行オブジェクトに変換されインジェクトされます

use Ray\Di\AbstractModule;
use Ray\Query\SqlQueryModule;

class AppModule extends AbstractModule
{
    protected function configure()
    {
        // WebQueryModuleインストール
        $webQueryConfig = [
            'todo_post' => ['POST', 'https://httpbin.org/todo'], // bind-name => [method, uri]
            'todo_get' => ['GET', 'https://httpbin.org/todo']
        ];
        $guzzleConfig = []; // @see http://docs.guzzlephp.org/en/stable/request-options.html
        $this->install(new WebQueryModule($webQueryConfig, $guzzleConfig));
    }
}

利用コードはSqlQueryModuleの時と同じです。

/**
 * @Named("createTodo=todo_post, todo=todo_get")
 */
public function __construct(
    callable $createTodo,
    callable $todo
){
    $this->createTodo = $createTodo;
    $this->todo = $todo;
}
// POST
($this->createTodo)([
    'id' => $uuid,
    'title' => $title
]);

// GET
($this->todo)(['id' => $uuid]);

@Queryの利用コードも変わりません。

PHPクラスを束縛

複数のクエリーを実行したり、他の依存が必要な場合にはPHPクラスに束縛し依存を利用します。

class CreateTodo implements QueryInterface
{
    private $pdo;
    private $builder;
    
    public function __construct(PdoInterface $pdo, QueryBuilderInferface $builder)
    {
        $this->pdo = $pdo;
        $this->builder = $builder;
    }
    
    public function __invoke(array $query)
    {
        // $pdoと$builderを使ったクエリ実行
        return $result;
    }
}

callableに束縛します。

$this->bind('')->annotatedWith('cretate_todo')->to(CreateTodo::class); // callableはインターフェイスなし

利用コードは同じです。@Queryの利用コードも変わりません。

ISO8601 DateTimeモジュール

指定したコラム名の値をISO8601形式に変換します。PHPではDateTime::ATOMの定数で定義されているフォーマットです。 日付のコラム名を配列にしてIso8601FormatModuleの引数に渡してインストールします。

$this->install(new Iso8601FormatModule(['created_at', 'updated_at']));

SQL file name log

SQLファイル名をコメントとしてSQL文に付加する事ができます。クエリーログに有用です。

use Ray\Query\SqlFileName;
use Ray\Query\SqlQueryModule;

$this->install(new SqlQueryModule(__DIR__ . '/Fake/sql', null, new SqlFileName()));

実行SQL

/* todo_item_by_id.sql */ SELECT * FROM todo WHERE id = :id

デモ

php demo/run.php

BEAR.Sunday