Речь пойдет о первом моем модуле для фреймворка Kohana.
![image](http://kohanaphp.com/media/img/kohana.png)
Признаюсь честно, при первом и последующих взглядах на этот фреймворк он мне очень понравился. Но как известно нет ничего идеального. Как мне показалось, одно из самых слабых мест в Кохане — довольно примитивные представления (View). По сути они предствляют из себя plain-php файл с экспортированными в глобальную область видимости переменными и доступным по ссылке $this контроллеру. Это очень удобно, когда вам нужно представление для вывода данных, нет ничего лишнего, можно сосредоточиться на коде. Но когда нам нужно вывести макет страницы со сложным расположением элементов, которые могут меняться от раздела к разделу… Что делать? Собирать все из мелких вьюшек в контроллере? Не удобно, особенно если контроллеров много — не дай бог, например, поменяется количество столбцов в разметке, придется в каждом контроллере перераспределять блоки с контентом по столбцам. Наверное по этому в версии 2.4 появится (я надеюсь) модуль интеграции со Смарти.
Я решил немного поискать по этой теме и нашел очень интересный топик на форуме Коханы, который заставил меня задуматься. По умолчанию мы имеем линейные представления в виде инклуд-файла. Нам нужны наследование, модульность и четкая иерархия представлений. Я знаю только одну сущность идеально подходящую под это описание — это классы :) В упомянутом топике автор как раз говорит, что использует этот подход для своего фреймворка. Дело было за малым — написать задуманное :)
Одно из моих требований к себе было то, чтобы можно было не отказываться полностью от привычных представлений, потому как в некоторых случаях они действительно удобны. Мне это удалось. Более того, мне даже удалось не использовать пользовательских надстроек вида MY_View.php для основных классов. Это плюс потому как никто не знает, в какой нелегкий час они могут пригодиться вам самим.
Моя реализация основана на наследовании нового класса от View:
Я намеренно здесь сократил код render() дабы не занимать много места, опущенный код не отличается от View::render();
Если в двух словах, то класс делает следующее: Перехватывает имя представления, еще до того как к нему добавится путь и расширение и сохраняет его как имя будущего класса + '_View' на конце. При рендеренге представления просто создается класс с сохраненным именем, которому передаются все переменные и текущий контроллер. Еще я перекрываю factory, дабы при обращении Inherit_View::factory создавался именно Inherit_View.
Теперь для создания представления с иерархической структурой достаточно вызвать new Inherit_View('Template'); а в файле Template.php должен быть объявлен класс Template_View, унаследованный от Base_Inherit_View, который в свою очередь наследуется от ArrayObject из SPL, и потому доступ к любому полю внутри Template_View осуществляется как $this->property или $this['property']. А $this->controller содержит ссылку на текущий контроллер.
Я включил в примеры демонстрационные представления Html_Strict_View, Simple_Page_View, Another_Page_View, я думаю глядя на них можно легко понять сколько дает плюсов такая обертка представлений. Также я включил в модуль Inherit_Template_Controller, аналогичный Template_Controller, только создающий не View а Inherit_View. Ну и конечно по традиции других модулей, я включил демо-контроллер. Полный боевой набор, в общем :)
Из минусов такого подхода могу отметить только то, что если ваш верстальщик — это не вы и он не знает PHP, скорее всего он вас пошлет :) Но я чаще всего верстаю сам, потому получаю от такого подхода только плюсы.
Ссылка на модуль в началае статьи и здесь. Чтобы модуль заработал, не забудьте включить его в $config['modules'].
Спасибо nex за то, что натолкнул на размышления и задал самый первый вопрос, почему с представлениями так плохо, без него я бы, наверное, не занялся этим делом.
Всем большое спасибо!
![image](http://kohanaphp.com/media/img/kohana.png)
Признаюсь честно, при первом и последующих взглядах на этот фреймворк он мне очень понравился. Но как известно нет ничего идеального. Как мне показалось, одно из самых слабых мест в Кохане — довольно примитивные представления (View). По сути они предствляют из себя plain-php файл с экспортированными в глобальную область видимости переменными и доступным по ссылке $this контроллеру. Это очень удобно, когда вам нужно представление для вывода данных, нет ничего лишнего, можно сосредоточиться на коде. Но когда нам нужно вывести макет страницы со сложным расположением элементов, которые могут меняться от раздела к разделу… Что делать? Собирать все из мелких вьюшек в контроллере? Не удобно, особенно если контроллеров много — не дай бог, например, поменяется количество столбцов в разметке, придется в каждом контроллере перераспределять блоки с контентом по столбцам. Наверное по этому в версии 2.4 появится (я надеюсь) модуль интеграции со Смарти.
Я решил немного поискать по этой теме и нашел очень интересный топик на форуме Коханы, который заставил меня задуматься. По умолчанию мы имеем линейные представления в виде инклуд-файла. Нам нужны наследование, модульность и четкая иерархия представлений. Я знаю только одну сущность идеально подходящую под это описание — это классы :) В упомянутом топике автор как раз говорит, что использует этот подход для своего фреймворка. Дело было за малым — написать задуманное :)
Одно из моих требований к себе было то, чтобы можно было не отказываться полностью от привычных представлений, потому как в некоторых случаях они действительно удобны. Мне это удалось. Более того, мне даже удалось не использовать пользовательских надстроек вида MY_View.php для основных классов. Это плюс потому как никто не знает, в какой нелегкий час они могут пригодиться вам самим.
Моя реализация основана на наследовании нового класса от View:
class Inherit_View extends View {
protected $class_name = NULL;
public function set_filename($name, $type = NULL)
{
parent::set_filename($name, $type);
// no slashes allowed in class names.
$this->class_name = str_replace('/', '_', $name).'_View';
return $this;
}
public static function factory($name = NULL, $data = NULL, $type = NULL)
{
return new Inherit_View($name, $data, $type);
}
public function render($print = FALSE, $renderer = FALSE)
{
// Load the file with view only once
require_once($this->kohana_filename);
ob_start();
// Merge global and local data, local overrides global with the same name
new $this->class_name(array_merge(self::$kohana_global_data, $this->kohana_local_data), Kohana::$instance);
$output = ob_get_clean();
return $output;
}
}
* This source code was highlighted with Source Code Highlighter.
Я намеренно здесь сократил код render() дабы не занимать много места, опущенный код не отличается от View::render();
Если в двух словах, то класс делает следующее: Перехватывает имя представления, еще до того как к нему добавится путь и расширение и сохраняет его как имя будущего класса + '_View' на конце. При рендеренге представления просто создается класс с сохраненным именем, которому передаются все переменные и текущий контроллер. Еще я перекрываю factory, дабы при обращении Inherit_View::factory создавался именно Inherit_View.
Теперь для создания представления с иерархической структурой достаточно вызвать new Inherit_View('Template'); а в файле Template.php должен быть объявлен класс Template_View, унаследованный от Base_Inherit_View, который в свою очередь наследуется от ArrayObject из SPL, и потому доступ к любому полю внутри Template_View осуществляется как $this->property или $this['property']. А $this->controller содержит ссылку на текущий контроллер.
Я включил в примеры демонстрационные представления Html_Strict_View, Simple_Page_View, Another_Page_View, я думаю глядя на них можно легко понять сколько дает плюсов такая обертка представлений. Также я включил в модуль Inherit_Template_Controller, аналогичный Template_Controller, только создающий не View а Inherit_View. Ну и конечно по традиции других модулей, я включил демо-контроллер. Полный боевой набор, в общем :)
Из минусов такого подхода могу отметить только то, что если ваш верстальщик — это не вы и он не знает PHP, скорее всего он вас пошлет :) Но я чаще всего верстаю сам, потому получаю от такого подхода только плюсы.
Ссылка на модуль в началае статьи и здесь. Чтобы модуль заработал, не забудьте включить его в $config['modules'].
Спасибо nex за то, что натолкнул на размышления и задал самый первый вопрос, почему с представлениями так плохо, без него я бы, наверное, не занялся этим делом.
Всем большое спасибо!