Oczywiście, da się napisać widok bazujący na OPT, który po wstawieniu będzie z Zend_Layoutem współpracować, tylko że takie rozwiązanie jest krzywdzące dla tego pierwszego. Dziedziczenie szablonów, cała idea wyrugowania programowania z szablonów idzie sobie w las tylko dlatego, że cały ZL opiera się na założeniu, że w szablonach właśnie trzeba programować i ostro korzystać z obiektówki. Takie wnioski wyszły z dyskusji czy ewentualny integrator tej biblioteki z frameworkiem opierać na ZL czy nie.
Rozwiązaniem jest stworzenie własnej wersji ZL, w pełni dostosowanej do tego, co ten system szablonów oferuje oraz jak oferuje. Taki system musi:
- Umożliwiać prosty wybór layoutu
- Obsługiwać łańcuchy akcji
- Umożliwiać akcjom definiowanie bloków widocznych tylko w ich własnym szablonie
- Posiadać zestaw funkcji, instrukcji i komponentów do integracji z zendowym routerem i innymi niezbędnymi elementami.
- Umożliwiać akcjom dodawanie niezbędnych plików JS, znaczników do sekcji HEAD i innych rzeczy w podobny sposób, jak w ZL.
- Obsługiwać dziedziczenie szablonów i wszystko, co z nim związane (w tym gałęzie dziedziczenia).
Nie jest to trudne do zrobienia, zwłaszcza jak się zna każdy bajt kodu OPT, lecz należy pomyśleć nad wyglądem samego API tak, by było użyteczne. Od strony głównego szablonu można spodziewać się czegoś takiego:
<?xml version="1.0" ?> <opt:root escaping="yes"> <opt:prolog /> <opt:dtd template="xhtml10transitional /> <html> <head> <meta http-equiv="Content-Type" parse:content="$contentType" /> <opt:generator from="$title" /> <opt:generator from="$style" /> <opt:generator from="$script" /> </head> <body> <div id="header"> <h1>Nagłówek strony...</h1> </div> <div id="left_menu"> <opt:section name="left_menu"> <div class="menu"> <opt:include from="left_menu"> <p class="error">Oops, nie mogłem załadować {$left_menu.file}</p> </opt:include> </div> </opt:section> </div> <div id="content"> <opt:section name="content"> <opt:include from="content" /> </opt:section> </div> <div id="footer"> <p>Copyright © by Foo {$currentYear}</p> </div> </body> </html> </opt:root>
Wszystkie niezbędne bloki zostaną stworzone przez naszego hipotetycznego przyjaciela Opt_Layout na podstawie danych dostarczonych przez akcje. Szablony poszczególnych akcji mogą swobodnie korzystać z dziedziczenia, co pozwala np. w prosty sposób rozszerzać formularze:
<?php class FormController extends Zend_Controller_Action { public function form1Action() { // forma odwolania jeszcze nieznana, wiec ustalmy $this :) $this->setTemplate('content', 'form1.tpl'); } // end form1Action(); public function form2Action() { $this->setTemplate('content', 'form2.tpl'); } // end form2Action(); }
oraz szablon:
<!-- form1.tpl --> <opt:root> <form method="post"> <opt:route _type="action" str:controller="form" action="$this.currentAction" /> Pole 1: <input type="text" name="field1" value="{$form.field1}" /> Pole 2: <input type="text" name="field2" value="{$form.field2}" /> <opt:insert snippet="formExtension" /> <input type="submit" value="OK"/> </form> </opt:root> <!-- form2.tpl --> <opt:extend file="form1.tpl"> <opt:snippet name="formExtension"> Pole 3: <input type="text" name="field3" value="{$form.field3}" /> </opt:snippet> </opt:extend>
Akcja form2 w rzeczywistości korzysta tutaj z szablonu form1.tpl, lecz rozszerzonego o nową funkcjonalność. Dziedziczenie w OPT pozwala na skonfigurowanie gałęzi dziedziczenia (czyli różnych wariantów plików, po których możemy dziedziczyć), a niebawem będzie zezwalać akcjom na samodzielne wybranie nazwy dziedziczonego szablonu.
Oczywiście pełna obsługa formularzy pojawi się wówczas, gdy zacznie powstawać Open Power Forms, jako że integrator byłby później rozbudowywany o kolejne biblioteki, które będą się pojawiać.
Zakończenie
Mam nadzieję, że realizowany projekt pozwoli mi opracować idealne wzorcowe rozwiązanie dla użytkowników Zend Frameworka. Ostatnie trzy miesiące poświęciłem na przeprojektowywanie całej serii bibliotek nie tylko pod kątem integracji jednej z drugą, ale także współpracy z innymi narzędziami, bez których o stworzeniu dużego projektu nie ma obecnie co marzyć.
OPT 2 jest na najlepszej drodze do udowodnienia, że systemy szablonów wcale nie są takie bez sensu, o ile oferują coś więcej, niż zwykłą kalkę PHP. Mamy zaledwie kilka klocków oraz reguł, dzięki którym można zmontować już niemal wszystko bez konieczności programowania, w pełni skupiając się na tym, co chcemy uzyskać. W PHP też da się osiągnąć podobne rezultaty, lecz pewne ograniczenia wpływające na przyjemność użytkowania narzuca sam język. Nowa składnia jest właśnie po to, by te ograniczenia usunąć i pozwolić prosto robić coś, co w PHP jest z natury trudne... do tego dodajmy modne ponowne wykorzystanie kodu. Wklej pętlę foreach z PHP w inne miejsce, to przestanie działać. Wklej sekcję w inne miejsce, ochoczo zabierze się do pracy, nawet jeśli nowa lokalizacja dostarcza jej danych w zupełnie innym formacie. Chcesz mieć to samo w PHP, musisz porządnie zaangażować w sprawę programowanie obiektowe. Przykłady można mnożyć. Dość, by powiedzieć, że dobrze napisany szablon OPT mógłby być nawet wykorzystywany przez Ruby'ego bez zmiany czegokolwiek, gdyby tylko istniał parser dla tego języka... a wszystko to powstało dzięki zjechaniu mnie 3 lata temu za klonowanie Smarty'ego :).







Napisał eXtreme w piątek, 22 sierpnia 2008 o 21:35
"projektanci wyszli z założenia, że systemy szablonów są za głupie, by potrafić takie zaawansowane rzeczy."
ROFLMAO :D znasz jakiś system szablonów prócz OPT który by robił coś podobnego? Oni po prostu podeszli do tego racjonalnie. Mają zend_view na PHP i tam po prostu było to potrzebne. I - choćbyś się zes**ł - nie zrobisz tego tak by wszystkim dogodzić. Myślisz, że twórcy ZF słyszeli o jakimś OPT2? Dlaczego więc mięli "wychodzić z założenia", że systemy szablonów to potrafią?