Привет.
Хочу поделиться небольшим модулем, предназначенным для создания страницы настроек в своём приложении. А заодно узнать у сообщества, что в нём можно было бы улучшить.
Задача по своей идее простая — сделать табличку в БД, хранящую параметры типа «ключ -> значение», а к ней сделать страничку редактирования, позволяющую изменять данные значения. ну и конечно же реализовать программный интерфейс для доступа к параметрам хранимым в БД.
Срок реализации — около получаса. В интернете почему-то готового решения было не найти. Исправим положение, авось кому пригодится.
Делать будем на конкретном примере. Допустим, нам необходимо хранить такие настройки: Имя приложения, Описание приложения, Пароль для Gii, Email администратора.
Пишем
Итак, для начала создадим структуру каталогов, в которой сложим наш модуль:
configpage
components
Econfig.php
conrollers
WtsController.php
models
WtsConfigForm.php
views
wts
config.php
configForm.php
ConfigpageModule.php
Не будем ничего выдумывать и используем готовое расширения для хранения настроек в БД — EConfig. Его и сложим в каталог components. Данное расширение имеет два метода «get» и «set», а также само умеет создавать таблицу в БД, то есть париться по его настройке не придётся.
Шаблон для нашего модуля сгенерирован через Gii и основной файл модуля ConfigpageModule.php остаётся без изменений:
class ConfigpageModule extends CWebModule
{
public function init()
{
$this->setImport(array(
'configpage.models.*',
'configpage.components.*',
));
}
public function beforeControllerAction($controller, $action)
{
if(parent::beforeControllerAction($controller, $action))
{
return true;
}
else
return false;
}
}
Куда интереснее обстоят дела с самой формой. Для её создания мы можем воспользоваться конструктором форм, входящим в поставку Yii. Подробнее о нём можно почитать здесь.
Если вкратце, то нам понадобится создать модель формы, контроллер, описание формы и вьюшку. Начнём с модели.
WtsConfigForm.php:
class WtsConfigForm extends CFormModel
{
public $applicationName;
public $applicationShortDesc;
public $giiPassword;
public $adminEmail;
public function rules()
{
return array(
array('applicationName, giiPassword, adminEmail, applicationShortDesc', 'required'),
);
}
public function attributeLabels()
{
return array(
'applicationName' => Yii::t('app', 'Наименование приложения'),
'applicationShortDesc' => Yii::t('app', 'Краткое описание приложения'),
'giiPassword' => Yii::t('app', 'Пароль для генератора кода Gii'),
'adminEmail' => Yii::t('app', 'Email администратора'),
);
}
}
Всё просто — описали 4 поля, описали их метки и указали правило, утверждающее, что поле является обязательным. Хинт: если не указать поле как обязательное, оно не появится на форме.
Окейно. Контроллер оставим на сладкое, а пока опишем форму и вьюшку. Описание формы — это простой массив, в котором хранится описание полей и элементов управления формы.
configForm.php:
return array(
'elements'=>array(
'mainSettings'=>array(
'type'=>'form',
'title'=>'Основные настройки',
'elements'=>array(
'applicationName'=>array('type'=>'text',),
'applicationShortDesc'=>array('type'=>'text',),
),
),
'systemSettings'=>array(
'type'=>'form',
'title'=>'Системные настройки',
'elements'=>array(
'adminEmail'=>array('type'=>'text',),
'giiPassword'=>array('type'=>'text', ),
),
),
),
'buttons'=>array(
'configPage'=>array(
'type'=>'submit',
'label'=>'Сохранить',
),
),
);
Просто? Вот и я думаю что да. Мы выделили две группы настроек — основные и системные, в каждой группе описали некие поля, присутствующие в модели и снизу расположили кнопку «Сохранить».
Выводить всё это мы будем простейшую вьюшку, имя которой config.php:
<?php
$this->breadcrumbs = array(
'Администрирование',
'Настройки приложения',
);
?>
<div class="form">
<?php echo $form; ?>
</div>
Ну тут совсем всё тривиально. Разве что для красоты оставим breadcrumbs.
А вот теперь будет самое интересное. В контроллере мы свяжем нашу модель с произвольным количеством полей и спец. табличку БД, хранящую пары «ключ->значение». Связью как я и говорил будет сложить модуль EConfig. Файл WtsController.php:
class WtsController extends Controller
{
public function actionIndex()
{
$model = new WtsConfigForm;
foreach ($model->attributes as $attr => $val) {
$model->$attr = Yii::app()->getModule('configpage')->config->get($attr);
}
$form = new CForm('configpage.views.wts.configForm', $model);
if ($form->submitted('configPage') && $form->validate()) {
foreach ($model->attributes as $attr => $val) {
Yii::app()->getModule('configpage')->config->set($attr, $val);
}
$this->render('config', array('form' => $form));
} else {
$this->render('config', array('form' => $form));
}
}
}
Что здесь происходит. В actionIndex (чтобы не плодить лишнего) мы создаём экземпляр модели, заполняем её значениями из БД, причём если в БД отсутствует требуемое значение, то в поле проставляется значение null, затем мы создаём форму, используя наше описание и экземпляр модели.
А дальше проверяем — если есть данные из браузера — если таковые найдутся, то модель самостоятельно загрузит их, после чего эти данные будут записаны в БД и страница настроек будет вновь показана пользователю.
Кстати да, заметьте, что я за ненадобностью не описал правил фильтрации пользователей. Вы этого сделать не забудьте, а то все смогут поназаписывать настроек в базу.
Остаются мелочи. Подключить и начать использовать модуль.
Подключаем
Подключить модуль проще простого. Просто вписываем следующий код в раздел modules главного файла конфигурации приложения (main.php).
...
'modules' => array(
'configpage' => array(
'components' => array(
'config' => array(
'class' => 'EConfig',
'strictMode' => false,
),
),
),
),
...
Вот и всё, модуль подключен.
Используем
Естественно сама по себе страничка нам нафиг не упала, нам нужен какой-то способ доступа к информации хранящейся в БД. Для данного конкретного примера мы можем реализовать загрузку данных в файле index.php нашего приложения:
$app = Yii::createWebApplication($config);
function loadSettings() {
Yii::app()->getModule('gii')->password = Yii::app()->getModule('configpage')->config->get('giiPassword');
Yii::app()->name = Yii::app()->getModule('configpage')->config->get('applicationName');
Yii::app()->params['adminEmail'] = Yii::app()->getModule('configpage')->config->get('adminEmail');
}
loadSettings();
$app->run();
То есть, мы создаём экземпляр приложения, оно подгружает модули и настройки, затем мы перезаписываем некоторые из настроек и только после этого выполняем приложение.
Как-то так. Единственное, что мне не нравится — это строка вызова метода get:
Yii::app()->getModule('configpage')->config->get('applicationName');
Уж слишком она длинная. К сожалению придумать как её укоротить я пока не могу. Может кто подскажет?
Ну и куда же без картинок. Вот что у нас примерно должно получиться в итоге:
За картинку кстати не ругайте, если найдёте сходство с данным проектом. OpenSource, все дела, можно использовать чужие наработки. В данном случае — понравилось расположение панельки слева. В остальном никакого сходства =). Ди а вообще, Twitter Bootstrap он везде одинаковый.
Из позитивного
Я по специализации вообще-то нифига не web-разработчик, но почему-то в последнее время всё больше приходится заниматься именно данным видом кодинга. И почему-то мне нравится, куда проще чем Qt и C++ =). Когда я открыл для себя такие вещи как генерация кода, фреймворк Yii, Twitter Bootstrap и множество других ништяков, я понял что проекты под web могут вылетать из под пера более-менее опытного разработчика как горячие пирожки — по три штуки в месяц.
Так что кипящие в соседних топиках дискуссии о постоянной нехватке квалифицированных кадров — какая-то глупость.
Современные средства разработки настолько просты, что 90% работы можно выполнить никогда так и не узнав разницы между MySql индексами типа BTree и hash. А оставшиеся 10% всегда можно где-то подглядеть.
Ну да ладно, всё это лирика.
Что ещё хотелось бы отметить
Расширить данный модуль очень легко — достаточно добавить ещё по одному экзепляру контроллера, модели, описания формы и вьюшки. А можно обойтись и меньшими усилиям — новый action, описалово формы и модель. Вьюшку можно юзать ту же самую. И тогда у вас будет уже две-три-десять независимых друг от друга страниц настроек.
Для меня кстати унификация и оптимизация — это вообще болезнь, так что хотелось бы конечно прикрутить ко всему этому интерфейс по редактированию полей формы настроек прямо в браузере, но это уже в каком-нибудь другом проекте.
Вообще после года работы с Yii у меня накопился целый ящик всяких примеров, архитектурных решений и извращений, всё собираюсь их по человечески описать, но как обычно время, время…
Вроде всё. Вопросы? Предложения?
Автор: vitaly_KF