Symfony 4 + 奏鸣曲管理包 + 关系。表单正在删除子项,但不仅是 parentId

Posted

技术标签:

【中文标题】Symfony 4 + 奏鸣曲管理包 + 关系。表单正在删除子项,但不仅是 parentId【英文标题】:Symfony 4 + sonata admin bundle + relations. Form is deleting children but not only parentId 【发布时间】:2021-07-30 11:27:19 【问题描述】:

大家好!我遇到了一些问题。我有奏鸣曲管理员 + symfony 4 + 一些具有多面关系的实体。我有 3 个名为banner videobanner photobanner 的简单表格,现在我想创建管理部分,它将由 1 2 或 3 个简单的横幅视频横幅或 photobbanner 创建。它几乎完成了,但表格有一些错误。我可以创建简单的横幅,并且可以成功创建记录,但是 parentId 是空的,因为它现在没有任何父母,但是后来当我在管理员中设置时 parentId 正在子表中创建,但后来当我尝试删除关系奏鸣曲管理员用子记录删除它,但我希望奏鸣曲管理员只删除 parentId 子记录必须保留 parentId = NULL。

<?php

namespace App\Admin\Action\Banner;

use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Sonata\AdminBundle\Form\Type\ModelType;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use App\Cms\Entity\Banner\NestedBanner;
use App\Admin\Form\DataTransformer\BannerDataTransformer;
use App\Cms\Entity\Banner\Banner;

/**
 * 
 * Class NestedBannerAdmin.
 */
class NestedBannerAdmin extends AbstractAdmin

    /**
     * 
     * @param FormMapper $formMapper
     */
    protected function configureFormFields(FormMapper $formMapper)
    
        $formMapper->add('title', TextType::class);
        $formMapper->add('description', TextareaType::class);
        $formMapper->add('banners');
        $formMapper->add('photoBanners');
        $formMapper->add('videoBanners');
        $formMapper->add('promoBlockBanners');

//        $formMapper
//            ->get('banners')
//            ->addModelTransformer(new BannerDataTransformer($this->getSubject()));

    

    /**
     * 
     * @param DatagridMapper $datagridMapper
     */
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    
        $datagridMapper->add('title');
        $datagridMapper->add('description');
        $datagridMapper->add('banners');
        $datagridMapper->add('photoBanners');
        $datagridMapper->add('videoBanners');
        $datagridMapper->add('promoBlockBanners');
    

    /**
     * 
     * @param ListMapper $listMapper
     */
    protected function configureListFields(ListMapper $listMapper)
    
        $listMapper->addIdentifier('title');
        $listMapper->addIdentifier('description');
        $listMapper->add(
            'banners',
            null,
            [
                'label' => 'Banners',
                'sortable' => false,
                'allow_add' => false,
                'allow_delete' => false,
            ]
        );
        $listMapper->add(
            'photoBanners',
            null,
            [
                'label' => 'Photo banners',
                'sortable' => false,
                'allow_add' => true,
                'allow_delete' => false,
            ]
        );
        $listMapper->add(
            'videoBanners',
            null,
            [
                'label' => 'Video banners',
                'sortable' => false,
                'allow_add' => true,
                'allow_delete' => false,
            ]
        );
        $listMapper->add(
            'promoBlockBanners',
            null,
            [
                'label' => 'Promo block banners',
                'sortable' => false,
                'allow_add' => true,
                'allow_delete' => false,
            ]
        );
    
    
    public function preUpdate($object)
    
//        dd($object);
        if($object instanceof NestedBanner)
            foreach ($object->getBanners() as $banner) 
                $nestedBanner = $banner->getNestedBanner();
                if(null == $nestedBanner)
                    $banner->setNestedBanner($object);
                
            
            foreach ($object->getVideoBanners() as $banner) 
                $nestedBanner = $banner->getNestedBanner();
                if(null == $nestedBanner)
                    $banner->setNestedBanner($object);
                
            
            foreach ($object->getPhotoBanners() as $banner) 
                $nestedBanner = $banner->getNestedBanner();
                if(null == $nestedBanner)
                    $banner->setNestedBanner($object);
                
            
            foreach ($object->getPromoBlockBanners() as $banner) 
                $nestedBanner = $banner->getNestedBanner();
                if(null == $nestedBanner)
                    $banner->setNestedBanner($object);
                
            
        
    




<?php

namespace App\Cms\Entity\Banner;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use App\Cms\Entity\Banner\Banner;
use App\Cms\Entity\Banner\PhotoBanner;
use App\Cms\Entity\Banner\VideoBanner;
use App\Cms\Entity\Banner\PromoBlockBanner;

/**
 * 
 * @ORM\Entity(repositoryClass="App\Cms\Repository\Banner\NestedBannerRepository")
 * @ORM\Table(name="nested_banner")
 */
class NestedBanner 

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @ORM\Column(name="description", type="string", length=255)
     */
    private $description;
    
    /**
     * @var bannerMaps
     *
     * @ORM\OneToMany(
     *     targetEntity="App\Cms\Entity\Banner\Banner",
     *     mappedBy="nestedBanner",
     *     orphanRemoval=true,
     *     cascade="persist"
     * )
     *
     * @ORM\JoinColumn(onDelete="CASCADE")
     */
    private $banners;

    /**
     * @var bannerMaps
     *
     * @ORM\OneToMany(
     *     targetEntity="App\Cms\Entity\Banner\VideoBanner",
     *     mappedBy="nestedBanner",
     *     orphanRemoval=true,
     *     cascade="persist")
     *
     * @ORM\JoinColumn(onDelete="CASCADE")
     */
    private $videoBanners;

    /**
     * @var bannerMaps
     *
     * @ORM\OneToMany(
     *     targetEntity="App\Cms\Entity\Banner\PhotoBanner",
     *     mappedBy="nestedBanner",
     *     cascade="persist"),
     *     orphanRemoval=false
     *
     * @ORM\JoinColumn(onDelete="CASCADE")
     */
    private $photoBanners;

    /**
     * @var bannerMaps
     *
     * @ORM\OneToMany(
     *     targetEntity="App\Cms\Entity\Banner\PromoBlockBanner",
     *     mappedBy="nestedBanner",
     *     cascade="persist")
     *
     * @ORM\JoinColumn(onDelete="CASCADE")
     */
    private $promoBlockBanners;

    /**
     * 
     * @param type $id
     * @param type $title
     * @param type $description
     * @param Collection $bannerMaps
     */
    public function __construct() 
//        $this->banners = new ArrayCollection();
//        $this->videoBanners = new ArrayCollection();
//        $this->photoBanners = new ArrayCollection();
//        $this->promoBlockBanners = new ArrayCollection();
    

    /**
     * 
     * @return int
     */
    public function getId(): ?int 
    
        return $this->id;
    

    /**
     * 
     * @return string
     */
    public function getTitle(): ?string
    
        return $this->title;
    

    /**
     * 
     * @return string
     */
    public function getBanners(): ?Collection
    
        return $this->banners;
    

    /**
     * 
     * @return string
     */
    public function getVideoBanners(): ?Collection
    
        return $this->videoBanners;
    

    /**
     * 
     * @return string
     */
    public function getPhotoBanners(): ?Collection
    
        return $this->photoBanners;
    

    /**
     * 
     * @return string
     */
    public function getPromoBlockBanners(): ?Collection
    
        return $this->promoBlockBanners;
    

    /**
     * 
     * @return string
     */
    public function getDescription(): ?string
    
        return $this->description;
    

    /**
     * 
     * @param int $id
     */
    public function setId(int $id) 
    
        $this->id = $id;
    

    /**
     * 
     * @param string $title
     */
    public function setTitle(string $title) 
    
        $this->title = $title;
    

    /**
     * 
     * @param Collection $banners
     */
    public function addBanner(Banner $banner): self
    
        dd('addBanner');
        $this->banners[] = $banner;

        return $this;
    

    /**
     * 
     * @param Collection $banners
     */
    public function addBanners(Collection $banners): self
    
        dd('addBanners');
        $this->banners[] = $banner;

        return $this;
    

    /**
     * 
     * @param Collection $banners
     */
    public function setBanners(Collection $banners): self
    
        dd('setBanners');
        foreach($banners as $banner)
            $banner->setNestedBanner($this);
        
        $this->banners = $banners;
        
        return $this;
    

    /**
     * 
     * @param Collection $banners
     */
    public function removeBanner(Banner $banners): self
    
        dd('removeBanner');
        foreach($banners as $banner)
            $banner->setNestedBanner($this);
        
        $this->banners = $banners;
        
        return $this;
    

    /**
     * 
     * @param Collection $banners
     */
    public function banner(Banner $banners): self
    
        dd('Banner');
        foreach($banners as $banner)
            $banner->setNestedBanner($this);
        
        $this->banners = $banners;
        
        return $this;
    

    /**
     * 
     * @param Collection $videoBanners
     */
    public function setVideoBanners(Collection $videoBanners): self
    
        $this->videoBanners = $videoBanners;

        return $this;
    

    /**
     * 
     * @param Collection $photoBanners
     */
    public function setPhotoBanners(Collection $photoBanners): self
    
        $this->photoBanners = $photoBanners;
        
        return $this;
    

    /**
     * 
     * @param Collection $banners
     */
    public function setPromoBlockBanners(Collection $promoBlockBanners): self
    
        $this->promoBlockBanners = $promoBlockBanners;

        return $this;
    

    /**
     * 
     * @param string $description
     */
    public function setDescription(string $description) 
    
        $this->description = $description;
    

//    public function addBanner(Banner $banner): NestedBanner
//    
//        
//        dd($banner);
//        $this->banners->add($banner);
//
//        return $this;
//    
//
//    public function setBanner(Banner $banner): NestedBanner
//    
//        
//        dd($banner);
//        $this->banners->add($banner);
//
//        return $this;
//    

//    public function addPhotoBanner(PhotoBanner $photoBanner): NestedBanner
//    
//        $this->photoBanners->add($photoBanner);
//
//        return $this;
//    
//
//    public function addVideoBanner(VideoBanner $videoBanner): NestedBanner
//    
//        $this->videoBanners->add($videoBanner);
//
//        return $this;
//    
//
//    public function addPromoBlockBanner(PromoBlockBanner $promoBlockBanner): NestedBanner
//    
//        $this->promoBlockBanners->add($promoBlockBanner);
//
//        return $this;
//    

//    public function removeBanner(Banner $banner): NestedBanner
//    
//        $this->banners->removeElement($banner);
//
//        return $this;
//    
//
//    public function removePhotoBanner(PhotoBanner $photoBanner): NestedBanner
//    
//        $this->photoBanners->removeElement($photoBanner);
//
//        return $this;
//    
//
//    public function removeVideoBanner(VideoBanner $videoBanner): NestedBanner
//    
//        $this->videoBanners->removeElement($videoBanner);
//
//        return $this;
//    
//
//    public function removePromoBlockBanner(PromoBlockBanner $promoBlockBanner): NestedBanner
//    
//        $this->promoBlockBanners->removeElement($promoBlockBanner);
//
//        return $this;
//    
    
    public function remove($param)
        dd($param);
    





<?php

namespace App\Cms\Entity\Banner;

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\File;
use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use App\Cms\Entity\Banner\NestedBanner;

/**
 * 
 * @ORM\Entity(repositoryClass="App\Cms\Repository\Banner\BannerRepository")
 * @ORM\Table(name="banner")
 * @Vich\Uploadable()
 */
class Banner 

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @var File
     * @Vich\UploadableField(mapping="banner_background_image", fileNameProperty="backgroundImageName")
     * @Assert\Image(
     *     mimeTypes = "image/jpeg", "image/png", "image/svg+xml",
     *     mimeTypesMessage = "Дозволені тільки формати (jpg,png,svg)",
     *     maxSize = "2M",
     *     maxSizeMessage = "Максимальний розмір 2Mb"
     * )
     */
    private $backgroundImage;
    
    /**
     * @var string
     * @ORM\Column(type="string", nullable=true)
     */
    private $backgroundImageName;

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

    
    /**
     * @var $nestedBanner
     *
     * @ORM\ManyToOne(
     *     targetEntity="App\Cms\Entity\Banner\NestedBanner",
     *     inversedBy="banners")
     * 
     */
    private $nestedBanner;

    public function __construct() 
    
    

    /**
     * 
     * @return type
     */
    public function getId() 
    
        return $this->id;
    

    /**
     * 
     * @return type
     */
    public function getTitle(): ?string
    
        return $this->title;
    

    /**
     * 
     * @return type
     */
    public function getName(): ?string
    
        return $this->getBackgroundImageName();
    

    /**
     * 
     * @return type
     */
    public function getBackgroundImage(): ?File
    
        return $this->backgroundImage;
    

    /**
     * 
     * @return type
     */
    public function getBackgroundImageName() 
    
        return $this->backgroundImageName;
    

    /**
     * 
     * @return type
     */
    public function getLink() 
    
        return $this->link;
    
    
    /**
     * 
     * @return array
     */
    public function getNestedBanner(): ?NestedBanner 
    
        return $this->nestedBanner;
    

        /**
     * 
     * @param type $id
     */
    public function setId(int $id) 
    
        $this->id = $id;
    

    /**
     * 
     * @param string $title
     */
    public function setTitle(string $title) 
    
        $this->title = $title;
    

    /**
     * 
     * @param string $backgroundImage
     */
    public function setBackgroundImage(File $backgroundImage) 
    
        $this->backgroundImage = $backgroundImage;
        if(!$this->backgroundImageName)
            $this->backgroundImageName = $backgroundImage->getClientOriginalName();
        
    

    /**
     * 
     * @param string $backgroundImageName
     */
    public function setBackgroundImageName($backgroundImageName) 
    
        $this->backgroundImageName = $backgroundImageName;
    

    /**
     * 
     * @param string $link
     */
    public function setLink(string $link) 
    
        $this->link = $link;
    

    /**
     * 
     * @param NestedBanner $nestedBanner
     */
    public function setNestedBanner(NestedBanner $nestedBanner) 
    
        $this->nestedBanner = $nestedBanner;

        return $this;
    

        /**
     * @return string
     */
    public function __toString(): string
    
        return $this->title ?: '';
    

【问题讨论】:

【参考方案1】:

考虑看看奏鸣曲的saving hooks。

您似乎已经在使用preUpdate() 函数,并且可以利用preRemove() 函数来实现您正在寻找的内容。

您可能还必须从您的实体中删除 onDelete="CASCADE"

【讨论】:

是的,preUpdate 工作正常,但 preRemove - 不行。删除了 onDelete="CASCADE" 但现在当我试图从管理员中删除它时,表单不会保存关系更改。 在 preRemove 中,您是否尝试添加类似 $parent-&gt;getChildren(); 的内容,然后循环遍历它们并将每个子对象的父对象设置为 NULL?

以上是关于Symfony 4 + 奏鸣曲管理包 + 关系。表单正在删除子项,但不仅是 parentId的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 4 中的奏鸣曲媒体包模板

Sonata Bundle 之间的依赖关系

Symfony 2 Sonata 媒体包:在没有奏鸣曲管理员的情况下保存媒体文件图像

在 Symfony 4 中使用命令行生成管理员奏鸣曲

在 Sonata symfony 4 中创建管理员用户

无法使用 symfony 5 安装奏鸣曲管理员