Blog (2)
Komentarze (16)
Recenzje (0)

Smarty - Szablony w aplikacjach PHP #1

@dingo12Smarty - Szablony w aplikacjach PHP #118.07.2011 22:04

SPIS TREŚCI: Smarty - Szablony w aplikacjach PHP #1 Smarty - Szablony w aplikacjach PHP #2

Kilka słów wstępu...

Każdy starszy programista wie, że aby projektem swobodnie mogło zarządzać kilka osób należy rozdzielić politykę biznesową od polityki prezentacji. Osoby, które same zajmują się pisaniem w PHPie, czy też innym języku programowania wiedzą, że można od razu przystąpić do pracy - na bieżąco pisać kod i rozmyślać co dodać dalej. Nie jest to najlepsze podejście, chyba że potrzebujemy zrobić małą stronę, która będzie np. wyświetlać rekordy z bazy danych i wpisywać je do tabeli. Do takich zastosowań nie potrzeba wielkich, obszernych, pamięcio i moco-żernych frameworków. Jednak jeżeli chcemy stworzyć stronę o dużo większych wymaganiach, warto na początku zaprojektować i przemyśleć z jakich komponentów będzie składać się nasza strona, oraz jakie opcje musimy zaprogramować, aby osiągnąć dobre rezultaty. Dzięki podzieleniu strony na komponenty możemy później w łatwy sposób wykorzystać je w innym projekcie.

Dzisiejszym tematem jest...

Dzisiaj chciałem przedstawić wam pokrótce nie framework do PHP, a małą klasę pozwalająca na oddzielenie warstwy prezentacji od warstwy reguły biznesu i warstwy dostępu do danych - SMARTY. Podstawowym zadaniem Smartiego, bo tak go dalej będę "przezywał", jest oddzielenie logiki aplikacji od logiki jej prezentacji. Wbrew pozorom Smarty zawiera pewne cechy logiki, która ułatwia odseparowanie PHP'a od szablonu i styczności z kodem HTML.

Co to jest warstwa dostępu do danych?

Są to dane, które chcemy zaprezentować użytkownikom. Dane te mogą być zapisane w postaci plików XML, w bazie danych SQL, w pliku, a nawet na sztywno zapisane w tablicy.

Co to jest warstwa reguł biznesu?

Tutaj prowadzimy cała logikę strony. Programujemy przypadki, które różnymi interakcjami narzuca nam użytkownik. Kliknięcie w button wyślij, a następnie obrobienie danych i wrzucenie do bazy danych, czy nawet proste sortowanie filtrowanie danych z warstwy dostępu do danych.

Co to jest warstwa prezentacji?

To jest wszystko, co widzi użytkownik. Cały układ strony, wyświetlane dane, CSS, obrazki...

Jak to wygląda w praktyce?

Smarty jest specjalną klasą, której obiekt tworzymy w logice aplikacji. Przetwarzamy potrzebne dane i przed wyświetleniem szablonu przekazujemy do logiki prezentacji. Ustawiamy żądany szablon i za resztę odpowiedzialna jest osoba kreująca wizerunek do naszej strony. W praktyce (przykład: firma w której odbywam praktyki) za to odpowiedzialny też jest programista. Jedynie poprawki nanosi projektant, oprócz odwalenia całej roboty stworzenia szablonu i podstawowej integracji. Co dalej? Wywołując metodę display, na klasie Smarty, ustawiamy szablon, który wykorzystywany będzie do wyświetlenia naszej strony. Późniejszym zdaniem jest wyświetlić przekazane informacje. Więcej szczegółów zamieszczę niżej.

Smarty, a szybkość.

Smarty generuje z szablonów TPL, zwykły kod PHP i przetrzymuje go w pamięci cache. Przy kolejnych wywołaniach szablon, na który nie nanieśliśmy żadnych zmian brany jest z pamięci cache. Nie wpływa to znacznie na szybkość naszego kodu.

Smarty, a bezpieczeństwo.

Bezpieczeństwo. Kluczowa rzecz. Nie wiem, czy wcześniej udało mi się choć trochę naszkicować jak działa Smarty, warto tutaj wspomnieć, że nie ma on żadnego wpływu na pogorszenie bezpieczeństwa pisanej aplikacji. Ba, może nawet podnieść jej bezpieczeństwo zabraniając projektantom używać czystego PHP i nakazywać używanie wyłącznie wbudowanych funkcji, modyfikatorów i przesłanych przez programistę danych.

Jak stworzyć pierwszy szablon w Smartim?

Ponieważ nie będę zajmował się kwestią uruchomienia Smartiego, od tego jest dokumentacja, przejdę od razu do meritum sprawy - języka Smartiego! Języka opracowanego specjalnie dla projektantów możemy używać w szablonach z rozszerzeniem 'tpl'. Czym różni się tpl od szablonu w HTML'u? A tym, że oprócz html'a, CSS, JS, może zawierać też tagi języka Smarty. Pisząc dalej zajmę się właśnie zagłębieniem się w ten język.

1. Zmienne - zmienne w Smartim przeplatane są przez kod HTML. Od innych tagów odróżnią je użyte klamry { }. Przykładowo szablon może wyglądać tak:

<html>
<body>
Witaj świecie! Jestem {$imie}.
</body>
</html>

Zmienną w tym wypadku jest imię, które zostało przekazane przez programistę w postaci zmiennej typu string zawierające, np. imię zalogowanego użytkownika.

Zmienne można też przypisywać w szablonie. Służy do tego funkcja assign. Przykład użycia:

{assign var="imie" value="Paweł"}
Witaj świecie! Jestem {$imie}.

2. Przekazywanie wartości do szablonów - w Smartim całą logikę tworzy się w plikach PHP. Jak przystało na dobry system oddzielenia logiki od treści mamy dostęp do określania, który szablon ma być dołączony pod aktualnie opracowywaną logikę. Smarty to także klasa, która ma zdefiniowane metody, służące do określania ustawień jak i przesyłania danych, oraz wyświetlania wyników (szablonów). Przykładowy kod napisany w języku PHP, do wyświetlenia przykładu z punktu pierwszego, może wyglądać tak:

<?php
include("libs/Smarty.class.php");
$smarty = new smarty();
$imie = Paweł;
$smarty->assign("imie", $imie);
$smarty->display("przyklad.tpl");
?>

3. Warunki logiczne - tak jak w innych znanych językach programowanie, w Smartim istnieją warunki logiczne. Zasięg instrukcji if oznaczony jest za pomocą nawiasów klamrowych. Używa się tutaj nawiasów {if}{/if}, dostępne są także {else} oraz {elseif}. Smarty obsługuje operatory warunkowe dostępne w języku PHP jak i też dodaje własne operatory np. operator sprawdzający podzielność - $a is [not] div by $b - w PHP $a % $b == 0.

[code]{if $student->ocena >= 4}Dobry uczeń!

{else}Uczeń średni

{/if}[/code]

4. Pętle - w Smartim można tworzyć pętle za pomocą dwóch znaczników. {section} - tablice nieasocjacyjne. {foreach} - tablice asocjacyjne. Dlaczego taki podział? Ponieważ tam gdzie można, należy używać pętli foreach - łatwiejsza. Oczywiście tablice asocjacyjne można przeglądać funkcją section, ponieważ w PHP (nie wiem czy w innych językach także) można do każdej tablicy odwołać się przez jej indeks. Przykład dwóch rodzajów pętli.

[code]{section name=id loop=$titles}Tytuł: {$titles[id]} Cena: {$price[id]}

{/section} {foreach item=book from=$books}Tytuł: {$book.title} Cena: {$book.price}

{/foreach}[/code]

W pierwszym wypadku użyliśmy dwóch tablic jednowymiarowych. Natomiast w drugim przykładzie użyliśmy tablicy asocjacyjnej o nazwie $books, która zawiera kolejne tablice asocjacyjne. Wygląda to mniej więcej tak:

books:
....book0:
........title = Matematyka Dyskretna
........price = 100.99
....book1:
........title = Wprowadzenie do teorii grafów
........price = 28.00

Dopowiedzenie. Jak by jakiś czytelnik nie wiedział, tablica asocyacyjna jest to tablica, do której możemy odwołać się podając klucz złożony ze znaków. Do tablic nieasocjacyjnych odwołujemy się używając ich kolejnych indeksów zaczynając od indeksu równego zero.

Ponadto używając funkcji section mamy do dyspozycji zmienne, które mogą być przydatne w modyfikowaniu logiki pętli:

index - wyświetla bieżący indeks pętli. Przykład użycia:
{section name=id loop=3}
# indeksu: {$smarty.section.id.index}

{section}

first - zwraca true w trakcie pierwszej iteracji

iteration - podobna do zmiennej index, ale zwraca numer bieżącej iteracji. Ważne, jeżeli pętla ma indeks startowy np. 15.

total - zwraca całkowitą liczbę iteracji. JEDYNA ZMIENNA, KTÓRĄ MOŻNA UŻYĆ PO ZAKOŃCZENIU PĘTLI {section}.

loop - zwraca numer ostatniego indeksu.

5. Przydatne funkcje - powiem tylko o części przydatniejszych funkcji. Jest ich naprawdę sporo. W kolejnych wpisach rozpiszę się na ich temat więcej.

5.1. Funkcja html_table - funkcja pobiera parametry w postaci tablicy oraz opcjonalnie liczby kolumn (domyślnie cols=3). Na przykładzie kalendarza:

{html_table loop=$dni_tygodnia cols=7}

5.2. Funkcja cycle - funkcja, która cyklicznie przetwarza zbiór wartości i zwraca je jedną po drugiej. Funkcja cycle może mieć nieskończenie wiele wartości. Przykład dla 2 kolorów:

<tr bgcolor='{cycle values="#EBEBEB, #ACABAB"}'>

5.3. Funkcja include - aby ułatwić nam edycje szablonu, trzeba rozłożyć go na komponenty. Po co pisać wielokrotnie stopkę, bądź menu? Edycja jednego elementu z takiego menu będzie trwała tyle razy dłużej, ile mamy stworzonych podstron. Funkcja include pozwala nam załączyć szablon we wskazanym miejscu. Przykład działania funkcji include. Plik stopka.tpl:

<div id="stopka">Wszystkie prawa zastrzeżone 2009-2020</div>

Plik index.tpl:

<html>
<body>
<div id="naglowek">Nagłówek</div>
<div id="tresc">TREŚĆ TREŚĆ TREŚĆ</div>
{include file="stopka.tpl"}

Warto pomyśleć, aby dobrać odpowiednią ilość komponentów. Nie za dużo, oraz nie za mało. W zależności od strony może to być od 4 do 6,10... 5.4. Funkcja literal - funkcja ta przydaje się, kiedy musimy dołączyć kod, w którym zawarliśmy niedozwolone znaki, źle interpretowane przez kompilator Smartiego. Przykładem może być kod JavaScript napisany między znacznikami script, a nie dołączony z oddzielnego pliku. W języku JavaScript do oznaczenia bloków (np. warunków logicznych, funkcji, pętli) używa się klamerek { }, co jest znakiem zastrzeżonym przez Smartiego. Dlatego taki blok najlepiej otoczyć funkcją literal, aby nie była interpretowana przez kompilator. Przykład:

{literal}<a href="#">Click</a>

5.5. Funkcje ldelim i rdelim - funkcje służą do wyświetlania lewej klamerki - {ldelim} { oraz prawej klamerki - {rdelim} }. Dzięki czemu, szablon zostanie prawidłowo prze kompilowany, a wyświetleniem prawidłowych klamerek zajmie się Smarty, dzięki czemu możliwa będzie wewnętrzna (w szablonie) obsługa CSS i JavaScript.

Smarty, używać czy nie?

Nie ma co się zastanawiać! Oczywiście teraz po przeczytaniu takiej porcji informacji możesz nawet w czystym PHP spróbować oddzielić logikę prezentacji od aplikacji. Spójrzcie jak jeszcze miesiąc temu pisałem wyświetlanie prostej listy użytkowników. Widać, że źle nie jest (a może niektórzy powiedzą - tragicznie jest!), ale projekty trzeba pisać tak, aby umożliwić ich łatwiejszą edycję później, dużo później - kiedy już zapomnimy jak działał nasz skomplikowany kod przepleciony fragmentami HTML'a.

$listOfContacts = PrepareContacts::getContactsFT($page);
/* Sprawdzam czy zapytanie nie zwróciło false */
if ($listOfContacts !== false)
    foreach ($listOfContacts as $record) {
        echo '<div class="wiersz">';
        echo '<div class="kolumna"><a rel="nofollow" href="?contact,' . $record->getContactID() .
        '">' . Config::cutSting($record->getName(), 20) . '</a></div>
            <div class="kolumna">' . Config::cutSting($record->getSName(), 20) . '</div>
            <div class="kolumna">' . Config::cutSting($record->getEmail(), 20) . '</div>
            <div class="kolumna">' . Config::cutSting($record->getPhoneNumer() , 20). '</div>
            <div class="kolumna">' . Config::cutSting($record->getDate(), 20) . '</div>';
        echo '</div>';
    }

Moim zdaniem nie wygląda to źle. Ale jak by tak wszyscy pisali, to nie było by problemu, a jednak kody różnych ludzi wyglądają różnie. Smarty to standaryzuje. Po otrzymaniu od programisty tablicy z użytkownikami kod wyglądał by np tak (piszę z palca, przepraszam za wszelkie błędy), przy założeniu otrzymania tablicy obiektów User.

{if $users}
            {foreach item=user from=$users}
                <div class="wiersz">
                    <div class="kolumna"><a rel="nofollow" href="?contact,{$user->getId()}">{$user->getName()|truncate:20:"...":true}</a></div>
                    <div class="kolumna">{$user->getSName()|truncate:20:"...":true}</div>
                    <div class="kolumna">{$user->getEmail()|truncate:20:"...":true}</div>
                    <div class="kolumna">{$user->getPhoneNumer()|truncate:20:"...":true}</div>
                    <div class="kolumna">{$user->getDate()|date_format:"%d %b, %Y"}</div>
        </div>
            {/foreach}
        {else}
            <div class="wiersz">W bazie nie ma żadnych użytkowników</div>
        {/if}

To wszystko przepisałem w 4 minuty, zachowując ładne, czytelne formatowanie i prostotę. A przy tym nie napisałem żadnej funkcji (jak np. we wcześniejszym kodzie, obcinanie stringa).

Ponieważ, nie widać wcięć na blogu zamieściłem powyższy kod, wraz z wcięciami, na innej stronie http://ctrlv.it/id/MjQxNTk5.

Podsumowanie.

Wpis jak na mój pierwszy dość obszerny. Pewnie dało by się go napisać ładniej i zgrabniej. Wybaczcie. Mam tylko nadzieje, że ten wpis się komuś przyda. Jeżeli zajdzie taka potrzeba napiszę od postaw jak dodać Smartiego do projektu. Następnych części można spodziewać się w odstępie tygodnia, w których poruszę inne ważne funkcje, metody klasy Smarty, używanie modyfikatorów (użyłem do formatowania daty, ucięcia tekstu) i innych zagadnień związanych ze Smartim. Miejmy nadzieje, że nie utracę weny i podam bardziej praktycznie przykłady zastosowania, bo nie można uczyć się na sucho.

Mile widziane wszelkie poprawki! Przede wszystkim literówki utrudniające czytanie, jak i błędy które wkradły się do kodów i niedomówienia.

Szanowna Użytkowniczko! Szanowny Użytkowniku!
×
Aby dalej móc dostarczać coraz lepsze materiały redakcyjne i udostępniać coraz lepsze usługi, potrzebujemy zgody na dopasowanie treści marketingowych do Twojego zachowania. Twoje dane są u nas bezpieczne, a zgodę możesz wycofać w każdej chwili na podstronie polityka prywatności.

Kliknij "PRZECHODZĘ DO SERWISU" lub na symbol "X" w górnym rogu tej planszy, jeżeli zgadzasz się na przetwarzanie przez Wirtualną Polskę i naszych Zaufanych Partnerów Twoich danych osobowych, zbieranych w ramach korzystania przez Ciebie z usług, portali i serwisów internetowych Wirtualnej Polski (w tym danych zapisywanych w plikach cookies) w celach marketingowych realizowanych na zlecenie naszych Zaufanych Partnerów. Jeśli nie zgadzasz się na przetwarzanie Twoich danych osobowych skorzystaj z ustawień w polityce prywatności. Zgoda jest dobrowolna i możesz ją w dowolnym momencie wycofać zmieniając ustawienia w polityce prywatności (w której znajdziesz odpowiedzi na wszystkie pytania związane z przetwarzaniem Twoich danych osobowych).

Od 25 maja 2018 roku obowiązuje Rozporządzenie Parlamentu Europejskiego i Rady (UE) 2016/679 (określane jako "RODO"). W związku z tym chcielibyśmy poinformować o przetwarzaniu Twoich danych oraz zasadach, na jakich odbywa się to po dniu 25 maja 2018 roku.

Kto będzie administratorem Twoich danych?

Administratorami Twoich danych będzie Wirtualna Polska Media Spółka Akcyjna z siedzibą w Warszawie, oraz pozostałe spółki z grupy Wirtualna Polska, jak również nasi Zaufani Partnerzy, z którymi stale współpracujemy. Szczegółowe informacje dotyczące administratorów znajdują się w polityce prywatności.

O jakich danych mówimy?

Chodzi o dane osobowe, które są zbierane w ramach korzystania przez Ciebie z naszych usług, portali i serwisów internetowych udostępnianych przez Wirtualną Polskę, w tym zapisywanych w plikach cookies, które są instalowane na naszych stronach przez Wirtualną Polskę oraz naszych Zaufanych Partnerów.

Dlaczego chcemy przetwarzać Twoje dane?

Przetwarzamy je dostarczać coraz lepsze materiały redakcyjne, dopasować ich tematykę do Twoich zainteresowań, tworzyć portale i serwisy internetowe, z których będziesz korzystać z przyjemnością, zapewniać większe bezpieczeństwo usług, udoskonalać nasze usługi i maksymalnie dopasować je do Twoich zainteresowań, pokazywać reklamy dopasowane do Twoich potrzeb. Szczegółowe informacje dotyczące celów przetwarzania Twoich danych znajdują się w polityce prywatności.

Komu możemy przekazać dane?

Twoje dane możemy przekazywać podmiotom przetwarzającym je na nasze zlecenie oraz podmiotom uprawnionym do uzyskania danych na podstawie obowiązującego prawa – oczywiście tylko, gdy wystąpią z żądaniem w oparciu o stosowną podstawę prawną.

Jakie masz prawa w stosunku do Twoich danych?

Masz prawo żądania dostępu, sprostowania, usunięcia lub ograniczenia przetwarzania danych. Możesz wycofać zgodę na przetwarzanie, zgłosić sprzeciw oraz skorzystać z innych praw wymienionych szczegółowo w polityce prywatności.

Jakie są podstawy prawne przetwarzania Twoich danych?

Podstawą prawną przetwarzania Twoich danych w celu świadczenia usług jest niezbędność do wykonania umów o ich świadczenie (tymi umowami są zazwyczaj regulaminy). Podstawą prawną przetwarzania danych w celu pomiarów statystycznych i marketingu własnego administratorów jest tzw. uzasadniony interes administratora. Przetwarzanie Twoich danych w celach marketingowych realizowanych przez Wirtualną Polskę na zlecenie Zaufanych Partnerów i bezpośrednio przez Zaufanych Partnerów będzie odbywać się na podstawie Twojej dobrowolnej zgody.