Intereting Posts
CodeIgniter: set_value () или post () – что быстрее и что лучше всего хранить данные в базе данных Почему мой запрос ajax получает ответ 0? Как использовать wordwrap или иначе, чтобы разбить текст, чтобы он соответствовал ширине div Возврат нескольких строк с помощью MySqli и массивов Функция питания в php для вычисления 17 ^ 2147482999 Проверка подлинности HTTP с использованием проверки подлинности PHP Строка PHP заменит целое слово apache htaccess переписать url для удобства использования PHP mysqli – возвращает ассоциативный массив из подготовленного оператора Возможно ли получить количество понравившихся facebook для URL-адреса? как шифровать, а затем расшифровывать текст имени пользователя и пароля, используемых в файле класса базы данных Доктрина «Многие-ко-многим» – саморегуляция и взаимность php / mysql с несколькими запросами Важность секретного ключа сеанса в веб-среде Express Web Как оптимизировать время выполнения при вставке данных с помощью pdo?

OneToMany или 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); } 

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

Ошибка: вызов функции-члена getIdentificationType () для не-объекта в строке /var/www/html/tanane/src/Tanane/BackendBundle/Controller/OrderController.php 115

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

Попытка использовать репозитории и 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; 

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

введите описание изображения здесь

Таким образом, здесь нет столбцов 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(); } 

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

Вам придется:

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(); } 

Возможно, проблема в другом. Вы можете забыть назначить LegalPerson 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(); } }