Простенькая страница настроек для Yii-приложения

    Привет.

    Хочу поделиться небольшим модулем, предназначенным для создания страницы настроек в своём приложении. А заодно узнать у сообщества, что в нём можно было бы улучшить.

    Задача по своей идее простая — сделать табличку в БД, хранящую параметры типа «ключ -> значение», а к ней сделать страничку редактирования, позволяющую изменять данные значения. ну и конечно же реализовать программный интерфейс для доступа к параметрам хранимым в БД.

    Срок реализации — около получаса. В интернете почему-то готового решения было не найти. Исправим положение, авось кому пригодится.

    Делать будем на конкретном примере. Допустим, нам необходимо хранить такие настройки: Имя приложения, Описание приложения, Пароль для 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');
    

    Уж слишком она длинная. К сожалению придумать как её укоротить я пока не могу. Может кто подскажет?

    Ну и куда же без картинок. Вот что у нас примерно должно получиться в итоге:
    image

    За картинку кстати не ругайте, если найдёте сходство с данным проектом. OpenSource, все дела, можно использовать чужие наработки. В данном случае — понравилось расположение панельки слева. В остальном никакого сходства =). Ди а вообще, Twitter Bootstrap он везде одинаковый.

    Из позитивного


    Я по специализации вообще-то нифига не web-разработчик, но почему-то в последнее время всё больше приходится заниматься именно данным видом кодинга. И почему-то мне нравится, куда проще чем Qt и C++ =). Когда я открыл для себя такие вещи как генерация кода, фреймворк Yii, Twitter Bootstrap и множество других ништяков, я понял что проекты под web могут вылетать из под пера более-менее опытного разработчика как горячие пирожки — по три штуки в месяц.

    Так что кипящие в соседних топиках дискуссии о постоянной нехватке квалифицированных кадров — какая-то глупость.

    Современные средства разработки настолько просты, что 90% работы можно выполнить никогда так и не узнав разницы между MySql индексами типа BTree и hash. А оставшиеся 10% всегда можно где-то подглядеть.

    Ну да ладно, всё это лирика.

    Что ещё хотелось бы отметить


    Расширить данный модуль очень легко — достаточно добавить ещё по одному экзепляру контроллера, модели, описания формы и вьюшки. А можно обойтись и меньшими усилиям — новый action, описалово формы и модель. Вьюшку можно юзать ту же самую. И тогда у вас будет уже две-три-десять независимых друг от друга страниц настроек.

    Для меня кстати унификация и оптимизация — это вообще болезнь, так что хотелось бы конечно прикрутить ко всему этому интерфейс по редактированию полей формы настроек прямо в браузере, но это уже в каком-нибудь другом проекте.

    Вообще после года работы с Yii у меня накопился целый ящик всяких примеров, архитектурных решений и извращений, всё собираюсь их по человечески описать, но как обычно время, время…

    Вроде всё. Вопросы? Предложения?

    Only registered users can participate in poll. Log in, please.

    Стоит ли мне дальше писать про Yii?

    • 75.1%Да434
    • 6.8%Нет39
    • 9.0%Больше кода, меньше слов!52
    • 3.1%Ничерта не понятно, не пиши больше.18
    • 6.1%Зачем здесь такая элементарщина?35
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 14

      +4
      Обязательно пишите еще, интересно почитать, если даже в какой-то статье ничего полезного не найдется, то в следующей думаю, что-то да появится.
        0
        Спасибо.
        0
        это конечно удобно, но всё-таки запрос в базу при каждом выполнении приложения для таких редко меняемых настроек — стоит ли?
          0
          Ну во первых можно настроить кеширование, а во вторых — у многих приложений не так много пользователей, чтобы создать реальную нагрузку на сервер.

          В нашем конкретном случае — приложение рассчитано на использование в локалке, пользователей — порядка 10-15. Как разница, 10 или 20 запросов к БД будет происходить при каждом обращении к приложению.

          Ну и наконец, Вы же понимаете, что я описал именно пример того как можно использовать такую страничку. Ведь помимо редко меняемых, в приложении может быть ещё сотня-другая настроек, которые надо периодически менять. Согласны?
            0
            Да, и так можно сделать. Но есть другой вариант — вынести параметры в отдельный файл, подключаемый в конфиг, и редактировать с помощью этой формы сам файл параметров.

            P.S. Я не говорю, что какой-то подход лучше — везде есть плюсы и минусы. Действительно, для 10-15 пользователей — это вообще не страшно. Запрос скорее всего будет закеширован на уровне базы и о дополнительном кеше думать не надо даже.
          0
          Как-то так. Единственное, что мне не нравится — это строка вызова метода get
          Уж слишком она длинная. К сожалению придумать как её укоротить я пока не могу.

          Через компонент.
          Yii::app()->config->get('applicationName');
          


          Я не понял два момента:
          1. Зачем нужен отдельный модуль, когда конфигурация нужна для админки, когда админка сама является(скорей всего) модулем?
          2. Зачем нужно было делать надстройку над AR и Gii? Gii уже сам генерирует отличные функционал, используя ActiveRecord.
            0
            1) Просто так удобнее было оформить код
            2) Меньше шагов для добавления нового поля. Вместо создания нового поля в БД и перегенерации модели и вьюшек, его нужно лишь описать в двух файлах и всё мгновенно заработает.
              0
              Если это модулем, то просто создать в модуле метод get, чтобы получилось вот так
              Yii::app()->getModule('configpage')->get('applicationName');
              

              А код самого 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;
                  }
              
                  public function get($name)
                  {
                      $this->config->get($name);
                  }
              }
              


              Либо так:
              ConfigpageModule::get('applicationName')
              

              Тогда код будет такой:
              public static function get($name)
              {
                  Yii::app()->getModule('configpage')->config->get($name);
              }
              
              
                0
                Кстати да, про статический метод я почему то и не подумал. Большое спасибо за развёрнутый ответ!
              +4
              >>Так что кипящие в соседних топиках дискуссии о постоянной нехватке квалифицированных кадров — какая-то глупость.
              В том то и проблема что таких «спецов» уйма, а нормальных мало.
                +2
                Я согласен, но просто адекватных и трудолюбивых людей ведь хватает. Взять, поучить ведь не проблема? Тем более php, господи что в нём учить =)
                +1
                Если хотите реально сделать что-то полезное, то запилите crud для него через стд файлы конфигурации (чтобы в разных форматах можно было сохранять, например php array, yaml, xml, json), при этом не изобретите велосипед + добавьте версионность таких конфигов(например, dev, test, prod).
                А еще надо бы релизить(packagist) все это, чтобы сообщество пользовалось Вашей наработкой. Возможно потом ее даже включат в стандартную поставку Yii, если там такого еще нет(я не слежу за этим фреймворком, в Sf2, например, есть такая страничка)

                >>Так что кипящие в соседних топиках дискуссии о постоянной нехватке квалифицированных кадров — какая-то глупость.

                Увы, я с Вами не согласен.

                  0
                  Сделал нечто подобное, только работает не с базой, а с отдельным конфиг-файлом.

                  Т.е. делаем config-файл (например, params.php), в нём параметры, которые можно будет изменить при помощи этой модели:
                  <?php
                  
                  return array(
                      'name' => 'Мой сайт',
                      'params' => array(
                          'adminEmail' => 'admin@example.com',
                      ),
                  );
                  


                  В модели прописываем attributeLabels и всё. Метод save() сохраняет модель в файл (да, с форматированием и отступами), специальный form-builder строит форму на основе CForm или CActiveForm.

                  Если сообществу интересно, то могу поделиться
                    0
                    Конечно интересно! Выкладывайте =)

                  Only users with full accounts can post comments. Log in, please.