# Создание интерфейсов с помощью Dojo и Zend Framework

Zend Framework @ 02 Май 2010

Если кто не знает, Dojo это библиотека JavaScript которая позволяет быстро создавать пользовательские интефейсы для веб-приложений и сайтов.
В этой статье я хочу рассказать как освоить эту мощную библиотеку с помощью модуля Zend_Dojo популярного PHP-фреймворка ZendFramework.

Для начала скачайте обучающее приложение ZendFrameworkQuickstart (я использовал версию 1.10) с официального сайта. Этот простенький сайт с гостевой книгой – отличный способ понять работу MVC фреймворка. Но я предполагаю, что читатель уже имеет некоторый опыт в этой области, поэтому сразу перейдем к добавлению в него интерактивности с использованием возможностей Dojo.

Инициализация помощника вида Dojo

ZF для работы с Dojo предоставляет помощник вида. Инициализируем его в методе init IndexController-а:

Zend_Dojo::enableView( $this->view );

Выбираем одну из стандартных тем оформления (tundra, soria, nihilo).

$this->view->theme = 'tundra';
$this->view->Dojo()->addStylesheetModule( 'dijit.themes.' . $this->view->theme );

Кроме того, было бы не плохо включить режим дебагинга для этапа разработки и тестирования.

if ( APPLICATION_ENV != 'production' ) {
	$this->view->Dojo()->setDjConfigOption( 'isDebug', true );
}

Теперь остается только подправить файл макета (layout.phtml). Вот что мы будем использовать:

<!DOCTYPE html> 
<html> 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
<title>Dojo QuickStart</title>  
</head> 
<body class="<?=$this->theme?>">
<?=$this->layout()->content?> 
<?=$this->Dojo()?> 
</body>
</html>

Чтобы тема оформления заработала, в теге body устанавливается соответствующий класс.
Помощник вида Dojo добавляет на страницу скрипт, запрашивающий все необходимые файлы библиотеки, для работы вашего приложения (по умолчанию используется AJAX API библиотек Google).

Программирование интерфейса

Пришло время создать простенький интерфейс для нашего приложения. С помощью библиотеки Dojo можно создавать сложные интерфейсы с различным расположением элементов используя табы, аккордион, диалоги, формы, блоки с изменяющимися границами и прочее. Используя Zend_Dojo мы перекладываем операции подключения необходимых файлов и генерацию инициализирующих скриптов на фреймворк. Например, так будет выглядеть скрипт вида index.phtml Index контроллера для страницы разделенной на 3 части (обычно это header, content, footer):

<?php
$this->borderContainer()->captureStart(
	'main',
	array('design'=>'headline')
);
echo $this->contentPane(
	'toolbarPane',
	'Панель инструментов',
	array('region'=>'top', 'splitter'=>'true'),
	array('style'=>'background-color: blue;')
);
echo $this->contentPane(
	'mainPane',
	'Основной блок',
	array('region'=>'center')
);
echo $this->contentPane(
	'statusPane',
	'Панель статуса',
	array('region'=>'bottom', 'splitter'=>'true'),
	array('style'=>'background-color: lightgray;')
);
echo $this->borderContainer()->captureEnd('main');

Начало и конец виджета-контейнера оформляется методами captureStart и captureEnd соответственно. Все что будет выведено между ними попадет в текущий контейнер.
Если Вы попробовали запустить приложение и ничего не увидели – не беспокойтесь, BorderContainer требует установить для него стили:

html, body {
	width: 100%;
	height: 100%;
	margin: 0;
	padding: 0;
	overflow: hidden;
}
#main {
	width: 100%;
	height: 100%;
}

Не удивлюсь что Вы будете несколько разачарованы результатом, но это только начало.
Каждому помощнику вида Zend_Dojo соответствует одноименный элемент интерфейса Dojo. Их полный список можно посмотреть в документации. Но, к сожалению, не для всех виджетов Dojo существуют хелперы. В этом случае можно использовать хелпер customDijit. В качестве примера заменим верхний contentPane на виджет Toolbar:

$this->customDijit()->captureStart(
	'toolbar',
	array('dojoType'=>'dijit.Toolbar', 'region'=>'top')
);
echo $this->button(
	'newRecord',
	'Новая запись',
	array('iconClass'=>'dijitEditorIcon dijitEditorIconNewPage')
);
echo $this->button(
	'editOptions',
	'Настройки',
	array('iconClass'=>'dijitEditorIcon dijitEditorIconPaste')
);
echo $this->customDijit()->captureEnd('toolbar');

Использование хранилищ данных Dojo

Dojo предоставляет очень удобный способ работы с данными – хранилища данных, которые работают как посредники между источниками данных и виджетами Dojo. В нашем приложении уже есть источник даных – таблица guestbook для хранения записей гостевой книги. Для того чтобы передать эти данные в понятном для Dojo формате добавим в класс Application_Model_Guestbook метод toArray.

public function toArray()
{
	return array(
		'id'      => $this->getId(),
		'email'   => $this->getEmail(),
		'comment' => $this->getComment(),
		'created' => $this->getCreated()
	);
}

И изменим методы init и indexAction котроллера Guestbook.

public function init()
{
	$this->_helper->viewRenderer->setNoRender ();
	$this->_helper->getHelper ( 'layout' )->disableLayout ();
}
public function indexAction()
{
	$this->getResponse ()
		->setHeader ( 'Content-Type', 'application/json; charset=utf-8' );
	$guestbook = new Application_Model_GuestbookMapper();
	$entries = $guestbook->fetchAll();
	$data = new Zend_Dojo_Data('id', $entries);
	$this->getResponse()->setBody( $data->toJson() );
}

В выше приведенном коде, данные, полученные из БД, преобразуются в строку JSON в формате, который понимает хранилище данных Dojo. В конструктор обертчика Zend_Dojo_Data можно передавать как массив, так и итерируемый объект, хранимые данные также могут быть ассоциативным массивом или объектом для которого определен метод toArray (используемый для получения данных). Поскольку тело ответа устанавливается с помощью setBody объекта ответа, мы отключаем авторендеринг, и скрипты вида контроллера Guestbook можно удалить.

Вернемся к скрипту вида Index контроллера – заменим центральный contentPane вида на контейнер из 2-х табов, в первый из которых будем выводить данные гостевой книги в виде каблицы.

$this->tabContainer()->captureStart(
	'tabMain',
	array('region'=>'center')
);
$this->contentPane()->captureStart( // Tab1
	'bookPane',
	array('title'=>'Гостевая книга')
);
echo $this->customDijit(
	'recordsTable', '',
	array('dojoType'=>'dojox.grid.DataGrid')
);
echo $this->contentPane()->captureEnd('bookPane');
echo $this->contentPane(
	'usersPane',
	'Здесь может быть список пользователей',
	array('title'=>'Пользователи')
);
echo $this->tabContainer()->captureEnd('tabMain');

Теперь нужно создать хранилище и связать с ним виджет таблицы. Добавим в indexAction Index-контроллера следующие строчки:

$this->view->Dojo()
	->addStylesheet( 'http://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojox/grid/resources/'.$this->view->theme.'Grid.css' )
	->requireModule( 'dojo.data.ItemFileReadStore' )
	->addOnLoad( "function() {\n"
		. "      dijit.byId('recordsTable').attr('store', new dojo.data.ItemFileReadStore( {url: 'guestbook'} ) );\n" 
		. "      var layout = [{field:'email', name:'E-mail', width:'200px'}, {field:'comment', name:'Комментарий', width:'100%'}, {field:'created',name:'Добавлен', width:'200px'}];\n"
		. "      dijit.byId('recordsTable').attr('structure', layout );\n"
		. "}" 
	)
;

Помимо собственно связывания в выше приведенном коде производятся обычные действия по инициализации виджетов – все то что делает за нас Zend_Dojo при использовании помощников (ни для хранилищ ни для таблиц данных таковых в ZF-1.10 ещё нет).

Пример интерфейса Dojo

Окончательный результат

В заключение добавлю ссылку на исходники этого приложения. Бонусом – пример использования дилога с формой добавления записи.
Скачать исходники

One Response to “Создание интерфейсов с помощью Dojo и Zend Framework”

  1. IgSh Says:

    Спасибо. Побольше бы статей про Zend_Dojo ;)

Leave a Reply