gowork / dqo
Database Query Objects
Installs: 19 556
Dependents: 0
Suggesters: 0
Security: 0
Stars: 5
Watchers: 5
Forks: 2
Open Issues: 1
Requires
- php: >=8.2
- doctrine/dbal: ^4.0
- gowork/safe: ^0.2
- gowork/values: ^0.6
- nikic/php-parser: ^5.0
- open-serializer/type: ^0.1
- phpdocumentor/reflection-docblock: ^5.2
- symfony/config: ^6.0|^7.0
- symfony/console: ^6.0|^7.0
- symfony/dependency-injection: ^6.0|^7.0
- symfony/http-kernel: ^6.0|^7.0
- symfony/process: ^6.0|^7.0
Requires (Dev)
- phpstan/phpstan: ^1.7
- phpstan/phpstan-strict-rules: ^1.4
- phpunit/phpunit: ^9.5
- dev-master
- 0.5.3
- 0.5.2
- 0.5.1
- 0.5.0
- 0.4.1
- 0.4.0
- 0.3.3
- 0.3.2
- 0.3.1
- 0.3.0
- 0.2.1
- 0.1.0
- dev-feature/fix-type-typehints
- dev-fix-deprecated-null-param
- dev-dependabot/composer/phpunit/phpunit-tw-9.5or-tw-10.0
- dev-feature/dbal3v2
- dev-fix/fetch-col-null
- dev-fix/fetch-column
- dev-feature/php-8.1
- dev-feature/query-gen2
- dev-bronek89-patch-2
- dev-fix/remove-version
- dev-feature/update-values
- dev-feature/phpstan1
- dev-feature/switch-to-dbal3
- dev-feature/remove-better-reflection
- dev-bronek89-patch-4
- dev-feature/dbal-3
- dev-bronek89-patch-3
- dev-bronek89-patch-1
- dev-feature/symfony4
- dev-feature/run-tests
- dev-feature/dev-bundle
- dev-feature/fixers
- dev-feature/query-gen
- dev-add-license-1
- dev-feature/nikic-generate
This package is auto-updated.
Last update: 2024-11-13 13:05:22 UTC
README
Introduction
DQO provides an object representation of SQL database table, row and select query.
Features:
- Each database table can be described as
Table
class - Enables column name completion in IDE while writing queries
- Provides a table columns enumeration as constants
- Each row returned from SELECT query can be described as
Row
class - Table specific deserialization recipes can be added to corresponding
Row
class Table
andRow
classes code can be generated with Symfony console command- Provides immutable
DatabaseSelectBuilder
for building SELECT queries
DQO is based on Doctrine DBAL and uses Doctrine Types for data deserialization and Doctrine\DBAL\Connection
for query execution.
Table
definition
Classes representing specific database tables. It contains enumeration of table columns as constants and simplifies field aliasing. Multiple instances can be created with different aliases.
final class UserTable extends GW\DQO\Table { public const ID = 'id'; public const EMAIL = 'email'; public const NAME = 'name'; public function id(): string { return $this->fieldPath(self::ID); } public function email(): string { return $this->fieldPath(self::EMAIL); } public function name(): string { return $this->fieldPath(self::NAME); } public function createRow(array $raw): UserRow { return new UserRow($raw, $this); } } $userTable = new UserTable('user_alias'); $userTable->table(); // "user" $userTable->alias(); // "user_alias" $userTable->id(); // "user_alias.id" $userTable->selectField(UserTable::ID); // "user_alias.id as user_alias_id"
TableRow
definition
Classes that can be created to unify data extracting and deserializing from corresponding table.
final class UserRow extends ClientRow { public function id(): UserId { return $this->getThroughType('UserId', UserTable::ID); } public function name(): string { return $this->getString(UserTable::NAME); } public function email(): Email { return Email::fromString($this->getString(UserTable::EMAIL)); } public function optionalSecondEmail(): ?Email { return $this->getThrough([Email::class, 'fromString'], UserTable::OPTIONAL_SECOND_EMAIL); } public function about(): ?string { return $this->getNullableString(UserTable::NAME); } } $userTable = new UserTable(); $userRow = new UserRow($rowFromQuery, $userTable);
Building SELECT query with DatabaseSelectBuilder
DatabaseSelectBuilder
simplifies construction of SELECT statements using Table
objects.
/** @var Doctrine\DBAL\Connection $connection */ $builder = new GW\DQO\DatabaseSelectBuilder($connection); $meTable = new UserTable('me'); $friendTable = new UserTable('friend'); $builder ->from($meTable) ->join($friendTable, "{$friendTable->id()} = {$meTable->friendId()}") ->where("{$meTable->username()} = :me", ['me' => 'John Doe']) ->select($friend->name()) ->offsetLimit(0, 10);
SELECT column aliases
By default TableRow
expects that table column used in SELECT part has alias as follows: table_alias.column_name as table_alias_column_name
.
There are 2 ways to create such alias:
- Use
Table
methods creating column aliases$table = new UserTable(); $builder = $builder->select(...$table->select(UserTable::ID, UserTable::email)); // or $builder = $builder->select($table->selectField(UserTable::ID), $table->selectField(UserTable::email)); // or $builder = $builder->select(...$table->selectAll());
- Use simply
$table->column()
whenselect()
is aftertable()
orjoin()
$table = new UserTable(); // first add $table to builder so it can recognize `user.id`, `user.email` and create valid aliases... $builder = $builder->from($table); // ...then simply select $builder = $builder->select($table->id(), $table->email());
Query parameters
Query parameters can be specified directly in where/having
method or provided later.
$builder = $builder->from($user) ->where("{$user->name()} = :name", ['name' => 'John Doe']) ->having('orders > :limit', ['limit' => 10]); // or $builder = $builder->from($user) ->where("{$user->name()} = :name") ->withParameter('name', 'John Doe'); // or $builder = $builder->from($user) ->where("{$user->name()} = :name") ->withParameters(['name' => 'John Doe']);
Query parameter types can be specified as where()
argument.
$yesterday = new DateTime('yesterday'); $builder = $builder ->from($user) ->where("{$user->registered()} > :yesterday", ['yesterday' => $yesterday], ['yesterday' => 'datetime']);
You can also define mapping of parameter classes to proper Doctrine type.
$start = new DateTimeImmutable('first day of last month 00:00'); $end = new DateTimeImmutable('last day of last month 23:59'); $builder = $builder ->withTypes([DateTimeImmutable::class => 'datetime_immutable']) ->from($user) ->where("{$user->registered()} BETWEEN :start AND :end", ['start' => $start, 'end' => $end]);
Fetching results
/** @var array<string, mixed>|null $result one result row or null when there are no rows */ $result = $builder->fetch(); /** @var mixed|null $result one column from first result or null when no results */ $result = $builder->fetchColumn(); /** @var array<int, array<string, mixed>> $result fetch all result rows */ $result = $builder->fetchAll(); /** * @var ArrayValue<array<string, mixed>> $result * @see https://github.com/gowork/values */ $result = $builder->wrapAll(); /** @var int $result */ @result = $builder->count();
Install
composer require gowork/dqo
Setup
Symfony
Add the DatabaseAccessGeneratorBundle to your application's kernel (only on dev
environment):
<?php public function registerBundles(): array { $bundles = [ // ... ]; if ($this->getEnvironment() === 'dev') { // ... $bundles[] = new GW\DQO\Symfony\DatabaseAccessGeneratorBundle(); } ... }
Generate table class
dqo:generate-tables src/Database App/Database table_1 table_2
Table query pattern
All queries should extends GW\DQO\Query\AbstractDatabaseQuery
TODO
- generate queries for tables
- add command to update table/row with new fields
About
Used at: