【问题标题】:How to add custom property to Symfony Doctrine YAML mapping file如何将自定义属性添加到 Symfony Doctrine YAML 映射文件
【发布时间】:2016-06-27 21:09:21
【问题描述】:

谁能告诉我如何将自定义属性添加到学说 ORM yml 文件中?

我的想法是添加这样的属性:

fields:
    name:
        type: string
        localizable: true

然后我想通过使用

来获取关于这个localizable属性的信息
protected function getEntityMetadata($entity)
{
    $factory = new DisconnectedMetadataFactory($this->getContainer()->get('doctrine'));

    return $factory->getClassMetadata($entity)->getMetadata();
}

然后:

    $met    = $this->getEntityMetadata($bundle.'\\Entity\\'.$entity);
    $this->metadata = $met[0];
    $fields = $this->metadata->fieldMappings;

    if (isset($fields)) {

        foreach ($fields as $field => $fieldMapping) {
            if (isset($fieldMapping['localizable']) && $fieldMapping['localizable'] == true) {

                // Do sth with it
            }
        }
    }

【问题讨论】:

    标签: symfony orm doctrine-orm mapping yaml


    【解决方案1】:

    教义的写作方式使这很尴尬。您似乎想保留 Yaml 映射,但只需添加一个属性。我认为您可以创建自己的自定义驱动程序,从提供的驱动程序扩展。 Yaml 驱动程序具有大部分私有方法,因此覆盖一些功能很困难,但这是可能的。

    我创建了一个从SimplifiedYamlDriver 扩展的自定义驱动程序。驱动程序的命名很重要,因为原则扩展将尝试根据Driver 之前的内容加载其驱动程序之一。它还会对名称中的Simplified 进行strpos 检查,因此我认为最安全的选择是完全保留原始名称并为原始名称指定别名。

    use Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver as BaseDriver;
    
    class SimplifiedYamlDriver extends BaseDriver
    {
        public function loadMetadataForClass($className, ClassMetadata $metadata)
        {
            parent::loadMetadataForClass($className, $metadata);
    
            $element = $this->getElement($className);
    
            if (!isset($element['fields'])) {
                return;
            }
    
            foreach ($element['fields'] as $name => $fieldMapping) {
                if (isset($fieldMapping['localizable'])) {
                    $original = $metadata->getFieldMapping($name);
                    $additional = ['localizable' => $fieldMapping['localizable']];
                    $newMapping = array_merge($original, $additional);
                    $metadata->fieldMappings[$newMapping['fieldName']] = $newMapping;
                }
            }
        }
    }
    

    然后我告诉 Symfony 通过覆盖 app/config/parameters.yml 中的类来使用这个驱动程序

    parameters:
        doctrine.orm.metadata.yml.class: MyBundle\SimplifiedYamlDriver
    

    然后我像MyBundle/Resources/config/doctrine/Foo.orm.yml 中的示例一样更新了映射

    MyBundle\Entity\Foo:
        type: entity
        id:
            id:
                type: integer
                generator:
                    strategy: IDENTITY
        fields:
            text:
                type: string
                localizable: true
    

    而且我可以通过以下方式获取此映射:

    $mapping = $this
                ->getDoctrine()
                ->getEntityManager()
                ->getClassMetadata(Foo::class)
                ->getFieldMapping('text');
    

    会给我:

    Array
    (
        [fieldName] => text
        [type] => string
        [columnName] => text
        [localizable] => 1
    )
    

    【讨论】:

    • 这几乎可以工作。但问题是,如果我按照你写的那样做,DoctrineExtensions(可能与此类似)停止工作。我正在扩展默认使用的 Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver,所以它应该可以工作,但它没有。知道为什么吗?
    • 嗯,我发布的确切答案对我有用。也许这是教义版本的差异。我在 composer.json 中有 ^2.5
    • 我也是。教义/orm 2.5.4 和最新的 devmaster StofDoctrineExtensions Localizable 已显示,但 sluggable、blamable、timestampable 停止工作。
    • 也许这个驱动程序应该被链接起来?
    • 我花了一段时间,但我发现了问题。在 ExtensionMetadataFactory(~第 153 行)内,原则扩展包尝试根据原始驱动程序名称加载驱动程序:'Gedmo\Blameable\Mapping\Driver' . substr($driverName, 0, strpos($driverName, 'Driver')。在我的原始答案中,该驱动程序不存在,因此它使用了后备注释驱动程序(由于您不使用注释而失败)。所以名字是什么破坏了它,我已经更新了答案以使用与默认驱动程序相同的名称。
    【解决方案2】:

    不幸的是,如果不重写 Doctrine DBAL 的重要部分,这是不可能的。这会影响驱动程序(YAML、注释...)、元数据生成器...

    在你的情况下,我看到的最简单的方法是添加一个自定义类型,比如说LocalizableString(我猜你最多需要它,也许LocalizableText)。 添加类型相对简单,因为您可以扩展基本类型,因此您不必编写任何 SQL。您可以参考 Doctrine 文档here 和 Doctrine 捆绑包一here

    那么你可以这样做:

    $met    = $this->getEntityMetadata($bundle.'\\Entity\\'.$entity);
    $this->metadata = $met[0];
    $fields = $this->metadata->fieldMappings;
    
    if (isset($fields)) {
    
        foreach ($fields as $field => $fieldMapping) {
            if ($this->getClassMetadata()->getTypeOfField($field) === 'localized_string') {
    
                // Do sth with it
            }
        }
    }
    

    【讨论】:

    • 我不能这样做,因为我想将此属性添加到每种类型的字段中。所以我需要为每种基本类型准备一个新类型。我知道这是可能的,因为 DoctrineExtensions 可以做到这一点,但我不明白怎么做。
    • 据我所知,DoctrineExtensions 不会修改原始类型。他们添加自己的注释,并在构建元数据时调用自己的机制,这将跟踪“启用扩展”的实体:github.com/Atlantic18/DoctrineExtensions/blob/master/lib/Gedmo/…
    猜你喜欢
    • 1970-01-01
    • 2012-07-18
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2018-06-03
    • 1970-01-01
    相关资源
    最近更新 更多