From 7ffd3c02cd7ebbe0f74dbee55f42d5fc7fb66832 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sat, 14 Mar 2020 17:19:43 +0100 Subject: [PATCH] Extract HandlerProvider to own class --- config/services.yaml | 10 +++- src/Controller/Api/v1/StopsController.php | 10 ++-- .../UnsupportedModifierException.php | 5 +- ...hp => WithDestinationsDatabaseHandler.php} | 4 +- src/Modifier/IncludeDestinations.php | 7 --- src/Modifier/With.php | 18 +++++++ src/Provider/Database/DatabaseRepository.php | 50 ++++++------------- .../Database/GenericStopRepository.php | 10 ++-- src/Service/HandlerProvider.php | 44 ++++++++++++++++ 9 files changed, 103 insertions(+), 55 deletions(-) rename src/Handler/Database/{IncludeDestinationsDatabaseHandler.php => WithDestinationsDatabaseHandler.php} (97%) delete mode 100644 src/Modifier/IncludeDestinations.php create mode 100644 src/Modifier/With.php create mode 100644 src/Service/HandlerProvider.php diff --git a/config/services.yaml b/config/services.yaml index 4337891..9fe3e71 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -23,7 +23,7 @@ services: # this creates a service per class whose id is the fully-qualified class name App\: 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 # as action arguments even if you don't extend any base controller class @@ -35,6 +35,10 @@ services: resource: '../src/Provider' public: true + App\Handler\: + resource: '../src/Handler' + tags: [ app.handler ] + # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones @@ -90,3 +94,7 @@ services: # other servces App\Service\ProviderResolver: arguments: [!tagged app.provider, '%kernel.debug%'] + + App\Service\HandlerProvider: + arguments: [!tagged_locator app.handler] + shared: false diff --git a/src/Controller/Api/v1/StopsController.php b/src/Controller/Api/v1/StopsController.php index dc6ac45..2b83043 100644 --- a/src/Controller/Api/v1/StopsController.php +++ b/src/Controller/Api/v1/StopsController.php @@ -4,12 +4,12 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Stop; -use App\Model\TrackStop; use App\Model\StopGroup; -use App\Modifier\IdFilter; +use App\Model\TrackStop; use App\Modifier\FieldFilter; -use App\Modifier\IncludeDestinations; +use App\Modifier\IdFilter; use App\Modifier\RelatedFilter; +use App\Modifier\With; use App\Provider\StopRepository; use App\Provider\TrackRepository; use Nelmio\ApiDocBundle\Annotation\Model; @@ -95,7 +95,7 @@ class StopsController extends Controller */ 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')) { - yield new IncludeDestinations(); + yield new With("destinations"); } } } diff --git a/src/Exception/UnsupportedModifierException.php b/src/Exception/UnsupportedModifierException.php index f1e7145..1a03b80 100644 --- a/src/Exception/UnsupportedModifierException.php +++ b/src/Exception/UnsupportedModifierException.php @@ -3,12 +3,11 @@ namespace App\Exception; use App\Modifier\Modifier; -use App\Provider\Repository; 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))); } } diff --git a/src/Handler/Database/IncludeDestinationsDatabaseHandler.php b/src/Handler/Database/WithDestinationsDatabaseHandler.php similarity index 97% rename from src/Handler/Database/IncludeDestinationsDatabaseHandler.php rename to src/Handler/Database/WithDestinationsDatabaseHandler.php index b58287f..f3f7879 100644 --- a/src/Handler/Database/IncludeDestinationsDatabaseHandler.php +++ b/src/Handler/Database/WithDestinationsDatabaseHandler.php @@ -10,11 +10,11 @@ use App\Model\Stop; use App\Service\Converter; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; -use Tightenco\Collect\Support\Collection; use Kadet\Functional as f; use Kadet\Functional\Transforms as t; +use Tightenco\Collect\Support\Collection; -class IncludeDestinationsDatabaseHandler implements PostProcessingHandler +class WithDestinationsDatabaseHandler implements PostProcessingHandler { private $em; private $converter; diff --git a/src/Modifier/IncludeDestinations.php b/src/Modifier/IncludeDestinations.php deleted file mode 100644 index 01d74b2..0000000 --- a/src/Modifier/IncludeDestinations.php +++ /dev/null @@ -1,7 +0,0 @@ -relationship = $relationship; + } + + public function getRelationship(): string + { + return $this->relationship; + } +} diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index 8156253..e4021ec 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -5,28 +5,26 @@ namespace App\Provider\Database; use App\Entity\ProviderEntity; use App\Event\HandleDatabaseModifierEvent; use App\Event\PostProcessEvent; -use App\Exception\UnsupportedModifierException; +use App\Handler\Database\FieldFilterDatabaseHandler; use App\Handler\Database\IdFilterDatabaseHandler; use App\Handler\Database\LimitDatabaseHandler; -use App\Handler\Database\FieldFilterDatabaseHandler; use App\Handler\Database\RelatedFilterDatabaseGenericHandler; use App\Handler\ModifierHandler; use App\Handler\PostProcessingHandler; use App\Model\Referable; +use App\Modifier\FieldFilter; use App\Modifier\IdFilter; use App\Modifier\Limit; use App\Modifier\Modifier; -use App\Modifier\FieldFilter; use App\Modifier\RelatedFilter; use App\Provider\Repository; use App\Service\Converter; +use App\Service\HandlerProvider; use App\Service\IdUtils; use Doctrine\ORM\EntityManagerInterface; 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; @@ -42,7 +40,7 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit /** @var Converter */ protected $converter; - /** @var ContainerInterface */ + /** @var HandlerProvider */ protected $handlers; /** @@ -54,12 +52,19 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit EntityManagerInterface $em, IdUtils $id, Converter $converter, - ContainerInterface $handlers + HandlerProvider $handlers ) { $this->em = $em; $this->id = $id; $this->converter = $converter; $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 */ @@ -88,7 +93,7 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit $reducers = []; foreach ($modifiers as $modifier) { - $handler = $this->getHandler($modifier); + $handler = $this->handlers->get($modifier); if ($handler instanceof ModifierHandler) { $event = new HandleDatabaseModifierEvent($modifier, $this, $builder, array_merge([ @@ -120,10 +125,11 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit $builder->setMaxResults(self::DEFAULT_LIMIT); $reducers = $this->processQueryBuilder($builder, $modifiers, $meta); + $result = collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert'])); return $reducers->reduce(function ($result, $reducer) { return $reducer($result); - }, collect($builder->getQuery()->execute())->map(\Closure::fromCallable([$this, 'convert']))); + }, $result); } public function first(Modifier ...$modifiers) @@ -131,17 +137,6 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit 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: * [ IdFilter::class => IdFilterDatabaseHandler::class ] @@ -154,17 +149,4 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit { 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()); - } } diff --git a/src/Provider/Database/GenericStopRepository.php b/src/Provider/Database/GenericStopRepository.php index 62a7a90..82e41e6 100644 --- a/src/Provider/Database/GenericStopRepository.php +++ b/src/Provider/Database/GenericStopRepository.php @@ -3,10 +3,10 @@ namespace App\Provider\Database; use App\Entity\StopEntity; -use App\Handler\Database\IncludeDestinationsDatabaseHandler; +use App\Handler\Database\WithDestinationsDatabaseHandler; use App\Model\Stop; use App\Modifier\Modifier; -use App\Modifier\IncludeDestinations; +use App\Modifier\With; use App\Provider\StopRepository; use Tightenco\Collect\Support\Collection; @@ -30,7 +30,11 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository protected static function getHandlers() { return array_merge(parent::getHandlers(), [ - IncludeDestinations::class => IncludeDestinationsDatabaseHandler::class, + With::class => function (With $modifier) { + return $modifier->getRelationship() === 'destinations' + ? WithDestinationsDatabaseHandler::class + : GenericWithHandler::class; + }, ]); } } diff --git a/src/Service/HandlerProvider.php b/src/Service/HandlerProvider.php new file mode 100644 index 0000000..59d5edb --- /dev/null +++ b/src/Service/HandlerProvider.php @@ -0,0 +1,44 @@ +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; + } +}