Add support for multiple related objects filtering
This commit is contained in:
parent
45004444e6
commit
ee0cde0400
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
;
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user