2012-04-11 23 views
16

estoy usando la siguiente función de propulsión http://www.propelorm.org/documentation/09-inheritance.html.ramita instanceof para la herencia objetos

También estoy usando Symfony2 y Twig

que tienen una estructura de clases usando la característica anterior que se ve algo como esto

class Event {} 

class Birthday extends Event {} 

class Walking extends Event {} 

ahora me pase un objeto de evento a una plantilla ramita y quiero saber qué tipo de evento es

Por ejemplo quiero mostrar una imagen de una torta si es un cumpleaños y quiero mostrar rutas mapa si el evento de caminar.

no puedo usar instanceof en la ramita ya que esta característica no existe. ¿Alguien ahora por qué esto no existe? y hay una manera que puedo replicar esta funcionalidad sin tener que hacer algo como

public function getType() 

en cada clase, o

public function isBirthday() 

en la clase de evento.

He encontrado esto en github pero es de ninguna utilidad para mí. He comentado sobre ellos para ver si puedo obtener una respuesta.

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

Respuesta

49

Comparto la opinión, que no es otra cosa instanceof que debe aparecer en una plantilla. Yo uso ramita pruebas para este 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; }) 
     ]; 
    } 
} 

Y en la plantilla

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

Creo que estoy siendo tan densa , pero parece que no puedo encontrar esa clase TwigTest en ningún lugar de @ fabpot/Twig. ¿Ha definido una clase personalizada que se extiende '\ Twig_Test', o es un alias de otra clase? '\ Twig_Test' en sí mismo es abstracto y, por lo tanto, no se puede desinstalar. –

+2

Lo encontré. Supongo que la clase fue renombrada en algún momento en los últimos seis meses. '\ Twig_SimpleTest' funciona en lugar de' TwigTest' anterior. Ver: http://twig.sensiolabs.org/doc/advanced.html#tests –

+1

@TwoWholeWorms No, me gusta importarlos como 'use \ Twig_Test como TwigTest; // o incluso "como prueba" '(y fue copiado de alguna parte). Se adapta mejor al estilo de codificación general – KingCrunch

4

Uso de instanceof en una plantilla es mal visto desde un punto de vista arquitectónico. Si se encuentra en una posición en la que lo "necesita", probablemente haya descubierto un problema en su arquitectura. Su solución getType en su caso es probablemente la mejor. Todavía podría poner eso en la clase base del evento y leer el nombre de la clase implementadora.

5

Una forma indirecta de lograr esto sería probar el objeto de un método, si conocerse objeto heredado tiene un método único. Tal vez su clase de cumpleaños tiene un getBirthday(), mientras que su clase Walking tiene un getMap()?

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

No hay mágico '.method' getter agregado por Twig a cada objeto. Así que mientras 'yourobject' no tenga realmente un método llamado" method "tu expresión nunca se volverá verdadera. En su lugar, simplemente use '{% if yourObject.methodName se define%}' donde "methodName" es el nombre exacto de la función que está buscando. – flu

+0

Tienes razón, malinterpreté algunos documentos –

+0

Para aquellos, que quieren saber: Eso se llama "Duck-Typing" http://en.wikipedia.org/wiki/Duck_typing :) – KingCrunch

0

que estoy tratando de hacer una index.html.twig que enumera las entidades que están definidos por el usuario, y sólo los campos que se han marcado como 'addToListing' Llego al punto en el que no sé qué estoy imprimiendo.

{% 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 %} 

Y el encabezado pasa a ser \ DateTime:/Entonces, para ese caso, tendría que | fecha ('formato') o alguna solución mejor.

¿Algún consejo sobre una solución limpia para mí?

+0

¿No funcionaría la solución anterior bien, ya que es un DateTime que sabe que tiene el método -> format entre otras cosas. Si entiendo tu ejemplo algo así como 'if entity.format is defined' ¡debería ser el truco! –

+0

Yo, estaba preocupado por el tipo de encabezado. Reemplacé el innerHtml por una plantilla incluida que hasta ahora se parece a: '{% if bridge.is_scalar (attribute (entity, heading)) o attribute (entity, heading) .__ toString se define o attribute (entity, heading) es nulo%} {{atributo (entidad, encabezado)? : 'empty'}} {% else%} {% if bridge.get_class (attribute (entity, heading)) == 'DateTime'%} {# {dump (bridge.get_class (attribute (entity, heading)))} #} {{attribute (entity, heading) | date (dateFormat)}} {% else%} {% endif%} {% endif%} ' – juanmf

+0

aquí está Bridge: ' namespace DocDigital \ Bundle \ DocumentBundle \ Helper; /** * cosas desagradables para apoyar FNS php necesarias en ramita * * @author Juan Manuel Fernández <[email protected]> */ clase TwigPhpBridge { función __call pública ($ functionName, array $ argV) { return call_user_func_array ($ functionName, $ argV); } } ' – juanmf

0

tuve problema similar, que estaba relacionado con la herencia en el software del hotel. Tuve una clase base "RoomEquipment" y herencia con "Bed", "ElectricAppliances" ....

class BaseRoomEquipment {} 

class Bed extends BaseRoomEquipment {} 

class ElectricAppliances extends BaseRoomEquipment {} 

Y por supuesto, una clase "Habitación" con relación OneToMany hacia RoomEquipment.

En la plantilla, quería hacer solo las camas, pero la habitación tiene relación con el equipo de base, que incluye camas y electrodomésticos.

En lugar de probar en la plantilla twig, en la clase Room he creado un método getBeds, y eso es todo.

class Room { 

    private $equipment; 

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

    // Rest of class here.... 

} 

Y, por supuesto, en la ramita:

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

Gracias al componente propiedad de acceso - esto es posible. Ahora, su rama no tiene que comprobar sobre tipo de instancia, ni lo hace sin

0

Otra solución:

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

entonces será funciona con cualquier clase que heredan de

class Birthday extends Event {} 

class Walking extends Event {} 

continuación, en su rama:

{{ 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 %}