From db30d69cdb636f8a0eb4a0e77d0d6c2ebff7fe92 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 15 Mar 2020 22:35:12 +0100 Subject: [PATCH] #35 - Add Limit support for departure repository --- .../Api/v1/DeparturesController.php | 22 +++++--- .../RelatedFilterDatabaseGenericHandler.php | 2 +- src/Provider/DepartureRepository.php | 5 +- .../Dummy/DummyDepartureRepository.php | 27 +++++----- .../ZtmGdanskDepartureRepository.php | 51 ++++++++++++++++--- src/Service/ModifierUtils.php | 29 +++++++++++ 6 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 src/Service/ModifierUtils.php diff --git a/src/Controller/Api/v1/DeparturesController.php b/src/Controller/Api/v1/DeparturesController.php index da07d63..afa0798 100644 --- a/src/Controller/Api/v1/DeparturesController.php +++ b/src/Controller/Api/v1/DeparturesController.php @@ -5,7 +5,10 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Departure; +use App\Modifier\FieldFilter; use App\Modifier\IdFilter; +use App\Modifier\Limit; +use App\Modifier\With; use App\Provider\DepartureRepository; use App\Provider\StopRepository; use App\Service\SerializerContextFactory; @@ -33,11 +36,11 @@ class DeparturesController extends Controller * @SWG\Schema(type="array", @SWG\Items(ref=@Model(type=Departure::class))) * ) */ - public function stop(DepartureRepository $departures, StopRepository $stops, $stop) + public function stop(DepartureRepository $departures, StopRepository $stops, $stop, Request $request) { $stop = $stops->first(new IdFilter($stop)); - return $this->json($departures->getForStop($stop)); + return $this->json($departures->current(collect($stop), ...$this->getModifiersFromRequest($request))); } /** @@ -65,16 +68,21 @@ class DeparturesController extends Controller */ public function stops(DepartureRepository $departures, StopRepository $stops, Request $request) { - $stops = $stops - ->all(new IdFilter($request->query->get('stop'))) - ->flatMap(ref([ $departures, 'getForStop' ])) - ->sortBy(property('departure')); + $stops = $stops->all(new IdFilter($request->query->get('stop'))); + $result = $departures->current($stops, ...$this->getModifiersFromRequest($request)); return $this->json( - $stops->values()->slice(0, (int)$request->query->get('limit', 8)), + $result->values()->slice(0, (int)$request->query->get('limit', 8)), 200, [], $this->serializerContextFactory->create(Departure::class, ['Default']) ); } + + private function getModifiersFromRequest(Request $request) + { + if ($request->query->has('limit')) { + yield Limit::count($request->query->getInt('limit')); + } + } } diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index dbaa48d..f366e8e 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -72,7 +72,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) { throw new \InvalidArgumentException( - sprintf("Relationship %s is not supported for .", $type) + sprintf("Relationship %s is not supported for %s.", $modifier->getRelationship(), $type) ); } diff --git a/src/Provider/DepartureRepository.php b/src/Provider/DepartureRepository.php index 706274c..a6ea1f4 100644 --- a/src/Provider/DepartureRepository.php +++ b/src/Provider/DepartureRepository.php @@ -5,9 +5,10 @@ namespace App\Provider; use App\Model\Stop; +use App\Modifier\Modifier; use Tightenco\Collect\Support\Collection; interface DepartureRepository extends Repository { - public function getForStop(Stop $stop): Collection; -} \ No newline at end of file + public function current(iterable $stops, Modifier ...$modifiers); +} diff --git a/src/Provider/Dummy/DummyDepartureRepository.php b/src/Provider/Dummy/DummyDepartureRepository.php index 5210943..d265ce6 100644 --- a/src/Provider/Dummy/DummyDepartureRepository.php +++ b/src/Provider/Dummy/DummyDepartureRepository.php @@ -6,6 +6,7 @@ use App\Model\Departure; use App\Model\Line; use App\Model\Stop; use App\Model\Vehicle; +use App\Modifier\Modifier; use App\Provider\DepartureRepository; use App\Service\Proxy\ReferenceFactory; use Carbon\Carbon; @@ -25,21 +26,21 @@ class DummyDepartureRepository implements DepartureRepository $this->reference = $reference; } - public function getForStop(Stop $stop): Collection + public function current(iterable $stops, Modifier ...$modifiers) { return collect([ - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], - [ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], + [1, Line::TYPE_TRAM, 'lorem ipsum', 2137], ])->map(function ($departure) use ($stop) { - list($symbol, $type, $display, $vehicle) = $departure; + [$symbol, $type, $display, $vehicle] = $departure; $scheduled = new Carbon(); $estimated = (clone $scheduled)->addSeconds(40); @@ -53,4 +54,4 @@ class DummyDepartureRepository implements DepartureRepository ]); }); } -} \ No newline at end of file +} diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php index 6053ef5..eb7f401 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDepartureRepository.php @@ -10,18 +10,22 @@ use App\Model\Vehicle; use App\Modifier\FieldFilter; use App\Modifier\IdFilter; use App\Modifier\Limit; +use App\Modifier\Modifier; use App\Modifier\RelatedFilter; use App\Modifier\With; use App\Provider\Database\GenericScheduleRepository; use App\Provider\DepartureRepository; use App\Provider\LineRepository; use App\Provider\ScheduleRepository; +use App\Service\IterableUtils; +use App\Service\ModifierUtils; use App\Service\Proxy\ReferenceFactory; use Carbon\Carbon; use JMS\Serializer\Tests\Fixtures\Discriminator\Car; use Tightenco\Collect\Support\Collection; use Kadet\Functional\Transforms as t; use function App\Functions\setup; +use function Kadet\Functional\ref; class ZtmGdanskDepartureRepository implements DepartureRepository { @@ -46,16 +50,22 @@ class ZtmGdanskDepartureRepository implements DepartureRepository $this->schedule = $schedule; } - public function getForStop(Stop $stop): Collection + public function current(iterable $stops, Modifier ...$modifiers) { - $real = $this->getRealDepartures($stop); + $real = IterableUtils::toCollection($stops) + ->flatMap(ref([$this, 'getRealDepartures'])) + ->sortBy(t\property('estimated')) + ; + $now = Carbon::now()->second(0); $first = $real->map(t\getter('scheduled'))->min() ?? $now; - $scheduled = $this->getScheduledDepartures($stop, $first); + $scheduled = $this->getScheduledDepartures($stops, $first, ...$this->extractModifiers($modifiers)); - return $this->pair($scheduled, $real)->filter(function (Departure $departure) use ($now) { + $result = $this->pair($scheduled, $real)->filter(function (Departure $departure) use ($now) { return $departure->getDeparture() > $now; }); + + return $this->processResultWithModifiers($result, $modifiers); } private function getRealDepartures(Stop $stop) @@ -94,14 +104,14 @@ class ZtmGdanskDepartureRepository implements DepartureRepository })->values(); } - private function getScheduledDepartures(Stop $stop, Carbon $time) + private function getScheduledDepartures($stop, Carbon $time, Modifier ...$modifiers) { return $this->schedule->all( - new RelatedFilter($stop), + new RelatedFilter($stop, Stop::class), new FieldFilter('departure', $time, '>='), new With('track'), new With('destination'), - Limit::count(16) + ...$modifiers ); } @@ -181,4 +191,31 @@ class ZtmGdanskDepartureRepository implements DepartureRepository $converted->setStop($stop->getStop()); }); } + + private function extractModifiers(iterable $modifiers) + { + $result = []; + + /** @var Limit $limit */ + if ($limit = ModifierUtils::getOfType($modifiers, Limit::class)) { + $result[] = new Limit($limit->getOffset(), $limit->getCount() * 2); + } else { + $result[] = Limit::count(16); + } + + return $result; + } + + private function processResultWithModifiers(Collection $result, iterable $modifiers) + { + foreach ($modifiers as $modifier) { + switch (true) { + case $modifier instanceof Limit: + $result = $result->slice($modifier->getOffset(), $modifier->getCount()); + break; + } + } + + return $result; + } } diff --git a/src/Service/ModifierUtils.php b/src/Service/ModifierUtils.php new file mode 100644 index 0000000..69f0fb4 --- /dev/null +++ b/src/Service/ModifierUtils.php @@ -0,0 +1,29 @@ +first($predicate); + } + + public static function getOfType(iterable $modifiers, $class) + { + return self::get($modifiers, instance($class)); + } + + public static function hasAny(iterable $modifiers, Predicate $predicate) + { + return collect($modifiers)->contains($predicate); + } + + public static function hasAnyOfType(iterable $modifiers, $class) + { + return collect($modifiers)->contains(instance($class)); + } +}