Answer the question
In order to leave comments, you need to log in
Class Table Inheritance - Querying Inherited Classes on Inherited Entity Fields?
Good afternoon. The question may seem trivial. But there is no way to find the information accessible to the brain.
Created https://www.doctrine-project.org/projects/doctrine... tables .
Tell me where you can find documentation, but rather an example of how to filter by the fields of an Inherited entity using the createQueryBuilder method in the repository?
https://www.doctrine-project.org/projects/doctrine... documentation suggests using the createQuery method.
More precisely, how can you access the fields of the child table.
PS If you look at the generated SQL, then there is already a LEFT JOIN to the required table.
Answer the question
In order to leave comments, you need to log in
Via INSTANCE OF.
In queryBuilder it is in expressions.
$queryBuilder->expr()->isInstanceOf('alias', 'TargetClass')
The solution will not work, because the search will be by the field of the parent entity
$qb->expr()->andX(
$qb->expr()->andX(
$qb->expr()->isInstanceOf('sub1', 'TargetClass'),
$qb->expr()->eq('sub1.sub1Field', $sub1FieldValue)
)
);
UPD2 (recommendation): Do not solve such tasks through ORM, but just do SQL .
UPD1: Solution without instanceOf() .
You can find a more beautiful solution, but on your knee
/**
* @ORM\Entity
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="discr", type="string")
* @ORM\DiscriminatorMap({"cat" = "Cat", "dog" = "Dog"})
*
* @ORM\Entity(repositoryClass="AnimalRepository")
*/
class Animal
{
/**
* @ORM\Id
* @ORM\Column(type="integer", nullable=true)
* @ORM\GeneratedValue(strategy="AUTO")
*/
public ?string $id = null;
}
/** @ORM\Entity */
class Cat extends Animal
{
/**
* @ORM\Column(type="string")
*/
public $meow;
}
/** @ORM\Entity */
class Dog extends Animal
{
/**
* @ORM\Column(type="string")
*/
public $woof;
}
class AnimalRepository extends EntityRepository
{
/**
* @param array $filters
*
* @return \Generator<Animal::class>|Animal[]
*/
public function filter(array $filters): \Generator
{
foreach ($filters as $filter) {
[$entityClass, $conditions] = $filter;
if (!is_a($entityClass, Animal::class, true)) {
throw new \LogicException('Класс должен быть ребенком ' . Animal::class);
}
yield from $this->getSubEntities($entityClass, [$conditions]);
}
}
private function getSubEntities(string $subEntityClassName, array $conditions): \Generator
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('e')->from($subEntityClassName, 'e');
foreach ($conditions as $condition) {
[$param, $paramValue] = $condition;
$qb
->andWhere("e.$param = :$param")
->setParameter($param, $paramValue);
}
foreach ($qb->getQuery()->getResult() as $entity) {
yield $entity;
}
}
}
class AnimalRepositoryCest
{
/** @var EntityManagerInterface */
private $em;
public function _before(FunctionalTester $I): void
{
$this->em = $I->grabService('doctrine.orm.entity_manager');
}
public function testSuccessFilter(): void
{
$cat1 = new Cat();
$cat1->meow = 'meow1';
$cat2 = new Cat();
$cat2->meow = 'meow2';
$dog1 = new Dog();
$dog1->woof = 'woof1';
$dog2 = new Dog();
$dog2->woof = 'woof2';
$this->em->persist($cat1);
$this->em->persist($cat2);
$this->em->persist($dog1);
$this->em->persist($dog2);
$this->em->flush();
/** @var AnimalRepository $animalRepository */
$animalRepository = $this->em->getRepository(Animal::class);
assertInstanceOf(AnimalRepository::class, $animalRepository);
// этот код можно в репозитории сокрыть
$resultIter = $animalRepository->filter([
Cat::class, , // тут точка расширения гибкости добавления условий, чтобы все не только eq() было
Dog::class, ,
]);
$result = iterator_to_array($resultIter);
assertCount(2, $result);
assertInstanceOf(Cat::class, $result[0]);
assertSame('meow2', $result[0]->meow);
assertInstanceOf(Dog::class, $result[1]);
assertSame('woof1', $result[1]->woof);
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question