ďťż

[PHP] Lekki system szablonów łatwe w edycji skórki, stosowanie DOM...

       

Podstrony


telcocafe

7 stycznia 2008 - wypełnij ankietę - to tylko chwila
ankieta na temat budowy szybkiego CMS-a

Postanowiłem na 80% zastosować system szablonów, aby w pełni oddzielić kod HTML od PHP i ułatwić tworzenie stylów. Waham się, czy pisać własny, czy użyć gotowca. Mam nadzieję, że uzyskam tu poradę. :) Zastanawiam się nad XT i OPT (może są alternatywy?).

XT
:+: Brak szablonowego języka. Wykorzystuje potęgę CSS i DOM.
:+: Kilka razy szybszy od OPT
:-: Wszystko wykonuje w locie za każdym razem (złożenie skomplikowanego szablonu może nawet przekroczyć czas wykonywania się pozostałych funkcji CMS-a).

OPT
:+: Wykonuje cache - kompiluje szablony tylko po ich zmianie
:+: Możliwość wywalenia zbędnych funkcji
:-: Szablonowy język - {section} lub <opt:section>

Wspólne cechy
:+: Oferują dużo możliwości
:-: Zbyt duży rozmiar całości + zbyt wiele dołączanych plików

Trzeba znaleźć złoty środek. 8) Z szablonowego języka na pewno przydatne są wstawki {zmienna}. Nie zawsze wiemy, gdzie co się znajduje po edycji szablonu przez grafika lub webmastera. Resztę można zrobić przy pomocy DOM, tylko jest problem - cache. Czy to możliwe? W każdym razie system może wykonywać swą pracę w locie, o ile będzie robił to szybko.

Dużo osób radzi mi jednak pozostać przy szablonach w PHP. Może to też dobry pomysł? Zawsze można stworzyć narzędzie do kompilacji dokumentów utworzonych w przystępnej formie do plików PHP. Admin może je kompilować w panelu admina (a także sprawdzać, czy jest dostępna ich nowa wersja). Natomiast ci, co chcą dodać wstawki PHP w skórce, będą zadowoleni.
Użytkownik Ferrari edytował ten post 07 styczeń 2008, 18:51



XT
:+: Brak szablonowego języka. Wykorzystuje potęgę CSS i DOM.
:+: Kilka razy szybszy od OPT
:-: Wszystko wykonuje w locie za każdym razem (złożenie skomplikowanego szablonu może nawet przekroczyć czas wykonywania się pozostałych funkcji CMS-a).

OPT
:+: Wykonuje cache - kompiluje szablony tylko po ich zmianie
:+: Możliwość wywalenia zbędnych funkcji
:-: Szablonowy język - {section} lub <opt:section>

Wspólne cechy
:+: Oferują dużo możliwości
:-: Zbyt duży rozmiar całości + zbyt wiele dołączanych plików

To napisz swój i umieść wszystko w jednym pliku. Odradzam pchanie się w szablony działające na zasadzie parsowania XMLa lub zbliżonej - nie jest to przyjemne. Masz smarty, PEAR też coś ma, z ZendFrameworka też pewnie dałoby się coś użyć. Jak dla mnie system szablonów musi obsługiwać dziedziczenie, kompilowanie do gotowego kodu php oraz składnię odrębną od składni HTML żeby było to czytelne -> {coś} itd. a nie <opt:section>

I też nie baw się w nanosekundowe pomiary szybkości. Jeżeli system szablonów kompiluje się do gotowego kodu PHP, jest stosowany i działa to znaczy że jest wydajny. Przykładowo nasza-klasa.pl pada nie dlatego że zastosowali zły system szablonów albo np. ORM do bazy danych złożony z Xnastu plików tylko dlatego że ilość wejść drastycznie wzrosła i różnica w wydajności na poziomie obsłużenia kilkudziesięciu dodatkowych wejść w czasie na jednym serwerze nie ma znaczenia gdy są ich miliony. Ma znaczenie natomiast czytelność i elastyczność kodu - możliwość rozwoju poszczególnych komponentów przez odpowiednich członków zespołu - zarówno programistów server-side jak i client-side :)

kolejny taki sam twoj temat - ale co dla ciebie znaczy lekki?
to znaczy ze bedzie mial pol mega mniej w dokumentacji - czy wydajnie dizalal? bo jak wydajnie dzialal to nie szukaj dziury w calym tylko moze poprostu uzyj smarczy czy kameleona ?:>

Stwórz własny, pamiętaj o cache i o tym, że ma nam to ułatwiać pracę, a nie utrudniać (viva la {sdsd|sdf#gdf$} smarty).
Radzę stosować trójstopniowe parsowanie:
1. Zamiana pewnych tagów na odpowiedniki w czystym php - np. {? ... ?} na <?php ... ?> - to dzięki preg_replace
2. Uruchomienie tak otrzymanego kodu i przypisanie do zmiennej dzięki ob_start, include i ob_get_clean.
3. W końcowym etapie, to co otrzyma użytkownik, powinno być prawie czystym html, już bez wstawek php. Powinien być dodatkowy tag który spowoduje zamianę znacznika szablonu na kod php dopiero w drugim etapie, tak by teraz mieć kod php (przydatne gdy nie chcemy mieć opóźnień np. po dodaniu newsa. Albo lepiej - by jeden użytkownik nagle stał się innym ^^)

Oczywiście na każdym etapie szablon powinien być zapisany do jakiegoś pliku, a przy następnej wizycie - powinno nastąpić sprawdzenie czy i co trzeba uaktualnić. Można dodać coś w stylu wygasania ważności po X uruchomieniach/X czasu, sprawdzanie czy szablon na serwerze się nie zmienił etc.

Czy na pewno warto tworzyć własny język, te wszystkie {IF} i podobne? Przecież działamy na php i wystarczy zamienić wstawki szablonu na wstawki czystego php! Nie ma sensu dokonywać żadnych takich działań z poziomu systemu szablonów.
A owo trójstopniowe kompilowanie powoduje że w niektórych wypadkach wcale nie będzie kompilacji tylko include czystego kodu html (np strona która jest generalnie statyczna, po prostu autor chce mieć wygodne zarządzanie i edycję)

Ah - może warto wysyłać strony skompresowane np. gz? Można z poziomu apacza albo php.

Napisałem coś takiego na potrzeby frameworka, jakieś 150 linii kodu i działa jak złoto :^) sprawdzone :^)
A czemu tworzyć własny? Bo nie ma naprawdę dobrego który by pasował do każdego projektu idealnie. To jest godzinka pracy a będzie idealnie pasowało do reszty twojego kodu.



Nad systemem szablonów pomyślę. Jego klasa nawet nie musi pośredniczyć w procesie dołączania szablonów - wystarczy include(), jeśli są skompilowane do PHP w panelu admina. Problem stanowi kwestia techniczna CMS-a.

Jeśli każdy moduł ma mieć dostęp do <title> i <head>, muszę skorzystać z któregoś z obejść:
    labstrakcja wyglądu - czyli pośredniczenie klasy systemu szablonów - w głównym szablonie (layoucie) wystarczy wywołać: echo $template; (wykorzystujemy __toString())
    l
    lbez systemu szablonów - instrukcje typu include() w skórkach
    l
    lopakowanie modułów CMS-a w klasy - rozwiązuje problem, lecz w tym przypadku pakuję się w definiowanie wielu zmiennych globalnych (np. $cfg, $lang, $user, $db, itd.)
    l
    lbuforowanie wyjścia (jak w PunBB, Joomla...) - nic nie trzeba zmieniać w modułach (chyba tylko w index.php i głównym layoucie w skórkach) - ale w przypadku obciążenia serwera klient dłużej może czekać, zanim cokolwiek wyświetli się + większe zużycie RAM przy obszernych podstronachl
Waham się między 1, 3 a 4. Jakie są jeszcze zalety i wady tych rozwiązań i które sprawi najmniej kłopotów z tworzeniem aplikacji i jej wydajnością?

Na czym polega problem? Powiedzmy, że wyświetlamy artykuł. Na stronie muszą się pojawić:
- struktura katalogów (jeśli włączono), np. Artykuły > Kategoria 1
- artykuł (wraz z opcjami: oceń, edytuj, ocena, ilość wyświetleń, itd.)
- komentarze + formularz do komentowania (coś jak "szybka odpowiedź")

Przedstawiłem na prędko problem na podstawie modułu sondy. Kest kilka możliwości - oznaczyłem je cyframi:
http://www.unit1.pl/pb-630
Użytkownik Ferrari edytował ten post 05 styczeń 2008, 00:09
problemy to ty sam tworzysz... dlaczego ja takich nigdy nie miałem? :) dowolny system szablonów z dziedziczeniem rozwiąże problem np. dostępu do tytułu strony. Przykładowo u mnie szablon wyświetlający daną ankietę wygląda tak (dziedziczy szablon główny i podaje własną zawartość dla niektórych bloków):

{% extends "pages/body.html" %} {% block leftmenu %}<ul> <li><a href="/">Strona Główna</a></li> </ul>{% endblock %} {% block header %}Ankieta "{{ p.question }}"{% endblock %} {% block title %}Ankieta "{{ p.question }}"{% endblock %} {% block description %}Ankieta "{{ p.question }}"{% endblock %} {% block crumb %}<a href="/">Home</a> > <a href="/p/">Ankiety</a> > <a href="/p/{{ p.id }}/">{{ p.question }}</a>{% endblock %} {% block content %} ....tutaj treść.... {% endblock %}

No wiesz, jeśli zachowujesz złotą równowagę świata ® czyli MVC, to nie wiem tak naprawdę w czym jest problem.

1. Pamiętaj o OOP. Oczywiście że system szablonów opakuj w klasę (w tym wypadku liiterka M - model/librarka)
2. Nie potrzebujesz wcale zmiennych globalnych, pomyśl o czymś w stylu
$a = new Szablon('/plik/szablonu/cos.tpl'); $b = array('title' => 'super strona', 'autor' => 'roflwaffle'); /* szablon zamieni "{title}" na "super strona", przykladowo */ $a->Assign($b);
No a w naszym systemie szablonów, w etapie pierwszym, może być pętla foreach dla naszego $b, która zamienia wszystkie klucze (tej tablicy) znalezione w kodzie szablonu (np. {KLUCZ}) na wartość klucza tej tablicy. I owszem, kompilacja wstępna może być z panelu admina, o ile nie zapomnisz :)
Nic też nie stoi na przeszkodzie by używać w szablonie obiektów.
$head = new stdClass(); $head->title = 'super strona'; $head->meta = 'meta?'; $b = array('head'=>$head); //w szablonie <title>{head->title}</title>
Jak to zrobić? Np. preg_replace('\{(.*)\}/', '<?php $1 ?>', ...); (najprostrze co może być. Nieco głupie, ale można użyć np. {$ ... $} albo coś... No i nieco mądrzejszy regexp.

3. Buforowanie wyjścia pozwala na kompresję i wcale nie spowalnia a jedynie przyspiesza :)
w czasach serwerów z kilkunastoma procesorami po 3 ghz, i 25 tb ram, tego obciążenia nie widać. Najwięcej spowolnień jest z powodu łącz internetowych.

Swoją drogą, ten kod który pokazałeś nie jest zbyt ładny :P
Zorganizuj sobie jakoś pracę, oddziel interakcję z bazą danych od kontrolera i przede wszystkim od szablonu.

Wypełnijcie ankietę (link w pierwszym poście). Nie chcę implementować systemów szablonów z podobną składnią jak w Smarty. Na początek wystarczy kod PHP, a o reszcie potem pomyślę.

Potraktowałem moduły buforowaniem wyjścia (tzn. buforuję to, co wyświetlą, zapisuję do zmiennej, a potem umieszczam layoucie). Wg wielu osób jest to zła metoda. Czy rzeczywiście? Jeśli tak, mogę napisać klasę szablonów (lub: wyświetlacza), choć nie będzie już takiej swobody pisania kodu. *

http://rafb.net/p/t1olnT93.html

Niektóre moduły wyświetlają jeszcze np. informację nad zawartością bądź tylko informację (np. o braku głosów w ankiecie). Inne poniżej wyświetlają komentarze. * Wolałbym pobierać komentarze z bazy i wyświetlać je dopiero w sekcji <body> pod zawartością modułu (w przypadku dużego obciążenia klient krócej czeka, zanim będzie mógł przeczytać artykuł / news...). Jednak dołączony plik lib/coments.php w metodzie Display::__toString() nie będzie mógł dostać się do zmiennych $cfg, $lang, $db, $user, itd... - tak tam potrzebnych, o ile nie użyję global.

PS. Stracę możliwość szybkiego wysyłania danych z bazy do przeglądarki (zapytania z niebuforowanymi rekordami), choć to nie jest duża strata - http://rafb.net/p/SpqEP092.html

PS 2. Używanie include() w szablonach to raczej nie problem, więc nie ma kłopotu z używaniem kilku szablonów na raz.

Czy zastosowanie takiej klasy szablonów pomoże, czy jedynie utrudni tworzenie?
Użytkownik Ferrari edytował ten post 11 styczeń 2008, 16:26

PS. Stracę możliwość szybkiego wyświetlania danych z bazy (zapytania z niebuforowanymi rekordami), choć to nie jest duża strata.
http://rafb.net/p/SpqEP092.html

Ten kod to niby "przykładowy" szablon ma być? O_o

ankieta na temat budowy szybkiego CMS-a
503 Service Unavailable Serwer jest aktualnie przeciazony, prosimy spróbowac ponownie za chwile.
;)

Co dla ciebie oznacza szybki CMS? PHP-Fusion na localhoście będzie śmigał. Wrzucisz nie ten bloc co trzeba, albo będziesz miał wiele artykułów i nagle okaże się że wywala serwer MySQL :)

Szybka aplikacja:
- czytelna
- elastyczna
- nieprzekombinowana

Czyli:
- framework
- MVC lub podobne

"Optymalizacja" na localhoście - bo buforowanie %$#%@%# i szybko nie będę wyświetlał newsów możesz sobie wsadzić. Dodaj 1000 rekordów przy jakiś 50 MB danych i sprofiluj Xdebugiem jak i Xdebug + (httperf, siege) - jeżeli nie będzie niespodziewanych skoków zużycia RAMu czy czasu wykonywania to kod jest wydajny. Wydajny może być kod napisany zarówno z pomocą ślicznego frameworka jak i kod w stylu mix wszystkiego ze wszystkim - e107 czy PHP-Fusion, tyle że wydajny kod można: usprawnić, zaktualizować, rozszerzyć... a jak w kodzie syfiarnia to niczego się nie zrobi :) I z czasem kod straci i jakość i wydajność.

Gorąco polecam wykorzystanie istniejących i sprawdzonych rozwiązań jak Smarty czy w ogóle frameworki :) CodeIgniter +/- wspierany klasami ZE

Serwer ankiet ma czasami przeciążenia. :> Teraz działa.


Szybka aplikacja: - czytelna (...) Do tego dążę - przede wszystkim przez oddzielenie HTML/CSS od PHP/SQL. :) Czy użyję buforowania wyjścia, czy zastosuję abstrakcję szablonów, czy inną metodę - wydajność będzie podobna.


jeżeli nie będzie niespodziewanych skoków zużycia RAMu Zainstalowałem na localhost najnowszą wersję Drupala 6.0. 8 MB RAM-u to dla niego za mało, aby wyświetlić stronę główną, a strony mogą generować się nawet do kilku sekund (zazwyczaj ok. 1-3 s.).

Teraz istotny jest sposób oddzielenia wyglądu od logiki. Może zastosuję metodę 2: http://rafb.net/p/t1olnT93.html - czy jednak sam sposób implementacji jest dobry? System wyświetlania komentarzy mogę najwyżej opakować w klasę.

PS. W każdym razie zacznę modyfikować kod to się okaże, jakie są jeszcze problemy i jak je rozwiązać.
Użytkownik Ferrari edytował ten post 11 styczeń 2008, 19:39

Zainstalowałem na localhost najnowszą wersję Drupala 6.0. 8 MB RAM-u to dla niego za mało, aby wyświetlić stronę główną, a strony mogą generować się nawet do kilku sekund (zazwyczaj ok. 1-3 s.).

coś ściemniasz ;) Akurat do drupala przyczepić się nie można. Używany jest w wielu serwisach poddawanych znacznemu obciążeniu. To że otrzymałeś takie wyniki może być wywołane brakiem zasobów na komputerze.


Teraz istotny jest sposób oddzielenia wyglądu od logiki. Może zastosuję metodę 2: http://rafb.net/p/t1olnT93.html - czy jednak sam sposób implementacji jest dobry? System wyświetlania komentarzy mogę najwyżej opakować w klasę.
to jest kod PHP, pokaż jak według tego będzie wyglądał przykładowy szablon.

Zrzut ekranu: http://www.f4a.eu/up...01637287035.png - prawdopodobnie systemem skór używa ok. 7,6 MB RAM-u. Maksymalne zużycie pamięci na stronie głównej wynosi ok. 8.23 MB. Panel admina - ok. 10,3 MB.


pokaż jak według tego będzie wyglądał przykładowy szablon W przyszłości zamierzam umożliwić edycję szablonów w formie bardziej przyjaznej webmasterom, który nie umieją PHP. [kod 1]. Do tego dojdą jeszcze pewnie instrukcje warunkowe (może jak w PhpBB). Pliki w tej formie będą kompilowane do PHP automatycznie (jeśli zastosuję klasę szablonów) lub w panelu admina.

Na razie chcę skupić się na formie skompilowanej (czyli z kodem PHP). [Kod 2] łatwiej jest edytować, lecz zapewne trzeba tworzyć kolejne dowiązania do tablicy z danymi. [Kod 3] chyba też nie jest zły. To nie wszystkie zmienne - nie uwzględniłem np. awatara newsa, daty, przycisków lub linków administracyjnych (w tym: edytuj), struktury kategorii*... Wtedy śmietnik powstanie nawet w tej przyjaznej formie.

KODY: http://rafb.net/p/JQr4Iq47.html

Tak się teraz zastanawiam, czy są jakieś większe profity z wyświetlania szablonów za pośrednictwem klasy. Równie dobrze można je kompilować w PA wg ustalonych schematów (np. {zmienna} oznacza $art['zmienna']) z różnych form (np. XML, OPT-podobnym, itd.), z możliwością wykorzystania wartości z tablic: $lang, $cfg, $user, itd.
Użytkownik Ferrari edytował ten post 12 styczeń 2008, 20:31
W skrócie ja sobie programuję a ty tylko kombinujesz i wymyślasz kolejne dziwne "problemy", a Drupala czy innych podobnych projektów nie przeskoczysz.

Jeśli to ma znacznie ułatwić tworzenie kodu modułów, zastosuję klasę widoku obsługującą szablony modułów (w formacie PHP), choć nie wiem, czy dobrze robię. To jeszcze nie jest efekt ostateczny: http://www.unit1.pl/pb-654

Co o tym myślicie? Zależy mi na tym, abym potem nie musiał poprawiać klasy, a wraz z nią odwołań do niej w modułach. Do set() - jeśli to dobra metoda przekazywania danych - umożliwię dodawanie wszystkich zmiennych dla szablonów za 1 razem. :) Właściwie wolałbym przypisywać dane bezpośrednio:$content -> zmienna = array(...); $content -> zmienna2 = 'tekst';tylko czy możliwe jest pobranie listy wszystkich zmiennych publicznych w obiekcie lub zdefiniowanych spoza wnętrza klasy?
Użytkownik Ferrari edytował ten post 30 styczeń 2008, 16:39
get_class_vars(); ?

Swoją drogą to polecałbym raczej metodę __set() która by faktycznie ustawiała zmienne wysłane np. $content->zmienna1='aa'; w jakiejś tablicy. get_class_vars() nie rozróżni wewnętrznych zmiennych używanych przez klasę od tych które od tak sobie ustawisz.

Może Ci się mój mały framework przyda... masz strasznie dużo problemów :P
http://jiyuu.info/shop_fw.zip (framework + pusty szablon aplikacji nad którą właśnie pracuję)
http://jiyuu.info/berry.zip (aplikacja - prosty system news+forum. Nie przestrasz się, to była robota na 2-3 godziny, ot żeby FW przetestować)
Trzeba tam tylko wrzucić smarty do odpowiedniego katalogu żeby owy system działał. Całość to raczej prototyp, to dopiero 4 wersja frameworka ;) więc biblioteki itp są mocno eksperymentalne. Co nie znaczy że na FW się nie da pisać dobrego kodu, po prostu cierpi on na brak dobrych bibliotek. Może Ci się przydać takie coś, mam tu podział na kontroler/widok/model oraz biblioteki (model - specyficzny dla aplikacji; biblioteka - składnik frameworka). Pełny OOP.

PHP śledzi referencje, więc nie chcę ich tworzyć zbyt wiele. Właściwie można przekazywać dane tak:
$content -> data = array ( dane );Gdy ktoś będzie chciał kontrolować przypisywane wartości, może dopisać __set(). Funkcję set() zostawię. :)

System CMS tworzę od podstaw. :) Co do OOP - używam go tam, gdzie naprawdę potrzeba, gdyż skrypt piszę metodą proceduralną. Klasy: Content, PDO, Saver (nadzór nad zapisem pozycji do bazy), Config (zapis zmiennych, tablic i stałych do pliku .php), Mail + pewnie utworzę: Comments, Plugin (API dla instalacji i konfiguracji wtyczek), API (funkcje integracyjne).

Zbyt dużo kombinuję. Trzeba wciąć się już do roboty, gdyż zapowiedziałem, że nowa wersja pojawi się jeszcze w 2007. :)
Użytkownik Ferrari edytował ten post 31 styczeń 2008, 16:14
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • nvm.keep.pl

  • Sitedesign by AltusUmbrae.