Skip to content

Commit e38197c

Browse files
committed
feat(loader): Added possibility to configure default loader, to use raw loader or to use chained loader
1 parent 6452b74 commit e38197c

File tree

13 files changed

+240
-27
lines changed

13 files changed

+240
-27
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\CompilerPass;
6+
7+
use RunOpenCode\Bundle\QueryResourcesLoader\Contract\LoaderInterface;
8+
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\Extension;
9+
use RunOpenCode\Bundle\QueryResourcesLoader\Loader\RawLoader;
10+
use RunOpenCode\Bundle\QueryResourcesLoader\Loader\TwigLoader;
11+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
12+
use Symfony\Component\DependencyInjection\ContainerBuilder;
13+
14+
final readonly class ConfigureDefaultLoader implements CompilerPassInterface
15+
{
16+
/**
17+
* {@inheritdoc}
18+
*/
19+
public function process(ContainerBuilder $container): void
20+
{
21+
if (!$container->hasParameter(Extension::DEFAULT_LOADER)) {
22+
return;
23+
}
24+
25+
/** @var string $loader */
26+
$loader = $container->getParameter(Extension::DEFAULT_LOADER);
27+
28+
match ($loader) {
29+
'twig' => $container->setAlias(LoaderInterface::class, TwigLoader::class),
30+
'raw' => $container->setAlias(LoaderInterface::class, RawLoader::class),
31+
default => $container->setAlias(LoaderInterface::class, $loader),
32+
};
33+
}
34+
}

src/RunOpenCode/Bundle/QueryResourcesLoader/DependencyInjection/Configuration/Configuration.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,19 @@ public function getConfigTreeBuilder(): TreeBuilder
5353
EOT)
5454
->end()
5555
->append(new TwigNodeDefinition())
56+
->scalarNode('default_loader')
57+
->defaultValue('twig')
58+
->info(<<<EOT
59+
Which loader to use by default, if not specified. By default, "twig" loader will be used.
60+
61+
Library provides "twig" loader which uses Twig as template engine. There is "raw" loader as well, which does not process
62+
provided value, assuming that raw query is provided. There is "chained" loader which can be used to chain multiple loaders
63+
looking for query in each of them. If no loader is found, a "raw" loader will be used.
64+
65+
You may provide your own loader by implementing LoaderInterface and registering it as service. In that case, you may provide
66+
name of the service as loader name.
67+
EOT)
68+
->end()
5669
->end();
5770

5871
return $treeBuilder;

src/RunOpenCode/Bundle/QueryResourcesLoader/DependencyInjection/Extension.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*
1919
* @phpstan-type Config = array{
2020
* default_executor: string,
21+
* default_loader: string,
2122
* cache: array{
2223
* pool: string|null,
2324
* default_ttl: int|null,
@@ -47,6 +48,7 @@
4748
final class Extension extends BaseExtension
4849
{
4950
public const DEFAULT_EXECUTOR = 'runopencode.query_resources_loader.default_executor';
51+
public const DEFAULT_LOADER = 'runopencode.query_resources_loader.default_loader';
5052
public const CACHE_POOL = 'runopencode.query_resources_loader.cache.pool';
5153
public const CACHE_DEFAULT_TTL = 'runopencode.query_resources_loader.cache.default_ttl';
5254

@@ -97,6 +99,8 @@ public function load(array $configs, ContainerBuilder $container): void
9799
$container->setParameter(self::CACHE_DEFAULT_TTL, $configuration['cache']['default_ttl']);
98100
// Set name of the default executor.
99101
$container->setParameter(self::DEFAULT_EXECUTOR, $configuration['default_executor']);
102+
// Set name of the default loader.
103+
$container->setParameter(self::DEFAULT_LOADER, $configuration['default_loader']);
100104

101105

102106
$this->configureTwigGlobals($configuration, $container);

src/RunOpenCode/Bundle/QueryResourcesLoader/Loader/LoaderMiddleware.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,46 @@
77
use RunOpenCode\Bundle\QueryResourcesLoader\Contract\ExecutionResultInterface;
88
use RunOpenCode\Bundle\QueryResourcesLoader\Contract\LoaderInterface;
99
use RunOpenCode\Bundle\QueryResourcesLoader\Contract\MiddlewareInterface;
10+
use RunOpenCode\Bundle\QueryResourcesLoader\Exception\InvalidArgumentException;
1011
use RunOpenCode\Bundle\QueryResourcesLoader\Model\Options;
1112
use RunOpenCode\Bundle\QueryResourcesLoader\Model\Parameters;
1213

1314
final readonly class LoaderMiddleware implements MiddlewareInterface
1415
{
15-
public function __construct(private LoaderInterface $loader)
16-
{
17-
// noop
16+
private LoaderInterface $default;
17+
18+
/**
19+
* @var array<string, LoaderInterface>
20+
*/
21+
private array $loaders;
22+
23+
/**
24+
* @param iterable<string, LoaderInterface> $loaders
25+
*/
26+
public function __construct(
27+
LoaderInterface $default,
28+
iterable $loaders,
29+
) {
30+
$loaders = \is_array($loaders) ? $loaders : \iterator_to_array($loaders);
31+
$this->default = $default;
32+
$this->loaders = \array_merge($loaders, [
33+
'chained' => new ChainedLoader($loaders),
34+
]);
1835
}
1936

2037
/**
2138
* {@inheritdoc}
2239
*/
2340
public function __invoke(string $query, Parameters $parameters, Options $options, callable $next): ExecutionResultInterface
2441
{
42+
$requested = $options->getLoader();
43+
$loader = null === $requested ? $this->default : $this->loaders[$requested] ?? throw new InvalidArgumentException(\sprintf(
44+
'Requested loader "%s" not found.',
45+
$requested
46+
));
47+
2548
return $next(
26-
$this->loader->get($query, $parameters->getParameters()),
49+
$loader->get($query, $parameters->getParameters()),
2750
$parameters,
2851
$options
2952
);

src/RunOpenCode/Bundle/QueryResourcesLoader/Model/Options.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
*
2121
* @property string|null $executor
2222
* @property CacheIdentityInterface|CacheIdentifiableInterface|null $cache
23+
* @property string|null $loader
2324
*
2425
* @method string|null getExecutor()
2526
* @method CacheIdentityInterface|CacheIdentifiableInterface|null getCache()
27+
* @method string|null getLoader()
2628
*
2729
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
2830
*/
@@ -84,6 +86,16 @@ public static function cached(CacheIdentityInterface|CacheIdentifiableInterface
8486
]);
8587
}
8688

89+
/**
90+
* Create new instance of options with custom loader and default executor.
91+
*/
92+
public static function loader(string $loader): static
93+
{
94+
return static::create([
95+
'loader' => $loader,
96+
]);
97+
}
98+
8799
/**
88100
* @return array<string, mixed> Options.
89101
*/
@@ -185,6 +197,17 @@ public function withCache(CacheIdentityInterface|CacheIdentifiableInterface|null
185197
));
186198
}
187199

200+
/**
201+
* Set loader.
202+
*/
203+
public function withLoader(?string $loader): static
204+
{
205+
return static::create(\array_merge(
206+
$this->options,
207+
['loader' => $loader]
208+
));
209+
}
210+
188211
/**
189212
* Set arbitrary option.
190213
*/

src/RunOpenCode/Bundle/QueryResourcesLoader/QueryResourcesLoaderBundle.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace RunOpenCode\Bundle\QueryResourcesLoader;
66

77
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\CompilerPass\ConfigureCacheMiddleware;
8+
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\CompilerPass\ConfigureDefaultLoader;
89
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\CompilerPass\RegisterDbalExecutors;
910
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\CompilerPass\RegisterTwigExtensions;
1011
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\Extension;
@@ -35,5 +36,8 @@ public function build(ContainerBuilder $container): void
3536

3637
// Register middleware configuration compiler passes.
3738
$container->addCompilerPass(new ConfigureCacheMiddleware());
39+
40+
// Register loader compiler passes.
41+
$container->addCompilerPass(new ConfigureDefaultLoader());
3842
}
3943
}

src/RunOpenCode/Bundle/QueryResourcesLoader/Resources/config/loader.xml

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
label="twig"
2222
/>
2323
</service>
24-
24+
2525
<service
2626
id="RunOpenCode\Bundle\QueryResourcesLoader\Loader\RawLoader"
2727
class="RunOpenCode\Bundle\QueryResourcesLoader\Loader\RawLoader"
@@ -33,22 +33,6 @@
3333
/>
3434
</service>
3535

36-
<service
37-
id="RunOpenCode\Bundle\QueryResourcesLoader\Loader\ChainedLoader"
38-
class="RunOpenCode\Bundle\QueryResourcesLoader\Loader\ChainedLoader"
39-
>
40-
<argument
41-
type="tagged_iterator"
42-
tag="runopencode.query_resources_loader.loader"
43-
index-by="label"
44-
/>
45-
</service>
46-
47-
<service
48-
id="RunOpenCode\Bundle\QueryResourcesLoader\Contract\LoaderInterface"
49-
alias="RunOpenCode\Bundle\QueryResourcesLoader\Loader\ChainedLoader"
50-
/>
51-
5236
<service
5337
id="RunOpenCode\Bundle\QueryResourcesLoader\Loader\LoaderMiddleware"
5438
class="RunOpenCode\Bundle\QueryResourcesLoader\Loader\LoaderMiddleware"
@@ -57,6 +41,11 @@
5741
type="service"
5842
id="RunOpenCode\Bundle\QueryResourcesLoader\Contract\LoaderInterface"
5943
/>
44+
<argument
45+
type="tagged_iterator"
46+
index-by="label"
47+
tag="runopencode.query_resources_loader.loader"
48+
/>
6049

6150
<tag
6251
name="runopencode.query_resources_loader.middleware"

tests/Cache/CacheIntegrationTest.php

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,16 @@ public function testCacheIntegration(): void
1919
/** @var QueryResourcesLoaderInterface $loader */
2020
$loader = $this->getContainer()->get(QueryResourcesLoaderInterface::class);
2121
/** @var Result $resultSet */
22-
$resultSet = $loader->execute('SELECT id, title FROM bar ORDER BY id', null, Options::cached(new CacheIdentity(
23-
'foo',
24-
)));
22+
$resultSet = $loader->execute(
23+
'SELECT id, title FROM bar ORDER BY id',
24+
null,
25+
Options::create([
26+
'cache' => new CacheIdentity(
27+
'foo',
28+
),
29+
'loader' => 'raw',
30+
]),
31+
);
2532

2633
$this->assertEquals([
2734
['id' => 1, 'title' => 'Bar title 1'],
@@ -37,9 +44,16 @@ public function testCacheIntegration(): void
3744
/** @var QueryResourcesLoaderInterface $loader */
3845
$loader = $this->getContainer()->get(QueryResourcesLoaderInterface::class);
3946
/** @var Result $resultSet */
40-
$resultSet = $loader->execute('SELECT * FROM bar', null, Options::cached(new CacheIdentity(
41-
'foo',
42-
)));
47+
$resultSet = $loader->execute(
48+
'SELECT * FROM bar',
49+
null,
50+
Options::create([
51+
'cache' => new CacheIdentity(
52+
'foo',
53+
),
54+
'loader' => 'raw',
55+
]),
56+
);
4357

4458
$this->assertEquals([
4559
['id' => 1, 'title' => 'Bar title 1'],
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RunOpenCode\Bundle\QueryResourcesLoader\Tests\DependencyInjection\CompilerPass;
6+
7+
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractCompilerPassTestCase;
8+
use RunOpenCode\Bundle\QueryResourcesLoader\Contract\LoaderInterface;
9+
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\CompilerPass\ConfigureDefaultLoader;
10+
use RunOpenCode\Bundle\QueryResourcesLoader\DependencyInjection\Extension;
11+
use RunOpenCode\Bundle\QueryResourcesLoader\Loader\RawLoader;
12+
use RunOpenCode\Bundle\QueryResourcesLoader\Loader\TwigLoader;
13+
use Symfony\Component\DependencyInjection\ContainerBuilder;
14+
use Symfony\Component\DependencyInjection\Definition;
15+
16+
final class ConfigureDefaultLoaderTest extends AbstractCompilerPassTestCase
17+
{
18+
public function testItConfiguresRawLoader(): void
19+
{
20+
$this->setParameter(Extension::DEFAULT_LOADER, 'raw');
21+
$this->setDefinition(RawLoader::class, new Definition(RawLoader::class));
22+
23+
$this->compile();
24+
25+
$this->assertContainerBuilderHasAlias(LoaderInterface::class, RawLoader::class);
26+
}
27+
28+
public function testItConfiguresTwigLoader(): void
29+
{
30+
$this->setParameter(Extension::DEFAULT_LOADER, 'twig');
31+
$this->setDefinition(TwigLoader::class, new Definition(TwigLoader::class));
32+
33+
$this->compile();
34+
35+
$this->assertContainerBuilderHasAlias(LoaderInterface::class, TwigLoader::class);
36+
}
37+
38+
/**
39+
* {@inheritdoc}
40+
*/
41+
protected function registerCompilerPass(ContainerBuilder $container): void
42+
{
43+
$container->addCompilerPass(new ConfigureDefaultLoader());
44+
}
45+
}

tests/DependencyInjection/Configuration/ConfigurationTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function testItHasReasonableDefaults(): void
1616
{
1717
$this->assertProcessedConfigurationEquals([
1818
'default_executor' => null,
19+
'default_loader' => 'twig',
1920
'cache' => [
2021
'default_ttl' => null,
2122
'pool' => 'cache.app',
@@ -49,6 +50,7 @@ public function testItCanBeProperlyConfigured(): void
4950
{
5051
$this->assertProcessedConfigurationEquals([
5152
'default_executor' => 'some.default.executor',
53+
'default_loader' => 'twig',
5254
'cache' => [
5355
'default_ttl' => 3600,
5456
'pool' => 'foo',

0 commit comments

Comments
 (0)