I'm having a couple of entity with tags. I've created a dynamic relationship based in this blog post:
class TaggableListener implements EventSubscriber
{
/**
* @return array
*/
public function getSubscribedEvents()
{
return [
Events::loadClassMetadata
];
}
/**
* @param \Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs
*/
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
// the $metadata is the whole mapping info for this class
$metadata = $eventArgs->getClassMetadata();
$class = $metadata->getReflectionClass();
if (!$class->implementsInterface(TaggableEntityInterface::class)) {
return;
}
$namingStrategy = $eventArgs
->getEntityManager()
->getConfiguration()
->getNamingStrategy()
;
$metadata->mapManyToMany([
'targetEntity' => Tag::class,
'fieldName' => 'tags',
'cascade' => ['persist'],
'joinTable' => [
'name' => $namingStrategy->classToTableName($metadata->getName()) . '__Tags',
'joinColumns' => [
[
'name' => $namingStrategy->joinKeyColumnName($metadata->getName()),
'referencedColumnName' => $namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE',
'onUpdate' => 'CASCADE',
],
],
'inverseJoinColumns' => [
[
'name' => 'tag_id',
'referencedColumnName' => $namingStrategy->referenceColumnName(),
'onDelete' => 'CASCADE',
'onUpdate' => 'CASCADE',
],
]
]
]);
}
}
interface TaggableEntityInterface
{
public function addTag(Tag $tags);
public function removeTag(Tag $tags);
public function getTags();
}
trait Tags
{
protected $tags;
public function addTag(Tag $tags) { /*..*/ };
public function removeTag(Tag $tags) { /*..*/ };
public function getTags() { /*..*/ };
}
I can use $category->getTags()
or $product->getTags()
and get all tags. This works great. It's an old blog post, but apparently not outdated.
But since there is no Tag::getProducts()
method, there is no easy way to get all products related to a tag.
Ideally, I want a Tag::getRelatedEntities()
which returns TaggableEntityInterface[]
, so the Collection contains both Product
and Category
entities.
In my template, I'm thinking of something like this:
<h1>Related entities:</h1>
<ul>
{% for relatedEntity in tag.getRelatedEntities %}
<li>{{ relatedEntity }}</li> //..implementing `__toString()`
{% endfor %}
</ul>
What's the best way to get a Tag::getRelatedEntities()
and/or Tag::getProducts()
method?
Of course I can manually create a getProducts
method on my Tag entity, but that kind of breaks the idea of a dynamic relationship. In this example I've only got a Product and Category entity, but in reality I've got many entities which are Taggable.