2014-09-07 2 views
3

У меня есть эта модель DB: single databaseOneToMany или OneToOne, я на правильном или неправильном пути?

Тогда я сделал это лицо (я просто оставить отношение части, так как другой не является актуальным по теме):

Orders.php

class Orders { 
    /** 
    * @ORM\ManyToOne(targetEntity="Person", inversedBy="orders") 
    * @ORM\JoinColumn(name="person_id", referencedColumnName="id") 
    * */ 
    protected $person; 

    public function setPerson(Person $person) 
    { 
     $this->person = $person; 
     return $this; 
    } 

    public function getPerson() 
    { 
     return $this->person; 
    } 

} 

Person.php

class Person { 
    /** 
    * @ORM\OneToMany(targetEntity="NaturalPerson", mappedBy="person") 
    * */ 
    private $naturals; 

    /** 
    * @ORM\OneToMany(targetEntity="LegalPerson", mappedBy="person") 
    * */ 
    private $legals; 

    /** 
    * @ORM\OneToMany(targetEntity="Orders", mappedBy="person") 
    * */ 
    private $orders; 

    public function __construct() 
    { 
     $this->naturals = new ArrayCollection(); 
     $this->legals = new ArrayCollection(); 
     $this->orders = new ArrayCollection(); 
    } 

    public function getNaturals() 
    { 
     return $this->naturals; 
    } 

    public function getLegals() 
    { 
     return $this->legals; 
    } 

    public function getOrders() 
    { 
     return $this->orders; 
    } 

} 

NaturalPerson.php

class NaturalPerson { 

    /** 
    * @ORM\Id 
    * @ORM\ManyToOne(targetEntity="Person", inversedBy="naturals") 
    * @ORM\JoinColumn(name="person_id", referencedColumnName="id") 
    */ 
    protected $person; 

    /** 
    * @ORM\Column(name="identification_type", type="ci_type", nullable=false) 
    * @DoctrineAssert\Enum(entity="Tanane\FrontendBundle\DBAL\Types\CIType") 
    */ 
    protected $identification_type; 

    /** 
    * @ORM\Column(name="ci", type="integer", nullable=false) 
    */ 
    protected $ci; 

    public function setPerson(Person $person) 
    { 
     $this->person = $person; 
     return $this; 
    } 

    public function getPerson() 
    { 
     return $this->person; 
    } 

    public function setIdentificationType($identification_type) 
    { 
     $this->identification_type = $identification_type; 
     return $this; 
    } 

    public function getIdentificationType() 
    { 
     return $this->identification_type; 
    } 

    public function setCI($ci) 
    { 
     $this->ci = $ci; 
     return $this; 
    } 

    public function getCI() 
    { 
     return $this->ci; 
    } 

} 

Я опустил LegalPerson, так как это в значительной степени так же, как NaturalPerson так вот проблема. Отображение выглядит хорошо, но как я могу получить связанные записи от Orders?

Идея это для каждого Orders мне нужно знать, к которой принадлежит Person тоже (Заказы), а также дополнительную информацию, хранящуюся на NaturalPerson или LegalPerson в зависимости от person.type.

Смотреть этот код:

public function getOrdersAction() 
{ 
    $response = array(); 
    $em = $this->getDoctrine()->getManager(); 

    $entities = $em->getRepository("FrontendBundle:Orders")->findAll(); 

    if (!$entities) 
    { 
     $response['message'] = "No se encontraron resultados"; 
    } 

    $orders = array(); 
    foreach ($entities as $entity) 
    { 

     $personType = $entity->getPerson()->getPersonType(); 

     $order = array(); 
     $order[] = $entity->getNickname(); 

     // Here I'm trying to access to `Naturals` methods from `Orders` 
     if ($personType == 1) 
     { 
      $order[] = $entity->getPerson()->getNaturals()[0]->getIdentificationType() . $entity->getPerson()->getNaturals()[0]->getCI(); 
     } 
     elseif ($personType == 2) 
     { 
      $order[] = $entity->getPerson()->getLegals()[0]->getIdentificationType() . $entity->getPerson()->getLegals()[0]->getRIF(); 
     } 

     $orders[] = $order; 
    } 

    $response['data'] = $orders; 
    return new JsonResponse($response); 
} 

Но я получаю эту ошибку:

Error: Call to a member function getIdentificationType() on a non-object in /var/www/html/tanane/src/Tanane/BackendBundle/Controller/OrderController.php line 115

Может быть, мое отображение является неправильным, так как я должен OneToOne между Person и NaturalPerson (и это звучит неправильно мою логику как показывает DER), или, может быть, нет, но тогда я не знаю, как получить связанные свойства только для одной записи, я прочитал документы here, а также в here, но они не говорили о thi или я этого не вижу, никаких советов? идеи? чаевые?

Попытка использовать Хранилище и DQL решить проблему

Я строй функции в Repository классе для выборки данных и не попасть сложно, как, видимо, моя проблема, так что я сделал это:

public function getOrders($person_type = 1) 
{ 
    $qb = $this->getEntityManager()->createQueryBuilder(); 

    $qb 
      ->select('ord.*, ps.*') 
      ->from("FrontendBundle:Orders", "ord") 
      ->join('FrontendBUndle:Person', 'ps', 'WITH', 'ps.id = ord.person_id') 
      ->orderBy('ord.created', 'DESC'); 

    if ($person_type == 1) 
    { 
     $qb 
       ->select('np.*') 
       ->join('FrontendBundle:NaturalPerson', 'np', 'WITH', 'ps.id = np.person'); // Join NaturalPerson table 
    } 
    elseif ($person_type == 2) 
    { 
     $qb 
       ->select('lp.*') 
       ->join('FrontendBundle:LegalPerson', 'lp', 'WITH', 'ps.id = lp.person'); // Join NaturalPerson table 
    } 

    return $qb->getQuery()->getResult(); 
} 

Я еще не проверял, так может быть, это будет не работает, но, если идея заключается в том, чтобы получить дополнительную информацию для обеих таблиц, то с помощью этой DQL я сделал, как я прохожу $person_type, который находится внутри Person Таблица?Это становится немного сложнее, по крайней мере для меня

Запуска необработанного запроса, чтобы увидеть, если столбцы являются NULL

Я строй этого простого запроса только для тестирования, если результаты NULL:

SELECT 
    ord.id, 
    ord.person_id as ord_person_id, 
    ord.nickname, 
    ps.id, 
    ps.description, 
    np.person_id as natural_person_id, 
    np.identification_type, 
    np.ci 
FROM 
    orders ord 
LEFT JOIN person ps ON ord.person_id = ps.id 
LEFT JOIN natural_person np ON np.person_id = ps.id 
WHERE 
    ps.person_type = 1; 

И это то, что запрос возвращает:

enter image description here

Так что не NULL столбцы в там

CRUD для создания новых заказов

// Set Person entity 
$entityPerson = new Person(); 
$person_type === 1 ? $entityPerson->setDescription($orders['nat']['person']['description']) : $entityPerson->setDescription($orders['leg']['person']['description']); 
$person_type === 1 ? $entityPerson->setContactPerson($orders['nat']['person']['contact_person']) : $entityPerson->setContactPerson($orders['leg']['person']['contact_person']); 
$entityPerson->setPersonType($person_type); 

$em->persist($entityPerson); 
$em->flush(); 

... 

if ($person_type === 1) 
{ 
    // Set NaturalPerson entity 
    $entityNatural = new NaturalPerson(); 
    $entityNatural->setIdentificationType($orders['nat']['identification_type']); 
    $entityNatural->setCI($orders['nat']['ci']); 

    $em->persist($entityNatural); 
    $em->flush(); 
} 
elseif ($person_type === 2) 
{ 
    // Set LegalPerson entity 
    $entityLegal = new LegalPerson(); 
    $entityLegal->setIdentificationType($orders['leg']['identification_type']); 
    $entityLegal->setRIF($orders['leg']['rif']); 

    $em->persist($entityLegal); 
    $em->flush(); 
} 
+0

Я думаю, 'Person' может быть либо' NaturalPerson' ИЛИ 'LegalPerson', верно? Или это может быть и то, и другое? – FyodorX

+0

Нет, это просто может быть одним из персонажей Естественным или является законным – ReynierPM

ответ

1

С LegalPerson и NaturalPerson являются специализациями Person я рекомендовал бы использовать то, что доктрина называет Class Table Inheritance (documentation).

Вы бы:

Person.php

/** 
* @ORM\Table(name="person") 
* @ORM\Entity 
* @ORM\InheritanceType("JOINED") 
* @ORM\DiscriminatorColumn(name="discr", type="string") 
* @ORM\DiscriminatorMap({ 
*  "natural" = "NaturalPerson", 
*  "legal" = "LegalPerson", 
* }) 
*/ 
class Person { 
    /** 
    * @ORM\OneToMany(targetEntity="Orders", mappedBy="person") 
    * */ 
    private $orders; 

    public function __construct() 
    { 
     $this->orders = new ArrayCollection(); 
    } 

    public function getOrders() 
    { 
     return $this->orders; 
    } 

} 

NaturalPerson.php

/** 
* @ORM\Table(name="natural_person") 
* @ORM\Entity 
*/ 
class NaturalPerson extends Person { 
    /** 
    * @ORM\Column(name="identification_type", type="ci_type", nullable=false) 
    * @DoctrineAssert\Enum(entity="Tanane\FrontendBundle\DBAL\Types\CIType") 
    */ 
    protected $identification_type; 

    /** 
    * @ORM\Column(name="ci", type="integer", nullable=false) 
    */ 
    protected $ci; 

    public function setIdentificationType($identification_type) 
    { 
     $this->identification_type = $identification_type; 
     return $this; 
    } 

    public function getIdentificationType() 
    { 
     return $this->identification_type; 
    } 

    public function setCI($ci) 
    { 
     $this->ci = $ci; 
     return $this; 
    } 

    public function getCI() 
    { 
     return $this->ci; 
    } 
} 

Order.php остается неизменным.

Как вы можете видеть, теперь оба NaturalPerson и LegalPerson удлиняют Person. Поскольку вы изменили определение сущностей, вам придется обновить схему базы данных.

Теперь в вашем Controller вы только должны сделать это:

foreach ($entities as $entity) 
{ 
    $person = $entity->getPerson(); 

    $order = array(); 
    $order[] = $entity->getNickname(); 

    if ($person instanceof NaturalPerson) 
    { 
     $order[] = $person->getIdentificationType() . $person->getCI(); 
    } 
    else // it has to be LegalPerson 
    { 
     $order[] = $person->getIdentificationType() . $person->getRIF(); 
    } 

    $orders[] = $order; 
} 

Не забудьте добавить use заявление для NaturalPerson!

Таким образом, вы работаете только с экземплярами NaturalPerson или LegalPerson. Я уверен, что вы можете еще больше улучшить это.

Наконец, вам придется изменить свой CRUD для этого. Вы больше не работаете с Person (на самом деле это должно быть abstract), поэтому теперь вам нужно обрабатывать CRUD для NaturalPerson и для LegalPerson отдельно. Каждый из них будет иметь свой Type, Controller, вид и т.д.

Ваш код будет выглядеть следующим образом:

if ($person_type === 1) 
{ 
    $entityPerson = new NaturalPerson(); 
    $entityPerson->setDescription($orders['nat']['person']['description']); 
    $entityPerson->setContactPerson($orders['nat']['person']['contact_person']); 
    $entityPerson->setIdentificationType($orders['nat']['identification_type']); 
    $entityPerson->setCI($orders['nat']['ci']); 

    $em->persist($entityPerson); 
    $em->flush(); 
} 
elseif ($person_type === 2) 
{ 
    $entityPerson = new LegalPerson(); 
    $entityPerson->setDescription($orders['leg']['person']['description']); 
    $entityPerson->setContactPerson($orders['leg']['person']['contact_person']); 
    $entityPerson->setIdentificationType($orders['leg']['identification_type']); 
    $entityPerson->setRIF($orders['leg']['rif']); 

    $em->persist($entityPerson); 
    $em->flush(); 
} 
+0

Мне нравится больше этого подхода и в глубине, если вы заметили мою модель, именно это я и пытаюсь сделать, используя наследование SQL класса Antipattern Class Inheritance. t знаю, что это было охвачено Doctrine, теперь я знаю, в любом случае я получаю эту ошибку: «SQLSTATE [42S22]: Столбец не найден: 1054 Неизвестный столбец« t0.discr »в« списке полей ». Мне нужно выполнить любую команду? Может быть, для обновления базы данных? – ReynierPM

+0

Да, вам нужно обновить схему базы данных. – FyodorX

+0

Хорошо, я обновил схему, но теперь, когда я пытаюсь вставить новую запись, я получил эту другую ошибку. SQLSTATE [23000]: Нарушение ограничения целостности: 1048 Столбец «discr» не может быть пустым. «Что я должен установить на этом поле? – ReynierPM

1

Может быть, проблема в другом. Вы можете забыть назначить NaturalPerson или LegalPerson объекту Person. Таким образом, вы должны проверить его перед вызовом getIdentificationType():

if($personType == 1){ 
    if(null !== $natural = $entity->getPerson()->getNaturals()[0]){ 
     $order[] = $natural->getIdentificationType() . $natural->getCI(); 
    } 
}elseif($personType == 2){ 
    if(null !== $legal = $entity->getPerson()->getLegals()[0]){ 
     $order[] = $legal->getIdentificationType() . $legal->getRIF(); 
    } 
} 
Смежные вопросы