diff --git a/src/Controller/Api/v1/TracksController.php b/src/Controller/Api/v1/TracksController.php index 71e79c9..54cece5 100644 --- a/src/Controller/Api/v1/TracksController.php +++ b/src/Controller/Api/v1/TracksController.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use function App\Functions\encapsulate; +use function Kadet\Functional\ref; /** * @Route("/tracks") @@ -51,17 +52,17 @@ class TracksController extends Controller private function getModifiersFromRequest(Request $request) { if ($request->query->has('stop')) { - $stop = $request->query->get('stop'); - $stop = Stop::reference($stop); + $stop = encapsulate($request->query->get('stop')); + $stop = collect($stop)->map([Stop::class, 'reference']); - yield new RelatedFilter($stop); + yield new RelatedFilter($stop, Stop::class); } if ($request->query->has('line')) { - $line = $request->query->get('line'); - $line = Line::reference($line); + $line = encapsulate($request->query->get('line')); + $line = collect($line)->map([Line::class, 'reference']); - yield new RelatedFilter($line); + yield new RelatedFilter($line, Line::class); } if ($request->query->has('id')) { @@ -74,8 +75,8 @@ class TracksController extends Controller private function getStopsModifiersFromRequest(Request $request) { if ($request->query->has('stop')) { - $stop = $request->query->get('stop'); - $stop = Stop::reference($stop); + $stop = encapsulate($request->query->get('stop')); + $stop = collect($stop)->map(ref([Stop::class, 'reference'])); yield new RelatedFilter($stop); } diff --git a/src/Exception/InvalidOptionException.php b/src/Exception/InvalidArgumentException.php similarity index 70% rename from src/Exception/InvalidOptionException.php rename to src/Exception/InvalidArgumentException.php index b052f10..14789e4 100644 --- a/src/Exception/InvalidOptionException.php +++ b/src/Exception/InvalidArgumentException.php @@ -2,11 +2,11 @@ namespace App\Exception; -class InvalidOptionException extends \InvalidArgumentException +class InvalidArgumentException extends \InvalidArgumentException { public static function invalidType($parameter, $value, array $expected = []) { - return new \InvalidArgumentException( + return new static( sprintf('Expected %s to be of type: %s. %s given.', $parameter, implode(', ', $expected), gettype($value)) ); } diff --git a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php index 68d2fc9..315b99f 100644 --- a/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php +++ b/src/Handler/Database/RelatedFilterDatabaseGenericHandler.php @@ -85,7 +85,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub $builder ->join(sprintf('%s.%s', $alias, $relationship), $relationship) - ->andWhere(sprintf("%s = %s", $relationship, $parameter)) + ->andWhere(sprintf($modifier->isMultiple() ? "%s in (%s)" : "%s = %s", $relationship, $parameter)) ->setParameter($parameter, $reference); } diff --git a/src/Handler/Database/TrackByStopDatabaseHandler.php b/src/Handler/Database/TrackByStopDatabaseHandler.php index d5476a7..fe84aa0 100644 --- a/src/Handler/Database/TrackByStopDatabaseHandler.php +++ b/src/Handler/Database/TrackByStopDatabaseHandler.php @@ -34,9 +34,11 @@ class TrackByStopDatabaseHandler implements ModifierHandler $parameter = sprintf(":%s_%s", $alias, $relationship); $reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']); + $condition = $modifier->isMultiple() ? 'stop_in_track.stop IN (%s)' : 'stop_in_track.stop = %s'; + $builder ->join(sprintf("%s.%s", $alias, $relationship), 'stop_in_track') - ->andWhere(sprintf("stop_in_track.stop = %s", $parameter)) + ->andWhere(sprintf($condition, $parameter)) ->setParameter($parameter, $reference) ; } diff --git a/src/Modifier/IdFilter.php b/src/Modifier/IdFilter.php index f7b6a13..0e791a4 100644 --- a/src/Modifier/IdFilter.php +++ b/src/Modifier/IdFilter.php @@ -2,8 +2,9 @@ namespace App\Modifier; -use App\Exception\InvalidOptionException; +use App\Exception\InvalidArgumentException; use App\Modifier\Modifier; +use App\Service\IterableUtils; class IdFilter implements Modifier { @@ -13,10 +14,10 @@ class IdFilter implements Modifier public function __construct($id) { if (!is_iterable($id) && !is_string($id)) { - throw InvalidOptionException::invalidType('id', $id, ['string', 'array']); + throw InvalidArgumentException::invalidType('id', $id, ['string', 'array']); } - $this->id = $id instanceof \Traversable ? iterator_to_array($id) : $id; + $this->id = is_iterable($id) ? IterableUtils::toArray($id) : $id; } public function getId() diff --git a/src/Modifier/RelatedFilter.php b/src/Modifier/RelatedFilter.php index f3e9038..3375880 100644 --- a/src/Modifier/RelatedFilter.php +++ b/src/Modifier/RelatedFilter.php @@ -2,17 +2,23 @@ namespace App\Modifier; +use App\Exception\InvalidArgumentException; use App\Model\Referable; +use App\Service\IterableUtils; class RelatedFilter implements Modifier { private $relationship; - private $object; + private $reference; - public function __construct(Referable $object, ?string $relation = null) + public function __construct($reference, ?string $relation = null) { - $this->object = $object; - $this->relationship = $relation ?: get_class($object); + if (!is_iterable($reference) && !$reference instanceof Referable) { + throw InvalidArgumentException::invalidType('object', $reference, [Referable::class, 'iterable']); + } + + $this->reference = is_iterable($reference) ? IterableUtils::toArray($reference) : $reference; + $this->relationship = $relation ?: get_class($reference); } public function getRelationship(): string @@ -20,8 +26,13 @@ class RelatedFilter implements Modifier return $this->relationship; } - public function getRelated(): Referable + public function getRelated() { - return $this->object; + return $this->reference; + } + + public function isMultiple() + { + return is_array($this->reference); } } diff --git a/src/Service/EntityReferenceFactory.php b/src/Service/EntityReferenceFactory.php index d68bcc0..6a5d5fd 100644 --- a/src/Service/EntityReferenceFactory.php +++ b/src/Service/EntityReferenceFactory.php @@ -6,11 +6,16 @@ use App\Entity\LineEntity; use App\Entity\ProviderEntity; use App\Entity\StopEntity; use App\Entity\TrackEntity; +use App\Exception\InvalidArgumentException; use App\Model\Line; use App\Model\Referable; use App\Model\Stop; use App\Model\Track; use Doctrine\ORM\EntityManagerInterface; +use Tightenco\Collect\Support\Collection; +use function Kadet\Functional\partial; +use function Kadet\Functional\ref; +use const Kadet\Functional\_; final class EntityReferenceFactory { @@ -29,7 +34,25 @@ final class EntityReferenceFactory $this->id = $id; } - public function create(Referable $object, ProviderEntity $provider) + public function create($object, ProviderEntity $provider) + { + switch (true) { + case $object instanceof Referable: + return $this->createEntityReference($object, $provider); + case is_array($object): + return array_map(partial(ref([$this, 'createEntityReference']), _, $provider), $object); + case $object instanceof Collection: + return $object->map(partial(ref([$this, 'createEntityReference']), _, $provider)); + default: + throw InvalidArgumentException::invalidType( + 'object', + $object, + [Referable::class, Collection::class, 'array'] + ); + } + } + + private function createEntityReference(Referable $object, ProviderEntity $provider) { $class = get_class($object);