Ray.QueryModuleはデータベースなど外部メディアへの問い合わせを、インジェクトされる関数オブジェクトで行うようにします。
SqlQueryModuleはDB用です。SQLファイルをそのSQLを実行する単純な関数オブジェクトに変換します。WebQueryModuleはWeb API用です。URIをそのURIにWebレクエストする単純な関数オブジェクトに変換します。PhpQueryModuleは汎用のモジュールです。静的な変換では提供できないストレージアクセスをPHPの関数オブジェクトとして提供します。
- コードにドメイン層(利用コード)とインフラストラクチャ層(インジェクトされる関数)の明確な境界を持たせることが出来ます。
- 実行オブジェクトは自動で生成されるので実行のための手続きコードを記述する必要がありません。
- 利用コードは外部メディアの実態に無関心なので、ストレージを後で変更することができます。平行開発やスタブ化が容易です。
$ composer require ray/query-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']);
}
}$sqlDir/todo_insert.sql
INSERT INTO todo (id, title) VALUES (:id, :title)$sqlDir/todo_item_by_id.sql
SELECT * FROM todo WHERE id = :idSqlQueryModuleをインストールすると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のリスト)に応じてRowInterfaceかRowListInterfaceを指定することができます。
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が返ります。
WebQueryModuleは設定で束縛したURIをWebアクセスする実行関数がインジェクトされます。
例えば以下の例なら、https://httpbin.org/todoをPOSTリクエストする$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クラスに束縛し依存を利用します。
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形式に変換します。PHPではDateTime::ATOMの定数で定義されているフォーマットです。
日付のコラム名を配列にしてIso8601FormatModuleの引数に渡してインストールします。
$this->install(new Iso8601FormatModule(['created_at', 'updated_at']));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 = :idphp demo/run.php