fluent repository prototype

This commit is contained in:
Kacper Donat 2020-02-11 22:48:30 +01:00
parent 934561ca0e
commit c1a58f4bd6
13 changed files with 294 additions and 17 deletions

View File

@ -0,0 +1,34 @@
<?php
namespace App\Event;
use App\Event\HandleModifierEvent;
use App\Modifiers\Modifier;
use App\Provider\Repository;
use Doctrine\ORM\QueryBuilder;
class HandleDatabaseModifierEvent extends HandleModifierEvent
{
private $builder;
public function __construct(
Modifier $modifier,
Repository $repository,
QueryBuilder $builder,
array $meta = []
) {
parent::__construct($modifier, $repository, $meta);
$this->builder = $builder;
}
public function getBuilder(): QueryBuilder
{
return $this->builder;
}
public function replaceBuilder(QueryBuilder $builder): void
{
$this->builder = $builder;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Event;
use App\Modifiers\Modifier;
use App\Provider\Repository;
class HandleModifierEvent
{
private $repository;
private $modifier;
private $meta = [];
public function __construct(Modifier $modifier, Repository $repository, array $meta = [])
{
$this->repository = $repository;
$this->modifier = $modifier;
$this->meta = $meta;
}
public function getModifier(): Modifier
{
return $this->modifier;
}
public function getRepository()
{
return $this->repository;
}
public function getMeta(): array
{
return $this->meta;
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Exception;
class InvalidOptionException extends \InvalidArgumentException
{
public static function invalidType($parameter, $value, array $expected = [])
{
return new \InvalidArgumentException(
sprintf('Expected %s to be of type: %s. %s given.', $parameter, implode(', ', $expected), gettype($value))
);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Handlers\Database;
use App\Event\HandleDatabaseModifierEvent;
use App\Event\HandleModifierEvent;
use App\Handlers\ModifierHandler;
use App\Modifiers\Limit;
class LimitDatabaseHandler implements ModifierHandler
{
public function process(HandleModifierEvent $event)
{
if (!$event instanceof HandleDatabaseModifierEvent) {
return;
}
/** @var Limit $modifier */
$modifier = $event->getModifier();
$builder = $event->getBuilder();
$builder
->setFirstResult($modifier->getOffset())
->setMaxResults($modifier->getCount())
;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Handlers\Database;
use App\Handlers\ModifierHandler;
use App\Modifiers\WithId;
use App\Event\HandleDatabaseModifierEvent;
use App\Event\HandleModifierEvent;
use App\Service\IdUtils;
use function Kadet\Functional\apply;
use function Kadet\Functional\ref;
class WithIdDatabaseHandler implements ModifierHandler
{
/**
* @var IdUtils
*/
private $id;
public function __construct(IdUtils $id)
{
$this->id = $id;
}
public function process(HandleModifierEvent $event)
{
if (!$event instanceof HandleDatabaseModifierEvent) {
return;
}
/** @var WithId $modifier */
$modifier = $event->getModifier();
$builder = $event->getBuilder();
$alias = $event->getMeta()['alias'];
$provider = $event->getMeta()['provider'];
$id = $modifier->getId();
$mapper = apply([$this->id, 'generate'], $provider);
$builder
->where($modifier->isMultiple() ? "{$alias} in (:id)" : "{$alias} = :id")
->setParameter(':id', $modifier->isMultiple() ? array_map($mapper, $id) : $mapper($id));
;
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Handlers;
use App\Event\HandleModifierEvent;
interface ModifierHandler
{
public function process(HandleModifierEvent $event);
}

30
src/Modifiers/Limit.php Normal file
View File

@ -0,0 +1,30 @@
<?php
namespace App\Modifiers;
class Limit implements Modifier
{
private $offset;
private $count;
public function __construct(int $offset = 0, ?int $count = null)
{
$this->offset = $offset;
$this->count = $count;
}
public function getOffset()
{
return $this->offset;
}
public function getCount()
{
return $this->count;
}
public static function count(int $count)
{
return new static(0, $count);
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\Modifiers;
interface Modifier
{
}

31
src/Modifiers/WithId.php Normal file
View File

@ -0,0 +1,31 @@
<?php
namespace App\Modifiers;
use App\Exception\InvalidOptionException;
use App\Modifiers\Modifier;
class WithId implements Modifier
{
/** @var string|array */
private $id;
public function __construct($id)
{
if (!is_iterable($id) && !is_string($id)) {
throw InvalidOptionException::invalidType('id', $id, ['string', 'array']);
}
$this->id = $id instanceof \Traversable ? iterator_to_array($id) : $id;
}
public function getId()
{
return $this->id;
}
public function isMultiple()
{
return is_array($this->id);
}
}

View File

@ -3,8 +3,15 @@
namespace App\Provider\Database;
use App\Entity\LineEntity;
use App\Event\HandleDatabaseModifierEvent;
use App\Handlers\Database\LimitDatabaseHandler;
use App\Handlers\Database\WithIdDatabaseHandler;
use App\Handlers\ModifierHandler;
use App\Model\Line;
use App\Modifiers\Limit;
use App\Modifiers\WithId;
use App\Provider\LineRepository;
use App\Modifiers\Modifier;
use Tightenco\Collect\Support\Collection;
use Kadet\Functional as f;
@ -12,25 +19,52 @@ class GenericLineRepository extends DatabaseRepository implements LineRepository
{
public function getAll(): Collection
{
$repository = $this->em->getRepository(LineEntity::class);
$lines = $repository->findAll();
return collect($lines)->map(f\ref([$this, 'convert']));
return $this->all();
}
public function getById($id): ?Line
{
$repository = $this->em->getRepository(LineEntity::class);
return $this->convert($repository->find($id));
return $this->first(new WithId($id));
}
public function getManyById($ids): Collection
{
$ids = collect($ids)->map(f\apply(f\ref([$this->id, 'generate']), $this->provider));
$repository = $this->em->getRepository(LineEntity::class);
$lines = $repository->findBy(['id' => $ids->all()]);
return collect($lines)->map(f\ref([$this, 'convert']));
return $this->all(new WithId($ids));
}
}
public function first(Modifier ...$modifiers)
{
return $this->all(Limit::count(1), ...$modifiers)->first();
}
public function all(Modifier ...$modifiers)
{
$builder = $this->em
->createQueryBuilder()
->from(LineEntity::class, 'line')
->select('line')
;
foreach ($modifiers as $modifier) {
$event = new HandleDatabaseModifierEvent($modifier, $this, $builder, [
'alias' => 'line',
'provider' => $this->provider,
]);
$handler = $this->getHandlers()[get_class($modifier)];
$handler->process($event);
}
return collect($builder->getQuery()->execute())->map(f\ref([$this, 'convert']));
}
/** @return ModifierHandler[] */
private function getHandlers()
{
return [
WithId::class => new WithIdDatabaseHandler($this->id),
Limit::class => new LimitDatabaseHandler(),
];
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Provider;
use App\Modifiers\Modifier;
interface FluentRepository extends Repository
{
public function first(Modifier ...$modifiers);
public function all(Modifier ...$modifiers);
}

View File

@ -7,10 +7,10 @@ namespace App\Provider;
use App\Model\Line;
use Tightenco\Collect\Support\Collection;
interface LineRepository extends Repository
interface LineRepository extends FluentRepository
{
public function getAll(): Collection;
public function getById($id): ?Line;
public function getManyById($ids): Collection;
}
}

View File

@ -6,5 +6,4 @@ namespace App\Provider;
interface Repository
{
}
}