Creating a one to many polymorphic relationship with doctrine

前端 未结 5 2575
猫巷女王i
猫巷女王i 2021-02-18 23:37

Let me start by outlining the scenario. I have a Note object that can be assigned to many different objects

  • A Book can have one or moreNot
5条回答
  •  不要未来只要你来
    2021-02-19 00:07

    Personally I wouldn't use a superclass here. Think there's more of a case for an interface that would be implemented by Book, Image and Address:

    interface iNotable
    {
        public function getNotes();
    }
    

    Here's Book as an example:

    class Book implements iNotable {
        /**
         * @OneToMany(targetEntity="Note", mappedBy="book")
         **/
        protected $notes;
    
        // ...        
    
        public function getNotes()
        {
            return $this->notes;
        }
    }
    

    Note then needs @ManyToOne relationships going the other way, only one of which will apply for each entity instance:

    class Note {
        /**
         * @ManyToOne(targetEntity="Book", inversedBy="notes")
         * @JoinColumn
         **/
        protected $book;
    
        /**
         * @ManyToOne(targetEntity="Image", inversedBy="notes")
         * @JoinColumn
         **/
        protected $image;
    
        /**
         * @ManyToOne(targetEntity="Address", inversedBy="notes")
         * @JoinColumn
         **/
        protected $address;
    
        // ...
    }
    

    If you don't like the multiple references to each notable class here you could use inheritance and have something like an AbstractNotable superclass using single table inheritance. Although this might seem tidier now, the reason I wouldn't recommend it is as your data model grows you may need to introduce similar patterns that could eventually make the inheritance tree become unmanageable.

    EDIT: It would also be useful to have Note validator to ensure data integrity by checking that exactly one of $book, $image or $address is set for each instance. Something like this:

    /**
     * @PrePersist @PreUpdate
     */
    public function validate()
    {
        $refCount = is_null($book) ? 0 : 1;
        $refCount += is_null($image) ? 0 : 1;
        $refCount += is_null($address) ? 0 : 1;
    
        if ($refCount != 1) {
            throw new ValidateException("Note references are not set correctly");
        }
    }
    

提交回复
热议问题