开发者

Can I access discriminator field from php in doctrine2?

开发者 https://www.devze.com 2023-01-30 12:33 出处:网络
I have an entity which defines inheritance like this: * @DiscriminatorColumn(name=\"type\", type=\"string\")

I have an entity which defines inheritance like this:

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

I am wondering is it possible to have getter for field 'type'? I know I can use instanceof (and in most cases this is what I'm doing) but there are 开发者_Python百科few scenarios where $item->getType() would make my life so much easier.


Extending what beberlei said, you could declare some constants in the Attribute class, and an abstract getType() function. Then, overload it in every derived attribute class.

Something like:

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;
    }
}


Here is how I'd do.

First, you made an AttributeInterface, to be sure that all future new Attribute types will implement the need method :

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

Then you create the Attribute abstract class implementing the AttributeInterface interface.

Use the constants in the @DiscrimatorMap call for some consistency

/**
 * 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';
}

Finally, you create all needed classes, extending Attribute class and implementing the getType() method

/**
 * 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...


It's possible either with the EntityManager or using the DocumentManager.

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


My approach is to simply access it's value through the meta data doctrine generates

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

will give you the value, so as a method

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

I cache the metadata in a static variable for each class that extends my base entity, there is a lot of other useful information in there as well ...


No that is not possible, but you can do something like: get_class($object) == TYPE_CONST


There's a slicker way to do it in 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
}


Use something like this if you want, like me, avoid use of const :

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

    return end($type);
}


Another slicker and faster way than to overload the method in every child or define a constant in every child is to use reflection class to retrieve the name of the class without the namespace :

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

It also works in any php version since php 5

It might not return exactly the discriminator name depending on your discriminator map declaration but it will return the child entity name (the class name) which is a great way to name and distinguish the different subentities

Without a need to define anything in the subclasses.

0

精彩评论

暂无评论...
验证码 换一张
取 消