php 原则2:有没有一种方法可以使用yaml或xml从trait继承Map?

qmelpv7a  于 2023-05-05  发布在  PHP
关注(0)|答案(2)|浏览(193)

我找到了following example in the doctrine documentation,他们在其中添加了Map到trait:

/**
 * Trait class
 */
trait ExampleTrait
{
    /** @Id @Column(type="string") */
    private $id;

    /**
     * @Column(name="trait_foo", type="integer", length=100, nullable=true, unique=true)
     */
    protected $foo;

    /**
     * @OneToOne(targetEntity="Bar", cascade={"persist", "merge"})
     * @JoinColumn(name="example_trait_bar_id", referencedColumnName="id")
     */
    protected $bar;
}

我试图Map一个trait,而不必在继承它的类中复制Map。我还没有在上面诚实地尝试过,因为我目前的项目使用yaml进行Map,但它看起来像一个普通的php类在使用trait时也会继承Map。
有没有一种方法可以不使用关联而使用yaml或xml来继承这个trait的Map?我试着把这个特性设置为mapped superclass,但是没有成功,但是我基本上在寻找相同类型的想法。
谢谢

apeeds0o

apeeds0o1#

我发现实现Maptrait的唯一方法是使用订阅者。下面的代码应该适用于您的示例,并且很容易定制:

<?php

namespace App\EventSubscriber\Doctrine;

use App\Model\Bar;
use App\Model\ExampleTrait;
use Doctrine\Common\EventSubscriber;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Events;
use Doctrine\ORM\Mapping\ClassMetadataInfo;

final class ResolveTraitSubscriber implements EventSubscriber
{
    public function getSubscribedEvents(): array
    {
        return [
            Events::loadClassMetadata,
        ];
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $args): void
    {
        $methods = [
            ExampleTrait::class => [$this, 'addExampleTrait'],
            // add more traits if needed...
        ];

        $metadata = $args->getClassMetadata();
        $traits = (array) $metadata->reflClass?->getTraits();

        foreach ($traits as $trait) {
            $name = $trait->getName();
            if (isset($methods[$name])) {
                $methods[$name]($metadata);
            }
        }
    }

    private function addExampleTrait(ClassMetadataInfo $metadata): void
    {
        $metadata->mapField([
            'fieldName' => 'id',
        ]);
        $metadata->mapField([
            'fieldName' => 'trait_foo',
            'length' => 100,
            'nullable' => true,
            'unique' => true,
        ]);
        $metadata->mapOneToOne([
            'targetEntity' => Bar::class,
            'cascade' => ['persist', 'merge'],
        ]);
    }
}

不要忘记使用doctrine.event_subscriber标记将其定义为服务。

v6ylcynt

v6ylcynt2#

使用YAML声明mappedSupperClass:

Namespace\For\Your\MappingClass:
    type: mappedSuperclass
    fields:
        id:
            id:
                type: integer
                generator:
                    strategy: AUTO

        ... other fields and relations

使用XML声明它:

<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                  http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

    <mapped-superclass name="Namespace\For\Your\MappingClass">

        <field name="foo" column="foo" type="string" length="255" />

        <field name="bar" column="bar" type="string" length="255" unique="true" />

        ... other fields

    </mapped-superclass>

</doctrine-mapping>

如果你运行app/console doctrine:generate:entities,你将能够在其他实体中使用mappedSuperClass作为上位。

相关问题