[PHP] シンプルなクエリビルダー Atlas.Queryの使い方
こんにちは、ナカエです。
本日はデータベースフレームワークAtlasの記事の第四弾です。
クエリビルダーのパッケージ、Atlas.Queryの使い方を紹介します。
インストール
Composerを使ってインストールします。
composer require atlas/query
composer.jsonの例
{
"require": {
"php": "^7.2",
"ext-pdo": "*",
"atlas/query": "^1.2"
}
}
インスタンス化
SQL文に対応する、Select, Insert, Update, Deleteクラスが用意されています。
スタティックのnewメソッドにPdoまはたAtlas.PdoのConnectionオブジェクトを与えるのが一つ目の方法です。
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Atlas\Query\Select;
use Atlas\Query\Insert;
use Atlas\Query\Update;
use Atlas\Query\Delete;
$pdo = new PDO('sqlite::memory:');
$select = Select::new($pdo);
$insert = Insert::new($pdo);
$conn = Connection::new('sqlite::memory:');
$update = Update::new($conn);
$delete = Delete::new($conn);
ファクトリクラスを使うのがもう一つの方法です。 この場合でも、PdoまたはConnectionオブジェクトを引数に与える必要があります。
$conn = \Atlas\Pdo\Connection::new('sqlite::memory:');
$queryFactory = new \Atlas\Query\QueryFactory();
$select = $queryFactory->newSelect($conn);
$insert = $queryFactory->newInsert($conn);
$update = $queryFactory->newUpdate($conn);
$delete = $queryFactory->newDelete($conn);
クエリをビルドして実行する
Select, Insert, Update, Deleteそれぞれのクラスに、クエリを構築するためのビルダー系のメソッドと、クエリを実行するための実行用のメソッドが用意されています。一連の処理を通して見ていきましょう
準備
どんなクエリが実行されているかを把握するためにクエリロガーを設定しておくと便利です。 Atlas.PdoのConnectionのロギング機構がそのまま使えます。 今回はコマンドラインからの実行なので、実行されたSQLを装飾して出力するようにします。
// 出力用の補助関数
function info(string $message, string $colorCode = '0;32'): void
{
echo "\033[{$colorCode}m" . $message . "\033[0m" . PHP_EOL;
}
$conn = Connection::new('sqlite::memory:');
$conn->setQueryLogger(function (array $entry) {
$keys = array_map(function ($val) {
return ':' . $val;
}, array_keys($entry['values']));
$query = str_replace($keys, array_values($entry['values']), $entry['statement']);
info($query, '1;33');
});
$conn->logQueries(true);
Atlas.Queryにはテーブルスキーマの操作機能は含まれないので、Atlas.Pdoでテーブルを作成しておきます。
$conn->exec('CREATE TABLE users (id integer primary key, name varchar(255))');
Insert
まずはレコードを挿入します。 Insertオブジェクトには挿入するテーブルを指定するinto()と挿入するカラムと値を指定するcolumn()、columns()などのメソッドがあります。
$records = [
['id' => 1, 'name' => 'Taro'],
['id' => 2, 'name' => 'Hanako'],
['id' => 3, 'name' => 'Jiro'],
];
foreach ($records as $record) {
// クエリのビルド
$insert = Insert::new($conn);
$insert->into('users')->columns($record);
// クエリの実行
$insert->perform();
info('inserted id = ' . $insert->getLastInsertId(), '1;37');
}
クエリの実行はperform()メソッドを呼べばOKです。 実行後にはgetLasInsertID()により、挿入されたレコードのIDを取得できます。
出力
CREATE TABLE users (id integer primary key, name varchar(255))
INSERT INTO users (
"id",
"name"
) VALUES (
1,
Taro
)
inserted id = 1
INSERT INTO users (
"id",
"name"
) VALUES (
2,
Hanako
)
inserted id = 2
INSERT INTO users (
"id",
"name"
) VALUES (
3,
Jiro
)
inserted id = 3
Select
Select文です。usersテーブルから全てのレコードを取得するクエリは例えばこうなります。 取得するカラムをcolumns()で指定し、テーブルはfromで指定します。 元のSQL文を意識したインターフェースになっていますね。
// ビルド
$selectAll = Select::new($conn)
->columns('id', 'name')
->from('users');
// 実行
$results = $selectAll->fetchAll();
var_export($results);
実行結果の取得はAtlas.Pdoのメソッドと同じで、 実行結果を一気に取得するfetch()系のメソッドとGeneraterを使って取得するyield()系のメソッドが使えます。
SELECT
id,
name
FROM
users
array (
0 =>
array (
'id' => '1',
'name' => 'Taro',
),
1 =>
array (
'id' => '2',
'name' => 'Hanako',
),
2 =>
array (
'id' => '3',
'name' => 'Jiro',
),
)
WHERE, LIMIT
WHERE句やLIMIT句なども用意されています。 where()は第一引数に演算子までを記述し、第二引数に比較するパラメータを指定する形になっています。
// ビルド
$queryFactory = new QueryFactory();
$selectTaro = $queryFactory
->newSelect($conn)
->columns('id', 'name')
->from('users')
->where('name = ', 'Taro')
->limit(1);
// 実行
$result = $selectTaro->fetchOne();
var_export($result);
SELECT
id,
name
FROM
users
WHERE
name = Taro
LIMIT 1
array (
'id' => '1',
'name' => 'Taro',
)
Update
table()によって更新するテーブル名を、columns()によって更新するカラムを指定できます。 where()によって更新先の指定します。
// ビルド
$updateTaroName = $queryFactory
->newUpdate($conn)
->table('users')
->columns(['name' => 'Taro2'])
->where('name = ', 'Taro');
// 実行
$updateTaroName->perform();
// selectで結果確認
var_export($selectAll->fetchAll());
実行はInsertと同じくperform()です。
SET
"name" = Taro2
WHERE
name = Taro
SELECT
id,
name
FROM
users
array (
0 =>
array (
'id' => '1',
'name' => 'Taro2',
),
1 =>
array (
'id' => '2',
'name' => 'Hanako',
),
2 =>
array (
'id' => '3',
'name' => 'Jiro',
),
)
Delete
DeleteもInsertやUpdateとそう変わりません。 from()がテーブルの指定、where()で削除するレコードを絞り込みます。
$deleteJiro = $queryFactory
->newDelete($conn)
->from('users')
->where('name =', 'Jiro');
$deleteJiro->perform();
// yieldで取得してみる
$results = $selectAll->yieldAll();
assert($results instanceof \Generator);
foreach ($results as $result) {
var_export($result);
}
DELETE FROM users
WHERE
name =Jiro
SELECT
id,
name
FROM
users
array (
'id' => '1',
'name' => 'Taro2',
)array (
'id' => '2',
'name' => 'Hanako',
)
まとめ
テーブル作成からレコードのCRUDを一通り試してみました。SQL文さえわかっていればすぐに使えるなという印象です。 メソッドの確認のためソースも眺めましたが、Select,Insert,Update,Deleteの各クラスがすっきりしているのもいいですね。