Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Klasa szablonu - czy się nada?
Forum PHP.pl > Forum > Przedszkole
Evinek
Tworzę klasę do obsługi szablonów. Mógłbym dać ten temat do działu Oceny, ale nie warto chyba o taką rzecz.
Chciałbym się dowiedzieć czy mój kod jest: optymalny, napisany prawidłowo z zasadami OOP i czy się nadaje na strone. Dodatkowo możecie napisać czy dobre mam nazewnictwo klasy, funkcji, zmiennych.

Jest tam jedna funkcja (get_dir()) której będę najwyżej używał poza klasą, a wewnątrz używam zmiennej dir.
Jeszcze myślę nad tym aby dać private funkcji load() ponieważ jest ona używana tylko wewnątrz klasy.

Kod:
https://www.dropbox.com/sh/eddsygq5kwhv3ty/FRDwEvOfGJ
Live:
http://evinek.ugu.pl/template/

Z góry dziękuje.
Pozdrawiam, Paweł.
peter13135
Jest optymalne, ale... to raczej nie jest system szablonów, bo nie robisz swojego "języka" tylko korzystasz z "wbudowanego systemu szablonów w php". Smarty, czy twig to całkiem inna bajka. Tzn, szablon jest kodem php, więc trudno nazwać to system szablonów
Przydała by się opcja dodawania także tablic zmiennych, tzn zamiast set_var, funkca set_vars, trochę by to skróciło kod.

Poza tym, nazewnictwo zmiennych przyjeło się trochę inne np. getCośtam() lubięPlackiZMarmoladą() itd.

Poza tym... do stron sie nada, ale smarty czy twig są dużo lepsze.
Mephistofeles
  1. public function load($file){
  2. include ($this->dir.$file.'.php');
  3. $page = ob_get_contents();
  4. echo $page;

Jaki to ma sens? Nie potrzebujesz echo, include przecież też wyświetli efekt.

Dobry przykład takiego komponentu.
Ale i tak lepiej używać Twiga.
Evinek
Na początek funkcja load(). Jakimś cudem potrzebowałem kiedyś tego sposobu bo coś miałem nie tak. Samo include działa prawidłowo i się ciesze. Dzięki!

Co do peter13135, to tak:
Funkcją set() mogę dodać zmienną, tablice jak i nawet object. Chciałem po prostu abym mógł swobodnie przesyłać dane między szablonem a całym skryptem.
Co do nazewnictwa to również się zgodzę. Często widziałem, że pisali z podłogą nazwy i jakoś mi też się to napisało tak. Oczywiście przepisze te nazwy na nowo.

I jeszcze co do gotowych systemów. Nie chce mi się uczyć ich języków, ani bawić się ich skryptami. Wolę pouczyć się i robić w czystym PHP.

Pomógł dla oby dwóch. Jeszcze jakieś rady?

Mephistofeles
Tak. Brakuje funkcji takich jak escape (pisanie za każdym razem htmlspecialchars itp. jest mało przyjemne), obsługi helperów (np. do generowania absolutnych URLi), rozszerzania szablonów (dołączanie części z innych to nie to samo).
Evinek
Escape dodam. Helpery te dodać jako zwykłe funkcje w klasie czy jak? Bo za bardzo nie znam się na nich. Może parę słów więcej o tym?
Co masz na myśli "rozszerzenia szablonów"?
Mephistofeles
http://symfony.com/doc/current/book/templa...nce-and-layouts
Tu masz wytłumaczone na czym polega rozszerzanie i dziedziczenie szablonów i czym się różni od dołączania szablonu do innych.
A co do helperów to rób jak chcesz, możesz dodawać je jako funkcje, które można uruchomić z szablonu, możesz jako klasy i uruchamiać je jakoś pośrednio.
Chodzi tylko o to, żebyś w szablonie mógł zrobić np.:
escape($costam) zamiast htmlspecialchars(), url('/costam') zamiast wpisywać absolutną ścieżkę za każdym razem itd.
droslaw
Do helperów możesz użyć metody __call. Pozwoli ona ładować helpery w razie potrzeby. Jeśli będziesz miał dużo helperów, to lepsze niż dodawanie ich jako metody klasy Template.
Evinek
Nad helperami jeszcze pomyśle jak zrobić.

Co do dziedziczenia to, jeśli dobrze zrozumiałem, chodzi o to, że po prostu tworzę kod do innego szablonu (np. news.php) i tylko zamieniam dane w divie (id="content").
Przykład ze stronki:
  1. <!-- src/Acme/BlogBundle/Resources/views/Blog/index.html.php -->
  2. <?php $view->extend('::base.html.php') ?>
  3.  
  4. <?php $view['slots']->set('title', 'My cool blog posts') ?>
  5.  
  6. <?php $view['slots']->start('body') ?>
  7. <?php foreach ($blog_entries as $entry): ?>
  8. <h2><?php echo $entry->getTitle() ?></h2>
  9. <p><?php echo $entry->getBody() ?></p>
  10. <?php endforeach; ?>
  11. <?php $view['slots']->stop() ?>

Czyli block "body" będzie zawierał kod i dodam go tylko w szablonie sposobem:
  1. <?php $view['slots']->output('body') ?>

Trochę to dziwne dla mnie i pewnie nie zrozumiałem do końca. Może ktoś jeszcze bardziej to wytłumaczyć?

Pomógł oczywiście dla oby dwóch.

PS. Nie mam zaawansowanego słownictwa w angielskim więc na początek próbuje czytać trochę, a później z translatorem lecę.
droslaw
Wyobraź sobie taką sytuację. Masz dwa szablony: layout i news. News rozszerza layout. W momencie kiedy wyświetlasz szablon news, pojawia się layout z tym, że treść wybranych bloków/slotów layout`a może być określona w szablonie news. Przez to możesz stworzyć jeden layout dla całego serwisu, a pewne jego fragmenty będą zmienne w zależności od tego, czy wyświetlasz np. wiadomości, czy kategorie.

To co tworzy translator też zwykle chyba trudno zrozumieć.
Czytać teksty w obcych językach pomaga StarDict. StarDict nie tłumaczy całych zdań, ale możesz skonfigurować tak, że będzie wyświetlał okienko z tłumaczeniem zaznaczonego słówka. Tłumaczenie możesz zapisać na dysku w formacie html. Kiedyś napisałem skrypt, który te tłumaczenia konwertuje do formatu Paukera (dobrze się sprawdza w nauce słówek) i mogłem uczyć się np. w autobusie. Oszczędziło mi to sporo czasu.
Evinek
Czyli, jeśli dobrze rozumiem, to będę miał na przykład taki szablon(layout.php):
  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title><?php echo $this->get('title'); ?></title>
  6. </head>
  7. <body>
  8. <div id="error">
  9. <?php $this->block_load('error'); ?>
  10. </div>
  11. <div id="main">
  12. <div id="header">
  13. <!-- KOD HEADER -->
  14. </div>
  15. <?php $this->block_load('success'); ?>
  16. <div id="content">
  17. <?php $this->block_load('content'); ?>
  18. </div>
  19.  
  20. <div id="footer">
  21. <!-- KOD FOOTER -->
  22. </div>
  23. </div>
  24.  
  25. </body>
  26. </html>


A w szablonie news.php:
  1. <?php $this->block_start('content'); ?>
  2. //Pętla z newsami czy coś
  3. <?php $this->block_stop('content'); ?>
  4. <?php $this->block_start('success'); ?>
  5. <div id="success"> POPRAWNIE WYŚWIETLONO NEWSY </div>
  6. <?php $this->block_stop('success'); ?>


Klasa oczywiście automatycznie doda layout.php do news.php.
Dobrze rozumiem?

Ja miałem taki pomysł, aby zrobić takie coś:
Każdy szablon (np. news.php, contact.php) był by osobnym plikiem, a w nich bym ładował tylko te dane które są potrzebne. Przykład(news.php):
  1. <?php echo $this->getDoctype(); ?>
  2. <html>
  3. <head>
  4. <?php echo $this->getMeta(); ?>
  5. <title><?php echo $this->get('title'); ?></title>
  6. </head>
  7. <body>
  8. <div id="main">
  9. <?php $this->load('header'); ?>
  10. <?php $this->load('success'); ?>
  11. <div id="content">
  12. <?php $this->load('jeszcze_cos'); ?>
  13. </div>
  14.  
  15. <div id="footer">
  16. <?php $this->load('footer'); ?>
  17. </div>
  18. </div>
  19. </body>
  20. </html>

Wtedy będę mógł dodać menu (akurat na mojej stronce jest tylko w zakładce newsy) tylko do jednego szablonu, a jak będę chciał to do wielu.
W każdym "bloku" pobierał bym tylko dane ($this->get('zmienna')) i tam obrabiał ładnie w HTML'a.

Czy to nie jest lepszy pomysł niż z tymi blockami? Chyba nawet podobny bo w divie (id content) i tak będę ładował "bloki"(wyświetlenie listy newsów, podgląd itp.).

Czekam na odpowiedź. smile.gif
droslaw
Co do dziedziczenia, dobrze rozumiesz. Musisz tylko w szablonie potomnym zaznaczyć, który szablon rozszerzasz np:
  1. <?php
  2. // news.html.php
  3. $this->extend('layout.html.php');

W kodzie, który podałeś zmieniłbym jeszcze system nazewnictwa metod na CamelCase np. blockStart zamiast block_start.

W Twoim pomyśle jest ta wada, że mimo przechowywania nagłówków, menu itp. w osobnych sablonach dublujesz kod. Jeśli chciałbyś zmienić położenie menu, musiałbyś edytować każdy szblon.
Evinek
To jakim sposobem miał bym np. włączyć menu tylko dla news.php?
$this->on('menu')? haha.gif
Nie no, a tak serio, to jak taki problem rozwiązać?
Dziś lub jutro stworzę jakiś kod i zobaczymy wtedy czy będzie git. smile.gif
A te blockStart i stopStart zrobić na funkcjach ob_start() itp. jakoś? Nie wiem czy zadziała, że w funkcji start włączę, w stop wyłączę + dodam do zmiennej - później sprawdzę.
droslaw
Jeśli menu chcesz dołączyć tylko z szablonem news, możesz zdefiniować jego treść w tym szablonie, dla reszty ten blok będzie pusty.
blockStart i blockStop to właśnie ob_start i ob_get_clean.

Edit:

Ciągle piszemy blockStart i blockStop, ale te metody powinny nazywać się startBlock i stopBlock.
Evinek
Dobra, coś stworzyłem.
Kod: https://www.dropbox.com/sh/3udzl1row9oxhvc/mJ4GKAEFw5
Live: http://evinek.ugu.pl/template/

Czy teraz jest wszystko dobre aby robić na tym szablony? Oczywiście jakieś poprawki jeszcze będą. Myślę też nad funkcjami typu addMeta, addCss itp.
W template news.php muszę ładować główny szablon (index.php) na dole aby działały blocki - ale to chyba nie problem.
Jeszcze jakieś rady?
droslaw
Nazwę klasy pisze się z dużej litery.
U mnie konstruktor przyjmowałby jako parametr pełną ścieżkę do szablonu. Napisałbym jeszcze jakąś ładowarkę, która ładowałaby szablony z katalogów określonych w konfiguracji, zależnych od aktualnego kontrolera itp. (to już inna klasa).
Metoda setTitle nie jest potrzebna wystarczyłoby set('title', 'tytuł');
Dodałbym metodę extend. Oznaczałaby ona, że trzeba doładować szablon po zakończeniu przetwarzania głównego szablonu(np. news). To byłoby bardziej czytelne niż load().
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.