Add Limit support for departure repository

This commit is contained in:
Kacper Donat 2020-03-15 22:35:12 +01:00
parent 1a0515742e
commit 3e695bfef7
6 changed files with 106 additions and 30 deletions

View File

@ -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'));
}
}
}

View File

@ -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)
);
}

View File

@ -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;
}
public function current(iterable $stops, Modifier ...$modifiers);
}

View File

@ -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
]);
});
}
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Service;
use Kadet\Functional\Predicate;
use function Kadet\Functional\Predicates\instance;
final class ModifierUtils
{
public static function get(iterable $modifiers, Predicate $predicate)
{
return collect($modifiers)->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));
}
}