diff --git a/src/Controller/Api/v1/StopsController.php b/src/Controller/Api/v1/StopsController.php index 669e58f..dc6ac45 100644 --- a/src/Controller/Api/v1/StopsController.php +++ b/src/Controller/Api/v1/StopsController.php @@ -4,7 +4,7 @@ namespace App\Controller\Api\v1; use App\Controller\Controller; use App\Model\Stop; -use App\Model\Track; +use App\Model\TrackStop; use App\Model\StopGroup; use App\Modifier\IdFilter; use App\Modifier\FieldFilter; @@ -12,7 +12,6 @@ use App\Modifier\IncludeDestinations; use App\Modifier\RelatedFilter; use App\Provider\StopRepository; use App\Provider\TrackRepository; -use App\Service\Proxy\ReferenceFactory; use Nelmio\ApiDocBundle\Annotation\Model; use Swagger\Annotations as SWG; use Symfony\Component\HttpFoundation\Request; @@ -105,21 +104,12 @@ class StopsController extends Controller * @SWG\Response( * response=200, * description="Returns specific stop referenced via identificator.", - * @SWG\Schema(type="object", properties={ - * @SWG\Property(property="track", type="object", ref=@Model(type=Track::class)), - * @SWG\Property(property="order", type="integer", minimum="0") - * }) + * @SWG\Schema(ref=@Model(type=TrackStop::class)) * ) - * - * @SWG\Tag(name="Tracks") */ - public function tracks(ReferenceFactory $reference, TrackRepository $tracks, $id) + public function tracks(TrackRepository $tracks, $id) { - $stop = $reference->get(Stop::class, $id); - - return $this->json($tracks->getByStop($stop)->map(function ($tuple) { - return array_combine(['track', 'order'], $tuple); - })); + return $this->json($tracks->stops(new RelatedFilter(Stop::reference($id)))); } public static function group(Collection $stops) diff --git a/src/Controller/Api/v1/TracksController.php b/src/Controller/Api/v1/TracksController.php index 71b7ae8..71e79c9 100644 --- a/src/Controller/Api/v1/TracksController.php +++ b/src/Controller/Api/v1/TracksController.php @@ -19,6 +19,7 @@ use function App\Functions\encapsulate; /** * @Route("/tracks") + * @SWG\Tag(name="Tracks") */ class TracksController extends Controller { @@ -27,7 +28,6 @@ class TracksController extends Controller * response=200, * description="Returns all tracks for specific provider, e.g. ZTM GdaƄsk.", * ) - * @SWG\Tag(name="Tracks") * @Route("/", methods={"GET"}) */ public function index(Request $request, TrackRepository $repository) @@ -37,6 +37,17 @@ class TracksController extends Controller return $this->json($repository->all(...$modifiers)); } + /** + * @Route("/stops", methods={"GET"}) + * @Route("/{track}/stops", methods={"GET"}) + */ + public function stops(Request $request, TrackRepository $repository) + { + $modifiers = $this->getStopsModifiersFromRequest($request); + + return $this->json($repository->stops(...$modifiers)); + } + private function getModifiersFromRequest(Request $request) { if ($request->query->has('stop')) { @@ -59,4 +70,27 @@ class TracksController extends Controller yield new IdFilter($id); } } + + private function getStopsModifiersFromRequest(Request $request) + { + if ($request->query->has('stop')) { + $stop = $request->query->get('stop'); + $stop = Stop::reference($stop); + + yield new RelatedFilter($stop); + } + + if ($request->query->has('track') || $request->attributes->has('track')) { + $track = $request->get('track'); + $track = Track::reference($track); + + yield new RelatedFilter($track); + } + + if ($request->query->has('id')) { + $id = encapsulate($request->query->get('id')); + + yield new IdFilter($id); + } + } } diff --git a/src/Entity/TrackEntity.php b/src/Entity/TrackEntity.php index a0eaa1d..856297b 100644 --- a/src/Entity/TrackEntity.php +++ b/src/Entity/TrackEntity.php @@ -45,16 +45,18 @@ class TrackEntity implements Entity, Fillable /** * Stops in track - * @var StopInTrack[]|Collection - * @ORM\OneToMany(targetEntity=StopInTrack::class, fetch="LAZY", mappedBy="track", cascade={"persist"}) + * + * @var TrackStopEntity[]|Collection + * @ORM\OneToMany(targetEntity=TrackStopEntity::class, fetch="LAZY", mappedBy="track", cascade={"persist"}) * @ORM\OrderBy({"order": "ASC"}) */ private $stopsInTrack; /** * Final stop in this track. - * @var StopInTrack - * @ORM\OneToOne(targetEntity=StopInTrack::class, fetch="LAZY") + * + * @var TrackStopEntity + * @ORM\OneToOne(targetEntity=TrackStopEntity::class, fetch="LAZY") */ private $final; @@ -114,7 +116,7 @@ class TrackEntity implements Entity, Fillable $this->final = $this->stopsInTrack->last(); } - public function getFinal(): StopInTrack + public function getFinal(): TrackStopEntity { return $this->final; } diff --git a/src/Entity/StopInTrack.php b/src/Entity/TrackStopEntity.php similarity index 96% rename from src/Entity/StopInTrack.php rename to src/Entity/TrackStopEntity.php index 26cbd55..b32c84b 100644 --- a/src/Entity/StopInTrack.php +++ b/src/Entity/TrackStopEntity.php @@ -14,7 +14,7 @@ use Doctrine\ORM\Mapping as ORM; * @ORM\UniqueConstraint(name="stop_in_track_idx", columns={"stop_id", "track_id", "sequence"}) * }) */ -class StopInTrack implements Fillable, Referable +class TrackStopEntity implements Fillable, Referable { use FillTrait, ReferableEntityTrait; diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index 6a2683d..68d2fc9 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -8,9 +8,10 @@ use App\Handler\ModifierHandler; use App\Model\Line; use App\Model\Stop; use App\Model\Track; +use App\Model\TrackStop; use App\Modifier\RelatedFilter; use App\Service\IdUtils; -use App\Service\ReferenceFactory; +use App\Service\EntityReferenceFactory; use Doctrine\ORM\EntityManagerInterface; use Psr\Container\ContainerInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; @@ -18,10 +19,14 @@ use Symfony\Contracts\Service\ServiceSubscriberInterface; class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSubscriberInterface { protected $mapping = [ - Track::class => [ + Track::class => [ Line::class => 'line', Stop::class => TrackByStopDatabaseHandler::class, ], + TrackStop::class => [ + Stop::class => 'stop', + Track::class => 'track', + ], ]; private $em; @@ -33,11 +38,11 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub ContainerInterface $inner, EntityManagerInterface $em, IdUtils $idUtils, - ReferenceFactory $references + EntityReferenceFactory $references ) { - $this->inner = $inner; - $this->em = $em; - $this->id = $idUtils; + $this->inner = $inner; + $this->em = $em; + $this->id = $idUtils; $this->references = $references; } @@ -71,6 +76,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub /** @var ModifierHandler $inner */ $inner = $this->inner->get($relationship); $inner->process($event); + return; } @@ -80,8 +86,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub $builder ->join(sprintf('%s.%s', $alias, $relationship), $relationship) ->andWhere(sprintf("%s = %s", $relationship, $parameter)) - ->setParameter($parameter, $reference) - ; + ->setParameter($parameter, $reference); } /** diff --git a/src/Handler/Database/TrackByStopDatabaseHandler.php b/src/Handler/Database/TrackByStopDatabaseHandler.php index 12789e5..d5476a7 100644 --- a/src/Handler/Database/TrackByStopDatabaseHandler.php +++ b/src/Handler/Database/TrackByStopDatabaseHandler.php @@ -2,18 +2,18 @@ namespace App\Handler\Database; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Event\HandleDatabaseModifierEvent; use App\Event\HandleModifierEvent; use App\Handler\ModifierHandler; use App\Modifier\RelatedFilter; -use App\Service\ReferenceFactory; +use App\Service\EntityReferenceFactory; class TrackByStopDatabaseHandler implements ModifierHandler { private $references; - public function __construct(ReferenceFactory $references) + public function __construct(EntityReferenceFactory $references) { $this->references = $references; } diff --git a/src/Model/Line.php b/src/Model/Line.php index b339218..f905b7d 100644 --- a/src/Model/Line.php +++ b/src/Model/Line.php @@ -138,4 +138,4 @@ class Line implements Fillable, Referable { $this->operator = $operator; } -} \ No newline at end of file +} diff --git a/src/Model/ScheduledStop.php b/src/Model/ScheduledStop.php index abfda2d..2ae78f2 100644 --- a/src/Model/ScheduledStop.php +++ b/src/Model/ScheduledStop.php @@ -4,22 +4,8 @@ namespace App\Model; use Carbon\Carbon; -class ScheduledStop implements Fillable +class ScheduledStop extends TrackStop { - use FillTrait; - - /** - * Stop (as a place) related to that scheduled bus stop - * @var Stop - */ - private $stop; - - /** - * Order in trip - * @var int - */ - private $order; - /** * Arrival time * @var Carbon @@ -32,26 +18,6 @@ class ScheduledStop implements Fillable */ private $departure; - public function getStop() - { - return $this->stop; - } - - public function setStop($stop): void - { - $this->stop = $stop; - } - - public function getOrder(): int - { - return $this->order; - } - - public function setOrder(int $order): void - { - $this->order = $order; - } - public function getArrival(): Carbon { return $this->arrival; diff --git a/src/Model/TrackStop.php b/src/Model/TrackStop.php new file mode 100644 index 0000000..283151a --- /dev/null +++ b/src/Model/TrackStop.php @@ -0,0 +1,58 @@ +stop; + } + + public function setStop($stop): void + { + $this->stop = $stop; + } + + public function getOrder(): int + { + return $this->order; + } + + public function setOrder(int $order): void + { + $this->order = $order; + } + + public function getTrack(): ?Track + { + return $this->track; + } + + public function setTrack(?Track $track): void + { + $this->track = $track; + } +} diff --git a/src/Provider/Database/DatabaseRepository.php b/src/Provider/Database/DatabaseRepository.php index 60ad5ca..8156253 100644 --- a/src/Provider/Database/DatabaseRepository.php +++ b/src/Provider/Database/DatabaseRepository.php @@ -28,6 +28,8 @@ use Symfony\Contracts\Service\ServiceSubscriberInterface; abstract class DatabaseRepository implements ServiceSubscriberInterface, Repository { + const DEFAULT_LIMIT = 100; + /** @var EntityManagerInterface */ protected $em; @@ -115,6 +117,8 @@ abstract class DatabaseRepository implements ServiceSubscriberInterface, Reposit protected function allFromQueryBuilder(QueryBuilder $builder, iterable $modifiers, array $meta = []) { + $builder->setMaxResults(self::DEFAULT_LIMIT); + $reducers = $this->processQueryBuilder($builder, $modifiers, $meta); return $reducers->reduce(function ($result, $reducer) { diff --git a/src/Provider/Database/GenericScheduleRepository.php b/src/Provider/Database/GenericScheduleRepository.php index e1c2c29..ed7adbe 100644 --- a/src/Provider/Database/GenericScheduleRepository.php +++ b/src/Provider/Database/GenericScheduleRepository.php @@ -3,7 +3,7 @@ namespace App\Provider\Database; use App\Entity\StopEntity; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; use App\Entity\TripEntity; use App\Entity\TripStopEntity; diff --git a/src/Provider/Database/GenericTrackRepository.php b/src/Provider/Database/GenericTrackRepository.php index 82699d7..f25d7f2 100644 --- a/src/Provider/Database/GenericTrackRepository.php +++ b/src/Provider/Database/GenericTrackRepository.php @@ -2,33 +2,28 @@ namespace App\Provider\Database; -use App\Entity\StopEntity; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; +use App\Model\TrackStop; use App\Modifier\Modifier; use App\Model\Track; use App\Provider\TrackRepository; use Tightenco\Collect\Support\Collection; -use Kadet\Functional as f; -use function App\Functions\encapsulate; class GenericTrackRepository extends DatabaseRepository implements TrackRepository { - public function getByStop($stop): Collection + public function stops(Modifier ...$modifiers): Collection { - $reference = f\apply(f\ref([$this, 'reference']), StopEntity::class); + $builder = $this->em + ->createQueryBuilder() + ->from(TrackStopEntity::class, 'track_stop') + ->select(['track_stop']); - $tracks = $this->em->createQueryBuilder() - ->from(StopInTrack::class, 'st') - ->join('st.track', 't') - ->where('st.stop in (:stop)') - ->select(['st', 't']) - ->getQuery() - ->execute(['stop' => array_map($reference, encapsulate($stop))]); - - return collect($tracks)->map(function (StopInTrack $entity) { - return [ $this->convert($entity->getTrack()), $entity->getOrder() ]; - }); + return $this->allFromQueryBuilder($builder, $modifiers, [ + 'alias' => 'track_stop', + 'entity' => TrackStopEntity::class, + 'type' => TrackStop::class, + ]); } public function all(Modifier ...$modifiers): Collection diff --git a/src/Provider/TrackRepository.php b/src/Provider/TrackRepository.php index 3e70a03..2b66a36 100644 --- a/src/Provider/TrackRepository.php +++ b/src/Provider/TrackRepository.php @@ -3,9 +3,10 @@ namespace App\Provider; use App\Model\Track; +use App\Modifier\Modifier; use Tightenco\Collect\Support\Collection; interface TrackRepository extends FluentRepository { - public function getByStop($stop): Collection; + public function stops(Modifier ...$modifiers): Collection; } diff --git a/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php b/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php index 146ef55..38bf725 100644 --- a/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php +++ b/src/Provider/ZtmGdansk/ZtmGdanskDataUpdateSubscriber.php @@ -6,7 +6,7 @@ use App\Entity\LineEntity; use App\Entity\OperatorEntity; use App\Entity\ProviderEntity; use App\Entity\StopEntity; -use App\Entity\StopInTrack; +use App\Entity\TrackStopEntity; use App\Entity\TrackEntity; use App\Entity\TripEntity; use App\Entity\TripStopEntity; @@ -216,7 +216,7 @@ class ZtmGdanskDataUpdateSubscriber implements EventSubscriberInterface return !in_array($stop['stopId'], $this->stopBlacklist); }) ->map(function ($stop) use ($entity, $provider) { - return StopInTrack::createFromArray([ + return TrackStopEntity::createFromArray([ 'stop' => $this->em->getReference( StopEntity::class, $this->ids->generate($provider, $stop['stopId']) diff --git a/src/Service/ReferenceFactory.php b/src/Service/EntityReferenceFactory.php similarity index 80% rename from src/Service/ReferenceFactory.php rename to src/Service/EntityReferenceFactory.php index 3d91cd9..d68bcc0 100644 --- a/src/Service/ReferenceFactory.php +++ b/src/Service/EntityReferenceFactory.php @@ -5,16 +5,19 @@ namespace App\Service; use App\Entity\LineEntity; use App\Entity\ProviderEntity; use App\Entity\StopEntity; +use App\Entity\TrackEntity; use App\Model\Line; use App\Model\Referable; use App\Model\Stop; +use App\Model\Track; use Doctrine\ORM\EntityManagerInterface; -final class ReferenceFactory +final class EntityReferenceFactory { protected $mapping = [ - Line::class => LineEntity::class, - Stop::class => StopEntity::class, + Line::class => LineEntity::class, + Stop::class => StopEntity::class, + Track::class => TrackEntity::class, ]; private $em; diff --git a/src/Service/ScheduledStopConverter.php b/src/Service/ScheduledStopConverter.php index da20f28..c00faae 100644 --- a/src/Service/ScheduledStopConverter.php +++ b/src/Service/ScheduledStopConverter.php @@ -2,6 +2,7 @@ namespace App\Service; +use App\Entity\TrackStopEntity; use App\Entity\TripStopEntity; use App\Model\ScheduledStop; @@ -11,18 +12,28 @@ class ScheduledStopConverter implements Converter, RecursiveConverter public function convert($entity) { - /** @var ScheduledStop $entity */ - return ScheduledStop::createFromArray([ - 'arrival' => $entity->getArrival(), - 'departure' => $entity->getDeparture(), - 'stop' => $this->parent->convert($entity->getStop()), - 'order' => $entity->getOrder(), - ]); + if ($entity instanceof TrackStopEntity) { + return ScheduledStop::createFromArray([ + 'stop' => $this->parent->convert($entity->getStop()), + 'track' => $this->parent->convert($entity->getTrack()), + 'order' => $entity->getOrder(), + ]); + } + + if ($entity instanceof TripStopEntity) { + return ScheduledStop::createFromArray([ + 'arrival' => $entity->getArrival(), + 'departure' => $entity->getDeparture(), + 'stop' => $this->parent->convert($entity->getStop()), + 'order' => $entity->getOrder(), + ]); + } } public function supports($entity) { - return $entity instanceof TripStopEntity; + return $entity instanceof TripStopEntity + || $entity instanceof TrackStopEntity; } }