2010-12-15 107 views
19

J'ai une entité qui définit l'héritage comme celui-ci:Puis-je accéder au champ discriminant de php dans doctrine2?

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

Je me demande est-il possible d'avoir getter pour le champ « type »? Je sais que je peux utiliser instanceof (et dans la plupart des cas c'est ce que je fais) mais il y a peu de scénarios où $ item-> getType() me faciliterait la vie.

+0

Copie possible de [Mapper une colonne discriminante à un champ avec Doctrine 2] (https://stackoverflow.com/questions/21284964/map-a-discriminator-column-to-a-field-with-doctrine-2 – sroes

Répondre

13

Extension ce beberlei dit, vous pouvez déclarer certaines constantes dans la classe d'attributs, et une fonction getType() abstraite. Puis, surchargez-le dans chaque classe d'attribut dérivée.

Quelque chose comme:

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

Non, ce n'est pas possible, mais vous pouvez faire quelque chose comme: get_class ($ object) == de TYPE_CONST

+0

Qu'en est-il des cas où les valeurs discriminantes multiples sont mappées à la même classe? Je migre un projet vers Symfony et il y a 5 types (constantes de classe) mappés à 2 classes (hydratés par un champ de base de données, comme discriminateur). D'autres parties du code s'appuient sur 'MappedObject :: getType()' vs comparaison de constantes de classe, donc j'ai besoin de discriminer valeur ou je dois refactoriser codebase avec des classes uniques pour la valeur de chaque discriminateur ... – Wirone

3

Utilisez quelque chose comme ça si vous voulez, comme moi, éviter l'utilisation de const:

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

    return end($type); 
} 
4

Il y a une Slicker façon de le faire en 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 
} 
6

Mon approche consiste simplement à accéder à sa valeur grâce à la doctrine des métadonnées.

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

vous donnera la valeur, donc en tant que méthode

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

I mettre en cache les métadonnées dans une variable statique pour chaque classe qui étend mon entité de base, il y a beaucoup d'autres informations utiles là aussi ...

9

C'est possible avec EntityManager ou en utilisant DocumentManager.

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

Voici comment je ferais.

Tout d'abord, vous avez fait un AttributeInterface, pour être sûr que tous les futurs nouveaux types d'attributs mettront en œuvre la méthode de besoin:

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

Ensuite, vous créez la classe abstraite Attribute implémente l'interface AttributeInterface.

Utilisez les constantes du @DiscrimatorMap appel à une certaine cohérence

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

Enfin, vous créez toutes les classes nécessaires, l'extension Attribute classe et mettre en œuvre la méthode 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

Cela n'accède pas réellement au champ de discriminateur , il prétend juste. Considérez une carte discriminante qui a plusieurs valeurs pour la même classe, mais vous avez besoin de la valeur réelle de la base de données et non d'une estimation de la valeur qu'elle devrait être. –

0

Une autre façon plus lisse que la surcharge la méthode dans chaque enfant, avec symfony natif:

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

Il pourrait ne pas revenir exactement au nom de discriminateur en fonction de votre déclaration de carte de discriminateur, mais elle retourne le nom de l'entité enfant (le nom de la classe) qui est un excellent moyen de nommer et de distinguer les différents sous-entités

Sans un besoin de définir quoi que ce soit dans les sous-classes.