Итак, отношения 1: M / M: 1 не работают так, как работают отношения M: M (очевидно), но я думал, что при правильной конфигурации вы можете получить тот же результат, что и отношение M: M.
В принципе, мне нужно было добавить другое поле (позиция) в path_offer
.
Я думал, что $path->getOffers()
до тех пор, пока не $path->getOffers()
использовать $path->getOffers()
который возвратил PersistentCollection
вместо того, что, как я думал, принудительно ( ArrayCollection
of Offers). Во всяком случае, внутри текущей таблицы у меня две записи: два предложения по одному пути. $path->getOffers()
возвращает PathOffer
который имеет только одно Offer
а не оба.
Мой вопрос в том, как реально использовать эти типы отношений? Поскольку мне это нужно со многими другими аспектами этого проекта, над которым я работаю (многие коллекции M: M также должны быть расположены)
Мой код ниже!
[..] /** * @ORM\Entity * @ORM\Table(name="path") */ class Path { /** * @var integer * * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ protected $id; /** * @ORM\OneToMany(targetEntity="PathOffer", mappedBy="offer", cascade={"all"}) */ protected $offers; [..]
[..] /** * @ORM\Entity * @ORM\Table(name="path_offer") */ class PathOffer { /** * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ protected $id; /** * @ORM\ManyToOne(targetEntity="Path", inversedBy="offers", cascade={"all"}) */ protected $path; /** * @ORM\ManyToOne(targetEntity="Offer", inversedBy="offers", cascade={"all"}) */ protected $offer; /** * @ORM\Column(type="integer") */ protected $pos; [..]
[..] /** * @ORM\Entity * @ORM\Table(name="offer") */ class Offer { /** * @var integer * * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ protected $id; /** * @var \ZGoffers\MainBundle\Entity\PathOffer * * @ORM\OneToMany(targetEntity="PathOffer", mappedBy="path", cascade={"all"}) */ protected $paths; [..]
Я понял. Надеюсь, этот пост может помочь другим, кто так расстроен, как я!
<?php namespace JStout\MainBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="path") */ class Path { /** * @var integer * * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private $id; /** * @var \JStout\MainBundle\Entity\PathOffer * * @ORM\OneToMany(targetEntity="PathOffer", mappedBy="path", cascade={"all"}) * @ORM\OrderBy({"pos" = "ASC"}) */ private $offers; [...]
<?php namespace JStout\MainBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="path_offer") */ class PathOffer { /** * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private $id; /** * @ORM\ManyToOne(targetEntity="Path", inversedBy="offers", cascade={"all"}) */ private $path; /** * @ORM\ManyToOne(targetEntity="Offer", inversedBy="paths", cascade={"all"}) */ private $offer; /** * @ORM\Column(type="integer") */ private $pos; [...]
<?php namespace JStout\MainBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="offer") */ class Offer { /** * @var integer * * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private $id; /** * @var \JStout\MainBundle\Entity\PathOffer * * @ORM\OneToMany(targetEntity="PathOffer", mappedBy="offer", cascade={"all"}) */ private $paths; [...]
И для моей логики интерфейса:
<?php [...] /** * @Extra\Route("/path", name="admin_path") * @Extra\Route("/path/{id}/edit", name="admin_path_edit", requirements={"id" = "\d+"}) * @Extra\Template() */ public function pathAction($id = null) { $path = $this->_getObject('Path', $id); // this function either generates a new entity or grabs one from database depending on $id $form = $this->get('form.factory')->create(new Form\PathType(), $path); $formHandler = $this->get('form.handler')->create(new Form\PathHandler(), $form); // process form if ($formHandler->process()) { $this->get('session')->setFlash('notice', 'Successfully ' . ($this->_isEdit($path) ? 'edited' : 'added') . ' path!'); return $this->redirect($this->generateUrl('admin_path')); } return array( 'path' => $path, 'form' => $form->createView(), 'postUrl' => !$this->_isEdit($path) ? $this->generateUrl('admin_path') : $this->generateUrl('admin_path_edit', array('id' => $path->getId())), 'paths' => $this->_paginate('Path'), 'edit' => $this->_isEdit($path) ? true : false ); } [...]
<?php namespace JStout\MainBundle\Form; use Symfony\Component\Form\AbstractType, Symfony\Component\Form\FormBuilder; class PathType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder ->add('name') ->add('title') ->add('offers', 'collection', array( 'type' => new PathOfferType(), 'allow_add' => true, 'allow_delete' => true )) ->add('active'); } public function getDefaultOptions(array $options) { return array( 'data_class' => 'JStout\MainBundle\Entity\Path' ); } }
<?php namespace JStout\MainBundle\Form; use Symfony\Component\Form\AbstractType, Symfony\Component\Form\FormBuilder; class PathOfferType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder ->add('offer', 'entity', array( 'class' => 'JStout\MainBundle\Entity\Offer', 'query_builder' => function($repository) { return $repository->createQueryBuilder('o')->orderBy('o.name', 'ASC'); }, 'property' => 'name' )) ->add('pos', 'integer'); } public function getDefaultOptions(array $options) { return array( 'data_class' => 'JStout\MainBundle\Entity\PathOffer' ); } }
<?php namespace JStout\MainBundle\Form; use JStout\MainBundle\Component\Form\FormHandlerInterface, Symfony\Component\Form\Form, Symfony\Component\HttpFoundation\Request, Doctrine\ORM\EntityManager, JStout\MainBundle\Entity\Path; class PathHandler implements FormHandlerInterface { protected $form; protected $request; protected $entityManager; public function buildFormHandler(Form $form, Request $request, EntityManager $entityManager) { $this->form = $form; $this->request = $request; $this->entityManager = $entityManager; } public function process() { if ('POST' == $this->request->getMethod()) { // bind form data $this->form->bindRequest($this->request); // If form is valid if ($this->form->isValid() && ($path = $this->form->getData()) instanceOf Path) { // save offer to the database $this->entityManager->persist($path); foreach ($path->getOffers() as $offer) { $offer->setPath($path); $this->entityManager->persist($offer); } $this->entityManager->flush(); return true; } } return false; } }
Похоже, вы делаете все правильно. Не беспокойтесь о материалах PersistentCollection
/ ArrayCollection
– все, что имеет значение, это их коллекции.
$Path->getOffers()
действительно должен возвращать коллекцию PathOffers
, и каждый PathOffer
должен иметь предложение.
Поэтому он должен работать следующим образом:
//Output a all offers associated with a path, along with the position. $pathOffers = $path->getOffers(); foreach($pathOffers as $po){ echo $po->getOffer()->id . ' [' . $po->getPosition() . "]\n"; }
Я что-то упускаю?