Присоединяйтесь и фильтруйте данные в Doctrine для Symfony4
Я хочу использовать Symfony с Doctrine ORM для создания веб-приложения для управления летним лагерем. У меня есть люди и отношения между ними:
Робин Гуд (Отец) - (Сын) Питер Пэн
Для каждого человека (скажем, Робин Гуда) я хочу показать список с соответствующими лицами (в данном случае: сын - Питер Пэн)
Если бы я выбрал Питера Пэна, я бы хотел получить: Отец - Робин Гуд. Очевидно, у Питера может быть Сестра, или у Робина может быть Жена (может, Мэйд Мэриан?!)
Сущность (сокращенная) для Персона [Робин Гуд / Питер Пэн] выглядит следующим образом:
// /src/Entity/Person.php
class Person
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var string
* @ORM\Column(type="string", length=100)
*/
private $name;
/**
* One Person has Many Relationships.
* @ORM\OneToMany(targetEntity="Relationship", mappedBy="linkFrom")
*/
private $relationshipsFrom;
/**
* One Person has Many Relationships.
* @ORM\OneToMany(targetEntity="Relationship", mappedBy="linkTo")
*/
private $relationshipsTo;
}
Сущность (закороченная) для Отношения выглядит так:
// /src/Entity/Relationship.php
class Relationship
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* Many Persons have One Person.
* @var Person
* @ORM\ManyToOne(targetEntity="Person", inversedBy="relationshipsFrom")
* @ORM\JoinColumn(name="linkfrom_id", referencedColumnName="id")
*/
private $linkFrom;
/**
* Many Persons have One Person.
* @var Person
* @ORM\ManyToOne(targetEntity="Person", inversedBy="relationshipsTo")
* @ORM\JoinColumn(name="linkto_id", referencedColumnName="id")
*/
private $linkTo;
/**
* Many Relationships have One RelationshipLink.
* @var RelationshipLink
* @ORM\ManyToOne(targetEntity="RelationshipLink")
* @ORM\JoinColumn(name="link_id", referencedColumnName="id")
*/
private $link;
}
Сущность (закороченная) для RelationshipLink выглядит следующим образом:
// /src/Entity/RelationshipLink.php
class RelationshipLink
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* Stores the general name for the relation
* @ORM\Column(type="string", length=100)
*/
private $name;
/**
* A relation could be reversed: uncle <-> nephew. The reversed relation
* is stored in here.
* One RelationLink has One RelationLink.
* @ORM\OneToOne(targetEntity="RelationshipLink")
* @ORM\JoinColumn(name="inverse_id", referencedColumnName="id")
*/
private $inverse;
/**
* One relation could have different gendered descriptions: wife <-> husband
* One RelationLink has Many RelationshipLinkContexts.
* @ORM\OneToMany(targetEntity="RelationshipLinkContext", mappedBy="link", cascade={"persist"})
*/
private $relationshipLinkContexts;
И, наконец, сущность (закороченная) для RelationshipLinkContexts выглядит следующим образом:
// /src/Entity/RelationshipLinkContext.php
class RelationshipLinkContext
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
*
* Many RelationshipLinkContexts have One RelationshipLink.
* @var RelationshipLink
* @ORM\ManyToOne(targetEntity="RelationshipLink", inversedBy="relationshipLinkContexts")
* @ORM\JoinColumn(name="link_id", referencedColumnName="id")
*/
private $link;
/**
* Gender of this affinity
* @var Gender
* Many RelationshipLinkContexts have One Gender.
* @ORM\ManyToOne(targetEntity="Gender")
* @ORM\JoinColumn(name="gender_id", referencedColumnName="id")
*/
private $gender;
/**
* Name of this addinity: eg. Son, Father, Sister, Daughter, Wife...
* @var string
* @ORM\Column(type="string", length=100)
*/
private $affinity;
Таблицы базы данных могут выглядеть так:
table: person
id name
---------- ------------
2 Robin Hood
3 Peter Pan
table: relationship
id linkfrom_id linkto_id link_id
---------- ----------- ---------- ----------
1 2 3 7
3 3 2 8
table: relationship_link
id inverse_id name
---------- ---------- -------------
5 5 marriage
7 8 parent
8 7 child
9 9 siblings
table: relationship_link_context
id link_id gender_id affinity
---------- ---------- ---------- -----------
9 5 1 husband
10 5 2 wife
13 7 1 father
14 7 2 mother
15 8 1 son
16 8 2 doughter
17 9 1 brother
18 9 2 sister
Я попытался создать функцию в PersonRepository:
public function findAllRelatedTo(Person $person)
{
$qb = $this->createQueryBuilder('p')
->innerJoin('p.relationshipsTo', 'r')
->innerJoin('r.link', 'rl')
->innerJoin('rl.relationshipLinkContexts', 'rlc')
->addSelect('g')
->addSelect('r')
->addSelect('rl')
->addSelect('rlc')
->where('r.linkFrom = :from')
->setParameter('from', $person->getId())
//->setParameter('gender', $person->getGender()->getId())
->getQuery();
return $qb->execute();
}
Это не работает!
Как я могу получить правильную информацию из таблицы Relations_link_context:affinity, основанной на отношениях между данным человеком и всеми связанными и основанными на поле?
На самом деле, я хочу использовать об этом запросе SQL:
SELECT person.id, person.name, relationship_link_context.id, relationship_link_context.affinity FROM person
JOIN relationship ON person.id = relationship.linkfrom_id
JOIN relationship_link ON relationship.link_id = relationship_link.id
JOIN relationship_link_context ON relationship_link.id = relationship_link_context.link_id
where relationship_link_context.gender_id = person.gender_id and relationship.linkto_id = 2;
id name id affinity
---------- ---------- ---------- ----------
3 Peter Pan 15 son
Как мне вернуть его в контроллер для его рендеринга? Прямо сейчас функция выглядит так:
/**
* Finds and displays a Person entity.
*
* @Route("/{id}/relationship", requirements={"id": "\d+"}, name="admin_person_show_relationship")
* @Method("GET")
*
* @param Person $person
* @param PersonRepository $persons
* @return Response
*/
public function show_relationship(Person $person, PersonRepository $persons): Response
{
// ... security stuff ... //
$related = $persons->findAllRelatedTo($person);
return $this->render('admin/person/show_relationship.html.twig', [
'person' => $person,
'relationship' => $related,
]);
}
Я не хочу создавать функцию отложенной загрузки в Person, это создаст много отдельных запросов к БД - для каждой строки.