WIP - Add scheduled stop repository
This commit is contained in:
parent
7ffd3c02cd
commit
50a79470e7
@ -5,6 +5,7 @@ namespace App\Handler\Database;
|
||||
use App\Event\HandleDatabaseModifierEvent;
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\Stop;
|
||||
use App\Modifier\FieldFilter;
|
||||
use function App\Functions\encapsulate;
|
||||
@ -15,6 +16,10 @@ class FieldFilterDatabaseHandler implements ModifierHandler
|
||||
Stop::class => [
|
||||
'name' => 'name',
|
||||
],
|
||||
ScheduledStop::class => [
|
||||
'departure' => 'departure',
|
||||
'arrival' => 'arrival',
|
||||
]
|
||||
];
|
||||
|
||||
public function process(HandleModifierEvent $event)
|
||||
|
99
src/Handler/Database/GenericWithDatabaseHandler.php
Normal file
99
src/Handler/Database/GenericWithDatabaseHandler.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Handler\Database;
|
||||
|
||||
use App\Event\HandleDatabaseModifierEvent;
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\Track;
|
||||
use App\Model\TrackStop;
|
||||
use App\Modifier\RelatedFilter;
|
||||
use App\Service\EntityReferenceFactory;
|
||||
use App\Service\IdUtils;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use function Kadet\Functional\Transforms\property;
|
||||
|
||||
class GenericWithDatabaseHandler implements ModifierHandler
|
||||
{
|
||||
protected $mapping = [
|
||||
Track::class => [
|
||||
'line' => 'line',
|
||||
'stops' => 'stopsInTrack',
|
||||
],
|
||||
TrackStop::class => [
|
||||
'track' => 'track',
|
||||
],
|
||||
ScheduledStop::class => [
|
||||
'trip' => 'trip',
|
||||
'track' => 'trip.track',
|
||||
'destination' => 'trip.track.final',
|
||||
],
|
||||
];
|
||||
|
||||
private $em;
|
||||
private $id;
|
||||
private $references;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
IdUtils $idUtils,
|
||||
EntityReferenceFactory $references
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->id = $idUtils;
|
||||
$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'];
|
||||
$type = $event->getMeta()['type'];
|
||||
|
||||
if (!array_key_exists($modifier->getRelationship(), $this->mapping[$type])) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Relationship %s is not supported for .", $type)
|
||||
);
|
||||
}
|
||||
|
||||
$relationship = $this->mapping[$type][$modifier->getRelationship()];
|
||||
|
||||
foreach ($this->getRelationships($relationship, $alias) as [$relationshipPath, $relationshipAlias]) {
|
||||
$selected = collect($builder->getDQLPart('select'))->flatMap(property('parts'));
|
||||
|
||||
if ($selected->contains($relationshipAlias)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$builder
|
||||
->join($relationshipPath, $relationshipAlias)
|
||||
->addSelect($relationshipAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getSubscribedServices()
|
||||
{
|
||||
return [
|
||||
TrackByStopDatabaseHandler::class,
|
||||
];
|
||||
}
|
||||
|
||||
private function getRelationships($relationship, $alias)
|
||||
{
|
||||
$relationships = explode('.', $relationship);
|
||||
|
||||
foreach ($relationships as $current) {
|
||||
yield [sprintf("%s.%s", $alias, $current), $alias = sprintf('%s_%s', $alias, $current)];
|
||||
}
|
||||
}
|
||||
}
|
@ -6,9 +6,11 @@ use App\Event\HandleDatabaseModifierEvent;
|
||||
use App\Event\HandleModifierEvent;
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Model\Line;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\Stop;
|
||||
use App\Model\Track;
|
||||
use App\Model\TrackStop;
|
||||
use App\Model\Trip;
|
||||
use App\Modifier\RelatedFilter;
|
||||
use App\Service\IdUtils;
|
||||
use App\Service\EntityReferenceFactory;
|
||||
@ -27,6 +29,10 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
|
||||
Stop::class => 'stop',
|
||||
Track::class => 'track',
|
||||
],
|
||||
ScheduledStop::class => [
|
||||
Stop::class => 'stop',
|
||||
Trip::class => 'trip',
|
||||
],
|
||||
];
|
||||
|
||||
private $em;
|
||||
|
@ -7,17 +7,23 @@ use Carbon\Carbon;
|
||||
class ScheduledStop extends TrackStop
|
||||
{
|
||||
/**
|
||||
* Arrival time
|
||||
* Arrival time.
|
||||
* @var Carbon
|
||||
*/
|
||||
private $arrival;
|
||||
|
||||
/**
|
||||
* Departure time
|
||||
* Departure time.
|
||||
* @var Carbon
|
||||
*/
|
||||
private $departure;
|
||||
|
||||
/**
|
||||
* Exact trip that this scheduled stop is part of.
|
||||
* @var Trip|null
|
||||
*/
|
||||
private $trip;
|
||||
|
||||
public function getArrival(): Carbon
|
||||
{
|
||||
return $this->arrival;
|
||||
@ -37,4 +43,14 @@ class ScheduledStop extends TrackStop
|
||||
{
|
||||
$this->departure = $departure;
|
||||
}
|
||||
|
||||
public function getTrip(): ?Trip
|
||||
{
|
||||
return $this->trip;
|
||||
}
|
||||
|
||||
public function setTrip(?Trip $trip): void
|
||||
{
|
||||
$this->trip = $trip;
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,14 @@ class Track implements Referable, Fillable
|
||||
*/
|
||||
private $stops;
|
||||
|
||||
/**
|
||||
* Destination stop of this track
|
||||
* @var Stop|null
|
||||
* @Serializer\Type(Stop::class)
|
||||
* @SWG\Property(ref=@Model(type=Stop::class))
|
||||
*/
|
||||
private $destination;
|
||||
|
||||
/**
|
||||
* Track constructor.
|
||||
*/
|
||||
@ -89,4 +97,14 @@ class Track implements Referable, Fillable
|
||||
{
|
||||
return $this->stops = collect($stops);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDestination(): ?Stop
|
||||
{
|
||||
return $this->destination;
|
||||
}
|
||||
|
||||
public function setDestination(?Stop $destination): void
|
||||
{
|
||||
$this->destination = $destination;
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,12 @@ class Trip implements Referable, Fillable
|
||||
*/
|
||||
private $schedule;
|
||||
|
||||
/**
|
||||
* Destination stop of this trip
|
||||
* @var Stop|null
|
||||
*/
|
||||
private $destination;
|
||||
|
||||
/**
|
||||
* Track constructor.
|
||||
*/
|
||||
@ -87,4 +93,14 @@ class Trip implements Referable, Fillable
|
||||
{
|
||||
return $this->schedule = collect($schedule);
|
||||
}
|
||||
|
||||
public function getDestination(): ?Stop
|
||||
{
|
||||
return $this->destination;
|
||||
}
|
||||
|
||||
public function setDestination(?Stop $destination): void
|
||||
{
|
||||
$this->destination = $destination;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use App\Handler\Database\FieldFilterDatabaseHandler;
|
||||
use App\Handler\Database\IdFilterDatabaseHandler;
|
||||
use App\Handler\Database\LimitDatabaseHandler;
|
||||
use App\Handler\Database\RelatedFilterDatabaseGenericHandler;
|
||||
use App\Handler\Database\GenericWithDatabaseHandler;
|
||||
use App\Handler\ModifierHandler;
|
||||
use App\Handler\PostProcessingHandler;
|
||||
use App\Model\Referable;
|
||||
@ -17,6 +18,7 @@ use App\Modifier\IdFilter;
|
||||
use App\Modifier\Limit;
|
||||
use App\Modifier\Modifier;
|
||||
use App\Modifier\RelatedFilter;
|
||||
use App\Modifier\With;
|
||||
use App\Provider\Repository;
|
||||
use App\Service\Converter;
|
||||
use App\Service\HandlerProvider;
|
||||
@ -64,6 +66,7 @@ abstract class DatabaseRepository implements Repository
|
||||
Limit::class => LimitDatabaseHandler::class,
|
||||
FieldFilter::class => FieldFilterDatabaseHandler::class,
|
||||
RelatedFilter::class => RelatedFilterDatabaseGenericHandler::class,
|
||||
With::class => GenericWithDatabaseHandler::class,
|
||||
], static::getHandlers()));
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,10 @@ use App\Entity\TripEntity;
|
||||
use App\Entity\TripStopEntity;
|
||||
use App\Model\Departure;
|
||||
use App\Model\Line;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\Stop;
|
||||
use App\Model\Vehicle;
|
||||
use App\Modifier\Modifier;
|
||||
use App\Provider\ScheduleRepository;
|
||||
use Carbon\Carbon;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
@ -71,8 +73,19 @@ class GenericScheduleRepository extends DatabaseRepository implements ScheduleRe
|
||||
});
|
||||
}
|
||||
|
||||
protected static function getHandlers()
|
||||
public function all(Modifier ...$modifiers): Collection
|
||||
{
|
||||
return [];
|
||||
$builder = $this->em
|
||||
->createQueryBuilder()
|
||||
->select('trip_stop')
|
||||
->from(TripStopEntity::class, 'trip_stop')
|
||||
->orderBy('trip_stop.departure', 'ASC')
|
||||
;
|
||||
|
||||
return $this->allFromQueryBuilder($builder, $modifiers, [
|
||||
'alias' => 'trip_stop',
|
||||
'type' => ScheduledStop::class,
|
||||
'entity' => TripStopEntity::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Provider\Database;
|
||||
|
||||
use App\Entity\StopEntity;
|
||||
use App\Handler\Database\GenericWithDatabaseHandler;
|
||||
use App\Handler\Database\WithDestinationsDatabaseHandler;
|
||||
use App\Model\Stop;
|
||||
use App\Modifier\Modifier;
|
||||
@ -33,7 +34,7 @@ class GenericStopRepository extends DatabaseRepository implements StopRepository
|
||||
With::class => function (With $modifier) {
|
||||
return $modifier->getRelationship() === 'destinations'
|
||||
? WithDestinationsDatabaseHandler::class
|
||||
: GenericWithHandler::class;
|
||||
: GenericWithDatabaseHandler::class;
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use App\Model\Stop;
|
||||
use Carbon\Carbon;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
interface ScheduleRepository
|
||||
interface ScheduleRepository extends FluentRepository
|
||||
{
|
||||
const DEFAULT_DEPARTURES_COUNT = 16;
|
||||
|
||||
|
@ -4,9 +4,14 @@ namespace App\Provider\ZtmGdansk;
|
||||
|
||||
use App\Model\Departure;
|
||||
use App\Model\Line;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\Stop;
|
||||
use App\Model\Vehicle;
|
||||
use App\Modifier\FieldFilter;
|
||||
use App\Modifier\IdFilter;
|
||||
use App\Modifier\Limit;
|
||||
use App\Modifier\RelatedFilter;
|
||||
use App\Modifier\With;
|
||||
use App\Provider\Database\GenericScheduleRepository;
|
||||
use App\Provider\DepartureRepository;
|
||||
use App\Provider\LineRepository;
|
||||
@ -90,13 +95,33 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
|
||||
|
||||
private function getScheduledDepartures(Stop $stop, Carbon $time)
|
||||
{
|
||||
return $this->schedule->getDeparturesForStop($stop, $time);
|
||||
return $this->schedule->all(
|
||||
new RelatedFilter($stop),
|
||||
new FieldFilter('departure', $time, '>='),
|
||||
new With('track'),
|
||||
new With('destination'),
|
||||
Limit::count(16)
|
||||
);
|
||||
}
|
||||
|
||||
private function pair(Collection $schedule, Collection $real)
|
||||
{
|
||||
$key = function (Departure $departure) {
|
||||
return sprintf("%s::%s", $departure->getLine()->getSymbol(), $departure->getScheduled()->format("H:i"));
|
||||
$key = function ($departure) {
|
||||
if ($departure instanceof Departure) {
|
||||
return sprintf(
|
||||
"%s::%s",
|
||||
$departure->getLine()->getId(),
|
||||
$departure->getScheduled()->format("H:i")
|
||||
);
|
||||
} elseif ($departure instanceof ScheduledStop) {
|
||||
return sprintf(
|
||||
"%s::%s",
|
||||
$departure->getTrack()->getLine()->getId(),
|
||||
$departure->getDeparture()->format("H:i")
|
||||
);
|
||||
} else {
|
||||
throw new \Exception();
|
||||
}
|
||||
};
|
||||
|
||||
$schedule = $schedule->keyBy($key)->all();
|
||||
@ -110,21 +135,27 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
|
||||
unset($schedule[$key]);
|
||||
}
|
||||
|
||||
return [ $real, $scheduled ];
|
||||
})->merge(collect($schedule)->map(function (Departure $scheduled) {
|
||||
return [ null, $scheduled ];
|
||||
return [
|
||||
'estimated' => $real,
|
||||
'scheduled' => $scheduled,
|
||||
];
|
||||
})->merge(collect($schedule)->map(function (ScheduledStop $scheduled) {
|
||||
return [
|
||||
'estimated' => null,
|
||||
'scheduled' => $scheduled,
|
||||
];
|
||||
}))->map(function ($pair) {
|
||||
return $this->merge(...$pair);
|
||||
return $this->merge($pair['estimated'], $pair['scheduled']);
|
||||
})->sortBy(function (Departure $departure) {
|
||||
$time = $departure->getEstimated() ?? $departure->getScheduled();
|
||||
return $time->getTimestamp();
|
||||
});
|
||||
}
|
||||
|
||||
private function merge(?Departure $real, ?Departure $scheduled)
|
||||
private function merge(?Departure $real, ?ScheduledStop $scheduled)
|
||||
{
|
||||
if (!$real) {
|
||||
return $scheduled;
|
||||
return $this->convertScheduledStopToDeparture($scheduled);
|
||||
}
|
||||
|
||||
if (!$scheduled) {
|
||||
@ -132,10 +163,24 @@ class ZtmGdanskDepartureRepository implements DepartureRepository
|
||||
}
|
||||
|
||||
$departure = clone $real;
|
||||
$departure->setDisplay($scheduled->getDisplay());
|
||||
$departure->setDisplay($real->getDisplay());
|
||||
$departure->setTrack($scheduled->getTrack());
|
||||
$departure->setTrip($scheduled->getTrip());
|
||||
|
||||
return $departure;
|
||||
}
|
||||
|
||||
private function convertScheduledStopToDeparture(ScheduledStop $stop): Departure
|
||||
{
|
||||
$converted = new Departure();
|
||||
|
||||
$converted->setDisplay($stop->getTrack()->getDestination()->getName());
|
||||
$converted->setLine($stop->getTrack()->getLine());
|
||||
$converted->setTrack($stop->getTrack());
|
||||
$converted->setTrip($stop->getTrip());
|
||||
$converted->setScheduled($stop->getDeparture());
|
||||
$converted->setStop($stop->getStop());
|
||||
|
||||
return $converted;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ final class EntityConverter implements Converter, RecursiveConverter
|
||||
*/
|
||||
public function convert($entity, array $cache = [])
|
||||
{
|
||||
if (array_key_exists($key = get_class($entity).':'.$this->getId($entity), $cache)) {
|
||||
if (array_key_exists($key = get_class($entity) . ':' . $this->getId($entity), $cache)) {
|
||||
return $cache[$key];
|
||||
}
|
||||
|
||||
@ -78,6 +78,7 @@ final class EntityConverter implements Converter, RecursiveConverter
|
||||
->map(t\property('stop'))
|
||||
->map($convert),
|
||||
'line' => $convert($entity->getLine()),
|
||||
'destination' => $convert($entity->getFinal()->getStop()),
|
||||
]);
|
||||
break;
|
||||
|
||||
@ -154,7 +155,7 @@ final class EntityConverter implements Converter, RecursiveConverter
|
||||
|
||||
private function create(Entity $entity)
|
||||
{
|
||||
$id = $this->id->of($entity);
|
||||
$id = $this->id->of($entity);
|
||||
$class = $this->getModelClassForEntity($entity);
|
||||
|
||||
return $class::createFromArray(['id' => $id]);
|
||||
@ -162,7 +163,7 @@ final class EntityConverter implements Converter, RecursiveConverter
|
||||
|
||||
private function reference(Entity $entity)
|
||||
{
|
||||
$id = $this->id->strip($this->getId($entity));
|
||||
$id = $this->id->strip($this->getId($entity));
|
||||
$class = $this->getModelClassForEntity($entity);
|
||||
|
||||
return $this->reference->get($class, ['id' => $id]);
|
||||
|
@ -5,6 +5,7 @@ namespace App\Service;
|
||||
use App\Entity\TrackStopEntity;
|
||||
use App\Entity\TripStopEntity;
|
||||
use App\Model\ScheduledStop;
|
||||
use App\Model\TrackStop;
|
||||
|
||||
class ScheduledStopConverter implements Converter, RecursiveConverter
|
||||
{
|
||||
@ -12,9 +13,8 @@ class ScheduledStopConverter implements Converter, RecursiveConverter
|
||||
|
||||
public function convert($entity)
|
||||
{
|
||||
|
||||
if ($entity instanceof TrackStopEntity) {
|
||||
return ScheduledStop::createFromArray([
|
||||
return TrackStop::createFromArray([
|
||||
'stop' => $this->parent->convert($entity->getStop()),
|
||||
'track' => $this->parent->convert($entity->getTrack()),
|
||||
'order' => $entity->getOrder(),
|
||||
@ -27,6 +27,8 @@ class ScheduledStopConverter implements Converter, RecursiveConverter
|
||||
'departure' => $entity->getDeparture(),
|
||||
'stop' => $this->parent->convert($entity->getStop()),
|
||||
'order' => $entity->getOrder(),
|
||||
'track' => $this->parent->convert($entity->getTrip()->getTrack()),
|
||||
'trip' => $this->parent->convert($entity->getTrip()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user