Skip to content

Commit

Permalink
feat: fetch by ID (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
dkarlovi authored Feb 25, 2022
1 parent 0ba6a4f commit cf71562
Show file tree
Hide file tree
Showing 19 changed files with 279 additions and 66 deletions.
18 changes: 15 additions & 3 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ services:
exclude:
- '../src/Bridge/Symfony/Serializer/*'
- '../src/Database/*'
- '../src/DatabaseProvider.php'
- '../src/Kernel.php'

Sigwin\YASSG\Bridge\Symfony\Controller\:
Expand All @@ -32,6 +33,10 @@ services:
-
name: sigwin_yassg.database.storage.type
type: memory

Sigwin\YASSG\DatabaseProvider:
arguments:
$locator: !tagged_locator { tag: 'sigwin_yassg.database', index_by: 'name' }

sigwin_yassg.expression_language:
class: Symfony\Component\ExpressionLanguage\ExpressionLanguage
Expand All @@ -47,16 +52,23 @@ services:
tags:
-
name: serializer.normalizer
priority: 3000

priority: 3000
sigwin_yassg.serializer.denormalizer.collection:
class: Sigwin\YASSG\Bridge\Symfony\Serializer\Normalizer\CollectionNormalizer
arguments:
$expressionLanguage: '@sigwin_yassg.expression_language'
tags:
-
name: serializer.normalizer
priority: 5000
priority: 5000
sigwin_yassg.serializer.denormalizer.expression:
class: Sigwin\YASSG\Bridge\Symfony\Serializer\Normalizer\ExpressionNormalizer
arguments:
$expressionLanguage: '@sigwin_yassg.expression_language'
tags:
-
name: serializer.normalizer
priority: 4000

sigwin_yassg.fragment.renderer.inline:
class: Sigwin\YASSG\Bridge\Symfony\HttpKernel\Fragment\RelativeUrlInlineFragmentRenderer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
use Sigwin\YASSG\Bridge\Symfony\Serializer\AttributeMetadataTrait;
use Sigwin\YASSG\Database;
use Sigwin\YASSG\Database\MemoryDatabase;
use Sigwin\YASSG\DatabaseProvider;
use Sigwin\YASSG\Storage;
use Sigwin\YASSG\StorageWithOptions;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down Expand Up @@ -48,15 +48,14 @@ public function process(ContainerBuilder $container): void
throw new \LogicException(sprintf('Data source type %1$s already provided by %2$s', $type, $reference));
}

/** @var class-string<Storage> $class */
/** @var class-string<StorageWithOptions> $class */
$class = $storageDefinition->getClass();

$supportedStorageTypes[$type] = $class;
$container->removeDefinition($reference);
}
unset($type);

$databases = [];
$localizableClasses = [];

$classMetadata = $container->get('serializer.mapping.class_metadata_factory');
Expand All @@ -80,6 +79,7 @@ public function process(ContainerBuilder $container): void
$storageDefinition
->setAutowired(true)
->setAutoconfigured(true);

$callable = [$supportedStorageTypes[$type], 'resolveOptions'];
try {
$options = $callable($database['options'] ?? []);
Expand Down Expand Up @@ -107,22 +107,18 @@ public function process(ContainerBuilder $container): void
$databaseDefinition
->setArgument(0, new Reference($storageId))
->setArgument(1, new Reference('sigwin_yassg.expression_language'))
->setArgument(2, $this->getProperties($databaseClass));
->setArgument(2, $this->getProperties($databaseClass))
->addTag('sigwin_yassg.database', ['name' => $name]);
$databaseId = sprintf('sigwin_yassg.database.%1$s', $name);
$container->setDefinition($databaseId, $databaseDefinition);
$container->setAlias(sprintf('%1$s $%2$s', Database::class, $name), $databaseId);

$databases[$name] = new Reference($databaseId);

$localizableProperties = $this->getLocalizableProperties($databaseClass);
if ($localizableProperties !== []) {
$localizableClasses[$databaseClass] = $localizableProperties;
}
}
$container->setParameter('sigwin_yassg.databases_spec', null);
$container
->getDefinition(DatabaseProvider::class)
->setArgument(0, $databases);
$container
->getDefinition('sigwin_yassg.serializer.denormalizer.localizing')
->setArgument(0, $localizableClasses);
Expand Down
8 changes: 8 additions & 0 deletions src/Bridge/Symfony/ExpressionLanguage/FunctionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ public function getFunctions(): array

return $provider->getDatabase($name)->findAll(...$arguments);
}),
new ExpressionFunction('yassg_get', static function (string $name): string {
return sprintf('$provider->getDatabase(%s)', $name);
}, static function (array $variables, string $name, string $id) {
/** @var DatabaseProvider $provider */
$provider = $variables['provider'];

return $provider->getDatabase($name)->get($id);
}),
];
}
}
53 changes: 53 additions & 0 deletions src/Bridge/Symfony/Serializer/Normalizer/ExpressionNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

/*
* This file is part of the yassg project.
*
* (c) sigwin.hr
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sigwin\YASSG\Bridge\Symfony\Serializer\Normalizer;

use Sigwin\YASSG\DatabaseProvider;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

final class ExpressionNormalizer implements DenormalizerInterface
{
private ExpressionLanguage $expressionLanguage;
private DatabaseProvider $databaseProvider;

public function __construct(ExpressionLanguage $expressionLanguage, DatabaseProvider $databaseProvider)
{
$this->expressionLanguage = $expressionLanguage;
$this->databaseProvider = $databaseProvider;
}

public function denormalize(mixed $data, string $type, string $format = null, array $context = [])
{
/** @var string $data */
$value = $this->expressionLanguage->evaluate(mb_substr($data, 2), [
'provider' => $this->databaseProvider,
]);

/**
* @var class-string $type
* @phpstan-ignore-next-line
*/
if (is_a($value, $type, false) === false) {
throw new \LogicException(sprintf('Invalid value denormalized, %1$s expected, %2$s received', $type, get_debug_type($value)));
}

return $value;
}

public function supportsDenormalization(mixed $data, string $type, string $format = null): bool
{
return \is_string($data) && str_starts_with($data, '@=');
}
}
3 changes: 3 additions & 0 deletions src/Bridge/Twig/Extension/DatabaseExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public function getFunctions(): array
new TwigFunction('yassg_find_one_by_or_null', function (string $name, array $arguments = []) {
return $this->provider->getDatabase($name)->findOneByOrNull(...$arguments);
}),
new TwigFunction('yassg_get', function (string $name, string $id) {
return $this->provider->getDatabase($name)->get($id);
}),
];
}
}
26 changes: 26 additions & 0 deletions src/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,47 @@

namespace Sigwin\YASSG;

/**
* @template T of object
*/
interface Database
{
public function count(?string $condition = null): int;

public function countBy(array $condition): int;

/**
* @return Collection<string, T>
*/
public function findAll(?string $condition = null, ?array $sort = null, ?int $limit = null, int $offset = 0, ?string $select = null): Collection;

/**
* @return Collection<string, T>
*/
public function findAllBy(array $condition, ?array $sort = null, ?int $limit = null, int $offset = 0, ?string $select = null): Collection;

/**
* @return T
*/
public function findOne(?string $condition = null, ?array $sort = null, ?string $select = null): object;

/**
* @return T
*/
public function findOneBy(array $condition, ?array $sort = null, ?string $select = null): object;

/**
* @return null|T
*/
public function findOneOrNull(?string $condition = null, ?array $sort = null, ?string $select = null): ?object;

/**
* @return null|T
*/
public function findOneByOrNull(array $condition, ?array $sort = null, ?string $select = null): ?object;

/**
* @return T
*/
public function get(string $id): object;
}
11 changes: 8 additions & 3 deletions src/Database/MemoryDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ public function findOneByOrNull(array $condition, ?array $sort = null, ?string $
return $this->findOneOrNull($this->conditionArrayToString($condition), $sort, $select);
}

public function get(string $id): object
{
/** @var object $item */
$item = $this->storage->get($id);

return $item;
}

private function load(?string $condition, callable $callable): void
{
$conditionExpression = null;
Expand All @@ -129,9 +137,6 @@ private function load(?string $condition, callable $callable): void
}

foreach ($this->storage->load() as $id => $item) {
if ($item === null) {
continue;
}
if ($conditionExpression === null || $this->expressionLanguage->evaluate($conditionExpression, ['item' => $item]) !== false) {
$callable($id, $item);
}
Expand Down
25 changes: 13 additions & 12 deletions src/DatabaseProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,28 @@

namespace Sigwin\YASSG;

use Symfony\Component\DependencyInjection\ServiceLocator;

final class DatabaseProvider
{
/**
* @var array<Database>
*/
private array $databases;

/**
* @param array<Database> $databases
*/
public function __construct(array $databases)
private ServiceLocator $locator;

public function __construct(ServiceLocator $locator)
{
$this->databases = $databases;
$this->locator = $locator;
}

public function getDatabase(string $name): Database
{
if (isset($this->databases[$name]) === false) {
if ($this->locator->has($name) === false) {
throw new \LogicException(sprintf('No such database "%1$s"', $name));
}

return $this->databases[$name];
$database = $this->locator->get($name);
if ($database instanceof Database === false) {
throw new \LogicException(sprintf('Service "%1$s" is not a database', $name));
}

return $database;
}
}
13 changes: 11 additions & 2 deletions src/Storage.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@

namespace Sigwin\YASSG;

/**
* @template T of object
*/
interface Storage
{
public static function resolveOptions(array $options): array;

/**
* @return iterable<string, array|T>
*/
public function load(): iterable;

/**
* @return array|T
*/
public function get(string $id): object|array;
}
Loading

0 comments on commit cf71562

Please sign in to comment.