奏鸣曲3:删除OneToMany关系中的实体不适用于'by_reference'=>假

时间:2017-08-23 17:15:24

标签: symfony doctrine-orm symfony-sonata sonata symfony-3.3

我一定错过了什么。我的相关实体是:

EducationalModule

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Table(name="educational_module")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\CourseUnitRepository")
 *
 * Class EducationalUnit
 */
class EducationalModule
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\EducationalUnitCategory", inversedBy="educationalUnits")
     * @ORM\JoinColumn(name="category", referencedColumnName="course")
     */
    private $category;

    /**
     * @var string
     *
     * @ORM\Column(type="string", nullable=false)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Course", mappedBy="module")
     */
    private $courses;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\EducationalUnit", mappedBy="module", cascade={"persist","remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"position" = "ASC"})
     * @Assert\Count(min="1", minMessage="Module has to have at least one unit.")
     * @Assert\Valid()
     */
    private $units;


    public function __construct()
    {
        $this->units = new ArrayCollection();
    }

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

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

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

    /**
     * @return string
     */
    public function getName() : ?string
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName(string $name)
    {
        $this->name = $name;
    }

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

    /**
     * @return Collection
     */
    public function getUnits()
    {
        return $this->units;
    }


    public function setUnits(Collection $units)
    {
        $this->units = new ArrayCollection();

        foreach ($units as $unit) {
            $this->addUnits($unit);
        }

        return $this;
    }


    public function addUnits(EducationalUnit $unit)
    {
        $unit->setModule($this);
        $this->units->add($unit);
    }

    /**
     * @param $unit string
     *
     * @return $this
     */
    public function removeUnits($unit)
    {
        $this->units->removeElement($unit);

        return $this;
    }
}

EducationalUnit

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Table(name="educational_unit")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\CourseUnitRepository")
 *
 * Class EducationalUnit
 */
class EducationalUnit
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\EducationalModule", inversedBy="units")
     */
    private $module;

    /**
     * @ORM\Column(type="string", length=255, nullable=false)
     */
    private $name;

    /**
     * @ORM\Column(type="integer", options={"default" : 0})
     */
    private $position = 0;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\EducationalUnitCategory", inversedBy="educationalUnits")
     * @ORM\JoinColumn(name="category", referencedColumnName="course")
     */
    private $category;

    /**
     * @var EducationalFile
     *
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\EducationalFile", cascade={"persist","remove"}, orphanRemoval=true)
     * @Assert\NotBlank()
     * @Assert\Valid()
     */
    private $file;

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

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

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


    public function setModule($module)
    {
        $this->module = $module;
    }

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

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

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

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName(string $name)
    {
        $this->name = $name;
    }

    /**
     * @return EducationalFile
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * @param EducationalFile $file
     */
    public function setFile($file)
    {
        $this->file = $file;
    }
}

我的管理实体:

EducationalModuleAdmin

namespace AppBundle\Admin;

use AppBundle\Entity\EducationalFile;
use AppBundle\Entity\EducationalModule;
use AppBundle\Entity\EducationalUnit;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;

/**
 * Class EducationalModuleAdmin
 */
class EducationalModuleAdmin extends AbstractAdmin
{
    protected function configureFormFields(FormMapper $formMapper)
    {

        $formMapper->add('name', 'text');
        $formMapper->add('units', 'sonata_type_collection', [
            'required' => true,
            'by_reference' => false, // Has to be false. Thanks to that, our children entities will receive a reference to the parent.
            'btn_add' => 'Add unit',
        ], [
            'edit' => 'inline',
            'inline' => 'table',
            'sortable' => 'position',
            'multiple' => true,
        ]);

    }

    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper->add('id');
        $datagridMapper->add('name');
    }

    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper->add('id');
        $listMapper->add('name');
        $listMapper->add('_action', 'actions', [
            'actions' => [
                'show' => [],
                'edit' => [],
                'delete' => [],
            ],
        ]);
    }
}

EducationalUnitAdmin

namespace AppBundle\Admin;

use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;

/**
 * Class EducationalUnitAdmin
 */
class EducationalUnitAdmin extends AbstractAdmin
{
    protected $parentAssociationMapping = 'module';

    protected function configureFormFields(FormMapper $formMapper)
    {
        $is_creation = !$this->id($this->getSubject());

        $formMapper->add('module', 'sonata_type_model_hidden', [
            'attr' => ['hidden' => true],
        ]);

        $formMapper->add('id', 'integer', [
            'disabled' => true,
        ]);

        $formMapper->add('name', 'text');


        $formMapper->add('file', 'sonata_type_admin', [
            'required' => $is_creation,
            'by_reference' => true,
        ], [
            'edit' => 'inline',
            //'inline' => 'table',
        ]);

        $formMapper->add('position', 'hidden', [
            'attr' => ['hidden' => true],
        ]);
    }

    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper->add('id');
    }

    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper->add('id');
    }
}

我正在修改我的EducationalModule实体,而且每个EducationalUnit旁边都有“删除”复选框(EducationalModule的子项)。选中复选框并更新EducationalModule后,系统会删除EducationalUnit

有趣的是,当我将EducationalModuleAdmin 'by_reference' => false更改为true然后删除作品(但还有另一个问题 - 创建的孩子没有引用父母)

我试图彻底调试它,我可以在进入Sonata ->persist()的{​​{1}}和->flush()之前确认实体已被修改,但由于某种原因,我在最终没有坚持孩子的数量。

1 个答案:

答案 0 :(得分:2)

尝试删除setUnits方法。如果设置了add/remove,Sonata应该找到by_reference => false方法。现在只有setUnits方法正在使用,在这种方法中,你只设置与条目的关系,而不是解除不存在的条目。

您还应将方法重命名为addUnitremoveUnit