#35 - Add paginator to properly handle limits

This commit is contained in:
Kacper Donat 2020-03-16 20:32:15 +01:00
parent db30d69cdb
commit 720327424a
8 changed files with 49 additions and 19 deletions

View File

@ -5,6 +5,7 @@ namespace App\Controller\Api\v1;
use App\Controller\Controller; use App\Controller\Controller;
use App\Model\Trip; use App\Model\Trip;
use App\Modifier\IdFilter; use App\Modifier\IdFilter;
use App\Modifier\With;
use App\Provider\TripRepository; use App\Provider\TripRepository;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
@ -19,7 +20,7 @@ class TripController extends Controller
*/ */
public function one($id, TripRepository $repository) public function one($id, TripRepository $repository)
{ {
$trip = $repository->all(new IdFilter($id)); $trip = $repository->first(new IdFilter($id), new With('schedule'));
return $this->json($trip, Response::HTTP_OK, [], $this->serializerContextFactory->create(Trip::class)); return $this->json($trip, Response::HTTP_OK, [], $this->serializerContextFactory->create(Trip::class));
} }

View File

@ -8,6 +8,7 @@ use App\Handler\ModifierHandler;
use App\Model\ScheduledStop; use App\Model\ScheduledStop;
use App\Model\Track; use App\Model\Track;
use App\Model\TrackStop; use App\Model\TrackStop;
use App\Model\Trip;
use App\Modifier\RelatedFilter; use App\Modifier\RelatedFilter;
use App\Service\EntityReferenceFactory; use App\Service\EntityReferenceFactory;
use App\Service\IdUtils; use App\Service\IdUtils;
@ -21,6 +22,9 @@ class GenericWithDatabaseHandler implements ModifierHandler
'line' => 'line', 'line' => 'line',
'stops' => 'stopsInTrack', 'stops' => 'stopsInTrack',
], ],
Trip::class => [
'schedule' => 'stops.stop',
],
TrackStop::class => [ TrackStop::class => [
'track' => 'track', 'track' => 'track',
], ],

View File

@ -25,6 +25,7 @@ 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 Doctrine\ORM\Tools\Pagination\Paginator;
abstract class DatabaseRepository implements Repository abstract class DatabaseRepository implements Repository
{ {
@ -128,7 +129,10 @@ abstract class DatabaseRepository implements Repository
$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'])); $query = $builder->getQuery();
$paginator = new Paginator($query);
$result = collect($paginator)->map(\Closure::fromCallable([$this, 'convert']));
return $reducers->reduce(function ($result, $reducer) { return $reducers->reduce(function ($result, $reducer) {
return $reducer($result); return $reducer($result);

View File

@ -15,9 +15,7 @@ class GenericTripRepository extends DatabaseRepository implements TripRepository
$builder = $this->em $builder = $this->em
->createQueryBuilder() ->createQueryBuilder()
->from(TripEntity::class, 'trip') ->from(TripEntity::class, 'trip')
->join('trip.stops', 'ts') ->select('trip');
->join('ts.stop', 's')
->select('t', 'ts');
return $this->allFromQueryBuilder($builder, $modifiers, [ return $this->allFromQueryBuilder($builder, $modifiers, [
'alias' => 'trip', 'alias' => 'trip',

View File

@ -174,7 +174,7 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
} }
return setup(clone $real, function (Departure $departure) use ($scheduled, $real) { return setup(clone $real, function (Departure $departure) use ($scheduled, $real) {
$departure->setDisplay($real->getDisplay()); $departure->setDisplay($this->extractDisplayFromScheduledStop($scheduled));
$departure->setTrack($scheduled->getTrack()); $departure->setTrack($scheduled->getTrack());
$departure->setTrip($scheduled->getTrip()); $departure->setTrip($scheduled->getTrip());
}); });
@ -183,7 +183,7 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
private function convertScheduledStopToDeparture(ScheduledStop $stop): Departure private function convertScheduledStopToDeparture(ScheduledStop $stop): Departure
{ {
return setup(new Departure(), function (Departure $converted) use ($stop) { return setup(new Departure(), function (Departure $converted) use ($stop) {
$converted->setDisplay($stop->getTrack()->getDestination()->getName()); $converted->setDisplay($this->extractDisplayFromScheduledStop($stop));
$converted->setLine($stop->getTrack()->getLine()); $converted->setLine($stop->getTrack()->getLine());
$converted->setTrack($stop->getTrack()); $converted->setTrack($stop->getTrack());
$converted->setTrip($stop->getTrip()); $converted->setTrip($stop->getTrip());
@ -192,6 +192,11 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
}); });
} }
private function extractDisplayFromScheduledStop(ScheduledStop $stop)
{
return $stop->getTrack()->getDestination()->getName();
}
private function extractModifiers(iterable $modifiers) private function extractModifiers(iterable $modifiers)
{ {
$result = []; $result = [];

View File

@ -2,10 +2,7 @@
namespace App\Service; namespace App\Service;
use Hoa\Iterator\Recursive\Recursive; use Tightenco\Collect\Support\Collection;
use Symfony\Component\DependencyInjection\ServiceLocator;
use function Kadet\Functional\Predicates\equals;
use function Kadet\Functional\Predicates\method;
class AggregateConverter implements Converter class AggregateConverter implements Converter
{ {
@ -40,4 +37,9 @@ class AggregateConverter implements Converter
return $converter->supports($entity); return $converter->supports($entity);
}); });
} }
public function getConverters(): Collection
{
return clone $this->converters;
}
} }

View File

@ -0,0 +1,8 @@
<?php
namespace App\Service;
interface CacheableConverter extends Converter
{
public function flushCache();
}

View File

@ -11,17 +11,19 @@ use Kadet\Functional as f;
use Kadet\Functional\Transforms as t; use Kadet\Functional\Transforms as t;
use const Kadet\Functional\_; use const Kadet\Functional\_;
final class EntityConverter implements Converter, RecursiveConverter final class EntityConverter implements Converter, RecursiveConverter, CacheableConverter
{ {
use RecursiveConverterTrait; use RecursiveConverterTrait;
private $id; private $id;
private $reference; private $reference;
private $cache;
public function __construct(IdUtils $id, ReferenceFactory $reference) public function __construct(IdUtils $id, ReferenceFactory $reference)
{ {
$this->id = $id; $this->id = $id;
$this->reference = $reference; $this->reference = $reference;
$this->cache = [];
} }
/** /**
@ -30,10 +32,10 @@ final class EntityConverter implements Converter, RecursiveConverter
* *
* @return Line|Track|Stop|Operator|Trip|ScheduledStop * @return Line|Track|Stop|Operator|Trip|ScheduledStop
*/ */
public function convert($entity, array $cache = []) public function convert($entity)
{ {
if (array_key_exists($key = get_class($entity) . ':' . $this->getId($entity), $cache)) { if (array_key_exists($key = get_class($entity) . ':' . $this->getId($entity), $this->cache)) {
return $cache[$key]; return $this->cache[$key];
} }
if ($entity instanceof Proxy && !$entity->__isInitialized()) { if ($entity instanceof Proxy && !$entity->__isInitialized()) {
@ -41,10 +43,11 @@ final class EntityConverter implements Converter, RecursiveConverter
} }
$result = $this->create($entity); $result = $this->create($entity);
$cache = $cache + [$key => $result]; $this->cache[$key] = $result;
$convert = function ($entity) use ($cache) {
$convert = function ($entity) {
return $this->supports($entity) return $this->supports($entity)
? $this->convert($entity, $cache) ? $this->convert($entity)
: $this->parent->convert($entity); : $this->parent->convert($entity);
}; };
@ -173,4 +176,9 @@ final class EntityConverter implements Converter, RecursiveConverter
{ {
return $entity instanceof Entity; return $entity instanceof Entity;
} }
public function flushCache()
{
$this->cache = [];
}
} }