Когда нужно что-то почти готовое
Доброго времени суток, хабражитель!
Чуть более года назад столкнулся с ситуацией когда нужно было реализовать веб-приложение (как обычно в очень сжатые сроки) с богатым функционалом:
Управление учетными записями пользователей с различными ролями Назначение задач на пользователей и отслеживание дальнейшей жизнедеятельности этих задач Планирование работы пользователей (на день, месяц) Работа с результатами работы сотрудников (регистрация времени и типов работ) Формирование различных отчетов, статистических срезов информации и тп И это только десятая часть того что нужно было сделать еще «вчера». Сразу оговорюсь: я — не веб-разработчик, поэтому нужно было решение, на котором можно было бы построить веб-приложение как можно быстрее без глубокого погружения в мир PHP, JS, Java, Ruby, и тп.Я умышленно пропущу анализ и выбор средств реализации и сразу перейду к самому интересному: в качестве платформы был выбран Koala Framework — гремучая смесь из Zend Framework и ExtJS. В основу этого фреймворка легла модель MVC (model-view-controller). Но настоящей его силой являются автогенерируемые формы и таблицы (AutoForm и AutoGrid).Смысл авто-форм и авто-таблиц в том, что разработчику нужно описать модель (таблицу БД) и связать поля/свойста модели с колонками таблицы и полями формы. Например:
допустим у нас есть таблица в MySQL:
CREATE TABLE IF NOT EXISTS `tasks` ( `id` int (10) unsigned NOT NULL AUTO_INCREMENT, `userId` int NOT NULL, `title` varchar (300) COLLATE utf8_unicode_ci, `description` varchar (1000) COLLATE utf8_unicode_ci, `startDate` date, `endDate` date, `status` int NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `userId` (`userId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; Модель будет иметь вид:
'id', 'direction' => 'DESC'); protected $_paging = 30; protected $_buttons = array ('add');
public function indexAction () { $this→view→ext ('Tasks'); } protected function _initColumns () { $this→_columns→add (new Kwf_Grid_Column ('title', trl ('Title'), 200));
$this→_columns→add (new Kwf_Grid_Column_Date ('endDate', trl ('End Date'), 100))→setRenderer ('checkDate'); } } Здесь свойства класса описывают поведение: количество элементов на странице (да, постраничный вывод поддерживается из коробки!), модель данных, сортировку выборки (опиционально) и возможные действия. Из действий здесь указано только добавление задач, но доступны еще и удаление, сохранение и экспорт в Excel/PDF.
Теперь нужно загрузить задачи только для конкретного залогиненого пользователя. Для этого во фреймворке есть глобальные переменные. Теперь легко задаем условия для выборки задач в контроллере:
protected function _getWhere () { $users = Kwf_Registry: get ('userModel'); $ret = parent::_getWhere (); $ret['status = ?'] = 0; $ret['userId = ?'] = $users→getAuthedUserId (); return $ret; } Отлично, теперь пользователь видит только свои активные задачи!
Так, осталось добавить создание и изменение задач. Для этого нужен уже другой контроллер (AutoForm Controller):
protected function _initFields () { $this→_form→add (new Kwf_Form_Field_TextField ('title', trl ('Title'))) →setWidth (400) →setAllowBlank (false); $this→_form→add (new Kwf_Form_Field_DateField ('startDate', trl ('Start Date'))); $this→_form→add (new Kwf_Form_Field_DateField ('endDate', trl ('End Date'))); $this→_form→add (new Kwf_Form_Field_TextArea ('description', trl ('Description'))) →setHeight (70) →setWidth (400); $this→_form→add (new Kwf_Form_Field_Checkbox ('status', trl ('Done'))); } } Свойства класса описывают поведение формы, причем связи данных с полями задаются в функции initFields (). Но есть маленькая проблема: поле userId никак не связано с текущим пользователем и не привязано к полям формы. Пока… Чтобы освободить пользователя от работы по выбору самого себя в качестве владельца задачи нужно добавить триггер — функцию, срабатывающую во время создания новой записи:
protected function _beforeInsert (Kwf_Model_Row_Interface $row) { $users = Kwf_Registry: get ('userModel'); if ($row→startDate == NULL) { $row→startDate = new DateTime (); } $row→userId = $users→getAuthedUserId (); $row→status = 0; } В KWF также доступны и другие триггеры: на изменение и удаление данных.
Теперь как-то нужно связать оба этих контроллера между собой. Код обоих контроллеров генерирует ExtJS формы. Следовательно и связывать мы их будем в JS коде:
var Tasks = Ext.extend (Ext.Panel, { initComponent: function (test) { var form = new Kwf.Auto.FormPanel ({ controllerUrl: '/task', region: 'center' }); var grid = new Kwf.Auto.GridPanel ({ controllerUrl: '/tasks', region: 'west', width: 400, resizable: true, split: true, collapsible: true, title: trl ('Tasks'), bindings: [{ queryParam: 'id', item: form }] }); this.layout = 'border'; this.items = [grid, { layout: 'border', region: 'center', items: [form] }]; Tasks.superclass.initComponent.call (this); } }); Всем, кто уже работал с ExtJS, этот код наверно покажется очень знакомым =)
Осталось только определить точку доступа (входа) к этим контроллерам. Для этого в KWF есть отдельный предопределенный класс Kwf_Acl:
remove ('default_index'); $this→addResource (new Kwf_Acl_Resource_MenuUrl ('default_tasks', array ('text'=>trl ('Tasks'), 'icon'=>'time.png'), '/tasks'));
$this→addResource (new Zend_Acl_Resource ('default_task'), «default_tasks');
$this→addRole (new Zend_Acl_Role («user'));
$this→allow ('user', 'default_tasks'); $this→allow ('admin', 'default_tasks'); $this→allow ('admin', 'default_index'); } } Вот и все! Очередной TO-DO список готов! В добавок он многопользовательский и при необходимости задачи типа экспорт списка в Excel / PDF, фильтрации и сортировки списков добавляются максимум минут за 5!
Полный код приложения доступен тут: github.com/kronik/kwf-app-demo
Давайте создавать побольше полезных и удобных инструментов! =)
От себя еще хочу добавить что сейчас веб-приложение на KFW успешно разработано и внедрено в крупной Российской компании. Отзывы пользователей исключительно положительные.
PS: В команду ищутся разработчики PHP, ExtJS, MySQL, желающие поближе познакомиться с Koala Framework и готовые помочь (не бесплатно конечно) в развитии отечественной специализированной КИС. На все вопросы могу ответить в комментариях или в личке.