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 = :id
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のリスト
)に応じて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 = :id
php demo/run.php