Как стать автором
Обновить

Наследование шаблонов в Smarty — альтернативный подход

Время на прочтение6 мин
Количество просмотров1.6K
По следам хабратопика Наследование шаблонов в Smarty хочу рассказать как около полутора лет назад я решил подобную задачу. В оличие от marazmiki с Django я знаком не был (хотя сейчас занимаюсь изучением именно его). Но крайне поверхностно был знаком с механизмом Master Pages из ASP.NET. Механизм заключается в том, что у нас есть практически полноценная страница, у которой отсутствует только блок с основным контентом.

Немного прикинув придумалось решение через стандарные функции Smarty и механизм наследования в PHP.


Прежде всего шаблон смарти:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" «www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlnswww.w3.org/1999/xhtml»>

<head>
   <title>Main title{if i$ADDITIONAL_TITLE} | {$ADDITIONAL_TITLE}{/if}</title>
   <base href="{$ROOT_URL}" />
   <meta http-equiv=«Content-Type» content=«text/html; charset=UTF-8» />
</head>

<body>

<div id=«base_div»>
   <div id=«header_logo_div»>{include file=«header_logo.tpl»}</div>
   <div>
      <div id=«user_login_info»>{include file=«users/user_login_info.tpl»}</div>
      <div id=«lang_selector»>{include file=«lang/selector.tpl»}</div>
   </div>
   <div>
      <div id=«main_block»>
         {include file=$__file_to_display}
      </div>
   </div>
</div>

* This source code was highlighted with Source Code Highlighter.


Основные элементы на которые стоит обратить внимание это:
1. Main title{if $ADDITIONAL_TITLE} | {$ADDITIONAL_TITLE}{/if}
2. {include file=$__file_to_display}

Далее идет код, который со всем этим работает. Прежде всего, для применения настроек смарти и работы с данными общими для всего сайта у меня был создан абстракный класс, который наследовался напряму от Smarty:

<?php
abstract 
class smarty_page_ex extends Smarty {
    
protected $module;
    
protected $action;

    
public function __construct($module ""$action ""smarty_config_wrapper $config null) {
        
parent::Smarty();

        
$this->module $module;
        
$this->action $action;

        
$gconfig global_config::get_instance();

        if (
$config === null$config $gconfig->get_smarty_config();

        
$this->compile_check $config->get_tpl_compile_check();
        
$this->debugging $config->get_smarty_debug();

        
$this->compile_dir $config->get_tpl_compiled_path();
        
$this->cache_dir $config->get_tpl_cache_path();

        
$this->template_dir $config->get_tpl_path();
        
$this->config_dir $config->get_tpl_config_path();

        
$lang lang::get_instance();
        
$this->assign_by_ref("lang"$lang);

        
$this->assign("ROOT_URL"$gconfig->root_url);
        
$this->assign("MODULE"$module);

        
$this->assign("ACTION"$action);

        
$this->register_object("smarty_page_ex"$this);
    }

    
/**
     * Gets template full path
     *
     * @param string $base_path
     * @return string
     */
    
protected function get_full_path() {
        return (
strlen($this->module) > ? ($this->module "/") : "");
    }
}
?>



Тут стоит упомянуть что структура хранения шаблонов в проекте имела следующий вид:
<templates-dir>/
|-<module>
|  |-<action>.tpl
|-home
|  |-index.tpl
|-common_page.tpl
|-admin_page.tpl
|-mail_page.tpl


А шаблон приведенный выше является common_page.tpl (упрощенный меташаблона для пользовательских страниц).

Для каждого типа страниц существует свой наследник расширенного класса смарти, который занимался передачей в шаблон каких-то дополнительных данных. В частности наследник для common_page.tpl выглядит таким образом:

<?php
class common_page extends smarty_page_ex {
    
public function __construct($module ""$action ""$title ""smarty_config_wrapper $config null) {
        
parent::__construct($module$action$config);

        
$options options::get_instance();
        
$this->assign_by_ref("options"$options);

        
$auth_user auth_user::get_instance();
        
$this->assign_by_ref("auth_user"$auth_user);

        
$gconfig global_config::get_instance();
        
$this->assign_by_ref("gconfig"$gconfig);

        
$lang = new languages();
        
$lang_list db_adapter::get_instance()->get_list($lang);
        
$this->assign_by_ref("__languages"$lang_list);

        
$this->assign("ADDITIONAL_TITLE"$title);
    }

    
/**
     * Executes & returns or displays the template results
     *
     * @param string $template
     * @param string $cache_id
     * @param string $compile_id
     * @param boolean $display
     */
    
public function fetch($template$cache_id null$compile_id null$display false) {
        
$this->assign("__file_to_display"$this->get_full_path() . $template);
        return 
parent::fetch("common_page.tpl"$cache_id$compile_id$display);
    }
}
?>


Тут в шаблон отдаются какие-то общие данные и дополнительный заголовок, если требуется, все как обычно. А далее мы переопределяем метод fetch базового класса Smarty так, чтобы он не компилировал отданный ему шаблон, а вставлял его в меташлаблон, и отдаем на компиляцию уже меташаблон со вставленным блоком данных.

В простейшем виде использование такой структуры кода сводится к следующему:

<?php
$tpl 
= new common_page("home""index""Welcome!");
$tpl->display();
?>



Написав 1 основной шаблон и создав небольшую цепочку наслования в пхп-коде получили возможность наследования шаблона смарти для однотипных страниц. Для введения дополнительных блоков на страницы наследников смарти придется немного усложнить, но это не очень трудоемкая и сложная задача.

Готов выслушать критику в свой адрес по поводу данного спооба наследования шаблонов в смарти.
Теги:
Хабы:
Всего голосов 11: ↑6 и ↓5+1
Комментарии3

Публикации

Истории

Работа

PHP программист
150 вакансий

Ближайшие события