Jadro007
Jadro007

Reputation: 125

Doctrine ORM - entity implements interface

I have following problem - in project, I have interface called TaggableInterface

interface TaggableInterface {
   public function addTag(TagInterface $tag);
   public function deleteTag(TagInterface $tag);
   public function getTags();
}

It is implemented by some entity classes.

Is there any good way in Doctrine that creates relations between those entites and tags? If Taggable wasn't interface but abstarct class, I would be able to solve it with entity inheritance..

Without Doctrine I would probably use Party/Accountability design pattern (http://martinfowler.com/apsupp/accountability.pdf).

Upvotes: 2

Views: 2899

Answers (2)

Jadro007
Jadro007

Reputation: 125

In the end I decided to use more complex solution that requires more code writing:

Each entity that implements Taggable, is connected one-to-one relationship to its taggable entity, that is many-to-many connected to TagEntity.

Class diagrams:

enter image description here


enter image description here

that creates this database: enter image description here


enter image description here

Upvotes: 1

Damian Polac
Damian Polac

Reputation: 934

If I understood properly: you want to create mapping and implementation for interface without using abstract class and repeating code.

PHP have traits. You can create trait with common implementation of interface. From experience I know that you can also add doctrine annotations mapping to trait and everything will work well.

Create TaggableTrait. It behave like class or interface. It reside in namespace and will be loaded by your autoloader if you add it with use.

namespace My\Namespace;

use Doctrine\ORM\Mapping as ORM;

trait TaggableTrait 
{

   /**
    * @ORM\ManyToMany(targetEntity="Some\Namespace\Entity\Tag")
    */
   protected $tags;

   public function addTag(TagInterface $tag)
   {
      $this->tags->add($tag);
   }

   public function removeTag(TagInterface $tag)
   {
      $this->tags->removeElement($tags);
   }

   public function deleteTag(TagInterface $tag)
   {
      $this->removeTag($tag);
   }

   public function getTags()
   {
      return $this->tags;
   }

}

And in your taggable entity:

namespace Some\Namespace\Entity;

use Some\Namespace\TaggableInterface;
use My\Namespace\TaggableTrait;
use Doctrine\ORM\Mapping as ORM;
//...

/**
 * @ORM\Entity
 */
class TaggableEntity implements TaggableInterface
{
   use TaggableTrait;

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

   // rest of class code
}

Note that use inside class have different meaning. It add trait and have nothing to do with namespace importing.

You must always initialize $tags in your constructor, trait cannot do that.

That way you can create only unidirectional association. If you want more customization, remove mapping from trait and add it to class.

Upvotes: 1

Related Questions