动态学说关系的反面方法

问题描述 投票:3回答:1

我有几个带标签的实体。我在这个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() { /*..*/ };
}

我可以使用$category->getTags()$product->getTags()并获取所有标签。这非常有效。这是一篇很老的博客文章,但显然没有过时。

但由于没有Tag::getProducts()方法,因此没有简单的方法可以获得与标签相关的所有产品。

理想情况下,我想要一个返回Tag::getRelatedEntities()TaggableEntityInterface[],因此Collection包含ProductCategory实体。

在我的模板中,我正在考虑这样的事情:

<h1>Related entities:</h1>
<ul>
{% for relatedEntity in tag.getRelatedEntities %}
    <li>{{ relatedEntity }}</li> //..implementing `__toString()`
{% endfor %}
</ul>

获得Tag::getRelatedEntities()和/或Tag::getProducts()方法的最佳方法是什么?

当然,我可以在我的Tag实体上手动创建一个getProducts方法,但这种方法打破了动态关系的想法。在这个例子中,我只有一个产品和类别实体,但实际上我有很多实体是Taggable。

php symfony doctrine-orm doctrine
1个回答
2
投票

您无法在Doctrine中创建指向多个不同实体的单一关系。换句话说,如果TagrelatedEntities,它必须是同一类的对象数组或至少映射超类。

您可以做的是编写一个迭代所有Doctrine托管类的服务,检查它是否实现了给定的接口,通过标记搜索这些实体并将它们全部合并到一个数组中。

示例代码:

$entities = [];
foreach ($entityManager->getMetadataFactory()->getAllMetadata() as $classMetadata) {
    if (in_array(TaggableEntityInterface::class, class_implements($classMetadata->getName()))) {
        $repository = $entityManager->getRepository($classMetadata->getName());
        $entities = array_merge($entities, $repository->findBy(['tag' => $tag]));
    }
}

如果要从模板轻松访问此功能,还可以将其包装到twig函数中。

代码未经过实际测试,因此根据您的使用情况,可能需要进行一些更正或改进。

© www.soinside.com 2019 - 2024. All rights reserved.