Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]_autoload i klasa szablonu
Forum PHP.pl > Forum > Przedszkole
-Woody-
Witam,
Szukałem na forum, ale jakoś nie umiem wykorzystać tego co znalazłem. Więc do rzeczy. Mam sobie klase szablonu template.php - standard. Wywołuje ja w indeksie łącząc z plikiem szablonu html i css. Wszystko ładnie działa, jednak w katalogu class koło klasy template mam jeszcze kilka klass, które wykorzystuje dołączając je żmudnie ręcznie. Chciałem sobie to zautomatyzować próbując wykorzystać __autoload i dopisując go do klasy template. Jednak za nic nie chce ze mną to współpracować. Oczywiście manual na temat __autoload przeczytałem i nic mi to nie dało, przykład z manuala działa ale już próba połączenia z moim template niestety nie. Może mi ktoś pomóc i łopatologicznie wytłumaczyć jak to ogarnąć lub podsunąć jakiś przykład, naprowadzić na dobrą drogę - cokolwiek.

Pozdrawiam
Woody
by_ikar
Nie działa ci dlatego że te klasy które generuje twoja klasa templatek, są w niestandardowym katalogu. Musisz albo dodać żeby autoloader przeszukiwał dodatkowe ścieżki (polecam RecursiveDirectoryIterator) i wtedy ci dołączy te dodatkowe wygenerowane klasy przez obiekt template.
watas
Wielkie dzieki funkcja zadzialala wysmienicie. Troche sie nagimnastykowalem bo jest slabo opisana w internecie, ale zadzialalo i to jest najwazniejsze.

Mam jednak inna prozbe. Parser na mojej stronie zamienia {} na konkretne wartosci i teraz jezeli probuje zamienic:
  1. ...
  2. $page->add('menu', $menu);
  3. ...


to wynik funkcji $menu nie wyswietla sie w miejscu {menu} tylko wyskakuje poza div-y strony nie wiem o co kaman. Ktos bedzie tak mily i podsunie sugestie jak zmienic parser zeby byl funkcionlany dla funkcji.
Dodam, ze funkcja $menu wyswietla tylko aktywne linki do podstron i naklada na nie tlo buttona. Mam nadzieje, ze jasno sie wyrazilem :-)

Pozdrawiam
by_ikar
Bez jakiegoś kodu, to raczej nikt ci tutaj nie wyczaruje przyczyny twojego problemu. Pokaż kod, wtedy co kolwiek będzie można powiedzieć.
watas
oczywiscie kod bardzo wazna rzecz :-)
parser siedzi sobie w klasie template.php
  1. ...
  2. function add($name, $value = '')
  3. {
  4. if (is_array($name)) {
  5. $this->dane = array_merge($this->dane, $name);
  6. } else if (!empty($value)) {
  7. $this->dane[$name] = $value;
  8. }
  9. ...
  10. function execute() {
  11. return preg_replace('/{([^}]+)}/e', '$this->dane["\\1"]',
  12. $this->tpl);
  13. }

index.tpl oparty na div-ach
  1. ...
  2. <div class="menu"'>{menu}</div>
  3. ...

index.php laduje klase template.php i wyswietla index.tpl podmienia wszytskie wartosci z pomiedzy {}
  1. ...
  2. $page->add('menu', menu());
  3. ...

jednak jesli pojawia sie zamiana na funkcje to funcja ta nie dziala w miejscu pomiedzy div-ami.

dopiero sie ucze wiec proszeo wyrozumialosc :-)
by_ikar
Nie bardzo rozumiem o co chodzi z podmianą na funkcję, pokaż przykład co chcesz zrobić. Sam jakiś czas temu zrobiłem na swoje potrzeby system szablonów, który w sumie jest podobny do tego co chcesz uzyskać, więc nawet mógłbym się podzielić wink.gif
watas
jesli pisales system szablonow to napewno zamieniales miedzy znacznikami "{jakis ciag}". Przykladowo jesli miales w szablonie:
  1. <title>{title}</title>
  2. </head>

to przy wykonaniu pliku index.php tam podmieniales {title} na "moja strona domowa". Ja robie to samo w roznych miejscach mojego szablonu zamieniajac te ciagi pomiedzy znacznikami {}.
Jednak chcialem miec funcionalny szablon gdzie bede mial odseparowany kod php od html itd. wiec napisalem miedzy innymi funkcje menu (mam tez funkcje: news, galeria itp) i teraz chce w moim szablonie chce zamienic {jakis ciag} z pomiedzy znaczniki nie na inny ciag jak to jest w przypadku title tylko na funkcje. {menu} -> menu(). Calosc mi dziala tylko problem mam z tym ze te menu nie pojawia mi sie w miejscu gdzie w szablonie wstawilem {menu} tylko na samej gorze szablonu. Wyglada to w ten sposob ze pojawia sie menu a ponizej cala reszta szablonu. Jesli jednak zamieniam {menu}->"link 1", gdzie link to tylko tekst to pojawia sie on dokladnie tam gdzie chce.
Nie wiem czy to dosc jasno napisalem bo nie wiem jak mam to inaczej wytlumaczyc.
by_ikar
Mniej więcej rozumiem o co ci chodzi, ale trochę moim zdaniem źle do tego podchodzisz. Robienie takich "tagów" w szablonach jest według mnie bezsensu, bo narzucasz sobie pewne ograniczenia, i każda dodatkowa jakaś funkcjonalność, to jest albo rozbudowa klasy, albo pisanie jakichś zbędnych helperów do tej klasy.

Niestety, wciąż za mało kodu aby mógł powiedzieć coś więcej, zarzuć całą klasą, jak się tutaj nie zmieści, to wrzuć na coś typu no-paste.
watas
hmm wydawalo mi sie to dos logiczne takie rozdzielanie kodu jesli jednak namieszalem chetnie dowiem sie jak ma to wygladac poprawnie.
index.php
  1. include 'lib/templ.php';
  2.  
  3. $page = new template('tpl/szablon.tpl');
  4. $page->load('classes/');
  5. $page->add('lang', 'pl');
  6. $page->add('title', 'FICC HOME PAGE');
  7. $page->add('charset', 'iso-8859-2');
  8. $page->add('stylesheet', 'tpl/style.css');
  9. $page->add('footer', 'Copyright ? 2011 FICC');
  10. $page->add('menu', menu()); // tak probuje zastosowac funkcje w szablonie i owszem dziala ale nie tam gdzie trzeba :-)

plik szablon.tpl
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  2. <html xmlns="http://www.w3.org/1999/xhtml" lang="{lang}" xml:lang="{lang}">
  3. <title>{title}</title>
  4. <link rel="stylesheet" href="{stylesheet}" type="text/css" />
  5. <meta http-equiv="Content-Type" content="text/html; {charset}" />
  6. </head>
  7. <div class="container">
  8. <div class="header">
  9. <div class="logo">{logo]</div>
  10. </div>
  11. <div class="menu">{menu}</div>
  12. <div class="cont">{cont}</div>
  13. <div class="footer">
  14. <div class="copyright">{footer}</div>
  15. </div>
  16. </div>
  17. </body>
  18. </html>

plik templ.php
  1. class template {
  2. var $tpl;
  3. var $dane;
  4.  
  5. function template ($name)
  6. {
  7. $this->tpl = implode('', file($name));
  8. $this->dane = Array();
  9. }
  10.  
  11. function add($name, $value = '')
  12. {
  13. if (is_array($name)) {
  14. $this->dane = array_merge($this->dane, $name);
  15. } else if (!empty($value)) {
  16. $this->dane[$name] = $value;
  17. }
  18. }
  19.  
  20. function execute() {
  21. return preg_replace('/{([^}]+)}/e', '$this->dane["\\1"]',$this->tpl);
  22. }
  23.  
  24. function load($class_name) {
  25. $files = new RecursiveIteratorIterator(
  26. new RecursiveDirectoryIterator($class_name),
  27. RecursiveIteratorIterator::CHILD_FIRST
  28. );
  29. foreach( $files as $path => $file ) {
  30. include_once($file);
  31. }
  32. }
  33. }

plik menu.class, cont.class, tylko funkcje do uzytku
  1. function menu() {
  2.  
  3. }

plik style.css standardowo ze stylami dla div i innych pierdol.

P.S dzis juz musze uciekac, niestety czas mnie goni i bede dopiero jutro, ale napewno sie odezwe. Z gory dziekuje za sugestie.

Pozdrawiam
by_ikar
Pokaż mi jeszcze zawartość tej funkcji menu, ciekaw jestem w jaki sposób wyświetlasz dane z tej funkcji, podejrzewam że jest tam echo, zgadza się? IMO ja ten kod inaczej bym rozdzielił, i ogólnie tą klasę bym nieco inaczej zrobił, brak ci tutaj jakiegoś cache, efektem czego każdy request, to jest każdorazowe odpalenie wyrażenia, przy dużej ilości zmienneych się parser napoci, dodatkowo jakbyś chciał w tym szablonie użyć jakichś warunków, pętli, to musiałbyś je robić po stronie php, a nie szablonu, tym samym mieszając html z php, efektem czego tak na prawdę nie jest to czym szablon być powinien - separacją logiki od prezentacji.
watas
dokladnie w funcji nemu jest echo wyswietla mi linki i dolacza do nich grafike buttona. Skoro wszystko co mam jest delikatnie mowiac do d..py to prosze o naprowadzenie mnie na prawidlowe tory. Jakis przyklad lub ciekawy link bym poprosil. Chetnie sie naucze poprawnie jak pisac takie rzeczy.

Pozdrawiam
by_ikar
Więc tak jak myślałem wink.gif to echo ci wyświetla twoje menu przed wyświetleniem szablonu. Stąd taki efekt. Zarzucił bym ci swój system szablonów, tyle że bez innych klas (cache), będzie chodzić nawet trochę wolniej od twojego rozwiązania. Jeżeli ci to nie przeszkadza, to mogę się podzielić swoimi wypocinami. Zastąp echo na return w tej funkcji która ci wyświetla menu i sprawdź czy to rozwiąże twój problem.
watas
hmm postaram sie jakos to zwalczyc i chetnie zobacze twoje rozwiazanie w celach porownawczych. Jesli nie chcesz na forum to na prv. Przy okazji jak powinien wygladac poprawny uklad folderow w szablonie z malym zagniezdzeniem zeby nie bylo pozniej problemow. Wogole jak bys mial polecic cos do poczytania na nten temat to chetnie zglebil bym temat.

pozdrawiam
by_ikar
Nie mam powodu dlaczego miałbym nie pokazać swojego kodu na forum - nie wstydzę się go tongue.gif nie mniej, sama klasa templatek to nie wszystko, bo to jest tylko w sumie parser i domyślnie nie pobiera z jakiegoś cache przetworzonego szablonu. Podzielić na dwie klasy musiałem, żeby pierwsza klasa działała w sumie bez niczego, ponieważ wykorzystuje ją jeszcze do rendrowania szablonów stron błędów, a tak jako tako błędów być nie może, spowodowanych np przez system cache. Ale posiada ona swoje podstawowe funkcjonalności a wygląda ona tak: https://gist.github.com/1471387 jedyne co byś musiał w niej zmienić, to 35 linijkę:

  1. 'template_dir' => array(Config::get('path.app').DIRECTORY_SEPARATOR.'templates'.DIRECTORY_SEPARATOR, Config::get('path.common').DIRECTORY_SEPARATOR.'templates'.DIRECTORY_SEPARATOR)


zamiast tej tablicy ścieżek, bo można podać ich kilka, ze względu takiego że u siebie wykorzystuje coś w rodzaju aplikacji, gdzie jest domyślna aplikacja "common", która też służy jako aplikacja do współdzielenia (szablonów/tłumaczeń/modułów/komponentów/modeli) między innymi aplikacjami. Wymyśliłem sobie coś takiego, ponieważ w kilku miejscach zdarzało mi się wykorzystywać mojego fw, do kilku różnych aplikacji, więc żeby utrzymać jakoś w miarę rozsądnie ten kod, zrobiłem podział na aplikacje - raczej nic odkrywczego. Więc tą linijkę 35, możesz zmienić na taką linijkę:

  1. 'template_dir' => '/path/to/templates/'


Pamiętając o umieszczeniu slasha na końcu podanej ściezki. Możesz podać tablicę ścieżek. Z racji tego że jest to tylko parser, nie ma takich bajerów jak includowanie innych templatek, czy includowanie całego komponentu (coś w rodzaju akcji w module, może to być np jakiś system komentarzy etc). Jak tego używać? Już pokazuje:

  1. <?php
  2.  
  3. $template = new TemplateParser(); // tworzymy obiekt, możemy do konstruktora przekazać ustawienia
  4.  
  5. $template->add(array(
  6. 'title' => 'Tytuł mojej nowej strony!',
  7. 'content' => 'Lore ipsum'
  8. )); // podajesz tablicę asocjacyjną parametrów, gdzie kluczem jest nazwa zmiennej w szablonie
  9.  
  10. $wynik = $template->render('index'); //nazwa szablonu, bez rozszerzenia (domyślne rozszerzenie .tpl)
  11.  
  12. // do zmiennej $wynik został przekazany przetworzony szablon. Możemy ten szablon wyświetlić teraz:
  13.  
  14. echo $wynik;
  15.  
  16. // możemy go też przekazać dalej, lub wyświetlić dalej, w sumie gdzie chcemy.
  17. // U mnie przetworzony szablon jest przekazywany do klasy response, która przesyła go do przeglądarki wraz z nagłówkami.
  18.  


Tak wygląda kod php, a tak wygląda szablon:

  1. <!DOCTYPE html>
  2. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  3. <title>{@$title}</title>
  4. {ignore}
  5. body { margin: 0; padding: 0; text-align: center; background: #F2F2F2; font-family: Arial; font-size: 13px; line-height: 1.6; color: #444; }
  6. {/ignore}
  7. </style>
  8. </head>
  9.  
  10. {@$content}
  11.  
  12. </body>
  13. </html>


Przetworzony szablon wygląda tak:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  5. <title><?php echo $title ?></title>
  6. <style>
  7. body { margin: 0; padding: 0; text-align: center; background: #F2F2F2; font-family: Arial; font-size: 13px; line-height: 1.6; color: #444; }
  8. </style>
  9. </head>
  10. <body>
  11.  
  12. <?php echo $content ?>
  13.  
  14. </body>
  15. </html>


Pojedyncza małpa (@) w klamrach oznacza echo, ale można też normalnie używać echo i w sumie jakiejkolwiek składni php chcemy. Jedynie pamiętając, że jak będziemy w klamrze chcieli wykorzystać małpę, to musimy "escapować" małpę, małpą. Czyli postawić dwie mały, a wyjdzie nam jedna. Korzystanie z bloków kodu (pętle, warunki) jest takie samo jak w php, z tym że lepiej korzystać z alternatywnego zapisu tych bloków:

  1. <!DOCTYPE html>
  2. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  3. <title>{@$title}</title>
  4. {ignore}
  5. body { margin: 0; padding: 0; text-align: center; background: #F2F2F2; font-family: Arial; font-size: 13px; line-height: 1.6; color: #444; }
  6. {/ignore}
  7. </style>
  8. </head>
  9. {if(!empty($content)):}
  10. {@$content}
  11. {endif}
  12. </body>
  13. </html>


O alternatywnym zapisie można poczytać w dokumentacji php, a na szybko wygląda to tak:

  1. <?php
  2.  
  3. // warunek
  4. if($warunek):
  5. // ...
  6. endif;
  7.  
  8. if($warunek):
  9. // ...
  10. elseif($warunek2):
  11. // ...
  12. endif;
  13.  
  14. // blok switch
  15. switch($zmienna):
  16. case 1:
  17. // ...
  18. break;
  19.  
  20. case 2:
  21. // ...
  22. break;
  23.  
  24. default:
  25. // ...
  26. break;
  27. endswitch;
  28.  
  29. // pętla for
  30. for($i = 0; $i < 10; $i++):
  31. // ...
  32. endfor;
  33.  
  34. // pętla foreach
  35. foreach($array as $row):
  36. // ...
  37. endforeach;
  38.  
  39. // pętla while
  40. while($warunek):
  41. // ...
  42. endwhile;


Klamry prawdę mówiąc nie są niczym innym jak tagami php: <?php ({) oraz ?> (}). Ale żeby przypadkiem nam tych klamer nie podmieniło w miejscu w którym nie chcemy, a może to być css, javascript, lub nawet sam html. Wówczas taki kawałek kodu który zawiera klamry, łapiemy blokiem ignore:

  1. <!DOCTYPE html>
  2. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  3. <title>{@$title}</title>
  4. {ignore}
  5. body { margin: 0; padding: 0; text-align: center; background: #F2F2F2; font-family: Arial; font-size: 13px; line-height: 1.6; color: #444; }
  6. /* ten kod css zostanie pominięty, a w przetworzonym szablonie nie będzie bloku ignore */
  7. {/ignore}
  8. </style>
  9. </head>
  10.  
  11. {@$content}
  12.  
  13. </body>
  14. </html>


Odnośnie samej klasy szablonu - nie jest to szczyt, pewnie są lepsze, pewnie kale w oczy wredny eval, no ale inaczej nie wiedziałem jak to rozwiązać. Eval jest używany tylko wtedy kiedy nie można sobie za bardzo pozwolić na uruchomienie cache i skorzystanie z cache. W przypadku kiedy cache działa - czyli kiedy aplikacja działa prawidłowo, można napisać właściwą klasę szablonu, która nadpiszę metodę rendrer klasy TemplateParser, dodają dodatkowe funkcje (includowanie innych szablonów, lub includowanie komponentów), a wyglądać to może tak: https://gist.github.com/1471520 w ten sposób zyskujemy możliwość includowania komponentów i szablonów, oraz nasze szablony są już przetrzymywane w cache, dzięki czemu nie korzystamy z evala, a nasze szablony działają dużo szybciej, ponieważ cache szablonów, to zwykły kod php, czyli największym narzutem będzie includowanie tego szablonu. Użycie dodatkowych opcji:



  1. {include_component('layout::header')}
  2.  
  3. <div id="logowanie">
  4. <form method="post" action="{@BASE_URL}/login" name="logowanie">
  5. <label for="id_login">Login</label><br>
  6. <input type="text" id="id_login" name="login"><br>
  7. <label for="id_password">Hasło</label><br>
  8. <input type="password" id="id_password" name="password"><br>
  9. <button type="submit">Zaloguj</button>
  10. </form>
  11. </div>
  12.  
  13. {include('footer')}


komponentem może być nasz cały skomplikowany top strony, możemy przekazać do niego jakieś parametry etc. W stopce możemy mieć tylko zwykły kod html, więc wystarczy że zaincludujemy szablon.

Niektóre rozwiązania podpatrzone w symfony (metoda evaluate, z nieszczęsnym evalem ;p). Jak się komuś podoba - korzystać, nie zapominając napisać do tego klasy która będzie dziedziczyła klasę parsera i nadpisywała metodę render, która nie tylko nie potrzebnie przetworzy nam szablon w evalu, ale również w przypadku kiedy stosujemy cache, to metoda ta, sama sprawdzi czy szablon który chcemy przetworzyć, czy istnieje. W przypadku kiedy mamy w miarę przyzwoity system cache, w którym możemy podać sobie "zależność" od innego pliku, wówczas ta dodatkowa funkcjonalność parsera będzie zbędnym narzutem wydajnościowym (nie wielkim, ale grosz do grosza i będzie kokosza). Stosować możecie klasę gdzie chcecie, zmieniając ją jak chcecie, jedynie zostawiając info o autorze. Ewentualnie jak ktoś będzie chciał może zarzucić jakąś krytyką.

@watas odnośnie jakichś materiałów do czytania, w sumie obiektówki nie uczyłem się jakoś specjalnie z książek, znaczy podstawy tam przeczytałem, ale nie wiele tam na temat obiektywności tak na prawdę było. Resztę doczytałem z internetu, jak w sumie sporo osób. Czytaj blogi na planeta.php.pl analizuj popularne frameworki (symfony, zend, kohana, yii itp). W sumie najwięcej się nauczyłem z analizy frameworków.

EDIT: zapomniałem o jednej jeszcze rzeczy, w smarty podobał mi się sposób zapisywania tablicy wielowymiarowej:

  1. {$tablica.klucz.drugi_klucz.trzeci_klucz}


I w tej mojej klasie, również można tak zapisywać tablice, ale można również je zapisywać w klasyczny sposób:

  1. {$tablica['klucz']['drugi_klucz']['trzeci_klucz']}


Praktycznie żadnych ograniczeń, prócz właściwie 2:
- kod php umieszczamy w klamrach, lub w tagach php (nie wiem czy to ograniczenie, ten kod tak czy siak musimy umieścić w tagach, więc umieszczanie w klamrach chyba nie jest ograniczeniem)
- wewnątrz klamry lub kodu php, nie możemy umieszczać klamr przykładowo bloków warunkowych, lub pętli. Stąd alternatywny zapis tych instrukcji.
watas
UUU sporo tu tego :-) zanim to przetrawie to troche potrwa wiec dziekuje z gory, a kodem sie pobawie. Napewno czegos mnie nauczy.

Pozdrawiam
by_ikar
No nie jest jeszcze tego aż tak sporo, bo do tego jeszcze mam inne klasy podłączone (cache, response, klasa modułu, container). No i dlatego nie chciałem od razu tego tutaj dawać, bo raz że opisanie tego trochę mi zajęło, no a dwa, nie wiedziałem czy ci ćwieka nie zabije (ponoć tak się mówi ;p).
watas
Mysle, ze na chwile obecna wystarczy biggrin.gif zeby uporac sie z moim problemem. Wielkie dzieki za pomoc

Pozdrawiam
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.