Версия (-ы) платформы API : 2.4.5
Описание
Пользовательская или ApiPlatform фильтрация вложенных ресурсов не работает в объекте с составным основнымключ
Как воспроизвести
Создайте объект A с составным ключом и добавьте отношение ManyToOne к объекту B. Создайте объект B с одним ключом id и другими полями. Создание настраиваемого фильтра или фильтра api-платформы в объекте A для поля из объекта B (может быть первичным ключом объекта B или нет)
Дополнительный контекст
Фильтрация работаеткогда у объекта A есть один ключ идентификатора.
Пример объектов * ENTITY A
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\NumericFilter;
use App\Filter\TipoSancionFilter;
/**
* AntecedentesOSanciones
*
* @ORM\Entity
* @ApiResource(
* normalizationContext={"groups"={"getCollectionAntecedentes"}},
* )
* @ApiFilter(SearchFilter::class , properties={"codTipoSancion.codTipoSancion":"exact", "codTipoSancion.nombreSancion":"exact"})
*/
class AntecedentesOSanciones
{
/**
* @var \PadronEscribanos
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="NONE")
* @ORM\ManyToOne(targetEntity="PadronEscribanos" , inversedBy="antecedentes")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="matricula", referencedColumnName="matricula")
* })
* @Groups({ "getCollectionAntecedentes"})
*/
private $matricula;
/**
* @var int
*
* @ORM\Column(name="renglon", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="NONE")
* @Groups({"getCollectionAntecedentes"})
*/
private $renglon;
/**
* @var \TiposSanciones
*
* @ORM\ManyToOne(targetEntity="TiposSanciones")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="cod_tipo_sancion", referencedColumnName="cod_tipo_sancion")
* })
* @Groups({"getCollectionAntecedentes"})
*/
private $codTipoSancion;
public function getRenglon(): ?int
{
return $this->renglon;
}
public function setRenglon($renglon): self
{
$this->renglon = $renglon;
return $this;
}
public function getCodTipoSancion(): ?TiposSanciones
{
return $this->codTipoSancion;
}
public function setCodTipoSancion(?TiposSanciones $codTipoSancion): self
{
$this->codTipoSancion = $codTipoSancion;
return $this;
}
public function getMatricula(): ?PadronEscribanos
{
return $this->matricula;
}
public function setMatricula(?PadronEscribanos $matricula): self
{
$this->matricula = $matricula;
return $this;
}
}
* ENTITY B
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* TiposSanciones
*
* @ORM\Entity
* @ApiResource
*/
class TiposSanciones
{
/**
* @var int
*
* @ORM\Column(name="cod_tipo_sancion", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @Groups({"getCollectionAntecedentes"})
*/
private $codTipoSancion;
/**
* @var string
*
* @ORM\Column(name="nombre_sancion", type="string", length=36, nullable=false)
* @Groups({"getCollectionAntecedentes"})
*/
private $nombreSancion;
public function getCodTipoSancion(): ?int
{
return $this->codTipoSancion;
}
public function getNombreSancion(): ?string
{
return $this->nombreSancion;
}
public function setNombreSancion(string $nombreSancion): self
{
$this->nombreSancion = $nombreSancion;
return $this;
}
}
** ОШИБКАВЫХОД * Пример get url: http://localhost:8282/api/antecedentes_o_sanciones?codTipoSancion.codTipoSancion=4
[
{
matricula:{
matricula:325,
nombres:"AIDEE MARIA DEL ROSARIO",
apellidos:"COSTAMAGNA"
},
renglon:1,
codTipoSancion:{
codTipoSancion:1,
nombreSancion:"SUSPENSIÓN "
}
},
{
matricula:{
matricula:325,
nombres:"AIDEE MARIA DEL ROSARIO",
apellidos:"COSTAMAGNA"
},
renglon:2,
codTipoSancion:{
codTipoSancion:1,
nombreSancion:"SUSPENSIÓN "
}
},
{
matricula:{
matricula:325,
nombres:"AIDEE MARIA DEL ROSARIO",
apellidos:"COSTAMAGNA"
},
renglon:3,
codTipoSancion:{
codTipoSancion:1,
nombreSancion:"SUSPENSIÓN "
}
},
{
matricula:{
matricula:325,
nombres:"AIDEE MARIA DEL ROSARIO",
apellidos:"COSTAMAGNA"
},
renglon:4,
codTipoSancion:{
codTipoSancion:4,
nombreSancion:"DESTITUCIÓN "
}
},
{
matricula:{
matricula:325,
nombres:"AIDEE MARIA DEL ROSARIO",
apellidos:"COSTAMAGNA"
},
renglon:5,
codTipoSancion:{
codTipoSancion:4,
nombreSancion:"DESTITUCIÓN "
}
},
{
matricula:{
matricula:570,
nombres:"MARCELO MIGUEL",
apellidos:"GILETTA"
},
renglon:1,
codTipoSancion:{
codTipoSancion:1,
nombreSancion:"SUSPENSIÓN "
}
},
{
matricula:{
matricula:570,
nombres:"MARCELO MIGUEL",
apellidos:"GILETTA"
},
renglon:2,
codTipoSancion:{
codTipoSancion:2,
nombreSancion:"SUSPENSIÓN PREVENTIVA "
}
},
{
matricula:{
matricula:570,
nombres:"MARCELO MIGUEL",
apellidos:"GILETTA"
},
renglon:3,
codTipoSancion:{
codTipoSancion:4,
nombreSancion:"DESTITUCIÓN "
}
},
{
matricula:{
matricula:652,
nombres:"MARIA COVADONGA SUSANA",
apellidos:"MARCUZZI"
},
renglon:1,
codTipoSancion:{
codTipoSancion:2,
nombreSancion:"SUSPENSIÓN PREVENTIVA "
}
},
{
matricula:{
matricula:652,
nombres:"MARIA COVADONGA SUSANA",
apellidos:"MARCUZZI"
},
renglon:2,
codTipoSancion: {
codTipoSancion: 1,
nombreSancion: " SUSPENSIÓN "
}
}
]
** ОЖИДАЕМЫЙ ВЫХОД * Пример get url: http://localhost:8282/api/antecedentes_o_sanciones?codTipoSancion.codTipoSancion=4
[
{
matricula:{
matricula:325,
nombres:"AIDEE MARIA DEL ROSARIO",
apellidos:"COSTAMAGNA"
},
renglon:4,
codTipoSancion:{
codTipoSancion:4,
nombreSancion:"DESTITUCIÓN "
}
},
{
matricula:{
matricula:325,
nombres:"AIDEE MARIA DEL ROSARIO",
apellidos:"COSTAMAGNA"
},
renglon:5,
codTipoSancion:{
codTipoSancion:4,
nombreSancion:"DESTITUCIÓN "
}
},
{
matricula:{
matricula:570,
nombres:"MARCELO MIGUEL",
apellidos:"GILETTA"
},
renglon:3,
codTipoSancion:{
codTipoSancion:4,
nombreSancion:"DESTITUCIÓN "
}
}
]
** SQL Doctrine выполняет:
SELECT
...
FROM
sec_antecedentes_o_sanciones s0_
LEFT JOIN sec_padron_escribanos s1_ ON s0_.matricula = s1_.matricula
LEFT JOIN sec_tipos_sanciones s2_ ON s0_.cod_tipo_sancion = s2_.cod_tipo_sancion
WHERE
s0_.matricula IN (
SELECT
s3_.matricula AS sclr_40
FROM
sec_antecedentes_o_sanciones s3_
LEFT JOIN sec_padron_escribanos s4_ ON s3_.matricula = s4_.matricula
LEFT JOIN sec_tipos_sanciones s5_ ON s3_.cod_tipo_sancion = s5_.cod_tipo_sancion
WHERE
s5_.cod_tipo_sancion = '4'
)
ORDER BY
s0_.matricula ASC,
s0_.renglon ASC
LIMIT
10
Как вы можете видеть, проблема в том, что предложение WHERE для sql select в строке, которую пишет api-platform: s0_.matricula IN .., чем, запрос доставляет мне все "antecedentes_o_sanciones", гдеучаствующая матрикула имеет, по крайней мере, один cod_tipo_sancion = 4. Когда я делаю этот тест с сущностями с первичными ключами single_id, фильтр работает отлично.