Когда нужно что-то почти готовое

image

Доброго времени суток, хабражитель!

Чуть более года назад столкнулся с ситуацией когда нужно было реализовать веб-приложение (как обычно в очень сжатые сроки) с богатым функционалом:

  1. Управление учетными записями пользователей с различными ролями
  2. Назначение задач на пользователей и отслеживание дальнейшей жизнедеятельности этих задач
  3. Планирование работы пользователей (на день, месяц)
  4. Работа с результатами работы сотрудников (регистрация времени и типов работ)
  5. Формирование различных отчетов, статистических срезов информации и тп

И это только десятая часть того что нужно было сделать еще “вчера”. Сразу оговорюсь: я — не веб-разработчик, поэтому нужно было решение, на котором можно было бы построить веб-приложение как можно быстрее без глубокого погружения в мир 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;


Модель будет иметь вид:

<?php
class Tasks extends Kwf_Model_Db
{
    protected $_table = 'tasks';
}


Чтобы отобразить список задач необходимо создать контроллер (точнее AutoGrid Controller):

<?php
class TasksController extends Kwf_Controller_Action_Auto_Grid
{
    protected $_modelName = 'Tasks';
    protected $_defaultOrder = array('field' => '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):

<?php
class TaskController extends Kwf_Controller_Action_Auto_Form
{
    protected $_modelName = 'Tasks';
    protected $_permissions = array('save', 'add');
    protected $_buttons = array('save');

    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:

<?php
class Acl extends Kwf_Acl
{
    public function __construct()
    {
        parent::__construct();
        $this->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 успешно разработано и внедрено в крупной Российской компании. Отзывы пользователей исключительно положительные.

PS1: Попытка разобраться и показать технологии уже карается потерей кармы? Давайте лучше обсудим в комментах :)

PS 2: В команду ищутся разработчики PHP, ExtJS, MySQL, желающие поближе познакомиться с Koala Framework и готовые помочь (не бесплатно конечно) в развитии отечественной специализированной КИС. На все вопросы могу ответить в комментариях или в личке.

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 18

    +2
    Автор не веб-разработчик ни капельки…
    И не программист. Ну ни сколечко. :)
      +2
      Да-да :D Как точно :)
        –1
        и не писатель. ну ни сколечко. :(
        0
        Может я чего-то не понимаю, но каким образом в проекте, выпускающимся под BSD лицензией может использоваться GPL-библиотека?
          +1
          Там же следует вывод: «Все лицензии, за исключением самой первой оригинальной, совместимы с GPL-лицензиями». KWF идет под новой BSD лицензией: www.koala-framework.org/license.
            +1
            Таким образом, возникла пересмотренная лицензия BSD, известная так же как лицензия 3-ех пунктов. Этот вариант лицензии стал совместим с лицензиями GPL, что, несомненно, имело важные последствия. Теперь коды обеих лицензий, собранные вместе, можно было выпускать в одном продукте под одной GPL лицензией.

            Они совместимы, но не в обе стороны.
          +3
          Все бы хорошо, но не вижу смысла связывать жизнь нового проекта с фреймворком, который базируется на ZF1 старой версии.
            0
            Варианты?
              0
              Если вы не программист и нужно что-то сделать очень быстро, возможно вам поможет Delphi for PHP habrahabr.ru/post/40270/

              По поводу Kwf я хотел сказать, что хороший фреймворк, но жаль что на ZF1.
                0
                Я разрабатываю на Scala и Objective-C… Этот пост был в основном про то, как была решена задача не по профилю :) Разработчики KWF обещают вскоре перейти на ZF2 и ExtJS5
                  0
                  Не прошел по ссылке, но Delphi для PHP… Это разорвало в голове все и породило много эмоций. :)
                  0
                  Попробуйте DVelum habrahabr.ru/post/176689/ Для подобного примера код вообще писать не придется.
                    0
                    Обязательно
                +3
                Клёво. А в чем смысл поста?
                  0
                  В попытке познакомить с удобным фреймворком
                    0
                    Я не вижу сравнения с другими фреймворками в плане «удобства».
                    «Удобство» — это вообще субъективная метрика.
                      0
                      Абсолютно согласен. Перефразирую: «в попытке познакомить оказавшимся удобным для меня фреймворком» :)
                        0
                        Знакомство вышло скомканным.
                        На туториал не похоже, больше похоже на статью «как нарисовать сову в два шага».

                        Без обид, но ценность материала маленькая.
                        Не говоря уже о том, что «в попытке познакомить оказавшимся удобным для меня фреймворком» больше подходит для ЖЖ сообщества «один мой день» :)

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое