Doctrine2 отношения один-ко-многим / многие-к-одному - PullRequest
7 голосов
/ 29 июня 2011

Итак, отношения 1: M / M: 1 не работают так, как работают отношения M: M (очевидно), но я подумал, что при правильной конфигурации вы можете получить тот же результат, что и отношение M: M.

По сути, мне нужно было добавить еще одно поле (позицию) к path_offer.

Я думал, что заставил его работать, пока не попытался использовать $path->getOffers(), который вместо этого возвращал PersistentCollectionиз того, что я думал, является вынужденным (ArrayCollection предложений).Во всяком случае, внутри текущей таблицы у меня есть две записи: два предложения на один путь.$path->getOffers() возвращает PersistantCollection из PathOffer, который имеет только один Offer подключенный, а не оба.

Мой вопрос: как реально использовать эти типы отношений?Поскольку мне это нужно со многими другими аспектами этого проекта, над которым я работаю (многие коллекции M: M также должны быть расположены)

Мой код ниже!

Path.php

[..]

/**
 * @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;

[..]

PathOffer.php

[..]

/**
 * @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;

[..]

Offer.php

[..]

/**
 * @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;

[..]

Ответы [ 2 ]

4 голосов
/ 29 июня 2011

Я понял это. Надеюсь, этот пост поможет другим, кто разочаровался так же, как и я!

path.php

<?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;

    [...]

PathOffer.php

<?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;

    [...]

Offer.php

<?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;

    [...]

И для моей логики внешнего интерфейса:

PathController.php

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

    [...]

PathType.php (форма пути)

<?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'
        );
    }
}

PathOfferType.php (тип коллекции предложений PathType)

<?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'
        );
    }
}

PathHandler.php (как я обрабатываю форму)

<?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;
    }
}
2 голосов
/ 29 июня 2011

Похоже, вы делаете все правильно. Не беспокойтесь о вещах 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";
} 

Я что-то упустил?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...