2012-04-11 19 views
16

Korzystam z następującej funkcji z propel http://www.propelorm.org/documentation/09-inheritance.html.Instancja twig dla obiektów dziedziczenia

Jestem również za pomocą Symfony2 i gałązka

mam struktury klasy, stosując powyższą funkcję, która wygląda mniej więcej tak

class Event {} 

class Birthday extends Event {} 

class Walking extends Event {} 

teraz przekazać obiekt zdarzenia do szablonu gałązka i chcę Wiesz, jaki rodzaj zdarzenia to

Na przykład chcę wyświetlić obraz ciasta, jeśli jest to urodziny i chcę wyświetlić trasy mapy, jeśli jest to wydarzenie spacerowe.

Nie mogę użyć instanceof w Twig, ponieważ ta funkcja nie istnieje. Czy ktoś teraz, dlaczego to nie istnieje? i czy istnieje sposób można replikować ta funkcjonalność bez konieczności zrobić coś

public function getType() 

w każdej klasie lub

public function isBirthday() 

w klasie zdarzeń.

Znalazłem to na Githubie, ale nie ma dla mnie znaczenia. Skomentowałem ich, aby sprawdzić, czy mogę uzyskać odpowiedź.

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

Odpowiedz

49

Podzielam opinię, że instanceof ma nic, że powinien pojawić się w szablonie. Używam gałązka-testów w tym przypadku

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

I w szablonie

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

Myślę, że jestem po prostu gęsta , ale wydaje mi się, że nie mogę znaleźć tej klasy TwigTest w dowolnym miejscu w @ fabpot/Twig. Czy zdefiniowałeś niestandardową klasę, która rozszerza '\ Twig_Test', czy jest to alias do innej klasy? '' Twig_Test' sam w sobie jest abstrakcyjny, a przez to niezmienny. –

+2

Znaleziono. Zgaduję, że nazwa klasy została zmieniona w pewnym momencie w ciągu ostatnich sześciu miesięcy. '\ Twig_SimpleTest' działa zamiast' TwigTest' powyżej. Zobacz: http://twig.sensiolabs.org/doc/advanced.html#tests –

+1

@TwoWholeWorms Nie, po prostu lubię je importować jak 'use \ Twig_Test as TwigTest; // lub nawet "jako test" (i skądś skopiowany). Lepiej pasuje do ogólnego stylu kodowania. – KingCrunch

4

Korzystanie instanceof w szablonie jest mile widziana z architektonicznego punktu widzenia. Jeśli znajdziesz się w sytuacji, w której "potrzebujesz" go, prawdopodobnie odkryłeś problem w swojej architekturze. Twoje rozwiązanie getType w Twoim przypadku jest prawdopodobnie najlepsze. Wciąż możesz umieścić to w klasie bazowej zdarzeń i odczytać nazwę klasy implementującej.

5

Pośrednim sposobem na osiągnięcie tego byłoby przetestowanie obiektu pod kątem metody, jeśli wiesz, że każdy dziedziczny obiekt ma unikalną metodę. Może twoja klasa Urodzin ma getBirthday(), podczas gdy twoja klasa Walking ma getMap()?

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

Nie ma magicznego '.method' gettera dodanego przez Twiga do każdego obiektu. Tak długo, jak 'yourobject' nie ma metody zwanej" method ", wyrażenie nigdy nie stanie się prawdziwe. Zamiast tego po prostu użyj '{%, jeśli twojaObject.methodName jest zdefiniowana%}' gdzie "methodName" jest dokładną nazwą funkcji, którą sprawdzasz. – flu

+0

Masz rację, źle zinterpretowałem niektóre dokumenty –

+0

Dla tych, którzy chcą wiedzieć: To jest nazywane "Kaczka-pisanie" http://en.wikipedia.org/wiki/Duck_typing :) – KingCrunch

0

Próbuję dokonać index.html.twig z listą podmiotów, które są zdefiniowane przez użytkownika, a dopiero pola oznaczone jako 'addToListing' Dochodzę do punktu, w którym nie wiem, co drukuję.

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

Nagłówek jest taki, że \ DateTime:/Więc dla takiego przypadku musiałbym | data ("format") lub lepsze rozwiązanie.

Czy mogę doradzić mi rozwiązanie?

+0

Czy powyższe rozwiązanie nie działa dobrze, ponieważ jest to DateTime, o którym wiesz, że ma między innymi metodę -> format. Jeśli rozumiem twój przykład, coś jak 'if entity.format jest zdefiniowane' powinno wystarczyć! –

+0

Ja, martwiłem się o typ nagłówka. Zastąpiłam szablon innerHtml dołączonym szablonem, który do tej pory wygląda: '{%, jeśli bridge.is_scalar (atrybut (encja, nagłówek)) lub atrybut (encja, nagłówek) .__ toString jest zdefiniowany lub atrybut (encja, nagłówek) ma wartość null%} {{atrybut (jednostka, nagłówek)? : 'empty'}} {% else%} {% jeśli bridge.get_class (atrybut (entity, heading)) == 'DateTime'%} {# {dump (bridge.get_class (atrybut (entity, heading))}} #} {{atrybut (jednostka, nagłówek) | data (dateformat)}} {% else%} {% endif%} {% endif%} ' – juanmf

+0

tu jest most: ' nazw DocDigital \ Bundle \ DocumentBundle \ Helper; /** * nieprzyjemnych rzeczy na wsparcie potrzebne FNS php w gałązka * * @author Juan Manuel Fernandez <[email protected]> */ klasa TwigPhpBridge { publicznego __call function ($ functionName, array $ argV) { return call_user_func_array ($ functionName, $ argV); } } ' – juanmf

0

Miałem podobny problem, był związany z dziedziczeniem w oprogramowaniu Hotel. Miałem klasę podstawową "RoomEquipment" i dziedziczenie z "Bed", "ElectricAppliances" ....

class BaseRoomEquipment {} 

class Bed extends BaseRoomEquipment {} 

class ElectricAppliances extends BaseRoomEquipment {} 

I oczywiście klasa "Pokój" ze związkiem OneToMany ze sprzętem pokojowym.

Na szablonie, chciałem renderować tylko łóżka, ale pokój ma związek z podstawowym wyposażeniem, które obejmuje łóżka i urządzenia elektryczne.

Zamiast testować w szablonie twig, w klasie Room utworzyłem metodę getBeds, i to jest to.

class Room { 

    private $equipment; 

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

    // Rest of class here.... 

} 

I, oczywiście, w Gałązka:

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

Dzięki składowej nieruchomości Accessor - jest to możliwe. Teraz Twój gałązka nie musi sprawdzać o instancji typu, ani nie robi nie

0

Innym rozwiązaniem:

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

to będzie prace z każdej klasy, które dziedziczą z

class Birthday extends Event {} 

class Walking extends Event {} 

następnie w Twój gałązka:

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

LUB

{% if event.isInstanceOfBirthday %} 
    ... do something for Birthday instance ... 
{% else %} 
    ... do something for Walking instance ... 
{% endif %} 
Powiązane problemy