2012-04-11 10 views
16

Sto utilizzando la seguente funzione dalla propulsione http://www.propelorm.org/documentation/09-inheritance.html.Twig instanceof per gli oggetti ereditari

Inoltre sto usando Symfony2 e Twig

Ho una struttura di classe utilizzando la funzione di cui sopra, che sembra qualcosa di simile

class Event {} 

class Birthday extends Event {} 

class Walking extends Event {} 

ora mi passa un oggetto evento a un modello rametto e voglio sapere che tipo di evento è

Ad esempio, voglio visualizzare un'immagine di una torta se è un compleanno e voglio visualizzare percorsi di mappe se il suo evento di camminata.

Non riesco a utilizzare instanceof in Twig poiché questa funzione non esiste. Qualcuno ora perché questo non esiste? e c'è un modo posso replicare questa funzionalità senza dover fare qualcosa di simile

public function getType() 

in ogni classe, o

public function isBirthday() 

nella classe di eventi.

Ho trovato questo su Github ma non è utile per me. Ho commentato loro per vedere se riesco a ottenere una risposta.

https://github.com/fabpot/Twig/issues/553

risposta

49

condivido l'opinione, che instanceof è nulla che dovrebbe apparire in un modello. Io uso ramoscello-test per questo caso

class MyTwigExtension extends TwigExtension 
{ 
    public function getTests() 
    { 
     return [ 
      new \Twig_SimpleTest('birthday', function (Event $event) { return $event instanceof Birthday; }), 
      new \Twig_SimpleTest('walking', function (Event $event) { return $event instanceof Walking; }) 
     ]; 
    } 
} 

E nel modello

{% if event is birthday %}{# do something #}{% endif %} 
+0

Penso di essere solo denso , ma non riesco a trovare la classe TwigTest da nessuna parte in @ fabpot/Twig. Hai definito una classe personalizzata che estende '\ Twig_Test', o è un alias di un'altra classe? '\ Twig_Test' stesso è astratto e quindi non istanziabile. –

+2

Trovato. Immagino che la classe sia stata rinominata ad un certo punto negli ultimi sei mesi. '\ Twig_SimpleTest' funziona al posto di' TwigTest' sopra. Vedi: http://twig.sensiolabs.org/doc/advanced.html#tests –

+1

@TwoWholes No, mi piace importarli come 'use \ Twig_Test come TwigTest; // o anche "as Test" (ed è stato incollato da qualche parte). Si adatta meglio allo stile di codifica generale – KingCrunch

4

Utilizzando instanceof in un modello è disapprovato dal punto di vista architettonico. Se ti trovi in ​​una posizione in cui ne hai "bisogno", probabilmente hai scoperto un problema nella tua architettura. La tua soluzione getType nel tuo caso è probabilmente la migliore. Puoi ancora inserirlo nella classe base dell'evento e leggerlo con il nome della classe di implementazione.

5

Un modo indiretto per eseguire ciò sarebbe il test dell'oggetto per un metodo, se si conosce che ogni oggetto ereditato ha un metodo univoco. Forse la tua classe di compleanno ha un getBirthday(), mentre la tua classe Walking ha un getMap()?

{% if yourobject.methodName is defined %} 
    //Stuff that should only output when the object in question has the requested method 
{% endif %} 
+0

Non c'è un magico '.method' getter aggiunto da Twig a ciascun oggetto. Quindi fintanto che 'yourobject' non ha un metodo chiamato" metodo ", l'espressione non diventerà mai vera. Invece usa semplicemente '{% se yourObject.methodName è definito%}' dove "methodName" è il nome esatto della funzione che stai verificando. – flu

+0

Hai ragione, ho interpretato male alcuni documenti –

+0

Per coloro che vogliono sapere: Quello che si chiama "Duck-Typing" http://en.wikipedia.org/wiki/Duck_typing :) – KingCrunch

0

Sto cercando di fare un index.html.twig che elenca le entità definite dall'utente, e solo i campi che sono stati contrassegnati come 'addToListing' Così arrivo al punto in cui non so cosa sto stampando.

{% for entity in entities %} 
    <tr> 
     {% for heading in headings %} 
      <td><a href="{{ path('document_show', { 'id': entity.id, docType: metaData.className }) }}">{{ attribute(entity, heading) }}</a></td> 
     {% endfor %} 
    </tr> 
{% endfor %} 

E l'intestazione capita di essere un \ DateTime:/Quindi in tal caso, avrei bisogno di | data ('formato') o qualche soluzione migliore.

Qualche consiglio su una soluzione pulita per me?

+0

La soluzione di cui sopra non funzionerebbe correttamente, dal momento che è un DateTime che sai che ha il metodo di formattazione -> tra le altre cose. Se capisco il tuo esempio qualcosa come 'if entity.format is defined' dovrebbe fare il trucco! –

+0

I, ero preoccupato per il tipo di intestazione. Ho sostituito lo innerHtml da un modello incluso che finora assomiglia a: '{% se bridge.is_scalar (attributo (entità, intestazione)) o attributo (entità, intestazione) .__ toString è definito o attributo (entità, intestazione) è null%} {{attributo (entità, intestazione)? : 'empty'}} {% else%} {% if bridge.get_class (attribute (entity, heading)) == 'DateTime'%} {# {dump (bridge.get_class (attributo (entità, intestazione)))} #} {{attributo (entità, titolo) | Data (dateFormat)}} {% else%} {% endif%} {% endif%} ' – juanmf

+0

qui è Ponte: ' namespace DocDigital \ Bundle \ DocumentBundle \ Helper; /** * roba brutta per supportare FNS php necessario in ramoscello * * @author Juan Manuel Fernandez <[email protected]> */ class TwigPhpBridge { funzione pubblica __call ($ functionName, array $ argV) { return call_user_func_array ($ functionName, $ argV); } } ' – juanmf

0

Ho avuto un problema simile, era correlato all'ereditarietà del software Hotel. Ho avuto una classe base "RoomEquipment", e l'ereditarietà con "Bed", "ElectricAppliances" ....

class BaseRoomEquipment {} 

class Bed extends BaseRoomEquipment {} 

class ElectricAppliances extends BaseRoomEquipment {} 

E, naturalmente, una classe "Room" con relazione OneToMany verso RoomEquipment.

Sul modello, volevo rendere solo i letti, ma Room ha relazione con l'apparecchiatura di base, che include letti ed elettrodomestici.

Invece di eseguire il test nel modello di ramoscello, nella classe Room ho creato un metodo getBeds e questo è tutto.

class Room { 

    private $equipment; 

    public getBeds() 
    { 
    $res = []; 
    foreach($this->getEquipment() as $eq) { 
     if ($eq instanceof Bed) $res[] = $eq; 
    } 
    return $res; 
    } 

    // Rest of class here.... 

} 

E, naturalmente, in Twig:

<div> 
    {% for Bed in Room.beds %} 
     {{ Bed.nbPersons }} 
    {% endfor %} 
</div> 

Grazie alla componente Proprietà Accessor - questo è possibile. Ora, il vostro ramoscello non ha bisogno di controllare circa tipo di istanza, e non lo fa nessun

0

Un'altra soluzione:

class Event { 
    ... 
    public function isInstanceOfBirthday() { 
     return $this instanceof Birthday; 
    } 
} 

allora sarà opere con qualsiasi classe che ereditano da

class Birthday extends Event {} 

class Walking extends Event {} 

poi in il vostro ramoscello:

{{ event.isInstanceOfBirthday ? ... something for Birthday instance ... : ... something for Walking instance ... }} 

O

{% if event.isInstanceOfBirthday %} 
    ... do something for Birthday instance ... 
{% else %} 
    ... do something for Walking instance ... 
{% endif %}