Организация отношения один-ко-многим в Symfony2 с использованием ORM Doctrine
Думаю в начале нужно пару слов сказать об отношении один-ко-многим. В общем случае, это когда у одной записи в основной таблиц может быть несколько подчинённых в другой таблице. В моём случае имеет место быть следующее отношение:
В терминах Symfony2 / Doctrine, для каждой таблицы из базы данных создаётся своя сущность (а бывает, что и несколько разных сущностей). Класс Entity, для таблицы Customer он выглядит примерно так:
namespace QR1000\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use \Doctrine\Common\Collections\ArrayCollection as ArrayCollection;
/**
* QR1000\MainBundle\Entity\Customer
*
* @ORM\Table(name="customer")
* @ORM\Entity(repositoryClass="QR1000\MainBundle\StoreBundle\Repository\CustomerRepository")
*/
class Customer
{
/**
* @var integer $id
*
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
.
.
.
/**
* @ORM\OneToMany(targetEntity="CustomerInfo", mappedBy="customer", cascade={"all"}, orphanRemoval=true)
*/
protected $infoArray;
public function __construct()
{
$this->infoArray = new ArrayCollection();
.
.
.
}
.
.
.
/**
* Add infoArray
*
* @param QR1000\MainBundle\Entity\CustomerInfo $infoArray
*/
public function addCustomerInfo(\QR1000\MainBundle\Entity\CustomerInfo $infoArray)
{
$this->infoArray[] = $infoArray;
}
/**
* Get infoArray
*
* @return Doctrine\Common\Collections\Collection
*/
public function getInfoArray()
{
return $this->infoArray;
}
}
Как Вы возможно видите, тут требуемая связь уже описана, но детальнее об этом позже.
Также опишем сущность для customer_info:
namespace QR1000\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* QR1000\MainBundle\Entity\CustomerInfo
*
* @ORM\Table(name="customer_info")
* @ORM\Entity(repositoryClass="QR1000\MainBundle\StoreBundle\Repository\CustomerInfoRepository")
*/
class CustomerInfo
{
/**
* @var integer $id
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
.
.
.
/**
*
* @ORM\ManyToOne(targetEntity="Customer", inversedBy="infoArray")
* @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
protected $customer;
.
.
.
/**
* Set customer
*
* @param QR1000\MainBundle\Entity\Customer $customer
*/
public function setCustomer(\QR1000\MainBundle\Entity\Customer $customer)
{
$this->customer = $customer;
}
/**
* Get customer
*
* @return QR1000\MainBundle\Entity\Customer
*/
public function getCustomer()
{
return $this->customer;
}
}
Тут также уже всё описано.
Кстати, все геттеры/сеттеры не пишутся в ручную, а генерируются автоматически, с помощью одного из удобных консольных инструментов, а именно командой:
sudo php app/console doctrine:generate:entities QR1000
Теперь непосредственно к тому, как тут всё работает.
Для сущности Customer мы добавляем свойство infoArray, которое будет содержать массив элементов CustomerInfo. В его аннотации описан тип связи, условие и источник данных:
@ORM\OneToMany(targetEntity="CustomerInfo", mappedBy="customer", cascade={"all"}, orphanRemoval=true)
mappedBy — название класса содержащего 1-элемент, обратите внимание, название начинается с маленькой буквы..
cascade — тип действия при удалении родительского элемента. В данном случае будут автоматически удалены все дочерние.
В конструкторе для Customer добавляем строку:
$this->infoArray = new ArrayCollection();
для инициализации массива хранящего найденные описания.
Для сущности CustomerInfo связь с родительской сущностью описывается уже двумя строчками в аннотации:
@ORM\ManyToOne(targetEntity="Customer", inversedBy="infoArray")
@ORM\JoinColumn(name="customer_id", referencedColumnName="id")
inversedBy — название свойства родительского класса, в котором хранятся найденные экземпляры описаний.
name — имя поля описания, по которому находятся связанные объекты.
referencedColumnName — имя поля в родительской сущности, по которому находятся связанные объекты.
Вот собственно и всё, теперь, получив из ORM экземпляр сущности Customer:
$customer = $em -> getRepository( "QR1000MainBundle:Customer" )
-> findOneById( $customerID );
и передав его в шаблон:
$this -> render( "QR1000MainBundle::customer.html.twig", array( "customer" => $customer ) );
мы можем обращаться к его массиву infoArray с использованием такого синтаксиса:
{% for descr in customer.infoArray %}
А в РНР коде, это тоже свойство для Customer:
$descriptions = $customer -> getInfoArray();
foreach ( $descriptions as $descr ) {
...
}
Это конечно не полное руководство, но как обещано, описал только неочевидные моменты.
Надеюсь кому-нибудь пригодится.
Успешных проектов!