Присоединяйтесь и фильтруйте данные в 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, это создаст много отдельных запросов к БД - для каждой строки.

0 ответов

Другие вопросы по тегам