Symfony 3 One To Many:如何在持续反侧添加逆侧

时间:2017-03-22 14:33:43

标签: symfony doctrine-orm

我有这些实体有一对多的关系:

freightOrder has many shipments

shipment has many shipmentLines

freightOrder实体如下所示:

<?php
namespace Fraktportalen\Bundle\ShipmentBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Expose;

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ExclusionPolicy("all")
 */
class FreightOrder
{
    /**
     * @Expose
     *
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @Expose
     *
     * @ORM\OneToMany(
     *     targetEntity="Fraktportalen\Bundle\ShipmentBundle\Entity\Shipment",
     *     mappedBy="freightOrder",
     *     cascade={"persist","remove"}
     * )
     */
    private $shipments;

    /**
     * @Expose
     *
     * @ORM\ManyToOne(targetEntity="Fraktportalen\Bundle\AccountBundle\Entity\Account")
     * @ORM\JoinColumn(name="freighter_id", referencedColumnName="id")
     */
    private $freighter;



    /**
     * Order constructor.
     */
    public function __construct()
    {
        $this->shipments = new ArrayCollection();
    }

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getShipments()
    {
        return $this->shipments;
    }

    /**
     * @param mixed $shipment
     */
    public function addShipment(Shipment $shipment)
    {
        $shipment->setFreightOrder($this);
        $this->shipments->add($shipment);
    }

    public function removeShipment(Shipment $shipment)
    {
        $this->shipments->removeElement($shipment);
    }

    /**
     * @return mixed
     */
    public function getFreighter()
    {
        return $this->freighter;
    }

    /**
     * @param mixed $freighter
     */
    public function setFreighter($freighter)
    {
        $this->freighter = $freighter;
    }
}

装运实体:

<?php
namespace Fraktportalen\Bundle\ShipmentBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Fraktportalen\Bundle\AccountBundle\Entity\Account;
use Fraktportalen\Bundle\AddressBundle\Entity\Address;
use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Expose;

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ExclusionPolicy("all")
 */
class Shipment
{
    /**
     * @Expose
     *
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @Expose
     *
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $pickup;

    /**
     * @Expose
     *
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $delivery;

    /**
     * @Expose
     *
     * @ORM\OneToMany(
     *     targetEntity="Fraktportalen\Bundle\ShipmentBundle\Entity\ShipmentLine",
     *     mappedBy="shipment",
     *     fetch="EAGER",
     *     cascade={"persist"}
     * )
     */
    private $shipmentLines;

    /**
     * @Expose
     *
     * @ORM\ManyToOne(targetEntity="Fraktportalen\Bundle\ShipmentBundle\Entity\FreightOrder", inversedBy="shipments")
     * @ORM\JoinColumn(name="freight_order_id", referencedColumnName="id", nullable=false)
     */
    private $freightOrder;

    /**
     * @Expose
     *
     * @ORM\ManyToOne(targetEntity="Fraktportalen\Bundle\AccountBundle\Entity\Account")
     * @ORM\JoinColumn(name="sender_id", referencedColumnName="id")
     */
    private $sender;

    /**
     * @Expose
     *
     * @ORM\ManyToOne(targetEntity="Fraktportalen\Bundle\AccountBundle\Entity\Account")
     * @ORM\JoinColumn(name="receiver_id", referencedColumnName="id")
     */
    private $receiver;



    /**
     * Shipment constructor.
     */
    public function __construct()
    {
        $this->shipmentLines = new ArrayCollection();
    }

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getFreightOrder() {
        return $this->freightOrder;
    }

    /**
     * @param mixed $freightOrder
     *
     * @return Shipment
     */
    public function setFreightOrder($freightOrder) {
        $this->freightOrder = $freightOrder;
        $freightOrder->addShipment($this);
        return $this;
    }

    /**
     * @return mixed
     */
    public function getPickup()
    {
        return $this->pickup;
    }

    /**
     * @param mixed $pickup
     */
    public function setPickup(\DateTime $pickup = null)
    {
        $this->pickup = $pickup;
    }

    /**
     * @return mixed
     */
    public function getDelivery()
    {
        return $this->delivery;
    }

    /**
     * @param mixed $delivery
     */
    public function setDelivery(\DateTime $delivery = null)
    {
        $this->delivery = $delivery;
    }

    /**
     * @return mixed
     */
    public function getShipmentLines()
    {
        return $this->shipmentLines;
    }

    /**
     * @param mixed $shipmentLine
     */
    public function addShipmentLine(ShipmentLine $shipmentLine)
    {
        $shipmentLine->setShipment($this);
        $this->shipmentLines->add($shipmentLine);
    }

    public function removeShipmentLine(ShipmentLine $shipmentLine)
    {
        $this->shipmentLines->removeElement($shipmentLine);
    }

    /**
     * @return mixed
     */
    public function getSender()
    {
        return $this->sender;
    }

    /**
     * @param mixed $sender
     */
    public function setSender(Account $sender)
    {
        $this->sender = $sender;
    }

    /**
     * @return mixed
     */
    public function getReceiver()
    {
        return $this->receiver;
    }

    /**
     * @param mixed $receiver
     */
    public function setReceiver(Account $receiver)
    {
        $this->receiver = $receiver;
    }
}

FreightOrderType next:

<?php
namespace Fraktportalen\Bundle\ShipmentBundle\Form;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class FreightOrderType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('freighter', EntityType::class, array(
                'class' => 'AccountBundle:Account',
            ))
            ->add('shipments', CollectionType::class, array(
                'entry_type' => ShipmentType::class,
                'allow_add' => true
            ))
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Fraktportalen\Bundle\ShipmentBundle\Entity\FreightOrder',
            'csrf_protection' => false
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'freightOrder';
    }
}

从Ember应用程序保存货运单时,会发送此json:

{
    "freightOrder": {
        "freighter": "3",
        "shipments": [{
            "pickup": "2017-03-22 12:32:00",
            "delivery": "2017-03-23 12:32:00",
            "sender": "1",
            "receiver": "2",
            "shipment_lines": [{
                "package_weight": 45,
                "package_length": 240,
                "package_width": 120,
                "package_height": 240,
                "package_type": "3"
            }]
        }]
    }
}

除了不保存货件上的cargoOrder外,一切都按预期工作。即使我将它添加到freightOrder实体addShipment函数:

/**
 * @param mixed $shipment
 */
public function addShipment(Shipment $shipment)
{
    $shipment->setFreightOrder($this);
    $this->shipments->add($shipment);
}

正如您在货运实体中看到的那样,我甚至尝试将货件添加到货运单。但没有任何作用。

虽然发货线路也会被添加到货件中,这也是一对多的关系。

我是否必须向freightOrderType添加表单事件侦听器并手动将freightOrder添加到所有货件?我的印象是,在向FreightOrder添加所述货件时将货运单添加到货件中会解决它。至少这是我在搜索SO时发现的。

谢谢你的时间, 托米

1 个答案:

答案 0 :(得分:3)

我感觉到你的痛苦,我经常与这个问题作斗争。

这听起来像是没有被召集的人。您有时可以通过将by_reference声明为false来解决此问题。

试试这个..

    $builder
        ->add('freighter', EntityType::class, array(
            'class' => 'AccountBundle:Account',
        ))
        ->add('shipments', CollectionType::class, array(
            'entry_type' => ShipmentType::class,
            'allow_add' => true,
            'by_reference' => false,
        ))
    ;

阅读文档:

  

同样,如果您正在使用CollectionType字段,其中您的基础集合数据是一个对象(如与Doctrine的ArrayCollection一样),那么如果您需要加法器和移除器,则必须将by_reference设置为false(例如,要调用的addAuthor()和removeAuthor())。

就我个人而言,我仍然认为by_reference对于他们曾经犯过的错误是一种骇人听闻的修复方法。我想我们永远不会知道..