Tuesday, March 29, 2011

yii, облегчаем прототипирование.

Введение



Я давно работаю с yii framework. И пока это единственный framework в мире php. Из минусов для меня то, что он слишком низкоуровневый, отсутствует много плюшек, которые я с успехом возмещаю разумным использованием Zend компонент. Как набор компонент Zend хорош, чего не скажешь о его framework'е.

Ну так вот, возвращаясь к низкоуровневому yii. Его CRUD хорош, хорош для прототипирования, но плодит кучу файлов. Многие из которых со временем вырезаются и сильно модифицируются. Моим кошмаром была работа на небольшим по объему backend проектом. Где вся работа сводилась к администрированию кучи таблиц с текстовыми и буленовскими полями. При помощи CRUD все было сделано быстро, но большую часть времени я потратил на украшение админки, checkboxes вместо input, фильтры вида true|false вместо 0,1 и тому подобной ерунды. Таблиц было много, view еще больше. Я с нежностью вспоминал django и жалел что проект на PHP.



Прошло время, и вот во время работы над очередным проектом выдалась несколько часов, в результате которых было рождено небольшое расширение над CRUD.



Краткая суть. CRUD очень похожи, и их можно объединить. Второй задачей является способ указания системе типов данных в моделях, для того чтобы CRUD мог на основе этих типов создавать фильтры, приводить к строковому виду автоматически.

Это получилось, пока начало, но проект не закончен. Но уже можно пользоваться.

Что получилось? Получился модуль который позволяет не запуская CRUD получить CRUD странички над любой моделью при условии что она отнаследована от особого ActiveRecord + в ней определен один единственный метод. В качестве небольшого бонуса есть простая возможность слегка менять список полей и их порядок на полученных страницах.


Ниже небольшой туториал как заставить это работать. Текста много, но он расчитан на новичка в yii. Если вы накоротке с yii можете сразу читать с установки модуля.



Инициализация yii проекта


Можно пропустить, если хотите воспользоваться существующим.
Описание как создать yii проект с нуля. Для того чтобы потом использовать модуль.


Создание директории проекта.



Я буду использовать локальный вебсервер, с дефолтными настройками. Проект создам в папке AdminTest внутри моего document root /var/www/

 
claymore:$ mkdir /var/www/AdminTest
claymore:$ cd /var/www/AdminTest/
claymore:$


Папка создана, скачиваем yii-framework
 
Среда 2011-03-30 11:03 box:/var/www/AdminTest
claymore:$ wget http://yii.googlecode.com/files/yii-1.1.7.r3135.tar.gz
--2011-03-30 11:12:58-- http://yii.googlecode.com/files/yii-1.1.7.r3135.tar.gz
Преобразование адреса yii.googlecode.com... 74.125.87.82
Устанавливается соединение с yii.googlecode.com|74.125.87.82|:80... соединились.
Запрос HTTP послан, ожидание ответа... 200 OK
Длина: 2550331 (2,4M) [application/x-gzip]
Saving to: «yii-1.1.7.r3135.tar.gz»

100%[=============================================================================================================================>] 2 550 331 780K/s в 3,2s

2011-03-30 11:13:01 (780 KB/s) - «yii-1.1.7.r3135.tar.gz» saved [2550331/2550331]

Распаковываем

claymore:$ tar xf yii-1.1.7.r3135.tar.gz

Переименовываем, или делаем символическую ссылку( кому как удобнее), я переименовываю, т.к. работаю в рамках демонстрации
   
claymore:$ mv yii-1.1.7.r3135 yii

Удаляю скаченный архив

claymore:$ rm yii-1.1.7.r3135.tar.gz

Проверяем что у нас есть распаковааная папка с yii framework

claymore:$ ls
yii

Переходим в папку со скриптами yii framework
 
claymore:$ cd yii/framework/

Запускаем скрипт создания проекта

claymore:$ ./yiic webapp /var/www/AdminTest/
Create a Web application under '/var/www/AdminTest'? [Yes|No] Yes
mkdir /var/www/AdminTest/css
generate css/form.css
generate css/main.css
generate css/bg.gif
generate css/ie.css
generate css/screen.css
generate css/print.css
mkdir /var/www/AdminTest/assets
mkdir /var/www/AdminTest/images
generate index.php
generate index-test.php
mkdir /var/www/AdminTest/themes
mkdir /var/www/AdminTest/themes/classic
mkdir /var/www/AdminTest/themes/classic/views
mkdir /var/www/AdminTest/themes/classic/views/site
mkdir /var/www/AdminTest/themes/classic/views/layouts
generate themes/classic/views/.htaccess
mkdir /var/www/AdminTest/themes/classic/views/system
mkdir /var/www/AdminTest/protected
mkdir /var/www/AdminTest/protected/data
generate protected/data/schema.sqlite.sql
generate protected/data/testdrive.db
generate protected/data/schema.mysql.sql
generate protected/yiic
mkdir /var/www/AdminTest/protected/messages
mkdir /var/www/AdminTest/protected/tests
mkdir /var/www/AdminTest/protected/tests/unit
mkdir /var/www/AdminTest/protected/tests/functional
generate protected/tests/functional/SiteTest.php
generate protected/tests/phpunit.xml
generate protected/tests/bootstrap.php
generate protected/tests/WebTestCase.php
mkdir /var/www/AdminTest/protected/tests/fixtures
mkdir /var/www/AdminTest/protected/tests/report
mkdir /var/www/AdminTest/protected/views
mkdir /var/www/AdminTest/protected/views/site
mkdir /var/www/AdminTest/protected/views/site/pages
generate protected/views/site/pages/about.php
generate protected/views/site/login.php
generate protected/views/site/index.php
generate protected/views/site/contact.php
generate protected/views/site/error.php
mkdir /var/www/AdminTest/protected/views/layouts
generate protected/views/layouts/column1.php
generate protected/views/layouts/column2.php
generate protected/views/layouts/main.php
mkdir /var/www/AdminTest/protected/runtime
generate protected/.htaccess
mkdir /var/www/AdminTest/protected/components
generate protected/components/Controller.php
generate protected/components/UserIdentity.php
mkdir /var/www/AdminTest/protected/config
generate protected/config/main.php
generate protected/config/test.php
generate protected/config/console.php
mkdir /var/www/AdminTest/protected/commands
mkdir /var/www/AdminTest/protected/commands/shell
mkdir /var/www/AdminTest/protected/controllers
generate protected/controllers/SiteController.php
mkdir /var/www/AdminTest/protected/models
generate protected/models/ContactForm.php
generate protected/models/LoginForm.php
mkdir /var/www/AdminTest/protected/extensions
generate protected/yiic.bat
generate protected/yiic.php
mkdir /var/www/AdminTest/protected/migrations

Your application has been created successfully under /var/www/AdminTest.
Среда 2011-03-30 11:03 box:/var/www/AdminTest/yii/framework
claymore:$

Проверяем
 
claymore:$ wget http://127.0.0.1/AdminTest/index.php -q -O - | grep Yii
....
Congratulations! You have successfully created your Yii application.
...

Создаем базу данных admintest. При помощи вашего любимого средства.
 
mysql> create database admintest;
Query OK, 1 row affected (0.02 sec)


Прописываем настройки базы данных в protected/config/main.php


Теперь у нас есть болванка для веб сайта на основе шаблона yii.



Установка модуля.



Переходим в директорию расширений. (Если пропустили первый шаг, замените /var/www/AdminTest/ на путь до папки вашего проекта, содержащей protected)


 
claymore:$ cd /var/www/AdminTest/protected/extensions/

Скачиваем расширение.


 
claymore:$ hg clone -q https://yii-rextensions.googlecode.com/hg/ YiisyCrudAdmin -r YiisyCrudAdmin

[Опционально] удаляем информацию о репозитории, особенно ваш проект уже под системой контроля версий.


 
claymore:$ rm -rf YiisyCrudAdmin/.hg
Среда 2011-03-30 11:03 box:/var/www/AdminTest/protected/extensions

Модуль установлен.



Пример создания crud административной страницы.


Для примера нам понадобится любая модель.


Создаем таблицу в созданной базе данных.


  
mysql> create table example(id int primary key auto_increment, name char(20), is_good_record tinyint(1) default 0 , long_description text);
Query OK, 0 rows affected (0.08 sec)

Переходим в папку protected


  
claymore:$ cd /var/www/AdminTest/protected

Создаем модель.


  
claymore:$ ./yiic shell config/main.php
Yii Interactive Tool v1.1 (based on Yii v1.1.7)
Please type 'help' for help. Type 'exit' to quit.
>> model Example example
generate models/Example.php
generate fixtures/example.php
generate unit/ExampleTest.php

The following model classes are successfully generated:
Example

If you have a 'db' database connection, you can test these models now with:
$model=Example::model()->find();
print_r($model);
>>

Модифицируем модель.


Цель. Отнаследоваться от расширения CActiveRecord объявленному в YiisyCrudAdmin.RActiveRecord. И реализовать абстрактный метод getFieldsDescription


Открываем /var/www/AdminTest/protected/models/Example.php в любимом редакторе


   
Yii::import("ext.YiisyCrudAdmin.RActiveRecord"); //Добавляем эту строчку импорта в верх файла.

В модель Example добавляем новый метод


   
Yii::import("ext.YiisyCrudAdmin.RActiveRecord");
class Example extends RActiveRecord
{
//...
// в последней версии данный метод не требуется в модели, может создаваться по желанию в классе ExampleAdmin
public function getFieldsDescription()
{
return array(
'is_good_record' => 'RDbBoolean',
'long_description' => 'RDbText',
);
}
//...
}

Этот метод предоствляет расширенную информацию о полях модели. На данный момент реализованы пока Bool и Text.


Т.к. метод абстрактный ( чтобы про него не забывали), реализация обязательна, метод может возвращать пустой массив если нет желания заморачиваться.


Создаем в вашем любимом редакторе controllers/ExampleController.php


    
Yii::import('ext.YiisyCrudAdmin.RController');
class ExampleController extends RController
{
protected $_modelName = 'Example';
}

Тестируем


Открываем в браузере http://127.0.0.1/AdminTest/index.php?r=example/admin


Получаем типичный yii crud с небольшими улучшениями.



  • Поля, отмеченные как boolean, отображаются в виде чекбоксов при редактировании. Также в наличии встроенный фильтр для этих полей на странице actionAdmin.

  • Текстовые поля при редактировании редактируются в textarea. При просмотре в griidview обрезаются. (Пока и в view обрезаются, но это уже решаемый вопрос :) )


Из плюсов такого подхода, все сделано стандартными средствами yii. Т.е. после этапа прототипирования, вы уже можете использовать существующую базу кода, достаточно заглянуть в RController


Гибкость, например в методе getFieldsDescription модели, элеметом массива может быть массив, формирующий CGridColumn, в этом случае все обрабатывается в обычном для yii ключе.


Улучшаем внешний вид


Как поменять порядок полей в actionAdmin ?


Прямо в файле модели создаем класс


    
Yii::import('ext.YiisyCrudAdmin.RModelAdmin');
class ExampleAdmin extends RModelAdmin
{
public function getAdminFields()
{
return array(
'name', 'long_description', 'is_good_record', 'id'
);

}
}

После этого в actionAdmin наблюдаем поля в указанном порядке

.

Как исключить поле из отображения в actionAdmin ?


   
Yii::import('ext.YiisyCrudAdmin.RModelAdmin');
class ExampleAdmin extends RModelAdmin
{
public function getAdminExcludedFields()
{
return array(
'id',
);
}
}

И это все. Оба метода можно комбинировать.



Ну и вот интерфейс RModelAdmin, отвечающий за порядок и отображаемые поля


  
public function getViewExcludedFields();// список полей для исключения в actionView

public function getAdminExcludedFields();//список полей для исключения в actionAdmin

public function getViewFields();// список полей для отображения в actionView

public function getSearchFields();//список полей для отображения в расширенной форме поиска actionAdmin

public function getAdminFields();// список полей для отображения в actionAdmin

public function getFormFields();// список полей для создания/редактирования.


Почему методы а не массивы? Например для динамической генерации в зависимости от условий.




UPDATED:


В последней версии метод getFieldsDescription перенесен из модели в ModelAdmin класс.

6 comments:

bojlxb said...

Доброе время суток!
Очень понравился ваш подход:). А вы забросили проект? Или есть какие-то новые версии, которые вы просто не выкладывали?

Unknown said...

Ну есть более новая версия, там чуть другой подход, в плане еще меньше кода писать :)

Но я не люблю делать вещи ради вещей, а т.к. в последнее время нет проектов где требуется админка, то он не развивается. :)


Как появится такой проект, кстати возможно в одном из своих понадобится. То буду развивать дальше.

bojlxb said...

Понятно:). Не поделитесь?:)

Чего вот сейчас у вас не хватает, так это работы с MANY_MANY. Я, вообще, с Yii не работал практически, пару дней только копаю:), но мне кажется вполне это можно допилить, смотрел одним глазком код, который генерирует giix, вроде там всё просто. Попробую это сделать, если хватит умения разобраться:).

Unknown said...

Так я на данный момент не готов, давайте на выходных меня поймаете? В гугле толке? zadoev gmail.com. Я посмотрю где чего лежит, и в контекст въеду, как раз над своим проектом надо поработать, а там админка нужна.

Unknown said...

В любом разе, быстро не обещаю. Но могу повспоминать, дать доступ к репозиторию и рекомендации, ну и помочь при необходимости.

bojlxb said...

Хорошо, попробую вас поймать на выходных:)

 
Каталог сайтов, Добавить сайт