简体   繁体   English

Doctrine 2 索引继承

[英]Doctrine 2 Index Inheritance

i am new to Doctrine 2 am i trying to figure out how to do index inheritance with it.我是 Doctrine 2 的新手,我想弄清楚如何用它进行索引继承。

What i am trying to achieve is to have a base class that defines some default columns along with necessary indexes for all entities within the application.我想要实现的是有一个基类,它定义了一些默认列以及应用程序中所有实体的必要索引。

Example: All tables in my application will have created_on and modified_on , so i prepared one base @MappedSuperclass with those 2 columns in it.示例:我的应用程序中的所有表都将具有created_onmodified_on ,因此我准备了一个包含这两列的基础@MappedSuperclass

Here is my code:这是我的代码:

<?php

/**
 * @MappedSuperclass
 */
abstract class EntityAbstract
{
    /**
     * @Column(type="datetime", name="created_on", nullable=false)
     */
    protected $createdOn;

    /**
     * @Column(type="datetime", name="modified_on", nullable=true)
     */
    protected $modifiedOn;

}

/**
 * @Entity
 * @Table(name="member", indexes={@Index(name="credential", columns={"email_address", "password"})})
 */
class Member extends EntityAbstract
{
    /**
     * @Column(type="string", name="full_name", length=50)
     */
    protected $fullName;

    /**
     * @Column(type="string", name="email_address", length=50, unique=true, nullable=false)
     */
    protected $emailAddress;

    /**
     * @Column(type="string", name="password", length=40, nullable=false)
     */
    protected $password;       

}
?>

I want to enforce created_on to be an index, so i put @Index annotation in the base class for this particular column.我想强制created_on成为一个索引,所以我在这个特定列的基类中放置了@Index注释。 Hoping that this will result in 2 indexes for Member which is created_on and email_address + password combination.希望这将为Member产生 2 个索引,即created_onemail_address + password组合。 This however results in indexes of the base class being overriden by the child class, thus created_on is not an index.然而,这会导致子类覆盖基类的索引,因此created_on不是索引。

/**
 * @MappedSuperclass
 * @Table(indexes={@Index(name="timestampcreated", columns={"created_on"})})
 */
abstract class EntityAbstract

How do i achieve this in Doctrine 2?我如何在 Doctrine 2 中实现这一点? Have looked at single table inheritance, but my understanding is that it's meant for different purpose.看过单表继承,但我的理解是它用于不同的目的。

Here's a full solution for the way laid out at https://github.com/doctrine/orm/issues/5928#issuecomment-273624392 , thanks to https://medium.com/@alexkunin/doctrine-symfony-adding-indexes-to-fields-defined-in-traits-a8e480af66b2这是https://github.com/doctrine/orm/issues/5928#issuecomment-273624392的完整解决方案,感谢https://medium.com/@alexkunin/doctrine-symfony-adding-indexes -to-fields-defined-in-traits-a8e480af66b2

namespace App\EventListener;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use App\Entity\Member;

class MemberIndexListener
{
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        /** @var Doctrine\ORM\Mapping\ClassMetadata $classMetadata */
        $classMetadata = $eventArgs->getClassMetadata();
        if (Member::class === $classMetadata->getName())
        {
            $prefix = strtolower((new \ReflectionClass($classMetadata->getName()))->getShortName()); // you can omit this line and ...
            $classMetadata->table['indexes'][$prefix.'_created_on'] =  // ... replace `[$prefix.'_created_on']` with `[]` for automatic index naming
                ['columns' => ['username']
            ];
            // For UniqueConstraints, use:
            // $classMetadata->table['uniqueConstraints'][...] = ...
        }
    }
}

And in services.yaml :services.yaml

services:
    App\EventListener\MemberIndexListener:
        tags:
            - { name: doctrine.event_listener, event: loadClassMetadata }

I wanted to do the same thing, but @Table is not allowed in @mappedSuperclass classes.我想做同样的事情,但是@mappedSuperclass类中不允许使用@Table I've posted issue on doctrine2 github page https://github.com/doctrine/doctrine2/issues/5928 and the answer is:我在doctrine2 github页面https://github.com/doctrine/doctrine2/issues/5928上发布了问题,答案是:

@Table is not valid on a mappedsuperclass. @Table 在映射超类上无效。

When you think about it is sounds logical, but still, it would be nice if there is such functionality, to inherit indexes and other declarations.当您考虑它时听起来很合乎逻辑,但是,如果有这样的功能,继承索引和其他声明,那就太好了。

This is my solution for automatic index inheritance.这是我的自动索引继承解决方案。

You can specify indexes in table annotation of mapped superclass.您可以在映射超类的表注释中指定索引。 And all children will extend them.所有的孩子都会扩展它们。

The listener takes indexes of all parent mapped superclases.侦听器获取所有父映射超类的索引。

#src/EventListener/InheritIndexListener.php
<?php

namespace App\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadata;

final class InheritIndexListener
{
    /** @var EntityManagerInterface */
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        $name = $classMetadata->name;

        if (!$classMetadata->isMappedSuperclass) {
            foreach (class_parents($name) as $parent) {
                $this->addParentIndexes($parent, $classMetadata);
            }
        }
    }

    private function addParentIndexes(string $parent, ClassMetadata $classMetadata): void
    {
        $parentMetadata = $this->entityManager
            ->getClassMetadata($parent);

        foreach ($parentMetadata->table['indexes'] as $index) {
            if (!$this->hasSameIndex($index, $classMetadata->table['indexes'])) {
                $classMetadata->table['indexes'][] = $index;
            }
        }

        foreach ($parentMetadata->table['uniqueConstraints'] as $uniqueConstraint) {
            if (!$this->hasSameIndex($uniqueConstraint, $classMetadata->table['uniqueConstraints'])) {
                $classMetadata->table['uniqueConstraints'][] = $uniqueConstraint;
            }
        }
    }

    private function hasSameIndex(array $needle, array $haystack): bool
    {
        foreach ($haystack as $item) {
            if ($item['columns'] === $needle['columns']) {
                return true;
            }
        }

        return false;
    }
}


#config/services.yaml
services:
    App\EventListener\InheritIndexListener:
        tags:
            - { name: doctrine.event_listener, event: loadClassMetadata }

And entities.和实体。

#src/Entity/BaseResource.php
<?php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\MappedSuperclass
 * @ORM\Table(
 *     indexes={
 *     @ORM\Index(columns={"external_id"}),
 *     }
 *     )
 */
abstract class BaseResource
{
    /**
     * @var int|null
     * @ORM\Column(type="integer")
     */
    private $externalId;
    //...
}

#src/Entity/BaseSlugableResource.php
<?php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\MappedSuperclass
 * @ORM\Table
 *     uniqueConstraints={
 *     @ORM\UniqueConstraint(columns={"slug"}),
 *     },
 *     )
 */
abstract class BaseSlugableResource extends BaseResource
{
    /**
     * @var string|null
     * @ORM\Column(type="string")
     */
    private $slug;
    //...
}

#src/Entity/Article.php
<?php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Article extends BaseSlugableResource
{
    //...
}

In result the Article entity will have externalId index and slug unique index.结果,文章实体将具有 externalId 索引和 slug 唯一索引。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM