Могу ли я получить доступ к полю дискриминатора из php в doctrine2? - PullRequest
22 голосов
/ 15 декабря 2010

У меня есть объект, который определяет наследование следующим образом:

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

Мне интересно, можно ли получить геттер для поля 'type'? Я знаю, что могу использовать instanceof (и в большинстве случаев именно это я и делаю), но есть несколько сценариев, когда $ item-> getType () сделает мою жизнь намного проще.

Ответы [ 8 ]

17 голосов
/ 27 декабря 2010

Расширяя сказанное 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;
    }
}
14 голосов
/ 11 февраля 2014

Вот как я это сделаю.

Во-первых, вы создали AttributeInterface, чтобы быть уверенным, что все будущие новые типы атрибутов будут реализовывать необходимый метод:

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

Затем вы создаете абстрактный класс Attribute, реализующий интерфейс AttributeInterface.

Используйте константы в вызове @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...
10 голосов
/ 09 января 2014

Это возможно либо с EntityManager, либо с помощью DocumentManager.

$documentManager->getClassMetadata(get_class($entity))->discriminatorValue;
8 голосов
/ 26 июня 2013

Мой подход заключается в том, чтобы просто получить доступ к его значению с помощью доктрины метаданных, генерирующей

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

Я кэширую метаданные в статической переменной для каждого класса, который расширяет мою базовую сущность, там также есть много другой полезной информации ...

4 голосов
/ 19 июня 2013

Есть более простой способ сделать это в 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
}
4 голосов
/ 16 декабря 2010

Нет, это невозможно, но вы можете сделать что-то вроде: get_class ($ object) == TYPE_CONST

3 голосов
/ 11 апреля 2013

Используйте что-то подобное, если хотите, как я, избегайте использования const:

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

    return end($type);
}
0 голосов
/ 27 июня 2017

Другой более простой и быстрый способ, чем перегрузка метода в каждом дочернем элементе или определение константы в каждом дочернем элементе, - это использование класса отражения для извлечения имени класса без пространства имен:

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

Это такжеработает в любой версии php, так как php 5

Может не возвращать точно имя дискриминатора в зависимости от вашего объявления карты дискриминатора, но будет возвращать имя дочерней сущности (имя класса), что является отличным способом назвать и отличитьразличные сущности

Без необходимости что-либо определять в подклассах.

...