Using Symfony 4 / Doctrine 2.6. I have two entities Post and Comment. I want both to be taggable. So I create an entity Tag. I use Doctrine's class table inheritance to create the relationship:
/**
* @ORM\Entity(repositoryClass="App\Repository\TagRepository")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="type", type="string")
* @ORM\DiscriminatorMap({"post" = "PostTag", "comment" = "CommentTag"})
*/
abstract class Tag
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
// Getters and setters...
}
/** @ORM\Entity */
class PostTag extends Tag
{
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Post", inversedBy="tags")
*/
private $post;
public function getPost(): ?Post
{
return $this->post;
}
}
/** @ORM\Entity */
class CommentTag extends Tag
{
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Comment", inversedBy="comments")
*/
private $comment;
public function getComment(): ?Comment
{
return $this->comment;
}
}
This creates 3 tables: tag
, post_tag
, and comment_tag
. The post_tag
table structure looks like this:
id | post_id
The tag
table structure looks like this:
id | title | type
How are e.g. posts and tags associated? If I want to associate post 13
with tag test
, would the result be this:
post_tag
table:
id | post_id
------------
1 | 13
tag
table:
id | title | type
-----------------
1 | test | post
?
If so, then what if I want to associate the same tag (test
) with a comment. Would the tag
table then look like this?
id | title | type
--------------------
1 | test | post
2 | test | comment
That seems a bit redundant. The same entity (the test
tag) is then represented by 2 rows in the tag
table. Am I getting this wrong?
tl;dr: inheritance is the wrong tool. A tag is a tag is a tag. Inheritance is inherently provided by using multiple associations (many-to-many).
Your inheritance essentially says: There are two distinct types of tags, that are essentially different. One tag, that can be applied to posts, and one tag, that can be applied to comments, and those aren't the same tags, but different tags.
Since both kinds of tags are stored in the same table, there must be some mechanism on how to discriminate one from the other. That's what the type column is for. (So, this is essentially the answer to your main question, afaict)
So essentially, if you want to tag comments and blog (posts) alike, these are the more common options:
You chose a different approach: Tags: (tag_id, tag_name, object_type), Tagassignments: (tag_id, object_id) (<-- object type is implicitly given by tagid, but since you're using relations, Tagassignments is split up into blog_tags and comment_tags)
However, as Magnus Eriksson correctly commented, this might make sense. I have my doubts. I assume, that either option 1 or option 2 are much more common and convenient. And you should drop the inheritance on the Tag and instead add inheritance on the association (if needed, you'd need to make it an extra Entity to make it work), but rather advise on chosing option 1 because it's waaay easier to implement with doctrine and it's annotations. (although you'd need to add one get{Object}s() for each different object type that is supposed to be taggable.)
¹as Magnus correctly comments below (and co-commented by me): You lose most advantages databases provide, mainly performance, clarity and consistency. I would generally advise against this approach.