Witaj, Gościu O nas | Kontakt | Mapa
Wortal Forum PHPEdia.pl Planeta Kubek IRC Przetestuj się!
Wyszukiwarka

Wyszukiwarka

Aby odnaleźć interesujące Cię informacje wpisz poniżej szukane frazy:
Logowanie

Logowanie

Zaloguj się aby zobaczyć swój profil:

Rekurencja w Smarty

Projektując aplikację wykorzystującą strukturę drzewiastą o nieograniczonej liczbie zagłębień prędzej, czy później będziemy musieli zmierzyć się z rekurencją.

Pisanie funkcji rekurencyjnych w PHP nie jest rzeczą trudną, do chwili, gdy zapragniemy skorzystać z szablonów Smarty.

Twórcy pakietu Smarty - Monte Ort oraz Andrei Zmievski nie uwzględnili potrzeby stosowania rekurencji w swoich szablonach, ale będąc świadomymi ograniczeń swojego produktu pozostawili projektantom furtkę w postaci znaczników {php}{/php}, pomiędzy którymi można zamieścić dowolny kod PHP. Co jednak zrobić jeśli projektując aplikację przewidujemy możliwość edytowania szablonów przez przypadkowego użytkownika - tak jak ma to miejsce w blogach internetowych? Przede wszystkim ze względu bezpieczeństwa musimy zablokować możliwość korzystania w Smarty z bloków php i poszukać innego sposobu wyświetlenia drzewa w szablonie.

Rozwiązaniem od razu nasuwającym się na myśl jest zapisanie wygenerowanego kodu html w zmiennej i włączenie jej w takiej postaci do obiektu Smarty.

<?php
$smarty->assign( 'full_tree', $tree );
 ?>

Generowanie kodu html poza szablonami burzy logikę wzorca MVC i jest sprzeczne z samą ich ideą. Szablony powstały głównie po to, aby wyraźnie oddzielić część logiczną aplikacji od części wizualnej. Ponadto jeśli użytkownik ma jedynie dostęp do szablonów to stosując takie rozwiązanie odbiera mu się możliwość wpływania na sposób prezentowania drzewa.

Na szczęście, jak się nieoczekiwanie okazuje istnieje w Smarty składnia umożliwiająca zastosowanie rekurencji - choć wcale nie została do tego wymyślona.

Dla przykładu mamy tablicę:

$tree = array('element'=>array(array('name' => 'test1',
                                     'element' => array(array('name' => 'test1.1'),
                                                        array('name' => 'test1.2',
                                                              'element' => array(array('name' => 'test1.2.1'),
                                                                                 array('name' => 'test1.2.2')
                                                                                )
                                                             ),
                                                        array('name' => 'test1.3',
                                                              'element' => array(array('name' => 'test1.3.1')
                                                                                )
                                                             )
                                                       )
                                    )
                              )
             );

Włączamy ją do obiektu smarty:

<?php
$smarty->assign('tree', $tree);
?>

I wyświetlamy szablon:

<?php
$smarty->display('tree.tpl');
?>

tree.tpl:

{foreach from=$tree.element item=element}
     <li>{$element.name}</li>
     {if $element.element}
     <ul>{include file="tree_recursion.tpl" element=$element.element}</ul>
     {/if}
{/foreach}

Jak widać w szablonie tree.tpl - po spełnieniu określonego warunku - includowany jest kolejny szablon tree_recursion.tpl, który z kolei includuje samego siebie:

tree_recursion.tpl:

{foreach from=$element item=element}
     <li>{$element.name}</li>
     {if $element.element}
     <ul>{include file="tree_recursion.tpl" element=$element.element}</ul>
     {/if}
{/foreach}

Wadą tego rozwiązania jest niestety spadek wydajności w stosunku do czystego kodu php.

Istnieje również inny, bardziej elegancki sposób rozwiązania trapiącego nas problemu. Pakiet Smarty daje możliwość zaawansowanym użytkownikom stworzenia własnych funkcji i filtrów i zarejestrowania ich w obiekcie smarty. Z mechanizmu tego korzysta miedzy innymi plugin compiler.defun, który służy do rekurencyjnego przetwarzania tablicy. Po pobraniu pliku compiler.defun.php wystarczy go umieścić w katalogu plugins znajdującym się w głównym katalogu pakietu smarty i już możemy korzystać z nowego bloku {defun} oraz znacznika {fun}. Możemy też plugin umieścić w dowolnym innym katalogu i poinformować o tej lokalizacji obiekt Smarty.

mySmarty:

<?php
   define('MYSMARTY_DIR',dirname(__FILE__));
   include(MYSMARTY_DIR.'/../smarty/Smarty.class.php');
 
   class mySmarty extends Smarty {
     public function __construct($templates_dir){
       $this->Smarty();
       $this->template_dir = $templates_dir;
       $this->compile_dir = MYSMARTY_DIR.'/templates_c/';
       $this->config_dir = MYSMARTY_DIR.'/configs/';
       $this->cache_dir = MYSMARTY_DIR.'/cache/';
       
       // Wylancza m.in. mozliwosc uzycia blokow {php}{/php}
       $this->security = true;
 
       // W tablicy przechowywane sa lokalizacje katalogow z pluginami do Smarty
       // SMARTY_DIR.'/plugins/' &#8211; domyslny katalog pluginow Smarty
       // MYSMARTY_DIR.'/plugins/' &#8211; moj catalog pluginow do Smarty
       $this->plugins_dir = array(SMARTY_DIR.'/plugins/', MYSMARTY_DIR.'/plugins/');    
     }
   }
 
   $smarty = new mySmarty(MYSMARTY_DIR.'/templates/');
   $smarty->assign('tree', $tree);
   $smarty->display('tree_defun.tpl');
 ?>

tree_defun.tpl:

 <ul>
 {defun name="testrecursion" list=$tree.element}
 {foreach from=$list item=element}
   <li>{$element.name}</li>
   {if $element.element}
   <ul>
     {fun name="testrecursion" list=$element.element}
   </ul>
   {/if}
 {/foreach}
 {/defun}
 </ul>

Zaletą korzystania z pluginu w stosunku do pierwszego rozwiązania jest lepsza wydajność oraz pojedynczy plik szablonu (a co za tym idzie mniejsza ilość kodu Smarty).

Informacje na podobny temat:
Wasze opinie
Wszystkie opinie uzytkowników: (4)
drzewka n-poziomowe
Czwartek 23 Listopad 2006 11:40:14 am - ppysznik

dla rozwiazania problemu drzewek n-poziomowy polecam ten artykul http://www.phpriot.com/d/articles/php/application-design/nested-trees-2/index.html

naprawde dobre rozwiazanie, rekurencja jest tylko prz przeliczaniu drzewka (po jego modyfikacji) potem pobieramy juz ulozona strukture, dodam ze z dowolnego poziomu

Hmm
Środa 08 Listopad 2006 11:22:11 pm - dwapinski <d.wapinski_at_dominet.pl>

I tak nie unikniemy skladni {php}{/php} w przypadku gdy
chce walodowac dane ktore sa w drzewie. Oczywiscie mozna zadbac o walidacje juz przy samej budowie drzewa, ale to nie rozwiazuje problemu. Smarty nie nadaje sie do rekurencyjnych danych, napewno nie na wszelkiego rodzaju grup-listy. Mozna w inny sposob trzymac sie MVC bez szablonu.

Dynamiczna tablica.
Wtorek 11 Lipiec 2006 9:41:52 pm - anas <robert_at_acs.pl>

Temat jak się okazało (przynajmniej dla mnie) nie jest do końca taki prosty. Tutaj topic na forum: http://forum.php.pl/Drzewka-raz-jeszcze-t49772.html

jak zbudowac taka tablice?!
Czwartek 06 Lipiec 2006 11:41:17 am - cube81 <cube81_at_o2.pl>

hm, moze jestem leszcz ale jak zbudowac taka tablice majac do dyspozycji tabele mySql gdzie jest id, id_parent i nazwa

Mentax.pl    NQ.pl- serwery z dodatkiem świętego spokoju...   
O nas | Kontakt | Mapa serwisu
Copyright (c) 2003-2024 php.pl    Wszystkie prawa zastrzeżone    Powered by eZ publish Content Management System eZ publish Content Management System