Smarty: {include} i widoczność zmiennych
11 lutego 2008
Do projektu nad którym teraz siedzę specjalnie wybrałem system szablonów Smarty bo wiedziałem, że będę miał przeróżne dziwaczne potrzeby a Smarty jest bardzo rozbudowane i nie powinno być problemów ze spełnieniem moich zachcianek. Dlatego bardzo byłem zaskoczony gdy się okazało, że wszystko wywala się na banalnym problemie...
Smarty pozwala w jednym szablonie dołączyć inny szablon. Służy do tego komenda {include}. Działa to tak samo jak include w php. A tak przynajmniej do dzisiaj sądziłem...
Prosty przykład użycia {include}:
Plik index.tpl
-
Jakiś tekst, html etc.
-
reszta dokumentu
W ten prosty sposób w miejscu użycia {include} pojawia się zawartość szablonu test.tpl.
Pójdźmy dalej. Załóżmy, że chcemy przekazać do test.tpl jakąś zmienną. Można to osiągnąć przy pomocy samej komendy {include} (zapraszam do dokumentacji) ale skoro to ma działać tak samo jak w php to powinno zadziałać coś takiego:
Plik index.tpl
Plik test.tpl
-
{$zmienna}
Krótkie objaśnienie. W pliku index.tpl inicjujemy zmienną $zmienna o zadanej wartości, następnie dołączamy szablon test.tpl i wyświetlamy w nim tą zmienną. Działa? Działa ![]()
A więc już wiemy, że w includowanych szablonach są widoczne zmienne wcześniej zainicjowane.
A teraz odwrotny przykład:
Plik index.tpl
-
{$zmienna}
Plik test.tpl
W pliku index.tpl dołączamy szablon test.tpl a w nim inicjujemy zmienną $zmienna. Następnie, już po zaincludowaniu szablonu, chcemy wyświetlić zmienną $zmienna, która przecież przed chwilą została zainicjowana. I tu niestety pojawia się problem... Zmienna z pliku test.tpl NIE została przekazana do pliku index.tpl. Nic nam się nie wyświetli.
Niestety jest to dość istotna różnica między {include} w smarty a include w php. Jest to zresztą wyraźnie zaznaczone w dokumentacji czego nie dostrzegłem wcześniej. Co gorsza, nie znalazłem żadnego rozsądnego rozwiązania tego problemu w Internecie. Ludzie kombinują na wiele sposobów ale wszystkie są mało praktyczne. Ja się jednak nie poddałem tak łatwo, musiało to zadziałać bo inaczej rozwalała mi się cała moja koncepcja
Powód takiego a nie innego zachowania smarty znalazłem w skompilowanym szablonie. Wygląda to tak:
Widać jak na dłoni, że twórcy smarty specjalnie tak to skonstruowali aby zmienne stworzone w includowanym pliku nie były widoczne na zewnątrz.
Rozwiązanie jest proste chociaż bardzo mi się nie podoba bo wymaga modyfikacji smarty. Ale chyba nie ma innego wyjścia.
Otwieramy plik Smarty_Compiler.class.php i szukamy takiej linijki:
-
"\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
W mojej wersji smarty (w tej chwili najnowsza, 2.6.18) jest to linijka numer 1003. Zamieniamy ją na to:
-
"\$this->_tpl_vars = array_merge(\$this->_tpl_vars, \$_smarty_tpl_vars);\n" .
Ot zwykłe połączenie tablic. Oba rozwiązania (to standardowe i to moje) mają oczywiście swoje plusy i minusy. To co mnie tak zirytowało zapewne wielu programistów bardzo cieszy. Wszystko zależy od potrzeb. Moim skromnym zdaniem powinno to być jakoś konfigurowalne, najlepiej z poziomu komendy {include}. Wprowadzenie takiego rozwiązania byłoby banalne a oszczędziłoby nie jednej osobie wielu nerwów. A tak ja teraz będę musiał pamiętać o modyfikacji przy każdej aktualizacji smarty... :/
Blog przede wszystkim o Internecie i mojej pasji jaką jest tworzenie stron www. Ale nie ograniczam się do jednej tematyki, piszę o wszystkim o czym mam ochotę :-)
macem napisał: 08.03.08 o godzinie 15:16
Ale w ten sposób bedzie to nieczytelne, pózniej będziesz się zastanawiał skąd ta zmienna się wzięła i szukał po ‘zaincludowanych’ plikach.
MariuszT napisał: 08.03.08 o godzinie 20:43
Tak jak napisałem, każdy ma inne potrzeby
macem napisał: 12.03.08 o godzinie 1:27
Zgadzam się, że każdy ma własne potrzeby, ale warto pisać czytelny kod, łatwiej go utrzymywać i debugować.
MariuszT napisał: 12.03.08 o godzinie 17:49
Ale takie właśnie rozwiązanie jest dla mnie czytelne
Tak jest w PHP i sądziłem, że tak będzie w Smarty.
Kamil napisał: 06.07.10 o godzinie 22:29
A może lepiej byłoby wywołać include z PHP i wtedy zdefiniować te zmienne?
{php}
include („html_dir/section_other.html”);
{/php}
Ma to też swoje wady, ale powyższego problemu by raczej nie było
MariuszT napisał: 20.07.10 o godzinie 16:42
Nie po to się używa systemu szablonów żeby korzystać z czystego PHP. W wyżej wymienionym projekcie zależało mi aby z poziomu szablonu nie było dostępu do PHP. Znacznik {php} był zablokowany.