Решение не заработает, тк поиск будет по полю родительской сущности
$qb->expr()->andX(
$qb->expr()->andX(
$qb->expr()->isInstanceOf('sub1', 'TargetClass'),
$qb->expr()->eq('sub1.sub1Field', $sub1FieldValue)
)
);
UPD2 (рекомендация): Не решать такие задачи через ORM, а делать просто SQL.
UPD1: решение без instanceOf().
Можно найти решение по красивее, но вот на коленке
- Код не идеальный, но работает, как вариант
- Можно выражения (равенство, <> и прочее тоже вынести на уровень передачи параметра)
- Или заменить на вида Expr\Andx(), что даст много гибкости
- Ну и проверок добавить
Сущности:
/**
* @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;
}
Repository:
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, [['meow' => 'meow2']], // тут точка расширения гибкости добавления условий, чтобы все не только eq() было
Dog::class, [['woof' => 'woof1']],
]);
$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);
}
}