教义2 一对多/多对一关系


Doctrine2 One-To-Many / Many-To-One relations

所以,1:M/M:1 关系不像 M:M 关系

的工作方式那样工作(显然(,但我认为通过正确的配置,您可以获得与 M:M 关系相同的输出。

基本上,我需要添加另一个字段(位置(来path_offer.

以为我让它工作,直到我尝试使用返回PersistentCollection而不是我认为是强制的$path->getOffers()(ArrayCollection报价(。 无论如何,在当前表中,我有两个条目:一条路径的两个报价。 $path->getOffers()返回的PathOffer PersistantCollection,该仅附加了一个Offer,而不是同时附加了两个。

我的问题是如何真正使用这些类型的关系? 因为我需要它与我正在处理的这个项目的许多其他方面(许多 M:M 集合也需要定位(

我的代码在下面!

路径.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;
[..]

路径报价.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;
[..]

报价.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;
[..]

我想通了。 希望这篇文章可以帮助像我一样沮丧的人!

路径.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;
    [...]

路径报价.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;
    [...]

报价.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;
    [...]

对于我的前端逻辑:

路径控制器.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
        );
    }
    [...]

路径类型.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 的 offer 集合类型(

<?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(我如何处理表单(

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

我错过了什么吗?