【问题标题】:Can I access discriminator field from php in doctrine2?我可以从教义2中的php访问鉴别器字段吗?
【发布时间】:2010-12-15 13:28:42
【问题描述】:

我有一个这样定义继承的实体:

* @DiscriminatorColumn(name="type", type="string")
* @DiscriminatorMap({"text" = "TextAttribute", "boolean" = "BooleanAttribute", "numeric" = "NumericAttribute", "date" = "DateAttribute"})

我想知道是否可以为字段“类型”设置吸气剂?我知道我可以使用 instanceof(在大多数情况下,这就是我正在做的事情),但在少数情况下 $item->getType() 会让我的生活变得如此轻松。

【问题讨论】:

标签: php inheritance doctrine doctrine-orm


【解决方案1】:

扩展 beberlei 所说的,您可以在 Attribute 类中声明一些常量,以及一个抽象的getType() 函数。然后,在每个派生属性类中重载它。

类似:

abstract class Attribute {
    const TYPE_BOOL = 0;
    const TYPE_INT  = 1;
    ...
    abstract public function getType();
}

class BooleanAttribute extends Attribute {
    public function getType() {
        return parent::TYPE_BOOL;
    }
}

【讨论】:

    【解决方案2】:

    这是我的做法。

    首先,您创建了一个AttributeInterface,以确保所有未来的新属性类型都将实现需要方法:

    interface AttributeInterface
    {
        /**
         * Return the attribute type
         */
        public function getType();
    }
    

    然后创建实现AttributeInterface 接口的Attribute 抽象类。

    使用@DiscrimatorMap 调用中的常量来保持一致性

    /**
     * Attribute
     * ...
     * @DiscriminatorColumn(name="type", type="string")
     * @DiscriminatorMap({Attribute::TYPE_TEXT = "TextAttribute", Attribute::TYPE_BOOLEAN = "BooleanAttribute", Attribute::TYPE_NUMERIC = "NumericAttribute", Attribute::TYPE_DATE = "DateAttribute"})
     */
    abstract class Attribute implements AttributeInterface
    {
        const TYPE_TEXT    = 'text';
        const TYPE_BOOLEAN = 'boolean';
        const TYPE_NUMERIC = 'numeric';
        const TYPE_DATE    = 'date';
    }
    

    最后,您创建所有需要的类,扩展 Attribute 类并实现 getType() 方法

    /**
     * TextAttribute
     *
     * @ORM\Entity
     */
    class TextAttribute extends Attribute
    {
        public function getType()
        {
            return $this::TYPE_TEXT;
        }
    }
    
    /**
     * BooleanAttribute
     *
     * @ORM\Entity
     */
    class BooleanAttribute extends Attribute
    {
        public function getType()
        {
            return $this::TYPE_BOOLEAN;
        }
    }
    
    /**
     * NumericAttribute
     *
     * @ORM\Entity
     */
    class  NumericAttribute extends Attribute
    {
        public function getType()
        {
            return $this::TYPE_NUMERIC;
        }
    }
    
    /**
     * DateAttribute
     *
     * @ORM\Entity
     */
    class DateAttribute extends Attribute
    {
        public function getType()
        {
            return $this::TYPE_DATE;
        }
    }
    
    // And so on...
    

    【讨论】:

    • 这实际上并没有访问鉴别器字段,它只是假装访问。考虑一个鉴别器映射,它对同一类有多个值,但您需要数据库中的实际值,而不是猜测它应该是哪个值。
    【解决方案3】:

    可以使用 EntityManager 或使用 DocumentManager。

    $documentManager->getClassMetadata(get_class($entity))->discriminatorValue;
    

    【讨论】:

      【解决方案4】:

      我的方法是通过元数据原则生成简单地访问它的价值

      $cmf = $em->getMetadataFactory();
      $meta = $cmf->getMetadataFor($class);
      $meta->discriminatorValue
      

      会给你价值,所以作为一种方法

      public static function get_type()
      {
          //...get the $em instance 
          $cmf = $em->getMetadataFactory();
          $meta = $cmf->getMetadataFor(__CLASS__);
          return $meta->discriminatorValue;
      }
      

      对于扩展我的基础实体的每个类,我将元数据缓存在一个静态变量中,其中还有很多其他有用的信息......

      【讨论】:

        【解决方案5】:

        不,这是不可能的,但你可以这样做:get_class($object) == TYPE_CONST

        【讨论】:

        • 多个鉴别器值映射到同一个类的情况如何?我正在将一些项目迁移到 Symfony,并且有 5 种类型(类常量)映射到 2 个类(由一个数据库字段水合,如鉴别器)。代码的其他部分依赖于MappedObject::getType() 与类常量比较,所以我需要判别器值,或者我必须为每个判别器的值使用唯一的类重构代码库...
        【解决方案6】:

        在 PHP 5.3 中有一种更巧妙的方法:

        abstract Parent
        {
            const TYPE = 'Parent';
        
            public static function get_type()
            {
                $c = get_called_class();
                return $c::TYPE;
            }
        }
        
        class Child_1 extends Parent
        {
            const TYPE = 'Child Type #1';
            //..whatever
        }
        
        class Child_2 extends Parent
        {
            const TYPE = 'Child Type #2';
            //...whatever
        }
        

        【讨论】:

        • 请注意,在 php5.3 中,get_called_class 调用不是必需的,您可以使用 static 关键字,例如:return static::TYPE
        【解决方案7】:

        如果你想使用这样的东西,像我一样,避免使用 const :

        public function getType()
        {
            $type = explode('\\', get_class($this));
        
            return end($type);
        }
        

        【讨论】:

          【解决方案8】:

          另一种比在每个子节点中重载方法或在每个子节点中定义常量更简单快捷的方法是使用反射类来检索没有命名空间的类的名称:

          public function getType() {
              return (new \ReflectionClass($this))->getShortName();
          }
          

          它也适用于自 php 5 起的任何 php 版本

          根据您的鉴别器映射声明,它可能不会准确返回鉴别器名称,但它会返回子实体名称(类名),这是命名和区分不同子实体的好方法

          无需在子类中定义任何内容。

          【讨论】:

          • 就我而言,这是最好的方法。我没有地图集。类型将是小写的类名。所以我可以将我的图像(文件)放入单独的文件夹中: public function getFullPath(): ?string { return $this->getType() 。 “/”。 $this->getFolder() 。 $this->getFilename(); } 公共函数 getType(): string { return strtolower((new \ReflectionClass($this))->getShortName()); }
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-04-06
          • 2011-08-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-27
          相关资源
          最近更新 更多