Add stop filter for tracks

This commit is contained in:
Kacper Donat 2020-02-18 22:45:16 +01:00
parent a3de2b244f
commit 9f3f6bf22b
5 changed files with 137 additions and 72 deletions

View File

@ -1,6 +1,5 @@
<?php <?php
namespace App\Controller\Api\v1; namespace App\Controller\Api\v1;
use App\Controller\Controller; use App\Controller\Controller;
@ -42,7 +41,8 @@ class StopsController extends Controller
* name="id", * name="id",
* in="query", * in="query",
* type="array", * type="array",
* description="Stop identificators to retrieve at once. Can be used to bulk load data. If not specified will return all data.", * description="Stop identificators to retrieve at once. Can be used to bulk load data. If not specified will
* return all data.",
* @SWG\Items(type="string") * @SWG\Items(type="string")
* ) * )
* *
@ -136,27 +136,18 @@ class StopsController extends Controller
})->values(); })->values();
} }
/** private function getModifiersFromRequest(Request $request)
* @param Request $request
*
* @return array
*/
private function getModifiersFromRequest(Request $request): array
{ {
$modifiers = [];
if ($request->query->has('name')) { if ($request->query->has('name')) {
$modifiers[] = FieldFilter::contains('name', $request->query->get('name')); yield FieldFilter::contains('name', $request->query->get('name'));
} }
if ($request->query->has('id')) { if ($request->query->has('id')) {
$modifiers[] = new IdFilter($request->query->get('id')); yield new IdFilter($request->query->get('id'));
} }
if ($request->query->has('include-destinations')) { if ($request->query->has('include-destinations')) {
$modifiers[] = new IncludeDestinations(); yield new IncludeDestinations();
} }
return $modifiers;
} }
} }

View File

@ -9,6 +9,7 @@ use App\Model\Track;
use App\Modifier\IdFilter; use App\Modifier\IdFilter;
use App\Modifier\RelatedFilter; use App\Modifier\RelatedFilter;
use App\Provider\TrackRepository; use App\Provider\TrackRepository;
use App\Service\IterableUtils;
use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Annotation\Model;
use Swagger\Annotations as SWG; use Swagger\Annotations as SWG;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -31,43 +32,31 @@ class TracksController extends Controller
*/ */
public function index(Request $request, TrackRepository $repository) public function index(Request $request, TrackRepository $repository)
{ {
switch (true) { $modifiers = $this->getModifiersFromRequest($request);
case $request->query->has('stop'):
return $this->byStop($request, $repository); return $this->json($repository->all(...$modifiers));
case $request->query->has('line'): }
return $this->byLine($request, $repository);
case $request->query->has('id'): private function getModifiersFromRequest(Request $request)
return $this->byId($request, $repository); {
default: if ($request->query->has('stop')) {
throw new BadRequestHttpException( $stop = $request->query->get('stop');
sprintf( $stop = Stop::reference($stop);
'At least one parameter of %s must be set.',
implode(', ', ['stop', 'line', 'id']) yield new RelatedFilter($stop);
) }
);
if ($request->query->has('line')) {
$line = $request->query->get('line');
$line = Line::reference($line);
yield new RelatedFilter($line);
}
if ($request->query->has('id')) {
$id = encapsulate($request->query->get('id'));
yield new IdFilter($id);
} }
} }
private function byId(Request $request, TrackRepository $repository)
{
$id = encapsulate($request->query->get('id'));
return $this->json($repository->all(new IdFilter($id)));
}
private function byStop(Request $request, TrackRepository $repository)
{
$stop = $request->query->get('stop');
$stop = array_map([Stop::class, 'reference'], encapsulate($stop));
return $this->json($repository->getByStop($stop));
}
private function byLine(Request $request, TrackRepository $repository)
{
$line = $request->query->get('line');
$line = Line::reference($line);
return $this->json($repository->all(new RelatedFilter($line)));
}
} }

View File

@ -2,16 +2,15 @@
namespace App\Handler\Database; namespace App\Handler\Database;
use App\Entity\LineEntity;
use App\Entity\ProviderEntity;
use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleDatabaseModifierEvent;
use App\Event\HandleModifierEvent; use App\Event\HandleModifierEvent;
use App\Handler\ModifierHandler; use App\Handler\ModifierHandler;
use App\Model\Line; use App\Model\Line;
use App\Model\Referable; use App\Model\Stop;
use App\Model\Track; use App\Model\Track;
use App\Modifier\RelatedFilter; use App\Modifier\RelatedFilter;
use App\Service\IdUtils; use App\Service\IdUtils;
use App\Service\ReferenceFactory;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface;
@ -21,22 +20,25 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
protected $mapping = [ protected $mapping = [
Track::class => [ Track::class => [
Line::class => 'line', Line::class => 'line',
Stop::class => TrackByStopDatabaseHandler::class,
], ],
]; ];
protected $references = [
Line::class => LineEntity::class,
];
private $em; private $em;
private $inner; private $inner;
private $id; private $id;
private $references;
public function __construct(ContainerInterface $inner, EntityManagerInterface $em, IdUtils $idUtils) public function __construct(
{ ContainerInterface $inner,
EntityManagerInterface $em,
IdUtils $idUtils,
ReferenceFactory $references
) {
$this->inner = $inner; $this->inner = $inner;
$this->em = $em; $this->em = $em;
$this->id = $idUtils; $this->id = $idUtils;
$this->references = $references;
} }
public function process(HandleModifierEvent $event) public function process(HandleModifierEvent $event)
@ -65,8 +67,15 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
$relationship = $this->mapping[$type][$modifier->getRelationship()]; $relationship = $this->mapping[$type][$modifier->getRelationship()];
if ($this->inner->has($relationship)) {
/** @var ModifierHandler $inner */
$inner = $this->inner->get($relationship);
$inner->process($event);
return;
}
$parameter = sprintf(":%s_%s", $alias, $relationship); $parameter = sprintf(":%s_%s", $alias, $relationship);
$reference = $this->getEntityReference($modifier->getRelated(), $event->getMeta()['provider']); $reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']);
$builder $builder
->join(sprintf('%s.%s', $alias, $relationship), $relationship) ->join(sprintf('%s.%s', $alias, $relationship), $relationship)
@ -75,22 +84,13 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
; ;
} }
// todo: extract that to separate service
private function getEntityReference(Referable $object, ProviderEntity $provider)
{
return $this->em->getReference(
$this->references[get_class($object)],
$this->id->generate($provider, $object->getId())
);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function getSubscribedServices() public static function getSubscribedServices()
{ {
return [ return [
TrackRelatedFilterDatabaseHandler::class, TrackByStopDatabaseHandler::class,
]; ];
} }
} }

View File

@ -0,0 +1,43 @@
<?php
namespace App\Handler\Database;
use App\Entity\StopInTrack;
use App\Event\HandleDatabaseModifierEvent;
use App\Event\HandleModifierEvent;
use App\Handler\ModifierHandler;
use App\Modifier\RelatedFilter;
use App\Service\ReferenceFactory;
class TrackByStopDatabaseHandler implements ModifierHandler
{
private $references;
public function __construct(ReferenceFactory $references)
{
$this->references = $references;
}
public function process(HandleModifierEvent $event)
{
if (!$event instanceof HandleDatabaseModifierEvent) {
return;
}
/** @var RelatedFilter $modifier */
$modifier = $event->getModifier();
$builder = $event->getBuilder();
$alias = $event->getMeta()['alias'];
$relationship = 'stopsInTrack';
$parameter = sprintf(":%s_%s", $alias, $relationship);
$reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']);
$builder
->join(sprintf("%s.%s", $alias, $relationship), 'stop_in_track')
->andWhere(sprintf("stop_in_track.stop = %s", $parameter))
->setParameter($parameter, $reference)
;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Service;
use App\Entity\LineEntity;
use App\Entity\ProviderEntity;
use App\Entity\StopEntity;
use App\Model\Line;
use App\Model\Referable;
use App\Model\Stop;
use Doctrine\ORM\EntityManagerInterface;
final class ReferenceFactory
{
protected $mapping = [
Line::class => LineEntity::class,
Stop::class => StopEntity::class,
];
private $em;
private $id;
public function __construct(EntityManagerInterface $em, IdUtils $id)
{
$this->em = $em;
$this->id = $id;
}
public function create(Referable $object, ProviderEntity $provider)
{
$class = get_class($object);
if (!array_key_exists($class, $this->mapping)) {
throw new \InvalidArgumentException(sprintf("Cannot make entity reference of %s.", $class));
}
return $this->em->getReference(
$this->mapping[$class],
$this->id->generate($provider, $object->getId())
);
}
}