Klasa widoku

Często na Waszych stronach wstawiacie jakiś system szablonów, np. Smarty. A potem biegacie po forach z pytaniami a jak zrobić to a jak tamto w takim Smarty. Dodatkowo taki system to jedna wielka kobyła, która na dobrą sprawę w niczym nie usprawnia życia, a wręcz czasami komplikuje. Często wpadacie na pomysł, by napisać własny system szablonów. Ale to również nie jest zbyt dobry pomysł. Zadam Wam pytanie: ale po co w ogóle bawić się w system szablonów? Odpowiecie zapewne: by oddzielić wygląd aplikacji od jej logiki. Tak, po to. Ale po co bawić się w system szablonów, który oprócz wprowadzanie własnej nowej składni nie robi tak naprawdę nic użytecznego. Może po prostu wprowadzić system, który będzie operował jedynie na czystym HTML oraz PHP. Wówczas nie trzeba poznawać żadnej nowej składni ani bawić się w dzikie parsowania szablonów. I taką właśnie klasę widoku chcę Wam dziś pokazać.

Słowniczek

Na początek wyjaśnienie paru pojęć, które padną podczas tego artykułu:

  • Główny widok/szablon - plik, który zawiera ogólny wygląd naszej aplikacji. Zawiera całą otoczkę, nagłówek, stopkę, dołącza pliki js czy css. Może istnieć kilka widoków głównych, gdy np. jakaś akcja wymaga naprawdę innego wyglądu ogólnego
  • Widok/szablon akcji - plik, który zawiera wygląd konkretnej akcji. Plik ten jest dołączany w głównym widoku
  • Plik akcji - plik z kodem php, w którym wykonuje się logika danej akcji. W pliku tym można zapisywać dane odbierane w widoku.
  • Portlet - plik z widokiem jakiegoś kawałka, który może być wykorzystywany w kilku różnych widokach, np. portlet z menu może być dołączany w głównym widoku 1 oraz w głównym widoku 2. Zamiast powtarzać w obu głównych widokach ten sam kod, po prostu tworzymy portlet i dołączamy go do widoków
  • Plugin - kod php dołączany do widoku. Różni się od portletu tym, że w pluginie możemy wykonywać jakąś logikę, np. pobierać newsy z bazy i je wyświetlać, podczas gdy portlet służy jedynie do wyświetlania przygotowanych wcześniej danych

Klasa widoku

Klasa widoku ma za zadanie wyświetlanie naszych widoków, które tak naprawdę są zwykłym kodem PHP zmieszanym z HTML. Klasa jest naprawdę prosta i krótka. Posiada kilka podstawowych metod:

  • Render - wyświetla podany widok oraz ustawia w nim zmienne, jeśli podano
    Przykładowe wywołanie w widoku: $this->Render('portlet_menu');
  • Escape - przetwarza dane, które teoretycznie mogą być niebezpieczne, np. pochodzące od użytkownika
    Przykładowe wywołanie w widoku: $this->Escape($this->zmienna);
  • Plugin - wywołuje plugin, można przekazać tablicę parametrów
    Przykładowe wywołanie w widoku: $this->Plugin('Main_News'); $this->Plugin('User_Online',array('par1'=>'war1'));
Ponadto posiada metody magiczne (niewtajemniczonych odsyłam do manuala php), dzięki którym można przypisywać i odbierać zmienne. Przykładowo w pliku akcji możemy przypisać do widoku w taki sposób zmienne:
<?php
$view->zmienna1 = 'coś tam';
$view->zmienna2 = 5;
$view->tablica = array(1,2,3,4,5);
$view->tablica[5] = 6;
?>
Zaś w widoku zmienne te obieramy tak:
<?php
echo $this->zmienna1;
echo $this->zmienna2;
foreach ($this->tablica as $klucz => $wartosc) echo $klucz.' - '.$wartosc;
?>

Widok

Jak pisałem wcześniej widok, to po prostu plik z wymieszanym kodem HTML oraz PHP. W widoku do obiektu naszego widoku odwołujemy się przez $this. Przykładowy kod pliku widoku

<p>
<b>Witajcie na stronie głównej mojej testowej aplikacji</b>
</p>
<p>
A tutaj wartość zmiennej, którą przypisaliśmy w akcji: 
<?php echo $this->Escape($this->zmienna);  ?>
</p>
<p>A tutaj wyświetlamy zawartość tablicy</p>
<p>
	<?php foreach ($this->tablica as $val): ?>
		Wartość: <?php echo $val; ?><br />
	<?php endforeach; ?>
</p>

Oczywiście wszystkie wykorzystane tu zmienne czy tablice przypisałem wcześniej w pliku akcji.
Przyjąłem, że pliki widoku mają rozszerzenie .phtml

Pluginy

Plugin to klasa odpalana w widoku i wykonująca jakąś logikę. W pluginie np. można pobrać newsy z bazy i wyświetlić je. Każdy plugin powinien dziedziczyć z klasy ViewPluginBase i implementować metodę Run, która to będzie wyświetlać to co dany plugin ma wyświetlać. Nazwa klasy pluginu ma się składać ze stałego członu "Plugin" a następnie Moduł_Nazwapluginu. Przykładowy kod pluginu:

<?php
class PluginMain_News extends View {
	public function Run($params = array()){
		//tutaj kod odpowiedzialny za pobieranie newsów z bazy.
		//no wiecie, mysql_query, mysql_fetch_array i spółka
		
		//ja tu teraz wstawię przykładowe newsy, 
		//bo nie chce mi się tworzyć tabel na potrzeby tej aplikacji
		$news = 'Pierwszy news';
		$news.= '<br />Drugi news';
		$news.= '<br />Trzeci news';
		
		echo $news; //i wyświetlamy newsy
	}
}
?>
W widoku zaś do pluginu odwołujemy się tak:
<?php
$this->Plugin('Main_News');
//lub tak, jeśli chcemy przekazać jakieś parametry
$this->Plugin('Main_News', array('par1'=>$war1, 'par2'=> $war2));
?>

Struktura aplikacji

Na potrzeby zobrazowania jak działa widok stworzyłem na szybko pseudo aplikację MVC. Założyłem, że aplikacja składać się będzie z modułów a te zaś z akcji. W katalogu głównym znajdują się katalogi "actions" oraz "plugins". Pierwszy z nich jest katalogiem przeznaczonym na pliki akcji i pliki widoków. Katalog "actions" zawiera katalogi będące nazwami modułów a w nich są pliki akcji. Jeśli mamy np. akcję o nazwie "login" w module "user" to w katalogu "actions" znajdować się będzie katalog "user" z plikami login.php (plik akcji) oraz login.phtml (plik widoku).
Katalog "plugins" zawiera pluginy modułów. Tutaj również najpierw jest katalog z nazwą modułu a w nim dopiero pliki z pluginami modułu. Plik pluginu nazywać ma się tak: Nazwa.class.php, czyli np.: News.class.php
No i jeszcze bezpośrednio w katalogu "actions" znajdują się pliki głównych widoków czy też portlety przez nie wykorzystywane.
Przykładowa struktura aplikacji:

  • actions
    • main
      • main.php
      • main.phtml
    • user
      • login.php
      • login.phtml
      • register.php
      • register.phtml
    • index.phtml
    • portlet_menu.phtml
  • plugins
    • main
      • News.class.php
  • index.php

Podsumowanie

I tyle, to wszystko jeśli chodzi o widok i klasę widoku. Jak widzicie żadnej filozofii tutaj nie ma. Prosty kod php a załatwia nam sprawę oddzielenia logiki aplikacji od jej wyglądu i nie trzeba się bawić w żadne kobylaste systemy szablonów.
Paczkę z klasą oraz przykładową aplikację wykorzystującą tę klasę jak zwykle znajdziecie w dziale download. Po przejrzeniu tej aplikacji podejrzewam, że rozjaśni Wam się bardziej w głowach .

Edit:
Najnowsza wersja View 1.1

Komentarze

 

2013-06-13 09:06 gość_hwao

Metody magiczne w szablonach to zuoo, za kazdym razem potem nie wiadomo co jest albo trzeba PHPDoca generowac

2013-06-13 09:07 nospor

Mi to nie przeszkadza, wręcz nie wyobrażam sobie jak niby w szybki sposób miałbym dobierać się inaczej np. do tablicy wielowymiarowej. A tak:
$this->tablica['index1']['index2'];
i juz

2013-06-13 10:06 gość_jogi

Witam.

Teoretycznie ciekawa opcja.

Czy wykonywane były jakieś testy wydajnośći? Jak wygląda wydajnośc tego mechanizmu na tle innych systemów np RainTPL (jeden z lżejszych) ?

Troszeczke przeszkadza czytelmnośc kodu w szablonie. Ale ogólnie opcja ciekawa.

2013-06-13 10:10 nospor

Niestety nie używałem RainTPL więc nie wiem. Jeśli natomiat ten RainTPL jak każdy system szablonów ma swoją składnie, którą potem i tak kompiluje do kodu HTML/PHP, to klasa widoku nie będzie od tego wolniejsza, gdyż to już od razu działa na kodzie HTML/PHP

2013-06-13 10:48 gość_Kacper Kołodziej

Swego czasu, zainspirowany Smarty napisałem sobie coś podobnego, ale prostszego. Dopiero po jakimś czasie zorientowałem się jak bezsensowne to było. Teraz najczęściej piszę w Zend Frameworku, który rozwiązuje moje wszystkie problemy A "nawrócił" mnie chyba Spawn Framework

2013-06-13 11:01 nospor

ZF ma chyba podobny system, a przynajmniej tak mial ZF1 i napewno idea była podobna. Kodu wykonania nie porównywałem.

2013-06-13 11:24 nospor

Troszeczke przeszkadza czytelmnośc kodu w szablonie.
To chyba kwestia przyzwyczajenia. Na początku faktycznie trzeba się przestawić na taki widok. Mi kiedyś strasznie przeszkadzała składnia endforeach, a tutaj w tego typu widokach jest wręcz nieoceniona

2013-06-14 08:42 gość_WooDzu

Lepiej bym tego nie mógl ujac. Zamiast uczyc sie skladni systemu szblonów lepiej zmarnowac czas na cos bardziej pozytecznego jak skladnia nowego jezyka. Sorki za brak polskich znaków

2013-09-10 10:15 aleks365

Gdyby nie to, że zacząłem pewien projekt już dawno na innym silniku, to bym użył Twojej klasy

2013-12-05 13:44 gość_hyh

Osobiście szablony bym trzymał w osobnym katalogu niż akcje

2013-12-13 20:31 gość_com

Zapomniałeś o filtrowaniu akcji przyjmowanych od użytkownika np
http://localhost/view/index.php?m=user&a[]=0
http://localhost/view/index.php?m=user&a=0

2013-12-13 21:14 nospor

To tylko prosty przyklad wykorzystania a nie super hiper produkcja.... Chialem tu pokazac jak wykorzystac klase widoku, a nie tworzyc produkcyjną aplikacje. No tak trudno dostrzec roznice?

2013-12-14 19:05 gość_com

Ja Ciebie rozumiem, ale przeciętny Kowalski jak dostaje gotowe to już nic tam nie pozmienia... co najwyżej doda coś własnego do actions, a index.php czy też View.php pozostawi nie zmienione, dlatego o tym, wspomniałem, nie musisz się tak denerwować, sam dobrze wiesz z jakimi problemami ludzie na forum przychodzą i nawet jak im podsuwasz sposób, to oni dalej liczą na gotowca i tutaj pewnie będzie tak samo, bo ogólnie idea mi się podoba i jest to na pewno lepsze od tych wszystkich Smarty i tym podobnych...

2013-12-14 20:45 nospor

To w takim razie jest to problem przecietnego kowalskiego. Art jest kierowany dla nieprzecietnych kowalskich, do ludzi ktorzy umieją czytac i jak jest napisane, ze podana aplikacja jest tylko szybkim przykladem wykorzystania, to zrozumieją co to znaczy
Celem artu nie jest tlumaczenie jak filtrowac zmienne otrzymywane z forma czy urla

Jakos specjalnie sie nie zdenerwowalem, tylko pomyslalem ze ty tak na powaznie. A skoro nie, to sprawy nie ma.

2013-12-15 00:10 gość_com

Okej, ale mimo wszystko trafiają tu na pewno rożni kowalscy, bo sam nawet kilka razy im poleciłem ten twój art, ale jakoś wcześniej się nigdy mu nie przyjrzałem z bliska, wiec ta uwaga może się komuś przysłużyć, że zanim ktoś to wykorzysta na produkcji, powinien zadbać o filtrowanie url. W pełni się z Tobą zgadzam, że to nie było celem, ale uznałem, że skoro to zauważyłem to wspomnę, a zawsze te parę lini można w przykładzie zamieścić bez konkretnego rozpisywania się nad ich sensem istnienia, tym bardziej, że o dane z form w jakiś tam sposób zadbałeś (Escape - przetwarza dane, które teoretycznie mogą być niebezpieczne, np. pochodzące od użytkownika ) Czego nie musisz oczywiście robić, ale znając życie połowie przeciętnych kowalskich, jak zwykle będzie się wydawało, że są nieprzeciętni i zrobią tak jak powiedziałem...

2013-12-15 19:30 nospor

No dobrze, ale uwaga ktora zglosiles nie wplywa w zaden sposob na bezpieczenstwo czy na bledne dzialanie aplikacji. Jak ktos poda bledny parametr "a" to mu sie nie wyswetli zadna akcja, ot i wszystko.

Jedyne co mozna dodatkowo zrobic to sprawdzac czy plik istnieje przed include, w celu nie generowania warningow.

2014-02-27 12:04 gość_Piotr

Ciekawe rozwiązanie - właśnie testuję.
Dwie drobne rzeczy rzuciły mi się póki co w oczy:

1. Mamy sprawdzanie czy dany moduł istnieje, ale nie ma sprawdzenia czy dana akcji istnieje, więc jeśli odniesiesz się do modułu (istniejącego) z akcją, która nie istnieje - PHP "rzuca błędem" zamiast wyświetlić komunikat, że nie ma takiej akcji

2. Kwesta nazw. W tej chwili domyślną akcją każdego modułu jest main, co powoduje, że w naszej aplikacji mamy mnóstwo plików main.php i łatwo się można w tym pogubić. Czy nie byłoby lepiej gdyby domyślną akcją była nazwa danego modułu?
Np. dla modułu user - domyślna akcja user, a dla modułu klienci, akcja klienci itp.

..to tylko sugestie

2014-02-27 12:18 nospor

Piotrze,
ad1) w index.php masz taki kod z komentarzem:
include($pathAction); //tutaj można dodać sprawdzanie czy plik istnieje i odpowiednio reagować
To chyba wszystko wyjasnia

ad2) Nikt nie każe używać domyślnych akcji. Zauważ że moduł USER nie ma domyślnej akcji. Tak samo nie musi jej miec żaden inny.
A jeśli ktoś chce mieć domyślną akcje i nadal przeszkadza mu nazewnictwo main, to naprawdę nie widze problemu by zmienił.

To tutaj co pokazałem to tylko prosty przykład, jak można szybko i łatwo napisać własną klasę widoku.

Dodaj komentarz

 

Dostępne bbcode: b, u, i, url, code, php, css, html, sql, js

Ostatnio komentowane

  1. ShoutBox nospor
  2. ShoutBox Artur
  3. PHP South Coast conf... nospor
  4. PHP South Coast conf... srednioZaawansowanyPHPowiec
  5. Docker - podstawowy ... nospor
  6. Docker - podstawowy ... Leelum
  7. Pager nospor

Skrypty użytkowników

  1. Klasa obsługi szablo... Lirdoner
  2. Sekcje user76
  3. Klasa walidująca for... user76
  4. Licznik Gości online korey
  5. Form Builder Comandeer
  6. Dynamiczny licznik z... korey
  7. Captcha Comandeer