#35 - Add support for multiple related objects filtering
This commit is contained in:
parent
e8a31f60d1
commit
7fa5124577
@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use function App\Functions\encapsulate;
|
use function App\Functions\encapsulate;
|
||||||
|
use function Kadet\Functional\ref;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tracks")
|
* @Route("/tracks")
|
||||||
@ -51,17 +52,17 @@ class TracksController extends Controller
|
|||||||
private function getModifiersFromRequest(Request $request)
|
private function getModifiersFromRequest(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->query->has('stop')) {
|
if ($request->query->has('stop')) {
|
||||||
$stop = $request->query->get('stop');
|
$stop = encapsulate($request->query->get('stop'));
|
||||||
$stop = Stop::reference($stop);
|
$stop = collect($stop)->map([Stop::class, 'reference']);
|
||||||
|
|
||||||
yield new RelatedFilter($stop);
|
yield new RelatedFilter($stop, Stop::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->query->has('line')) {
|
if ($request->query->has('line')) {
|
||||||
$line = $request->query->get('line');
|
$line = encapsulate($request->query->get('line'));
|
||||||
$line = Line::reference($line);
|
$line = collect($line)->map([Line::class, 'reference']);
|
||||||
|
|
||||||
yield new RelatedFilter($line);
|
yield new RelatedFilter($line, Line::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->query->has('id')) {
|
if ($request->query->has('id')) {
|
||||||
@ -74,8 +75,8 @@ class TracksController extends Controller
|
|||||||
private function getStopsModifiersFromRequest(Request $request)
|
private function getStopsModifiersFromRequest(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->query->has('stop')) {
|
if ($request->query->has('stop')) {
|
||||||
$stop = $request->query->get('stop');
|
$stop = encapsulate($request->query->get('stop'));
|
||||||
$stop = Stop::reference($stop);
|
$stop = collect($stop)->map(ref([Stop::class, 'reference']));
|
||||||
|
|
||||||
yield new RelatedFilter($stop);
|
yield new RelatedFilter($stop);
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Exception;
|
namespace App\Exception;
|
||||||
|
|
||||||
class InvalidOptionException extends \InvalidArgumentException
|
class InvalidArgumentException extends \InvalidArgumentException
|
||||||
{
|
{
|
||||||
public static function invalidType($parameter, $value, array $expected = [])
|
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))
|
sprintf('Expected %s to be of type: %s. %s given.', $parameter, implode(', ', $expected), gettype($value))
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -85,7 +85,7 @@ class RelatedFilterDatabaseGenericHandler implements ModifierHandler, ServiceSub
|
|||||||
|
|
||||||
$builder
|
$builder
|
||||||
->join(sprintf('%s.%s', $alias, $relationship), $relationship)
|
->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);
|
->setParameter($parameter, $reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,11 @@ class TrackByStopDatabaseHandler implements ModifierHandler
|
|||||||
$parameter = sprintf(":%s_%s", $alias, $relationship);
|
$parameter = sprintf(":%s_%s", $alias, $relationship);
|
||||||
$reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']);
|
$reference = $this->references->create($modifier->getRelated(), $event->getMeta()['provider']);
|
||||||
|
|
||||||
|
$condition = $modifier->isMultiple() ? 'stop_in_track.stop IN (%s)' : 'stop_in_track.stop = %s';
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->join(sprintf("%s.%s", $alias, $relationship), 'stop_in_track')
|
->join(sprintf("%s.%s", $alias, $relationship), 'stop_in_track')
|
||||||
->andWhere(sprintf("stop_in_track.stop = %s", $parameter))
|
->andWhere(sprintf($condition, $parameter))
|
||||||
->setParameter($parameter, $reference)
|
->setParameter($parameter, $reference)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Modifier;
|
namespace App\Modifier;
|
||||||
|
|
||||||
use App\Exception\InvalidOptionException;
|
use App\Exception\InvalidArgumentException;
|
||||||
use App\Modifier\Modifier;
|
use App\Modifier\Modifier;
|
||||||
|
use App\Service\IterableUtils;
|
||||||
|
|
||||||
class IdFilter implements Modifier
|
class IdFilter implements Modifier
|
||||||
{
|
{
|
||||||
@ -13,10 +14,10 @@ class IdFilter implements Modifier
|
|||||||
public function __construct($id)
|
public function __construct($id)
|
||||||
{
|
{
|
||||||
if (!is_iterable($id) && !is_string($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()
|
public function getId()
|
||||||
|
@ -2,17 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Modifier;
|
namespace App\Modifier;
|
||||||
|
|
||||||
|
use App\Exception\InvalidArgumentException;
|
||||||
use App\Model\Referable;
|
use App\Model\Referable;
|
||||||
|
use App\Service\IterableUtils;
|
||||||
|
|
||||||
class RelatedFilter implements Modifier
|
class RelatedFilter implements Modifier
|
||||||
{
|
{
|
||||||
private $relationship;
|
private $relationship;
|
||||||
private $object;
|
private $reference;
|
||||||
|
|
||||||
public function __construct(Referable $object, ?string $relation = null)
|
public function __construct($reference, ?string $relation = null)
|
||||||
{
|
{
|
||||||
$this->object = $object;
|
if (!is_iterable($reference) && !$reference instanceof Referable) {
|
||||||
$this->relationship = $relation ?: get_class($object);
|
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
|
public function getRelationship(): string
|
||||||
@ -20,8 +26,13 @@ class RelatedFilter implements Modifier
|
|||||||
return $this->relationship;
|
return $this->relationship;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRelated(): Referable
|
public function getRelated()
|
||||||
{
|
{
|
||||||
return $this->object;
|
return $this->reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isMultiple()
|
||||||
|
{
|
||||||
|
return is_array($this->reference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,16 @@ use App\Entity\LineEntity;
|
|||||||
use App\Entity\ProviderEntity;
|
use App\Entity\ProviderEntity;
|
||||||
use App\Entity\StopEntity;
|
use App\Entity\StopEntity;
|
||||||
use App\Entity\TrackEntity;
|
use App\Entity\TrackEntity;
|
||||||
|
use App\Exception\InvalidArgumentException;
|
||||||
use App\Model\Line;
|
use App\Model\Line;
|
||||||
use App\Model\Referable;
|
use App\Model\Referable;
|
||||||
use App\Model\Stop;
|
use App\Model\Stop;
|
||||||
use App\Model\Track;
|
use App\Model\Track;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
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
|
final class EntityReferenceFactory
|
||||||
{
|
{
|
||||||
@ -29,7 +34,25 @@ final class EntityReferenceFactory
|
|||||||
$this->id = $id;
|
$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);
|
$class = get_class($object);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user