Extract HandlerProvider to own class
This commit is contained in:
parent
87255eaf13
commit
7ffd3c02cd
@ -23,7 +23,7 @@ services:
|
|||||||
# this creates a service per class whose id is the fully-qualified class name
|
# this creates a service per class whose id is the fully-qualified class name
|
||||||
App\:
|
App\:
|
||||||
resource: '../src/*'
|
resource: '../src/*'
|
||||||
exclude: '../src/{DependencyInjection,Exception,Modifiers,Entity,Model,Migrations,Tests,Functions,Kernel.php}'
|
exclude: '../src/{DependencyInjection,Exception,Modifie,Entity,Model,Migrations,Tests,Functions,Handler,Kernel.php}'
|
||||||
|
|
||||||
# controllers are imported separately to make sure services can be injected
|
# controllers are imported separately to make sure services can be injected
|
||||||
# as action arguments even if you don't extend any base controller class
|
# as action arguments even if you don't extend any base controller class
|
||||||
@ -35,6 +35,10 @@ services:
|
|||||||
resource: '../src/Provider'
|
resource: '../src/Provider'
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
|
App\Handler\:
|
||||||
|
resource: '../src/Handler'
|
||||||
|
tags: [ app.handler ]
|
||||||
|
|
||||||
# add more service definitions when explicit configuration is needed
|
# add more service definitions when explicit configuration is needed
|
||||||
# please note that last definitions always *replace* previous ones
|
# please note that last definitions always *replace* previous ones
|
||||||
|
|
||||||
@ -90,3 +94,7 @@ services:
|
|||||||
# other servces
|
# other servces
|
||||||
App\Service\ProviderResolver:
|
App\Service\ProviderResolver:
|
||||||
arguments: [!tagged app.provider, '%kernel.debug%']
|
arguments: [!tagged app.provider, '%kernel.debug%']
|
||||||
|
|
||||||
|
App\Service\HandlerProvider:
|
||||||
|
arguments: [!tagged_locator app.handler]
|
||||||
|
shared: false
|
||||||
|
@ -4,12 +4,12 @@ namespace App\Controller\Api\v1;
|
|||||||
|
|
||||||
use App\Controller\Controller;
|
use App\Controller\Controller;
|
||||||
use App\Model\Stop;
|
use App\Model\Stop;
|
||||||
use App\Model\TrackStop;
|
|
||||||
use App\Model\StopGroup;
|
use App\Model\StopGroup;
|
||||||
use App\Modifier\IdFilter;
|
use App\Model\TrackStop;
|
||||||
use App\Modifier\FieldFilter;
|
use App\Modifier\FieldFilter;
|
||||||
use App\Modifier\IncludeDestinations;
|
use App\Modifier\IdFilter;
|
||||||
use App\Modifier\RelatedFilter;
|
use App\Modifier\RelatedFilter;
|
||||||
|
use App\Modifier\With;
|
||||||
use App\Provider\StopRepository;
|
use App\Provider\StopRepository;
|
||||||
use App\Provider\TrackRepository;
|
use App\Provider\TrackRepository;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||||
@ -95,7 +95,7 @@ class StopsController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function one(Request $request, StopRepository $stops, $id)
|
public function one(Request $request, StopRepository $stops, $id)
|
||||||
{
|
{
|
||||||
return $this->json($stops->first(new IdFilter($id), new IncludeDestinations()));
|
return $this->json($stops->first(new IdFilter($id), new With("destinations")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +137,7 @@ class StopsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->query->has('include-destinations')) {
|
if ($request->query->has('include-destinations')) {
|
||||||
yield new IncludeDestinations();
|
yield new With("destinations");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,11 @@
|
|||||||
namespace App\Exception;
|
namespace App\Exception;
|
||||||
|
|
||||||
use App\Modifier\Modifier;
|
use App\Modifier\Modifier;
|
||||||
use App\Provider\Repository;
|
|
||||||
|
|
||||||
class UnsupportedModifierException extends \LogicException
|
class UnsupportedModifierException extends \LogicException
|
||||||
{
|
{
|
||||||
public static function createFromModifier(Modifier $modifier, Repository $repository)
|
public static function createFromModifier(Modifier $modifier)
|
||||||
{
|
{
|
||||||
return new static(sprintf("Modifier %s is not supported by %s.", get_class($modifier), get_class($repository)));
|
return new static(sprintf("Modifier %s is not supported.", get_class($modifier)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ use App\Model\Stop;
|
|||||||
use App\Service\Converter;
|
use App\Service\Converter;
|
||||||
use App\Service\IdUtils;
|
use App\Service\IdUtils;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Tightenco\Collect\Support\Collection;
|
|
||||||
use Kadet\Functional as f;
|
use Kadet\Functional as f;
|
||||||
use Kadet\Functional\Transforms as t;
|
use Kadet\Functional\Transforms as t;
|
||||||
|
use Tightenco\Collect\Support\Collection;
|
||||||
|
|
||||||
class IncludeDestinationsDatabaseHandler implements PostProcessingHandler
|
class WithDestinationsDatabaseHandler implements PostProcessingHandler
|
||||||
{
|
{
|
||||||
private $em;
|
private $em;
|
||||||
private $converter;
|
private $converter;
|
@ -1,7 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Modifier;
|
|
||||||
|
|
||||||
class IncludeDestinations implements Modifier
|
|
||||||
{
|
|
||||||
}
|
|
18
src/Modifier/With.php
Normal file
18
src/Modifier/With.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Modifier;
|
||||||
|
|
||||||
|
class With implements Modifier
|
||||||
|
{
|
||||||
|
private $relationship;
|
||||||
|
|
||||||
|
public function __construct(string $relationship)
|
||||||
|
{
|
||||||
|
$this->relationship = $relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelationship(): string
|
||||||
|
{
|
||||||
|
return $this->relationship;
|
||||||
|
}
|
||||||
|
}
|
@ -5,28 +5,26 @@ namespace App\Provider\Database;
|
|||||||
use App\Entity\ProviderEntity;
|
use App\Entity\ProviderEntity;
|
||||||
use App\Event\HandleDatabaseModifierEvent;
|
use App\Event\HandleDatabaseModifierEvent;
|
||||||
use App\Event\PostProcessEvent;
|
use App\Event\PostProcessEvent;
|
||||||
use App\Exception\UnsupportedModifierException;
|
use App\Handler\Database\FieldFilterDatabaseHandler;
|
||||||
use App\Handler\Database\IdFilterDatabaseHandler;
|
use App\Handler\Database\IdFilterDatabaseHandler;
|
||||||
use App\Handler\Database\LimitDatabaseHandler;
|
use App\Handler\Database\LimitDatabaseHandler;
|
||||||
use App\Handler\Database\FieldFilterDatabaseHandler;
|
|
||||||
use App\Handler\Database\RelatedFilterDatabaseGenericHandler;
|
use App\Handler\Database\RelatedFilterDatabaseGenericHandler;
|
||||||
use App\Handler\ModifierHandler;
|
use App\Handler\ModifierHandler;
|
||||||
use App\Handler\PostProcessingHandler;
|
use App\Handler\PostProcessingHandler;
|
||||||
use App\Model\Referable;
|
use App\Model\Referable;
|
||||||
|
use App\Modifier\FieldFilter;
|
||||||
use App\Modifier\IdFilter;
|
use App\Modifier\IdFilter;
|
||||||
use App\Modifier\Limit;
|
use App\Modifier\Limit;
|
||||||
use App\Modifier\Modifier;
|
use App\Modifier\Modifier;
|
||||||
use App\Modifier\FieldFilter;
|
|
||||||
use App\Modifier\RelatedFilter;
|
use App\Modifier\RelatedFilter;
|
||||||
use App\Provider\Repository;
|
use App\Provider\Repository;
|
||||||
use App\Service\Converter;
|
use App\Service\Converter;
|
||||||
|
use App\Service\HandlerProvider;
|
||||||
use App\Service\IdUtils;
|
use App\Service\IdUtils;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Psr\Container\ContainerInterface;
|
|
||||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
|
||||||
|
|
||||||
abstract class DatabaseRepository implements ServiceSubscriberInterface, Repository
|
abstract class DatabaseRepository implements Repository
|
||||||
{
|
{
|
||||||
const DEFAULT_LIMIT = 100;
|
const DEFAULT_LIMIT = 100;
|
||||||
|
|
||||||
@ -42,7 +40,7 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit
|
|||||||
/** @var Converter */
|
/** @var Converter */
|
||||||
protected $converter;
|
protected $converter;
|
||||||
|
|
||||||
/** @var ContainerInterface */
|
/** @var HandlerProvider */
|
||||||
protected $handlers;
|
protected $handlers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,12 +52,19 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit
|
|||||||
EntityManagerInterface $em,
|
EntityManagerInterface $em,
|
||||||
IdUtils $id,
|
IdUtils $id,
|
||||||
Converter $converter,
|
Converter $converter,
|
||||||
ContainerInterface $handlers
|
HandlerProvider $handlers
|
||||||
) {
|
) {
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
$this->converter = $converter;
|
$this->converter = $converter;
|
||||||
$this->handlers = $handlers;
|
$this->handlers = $handlers;
|
||||||
|
|
||||||
|
$this->handlers->loadConfiguration(array_merge([
|
||||||
|
IdFilter::class => IdFilterDatabaseHandler::class,
|
||||||
|
Limit::class => LimitDatabaseHandler::class,
|
||||||
|
FieldFilter::class => FieldFilterDatabaseHandler::class,
|
||||||
|
RelatedFilter::class => RelatedFilterDatabaseGenericHandler::class,
|
||||||
|
], static::getHandlers()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return static */
|
/** @return static */
|
||||||
@ -88,7 +93,7 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit
|
|||||||
$reducers = [];
|
$reducers = [];
|
||||||
|
|
||||||
foreach ($modifiers as $modifier) {
|
foreach ($modifiers as $modifier) {
|
||||||
$handler = $this->getHandler($modifier);
|
$handler = $this->handlers->get($modifier);
|
||||||
|
|
||||||
if ($handler instanceof ModifierHandler) {
|
if ($handler instanceof ModifierHandler) {
|
||||||
$event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([
|
$event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([
|
||||||
@ -120,10 +125,11 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit
|
|||||||
$builder->setMaxResults(self::DEFAULT_LIMIT);
|
$builder->setMaxResults(self::DEFAULT_LIMIT);
|
||||||
|
|
||||||
$reducers = $this->processQueryBuilder($builder, $modifiers, $meta);
|
$reducers = $this->processQueryBuilder($builder, $modifiers, $meta);
|
||||||
|
$result = collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert']));
|
||||||
|
|
||||||
return $reducers->reduce(function ($result, $reducer) {
|
return $reducers->reduce(function ($result, $reducer) {
|
||||||
return $reducer($result);
|
return $reducer($result);
|
||||||
}, collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert'])));
|
}, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function first(Modifier ...$modifiers)
|
public function first(Modifier ...$modifiers)
|
||||||
@ -131,17 +137,6 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit
|
|||||||
return $this->all(Limit::count(1), ...$modifiers)->first();
|
return $this->all(Limit::count(1), ...$modifiers)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getHandler(Modifier $modifier)
|
|
||||||
{
|
|
||||||
$class = get_class($modifier);
|
|
||||||
|
|
||||||
if (!$this->handlers->has($class)) {
|
|
||||||
throw UnsupportedModifierException::createFromModifier($modifier, $this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->handlers->get($class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns array describing handlers for each modifier type. Syntax is as follows:
|
* Returns array describing handlers for each modifier type. Syntax is as follows:
|
||||||
* [ IdFilter::class => IdFilterDatabaseHandler::class ]
|
* [ IdFilter::class => IdFilterDatabaseHandler::class ]
|
||||||
@ -154,17 +149,4 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit
|
|||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public static function getSubscribedServices()
|
|
||||||
{
|
|
||||||
return array_merge([
|
|
||||||
IdFilter::class => IdFilterDatabaseHandler::class,
|
|
||||||
Limit::class => LimitDatabaseHandler::class,
|
|
||||||
FieldFilter::class => FieldFilterDatabaseHandler::class,
|
|
||||||
RelatedFilter::class => RelatedFilterDatabaseGenericHandler::class,
|
|
||||||
], static::getHandlers());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
namespace App\Provider\Database;
|
namespace App\Provider\Database;
|
||||||
|
|
||||||
use App\Entity\StopEntity;
|
use App\Entity\StopEntity;
|
||||||
use App\Handler\Database\IncludeDestinationsDatabaseHandler;
|
use App\Handler\Database\WithDestinationsDatabaseHandler;
|
||||||
use App\Model\Stop;
|
use App\Model\Stop;
|
||||||
use App\Modifier\Modifier;
|
use App\Modifier\Modifier;
|
||||||
use App\Modifier\IncludeDestinations;
|
use App\Modifier\With;
|
||||||
use App\Provider\StopRepository;
|
use App\Provider\StopRepository;
|
||||||
use Tightenco\Collect\Support\Collection;
|
use Tightenco\Collect\Support\Collection;
|
||||||
|
|
||||||
@ -30,7 +30,11 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository
|
|||||||
protected static function getHandlers()
|
protected static function getHandlers()
|
||||||
{
|
{
|
||||||
return array_merge(parent::getHandlers(), [
|
return array_merge(parent::getHandlers(), [
|
||||||
IncludeDestinations::class => IncludeDestinationsDatabaseHandler::class,
|
With::class => function (With $modifier) {
|
||||||
|
return $modifier->getRelationship() === 'destinations'
|
||||||
|
? WithDestinationsDatabaseHandler::class
|
||||||
|
: GenericWithHandler::class;
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
src/Service/HandlerProvider.php
Normal file
44
src/Service/HandlerProvider.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Exception\UnsupportedModifierException;
|
||||||
|
use App\Modifier\Modifier;
|
||||||
|
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||||
|
|
||||||
|
class HandlerProvider
|
||||||
|
{
|
||||||
|
private $configuration = [];
|
||||||
|
private $handlerLocator;
|
||||||
|
|
||||||
|
public function __construct(ServiceLocator $handlerLocator)
|
||||||
|
{
|
||||||
|
$this->handlerLocator = $handlerLocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadConfiguration(array $providers)
|
||||||
|
{
|
||||||
|
$this->configuration = $providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(Modifier $modifier)
|
||||||
|
{
|
||||||
|
$class = get_class($modifier);
|
||||||
|
|
||||||
|
if (!array_key_exists($class, $this->configuration)) {
|
||||||
|
throw UnsupportedModifierException::createFromModifier($modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
$handler = $this->configuration[$class];
|
||||||
|
|
||||||
|
if (is_callable($handler)) {
|
||||||
|
$handler = $handler($modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($handler)) {
|
||||||
|
return $this->handlerLocator->get($handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $handler;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user