Skip to content

Commit 4b38067

Browse files
authored
Merge pull request #208 from nextras/custom-sql-factory
Update documentation & possibility to setup sqlProcessorFactory
2 parents 0a2fc35 + 7ded033 commit 4b38067

13 files changed

+76
-40
lines changed

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
"autoload": {
4040
"psr-4": { "Nextras\\Dbal\\": "src/" }
4141
},
42+
"autoload-dev": {
43+
"classmap": ["tests/inc/"]
44+
},
4245
"scripts": {
4346
"phpstan": "phpstan analyze -c .phpstan.neon --memory-limit=512M",
4447
"tests": "tester -C --colors 1 --setup ./tests/inc/setup.php ./tests/cases"

docs/config-nette.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ nextras.dbal:
1616
username: db-username
1717
password: db-password
1818
connectionTz: Europe/Prague
19+
sqlProcessorFactory: @Custom\SqlProcessorFactory
20+
21+
services:
22+
- Custom\SqlProcessorFactory
1923
```
2024

2125
If you need multiple connections, install the extension once again with a different name and choose which connection
@@ -37,7 +41,8 @@ nextras.dbal2:
3741

3842
**Configuration keys** are those accepted by `Connection` instance, the actual driver respectively. See [Connection](default) chapter.
3943

40-
The extension takes two additional configurations:
44+
The extension takes additional configurations:
4145

4246
- `panelQueryExplain` (default `true` if Tracy is available): enables/disables panel for Trace.
4347
- `maxQueries` (default `100`): number of logged queries in the Tracy panel.
48+
- `sqlProcessorFactory` a reference to `Nextras\Dbal\ISqlProcessorFactory` service.

docs/config-symfony.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ nextras_dbal:
4141

4242
**Configuration keys** are those accepted by `Connection` instance, the actual driver respectively. See [Connection](default) chapter.
4343

44-
The bundle takes an additional configuration:
44+
The bundle takes additional configurations:
4545

4646
- `maxQueries` (default `100`): number of logged queries into QueryDataCollector.
47+
48+
The define custom `Nextras\Dbal\ISqlProcessorFactory` instance, define `nextras_dbal.default.sqlProcessorFactory` named service, where the `default` is the name of relevant connection.

docs/param-modifiers.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ class SqlProcessorFactory implements ISqlProcessorFactory
148148
}
149149
```
150150

151+
Use `sqlProcessorFactory` configuration key to pass a factory instance. See configuration chapters.
152+
151153
### Modifier Resolver
152154

153155
SqlProcessor allows setting custom modifier resolver for any values passed for both implicit and explicit `%any` modifier. This way you may introduce custom processing for your custom types. For safety reasons it is possible to override only the `%any` modifier. To do so, implement `ISqlProcessorModifierResolver` interface and return the modifier name for the passed value. Finally, register the custom modifier resolver into SqlProcessor. This API is especially powerful in combination with custom modifiers.
@@ -163,7 +165,7 @@ class BrickSqlProcessorModifierResolver implements ISqlProcessorModifierResolver
163165
public function resolve($value): ?string
164166
{
165167
if ($value instanceof \Brick\DayOfWeek) {
166-
return 'brickDoW';
168+
return 'brickDayOfWeek';
167169
}
168170
return null;
169171
}
@@ -175,7 +177,7 @@ class SqlProcessorFactory implements ISqlProcessorFactory
175177
{
176178
$processor = new SqlProcessor($driver);
177179
$processor->setCustomModifier(
178-
'brickDoW',
180+
'brickDayOfWeek',
179181
function (SqlProcessor $processor, $value) {
180182
assert($value instanceof \Brick\DayOfWeek);
181183
return $processor->processModifier('s', $value->getValue());

src/Bridges/SymfonyBundle/DependencyInjection/NextrasDbalExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Nextras\Dbal\Connection;
88
use Nextras\Dbal\IConnection;
99
use Symfony\Component\DependencyInjection\ContainerBuilder;
10+
use Symfony\Component\DependencyInjection\ContainerInterface;
1011
use Symfony\Component\DependencyInjection\Definition;
1112
use Symfony\Component\DependencyInjection\Reference;
1213
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
@@ -53,6 +54,11 @@ private function loadConnection(
5354
int $maxQueries,
5455
): void
5556
{
57+
$config['sqlProcessorFactory'] = new Reference(
58+
"nextras_dbal.$name.sqlProcessorFactory",
59+
ContainerInterface::NULL_ON_INVALID_REFERENCE,
60+
);
61+
5662
$connectionDefinition = new Definition(Connection::class);
5763
$connectionDefinition->setArgument('$config', $config);
5864
$connectionDefinition->setPublic(true);

src/Connection.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use Nextras\Dbal\Utils\MultiLogger;
1414
use Nextras\Dbal\Utils\StrictObjectTrait;
1515
use function array_unshift;
16-
use function assert;
1716
use function is_array;
1817
use function spl_object_hash;
1918
use function str_replace;
@@ -349,7 +348,9 @@ private function createSqlProcessor(): SqlProcessor
349348
{
350349
if (isset($this->config['sqlProcessorFactory'])) {
351350
$factory = $this->config['sqlProcessorFactory'];
352-
assert($factory instanceof ISqlProcessorFactory);
351+
if (!$factory instanceof ISqlProcessorFactory) {
352+
throw new InvalidArgumentException("Connection's 'sqlProcessorFactory' configuration key does not contain an instance of " . ISqlProcessorFactory::class . '.');
353+
}
353354
return $factory->create($this);
354355
} else {
355356
return new SqlProcessor($this->getPlatform());

tests/bootstrap.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace NextrasTests\Dbal;
44

5+
56
use Tester\Environment;
67

78

@@ -10,18 +11,11 @@
1011
exit(1);
1112
}
1213

13-
require_once __DIR__ . '/inc/TestCase.php';
14-
require_once __DIR__ . '/inc/TestLogger.php';
15-
require_once __DIR__ . '/inc/QueryBuilderTestCase.php';
16-
require_once __DIR__ . '/inc/IntegrationTestCase.php';
17-
18-
1914
define('TEMP_DIR', __DIR__ . '/temp');
2015
date_default_timezone_set('Europe/Prague');
2116

2217
Environment::setup();
2318

24-
2519
if (getenv(Environment::RUNNER)) {
2620
# Runner
2721
header('Content-type: text/plain');

tests/cases/integration/DbalBundleTest.phpt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ namespace NextrasTests\Dbal;
99
use Nextras\Dbal\Bridges\SymfonyBundle\DependencyInjection\NextrasDbalExtension;
1010
use Nextras\Dbal\Connection;
1111
use Nextras\Dbal\IConnection;
12+
use Nextras\Dbal\ISqlProcessorFactory;
1213
use Symfony\Component\DependencyInjection\ContainerBuilder;
14+
use Symfony\Component\DependencyInjection\Definition;
1315
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
1416
use Tester\Assert;
1517

@@ -36,6 +38,9 @@ class DbalBundleTest extends IntegrationTestCase
3638
],
3739
],
3840
]);
41+
$containerBuilder->addDefinitions([
42+
'nextras_dbal.default.sqlProcessorFactory' => new Definition(SqlProcessorFactory::class),
43+
]);
3944

4045
$containerBuilder->compile();
4146

@@ -49,11 +54,13 @@ class DbalBundleTest extends IntegrationTestCase
4954
/** @var \Symfony\Component\DependencyInjection\Container $container */
5055
$container = new $dicClass;
5156

52-
$connectionClass = $container->get('nextras_dbal.default.connection');
53-
Assert::type(Connection::class, $connectionClass);
57+
$connection = $container->get('nextras_dbal.default.connection');
58+
Assert::type(Connection::class, $connection);
59+
60+
$connection = $container->get(IConnection::class);
61+
Assert::type(Connection::class, $connection);
5462

55-
$connectionClass = $container->get(IConnection::class);
56-
Assert::type(Connection::class, $connectionClass);
63+
Assert::type(ISqlProcessorFactory::class, $connection->getConfig()["sqlProcessorFactory"]);
5764
}
5865
}
5966

tests/cases/integration/DbalExtensionTest.configD.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ dbal:
22
driver: mysqli
33
username: bar
44
password: foo
5+
sqlProcessorFactory: @NextrasTests\Dbal\SqlProcessorFactory
56

67
dbal2:
78
driver: mysqli
89
username: bar2
910
password: foo2
1011
autowired: false
12+
13+
services:
14+
- NextrasTests\Dbal\SqlProcessorFactory

tests/cases/integration/DbalExtensionTest.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class DbalExtensionTest extends IntegrationTestCase
9191
$connection = $dic->getByType(Connection::class);
9292
Assert::type(Connection::class, $connection);
9393
Assert::equal('bar', $connection->getConfig()['username']);
94+
Assert::type(SqlProcessorFactory::class, $connection->getConfig()['sqlProcessorFactory']);
9495

9596
$connection = $dic->getService('dbal2.connection');
9697
Assert::type(Connection::class, $connection);

tests/cases/integration/sqlPreprocessor.phpt

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@
88
namespace NextrasTests\Dbal;
99

1010

11-
use Nextras\Dbal\Exception\InvalidArgumentException;
12-
use Nextras\Dbal\IConnection;
1311
use Nextras\Dbal\ISqlProcessorFactory;
1412
use Nextras\Dbal\Platforms\PostgreSqlPlatform;
1513
use Nextras\Dbal\Result\Row;
16-
use Nextras\Dbal\SqlProcessor;
1714
use Tester\Assert;
1815

1916

@@ -56,28 +53,11 @@ class SqlPreprocessorIntegrationTest extends IntegrationTestCase
5653

5754
public function testCustomModifier()
5855
{
59-
$sqlProcessorFactory = new class implements ISqlProcessorFactory {
60-
public function create(IConnection $connection): SqlProcessor
61-
{
62-
$sqlProcessor = new SqlProcessor($connection->getPlatform());
63-
$sqlProcessor->setCustomModifier(
64-
'%test',
65-
function (SqlProcessor $sqlProcessor, $value, string $type) {
66-
if (!is_array($value)) throw new InvalidArgumentException('%test modifer accepts only array.');
67-
return 'ARRAY[' .
68-
implode(', ', array_map(function ($subValue) use ($sqlProcessor): string {
69-
return $sqlProcessor->processModifier('any', $subValue);
70-
}, $value)) .
71-
']';
72-
}
73-
);
74-
return $sqlProcessor;
75-
}
76-
};
77-
7856
$this->connection->connect();
57+
/** @var ISqlProcessorFactory $sqlProcessorFactory */
58+
$sqlProcessorFactory = $this->connection->getConfig()['sqlProcessorFactory'];
7959
$sqlProcessor = $sqlProcessorFactory->create($this->connection);
80-
$result = $sqlProcessor->processModifier('%test', [1, '2', false, null]);
60+
$result = $sqlProcessor->processModifier('%pgArray', [1, '2', false, null]);
8161
if ($this->connection->getPlatform()->getName() === PostgreSqlPlatform::NAME) {
8262
Assert::same("ARRAY[1, '2', FALSE, NULL]", $result);
8363
} else {

tests/inc/IntegrationTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ protected function createConnection($params = [])
4242
'user' => null,
4343
'password' => null,
4444
'searchPath' => ['public'],
45+
'sqlProcessorFactory' => new SqlProcessorFactory(),
4546
], Environment::loadData(), $params);
4647
return new Connection($options);
4748
}

tests/inc/SqlProcessorFactory.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace NextrasTests\Dbal;
4+
5+
6+
use Nextras\Dbal\Exception\InvalidArgumentException;
7+
use Nextras\Dbal\IConnection;
8+
use Nextras\Dbal\ISqlProcessorFactory;
9+
use Nextras\Dbal\SqlProcessor;
10+
11+
12+
class SqlProcessorFactory implements ISqlProcessorFactory
13+
{
14+
public function create(IConnection $connection): SqlProcessor
15+
{
16+
$sqlProcessor = new SqlProcessor($connection->getPlatform());
17+
$sqlProcessor->setCustomModifier(
18+
'%pgArray',
19+
function(SqlProcessor $sqlProcessor, $value, string $type) {
20+
if (!is_array($value)) throw new InvalidArgumentException('%pgArray modifier accepts an array only.');
21+
return 'ARRAY[' .
22+
implode(', ', array_map(function($subValue) use ($sqlProcessor): string {
23+
return $sqlProcessor->processModifier('any', $subValue);
24+
}, $value)) .
25+
']';
26+
},
27+
);
28+
return $sqlProcessor;
29+
}
30+
}

0 commit comments

Comments
 (0)