【问题标题】:How to define a OneToMany relation with multiple mappedBy columns and one of them has fixed value in doctrine 2 & symfony 4?如何定义具有多个 mappedBy 列的 OneToMany 关系,其中一个在学说 2 和 symfony 4 中具有固定值?
【发布时间】:2019-07-31 20:02:46
【问题描述】:

我正在使用 symfony 4 框架构建一个 CMS,其中您可能有页面或博客等内容模块...

每个模块都有一组内容块,即Page has a OneToMany relation with ContentBlockBlog has a OneToMany relation with ContentBlock

我对教义-orm 完全陌生。不过,我已经做了一个抽象的MappedSuperclass 类,命名为Content

/** @ORM\MappedSuperclass */
abstract class Content
{
    /**
     * @var Collection|ContentBlock[]
     * @ORM\OneToMany(targetEntity="App\Entity\ContentBlock", mappedBy="id") <- I need to add one more column with a defined value (entity type) which refers to entity name
     * @ORM\OrderBy({"sort"="ASC"})
     */
    protected $blocks;

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

    public function addBlock(ContentBlock $block): self
    {
        if (!$this->blocks->contains($block)) {
            $block->setEntityId($this->getId());
            $block->setEntity(self::class);
            $this->blocks[] = $block;
        }

        return $this;
    }

    public function removeBlock(ContentBlock $block): self
    {
        if (!$this->blocks->contains($block)) {
            $this->blocks->removeElement($block);
        }

        return $this;
    }

    /**
     * @return Collection|ContentBlock[]
     */
    public function getBlocks(): Collection
    {
        return $this->blocks;
    }

    public function getType(): string
    {
        return self::class;
    }
}

并使内容实体继承自它,如下所示:

/**
 * @ORM\Entity(repositoryClass="App\Repository\PageRepository")
 */
class Page extends Content
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @Assert\NotBlank
     * @ORM\Column(type="string", length=255, nullable=false)
     */
    private $title;
/**
 * @ORM\Entity(repositoryClass="App\Repository\BlogRepository")
 */
class Blog extends Content
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

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

这里是ContentBlock 实体:

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

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

    /**
     * @ORM\Column(type="integer")
     */
    private $entity_id;

    // more columns in addition for their setters and getters 

我需要知道的是如何定义ContentBlock 和其他实体之间的关系,其中ContentBlock::$entity_id 代表Content::$idContentBlock::$entity 代表博客"App\Entity\Blog""App\Entity\Page" 代表博客页面,换句话说“应该定义实体类型”。

【问题讨论】:

    标签: php symfony doctrine-orm one-to-many


    【解决方案1】:

    问题是我定义了错误的MappedSuperclass 类,它应该是相反的,所以ContentBlock 应该分成单独的子类,每个子类必须用与关系的其他实体相对应的固定值。含义:

    /**
     * @ORM\MappedSuperclass()
     */
    abstract class ContentBlock
    {
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue()
         * @ORM\Column(type="integer")
         */
        protected $id;
    
        // the other fields of each ContentBlock with setters an
    }
    

    这个抽象实体被用作不同块类型的父级,例如PageContent

    /**
     * @ORM\Entity(repositoryClass="App\Repository\PageContentRepository")
     * @ORM\Table(name="content")
     */
    class PageContent extends ContentBlock
    {
        /**
         * @ORM\ManyToOne(targetEntity="App\Entity\Page", inversedBy="blocks")
         * @ORM\JoinColumn(nullable=false)
         */
        private $entity;
    
        /**
         * @ORM\Column(type="string", length=255)
         */
        private $entity_type = Page::class; // <- The second column has a fixed value
    
        public function getEntity(): ?Page
        {
            return $this->entity;
        }
    
        public function setEntity(?Page $entity): self
        {
            $this->entity = $entity;
    
            return $this;
        }
    
        public function getEntityType(): ?string
        {
            return $this->entity_type;
        }
    
        public function setEntityType(string $entity_type): self
        {
            $this->entity_type = $entity_type;
    
            return $this;
        }
    }
    

    并且Page 实体与PageContent 实体具有OneToMany 关系:

    /**
     * @ORM\Entity(repositoryClass="App\Repository\PageRepository")
     */
    class Page
    {
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue()
         * @ORM\Column(type="integer")
         */
        private $id;
    
        /**
         * @ORM\OneToMany(targetEntity="App\Entity\PageContent", mappedBy="entity", orphanRemoval=true)
         */
        private $blocks;
    
        /**
         * @return Collection|PageContent[]
         */
        public function getBlocks(): Collection
        {
            return $this->blocks;
        }
    
        public function addBlock(PageContent $block): self
        {
            if (!$this->blocks->contains($block)) {
                $this->blocks[] = $block;
                $block->setEntity($this);
            }
    
            return $this;
        }
    
        public function removeBlock(PageContent $block): self
        {
            if ($this->blocks->contains($block)) {
                $this->blocks->removeElement($block);
                // set the owning side to null (unless already changed)
                if ($block->getEntity() === $this) {
                    $block->setEntity(null);
                }
            }
    
            return $this;
        }
    

    所以每个模块都有自己的实体类(PageBlog...)和内容实体类(PageContentBlogContent...),它有一个$entity属性(外键) 来定义与模块实体的关系,以及一个$entity_type,其值取决于模块实体的名称。

    或者您可以简单地为每个内容实体设置单独的表格,而无需 $entity_type,如果它更适合您的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多