При постепенном изучении Zend Framework и построении с его помощью базовых приложений я заметил, что клиентский js-код и инлайновые стили попадают в скрипты вида, при этом они начинают занимать почти половину всего скрипта. В принципе, ничего плохого в этом нет, но мне такая мусорка начала давить на глаза. Кроме того, инлайновый js постепенно превращается в жестко привязанную к скрипту вида конструкцию, полностью зависимую как от самого скрипта, так и от переданных контроллером данных. При всем этом не оставляет желание писать на javascript код максимально красивый при помощи библиотеки jQuery.
Итак, что в данном случае можно сделать. Первая же мысль — вынести инлайновые скрипты и стили во внешние файлы и подключать их через помощники вида headLink и headStyle. Если со стилями все примерно понятно — достаточно специфический стиль для конкретного вида вынести в css файл и подключать его по мере необходимости, то js по-прежнему зависим от данных.
В качестве первого решения напишем плагин к frontController для подключения по мере необходимости нужных файлов:
Не забываем в Bootstrap классе подключить созданный плагин:
Как уже понятно, используемые css и js файлы размещаются в соответствии с полной аналогией размещения скриптов вида. Только вместо /application/views/script/controllerName/actionName/ корневыми директориями для них будет соответственно public/css/ и public/js/. Для этого нужно объявить три константы в index.php:
Плагин позволяет подключить в нашем Layout нужные файлы следующим кодом:
Открываем браузер — нужные файлы подключились.
Остается вопрос с жаваскриптом. Мы вынесли код во внешний файл в пределах public директории. Но есть необходимость, например, вывести приветственный текст на основе словаря функцией alert(). Естественно, для перевода используется Zend_Translate, но опять же, как быть, если все наши данные доступны только в скрипте вида?
Для собственных задач я посчитал идеальным решением организацию неймспейсов. К примеру, для переводчика внутри одного скрипта вида нам необходим ограниченный набор фраз. Значит мы можем организовать хранилище этих фраз и отдать их необходимому обработчику на уровне js.
Вот как это происходит.
В основном js-файле моего проекта application.js происходит настройка глобальных методов, объектов и обработчиков. Сюда можно добавить:
Хранилище огранизовано, теперь нужно заполнить его.
Для этого в скрипте вида нам понадобится следующий код:
Для использования данных из хранилища мы можем обратиться из любой функции, обрабатывающей этот участок проекта, достучаться до хранилища и получить нужные данные:
Итак, мы получили следующую картину: для контроллера index, экшена index существует файл в паблик-директории /js/index/index.js, являющийся набором функций для работы. При этом все необходимые данные попадают в хранилище данных непосредственно в скрипте вида, а само хранилище объявляется глобально для всех скриптов вида в основном js-файле приложения.
По модели MVC. Немного притянуто за уши, но все же.
В качестве контроллера (реакцией на пользователя) выступает плагин к frontController, организующий подключение, скрипт layout-а и основа — application.js.
В качестве модели выступает скрипт вида, накапливающий данные для js хранилища.
В качестве вида выступает подключаемый код javascript, полностью отвечающий за клиентское представление.
В хранилище можно накапливать любые данные для дальнейшего использования.
Итак, что в данном случае можно сделать. Первая же мысль — вынести инлайновые скрипты и стили во внешние файлы и подключать их через помощники вида headLink и headStyle. Если со стилями все примерно понятно — достаточно специфический стиль для конкретного вида вынести в css файл и подключать его по мере необходимости, то js по-прежнему зависим от данных.
В качестве первого решения напишем плагин к frontController для подключения по мере необходимости нужных файлов:
- class My_Controller_Plugin_Webinit extends Zend_Controller_Plugin_Abstract
- {
- public function preDispatch()
- {
- $controllerName = $this->_request->getControllerName();
- $actionName = $this->_request->getActionName();
-
- $view = Zend_Layout::getMvcInstance()->getView();
-
- if ( file_exists(APPLICATION_CSS_FOLDER.'/'.
- $controllerName.'/'.
- $actionName.'.css') )
- {
- $view->assign('cssControllerAction',$controllerName.'/'.$actionName.'.css');
- }
-
- if ( file_exists(APPLICATION_JS_FOLDER.'/'.
- $controllerName.'/'.
- $actionName.'.js') )
- {
- $view->assign('jsControllerAction', $controllerName.'/'.$actionName.'.js');
- }
- }
- }
* This source code was highlighted with Source Code Highlighter.
Не забываем в Bootstrap классе подключить созданный плагин:
- protected function _initFrontControllerPlugins()
- {
- $frontController = Zend_Controller_Front::getInstance();
- $frontController->registerPlugin( new My_Controller_Plugin_Webinit() );
- }
* This source code was highlighted with Source Code Highlighter.
Как уже понятно, используемые css и js файлы размещаются в соответствии с полной аналогией размещения скриптов вида. Только вместо /application/views/script/controllerName/actionName/ корневыми директориями для них будет соответственно public/css/ и public/js/. Для этого нужно объявить три константы в index.php:
- defined('APPLICATION_PUBLIC_FOLDER')
- || define( 'APPLICATION_PUBLIC_FOLDER',
- dirname(__FILE__) );
-
- defined('APPLICATION_CSS_FOLDER')
- || define( 'APPLICATION_CSS_FOLDER',
- realpath(APPLICATION_PUBLIC_FOLDER . '/css') );
-
- defined('APPLICATION_JS_FOLDER')
- || define( 'APPLICATION_JS_FOLDER',
- realpath(APPLICATION_PUBLIC_FOLDER . '/js') );
* This source code was highlighted with Source Code Highlighter.
Плагин позволяет подключить в нашем Layout нужные файлы следующим кодом:
- <? if ($this->cssControllerAction) $this->headLink()->appendStylesheet('/css/'.$this->cssControllerAction)?>
-
- <? if ($this->jsControllerAction) $this->headScript()->appendFile('/js/'.$this->jsControllerAction)?>
* This source code was highlighted with Source Code Highlighter.
Открываем браузер — нужные файлы подключились.
Остается вопрос с жаваскриптом. Мы вынесли код во внешний файл в пределах public директории. Но есть необходимость, например, вывести приветственный текст на основе словаря функцией alert(). Естественно, для перевода используется Zend_Translate, но опять же, как быть, если все наши данные доступны только в скрипте вида?
Для собственных задач я посчитал идеальным решением организацию неймспейсов. К примеру, для переводчика внутри одного скрипта вида нам необходим ограниченный набор фраз. Значит мы можем организовать хранилище этих фраз и отдать их необходимому обработчику на уровне js.
Вот как это происходит.
В основном js-файле моего проекта application.js происходит настройка глобальных методов, объектов и обработчиков. Сюда можно добавить:
- $(document).ready(function(){
- $.TRANSLATION = {};
- });
* This source code was highlighted with Source Code Highlighter.
Хранилище огранизовано, теперь нужно заполнить его.
Для этого в скрипте вида нам понадобится следующий код:
- <script type="text/javascript">
- $(document).ready(function(){
- $.data($.TRANSLATION, "Nice to see you!", '<?=$this->translate("Nice to see you!")?>');
- </script>
* This source code was highlighted with Source Code Highlighter.
Для использования данных из хранилища мы можем обратиться из любой функции, обрабатывающей этот участок проекта, достучаться до хранилища и получить нужные данные:
- alert( $.data($.TRANSLATION, "Nice to see you!") );
* This source code was highlighted with Source Code Highlighter.
Итак, мы получили следующую картину: для контроллера index, экшена index существует файл в паблик-директории /js/index/index.js, являющийся набором функций для работы. При этом все необходимые данные попадают в хранилище данных непосредственно в скрипте вида, а само хранилище объявляется глобально для всех скриптов вида в основном js-файле приложения.
По модели MVC. Немного притянуто за уши, но все же.
В качестве контроллера (реакцией на пользователя) выступает плагин к frontController, организующий подключение, скрипт layout-а и основа — application.js.
В качестве модели выступает скрипт вида, накапливающий данные для js хранилища.
В качестве вида выступает подключаемый код javascript, полностью отвечающий за клиентское представление.
В хранилище можно накапливать любые данные для дальнейшего использования.