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
namespace App\Controller\Api\v1;
use App\Controller\Controller;
@ -42,7 +41,8 @@ class StopsController extends Controller
* name="id",
* in="query",
* 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")
* )
*
@ -136,27 +136,18 @@ class StopsController extends Controller
})->values();
}
/**
* @param Request $request
*
* @return array
*/
private function getModifiersFromRequest(Request $request): array
private function getModifiersFromRequest(Request $request)
{
$modifiers = [];
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')) {
$modifiers[] = new IdFilter($request->query->get('id'));
yield new IdFilter($request->query->get('id'));
}
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\RelatedFilter;
use App\Provider\TrackRepository;
use App\Service\IterableUtils;
use Nelmio\ApiDocBundle\Annotation\Model;
use Swagger\Annotations as SWG;
use Symfony\Component\HttpFoundation\Request;
@ -31,43 +32,31 @@ class TracksController extends Controller
*/
public function index(Request $request, TrackRepository $repository)
{
switch (true) {
case $request->query->has('stop'):
return $this->byStop($request, $repository);
case $request->query->has('line'):
return $this->byLine($request, $repository);
case $request->query->has('id'):
return $this->byId($request, $repository);
default:
throw new BadRequestHttpException(
sprintf(
'At least one parameter of %s must be set.',
implode(', ', ['stop', 'line', 'id'])
)
);
$modifiers = $this->getModifiersFromRequest($request);
return $this->json($repository->all(...$modifiers));
}
private function getModifiersFromRequest(Request $request)
{
if ($request->query->has('stop')) {
$stop = $request->query->get('stop');
$stop = Stop::reference($stop);
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;
use App\Entity\LineEntity;
use App\Entity\ProviderEntity;
use App\Event\HandleDatabaseModifierEvent;
use App\Event\HandleModifierEvent;
use App\Handler\ModifierHandler;
use App\Model\Line;
use App\Model\Referable;
use App\Model\Stop;
use App\Model\Track;
use App\Modifier\RelatedFilter;
use App\Service\IdUtils;
use App\Service\ReferenceFactory;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
@ -21,22 +20,25 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
protected $mapping = [
Track::class => [
Line::class => 'line',
Stop::class => TrackByStopDatabaseHandler::class,
],
];
protected $references = [
Line::class => LineEntity::class,
];
private $em;
private $inner;
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->em = $em;
$this->id = $idUtils;
$this->references = $references;
}
public function process(HandleModifierEvent $event)
@ -65,8 +67,15 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
$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);
$reference = $this->getEntityReference($modifier->getRelated(), $event->getMeta()['provider']);
$reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']);
$builder
->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
*/
public static function getSubscribedServices()
{
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())
);
}
}