Yii и хранение настроек в базе данных

База Yii

Как многим известно, для хранения настроек приложения в Yii выделен специальный раздел params в конфигурационном файле. Это решение достаточно простое, но оно не позволяет легко менять настройки самому пользователю в панели управления сайта. Очередной вопрос на русском форуме Yii натолкнул меня поделиться своим вариантом решения упомянутого там вопроса.

Итак, представим, что в определённый момент мы всё-таки решились хранить настройки в базе данных, чтобы иметь возможность изменять их в админке. В своём вопросе автор упоминает о хранении массива значений в публичном поле $settings базового класса контроллера. Этот подход, конечно, имеет право на существование, но мы попытаемся пойти более универсальным путём.

Использование публичного поля контроллера имеет небольшой недостаток: наличие этого поля и инициализирующего метода, записывающего в него параметры из базы, немного «захламляет» контроллер и отвлекает его от своих непосредственных обязанностей. Настройки могут понадобиться не только контроллеру, но и любому другому компоненту (например, число элементов нужно виджету вывода последних комментариев, а адрес администратора может пригодиться какой-нибудь модели для отправки уведомлений). Для них обращение к полю контроллера будет не очень красивым:

Yii::app()->controller->settings['param'];

Всё это даёт лишнюю и не очень удобную привязку всех подсистем к контроллеру.

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

Создадим таблицу в базе данных для хранения наших настроек

CREATE TABLE IF NOT EXISTS `config` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `param` varchar(128) NOT NULL,
  `value` text NOT NULL,
  `default` text NOT NULL,
  `label` varchar(255) NOT NULL,
  `type` varchar(128) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `param` (`param`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

и сгенерируем к ней стандартную модель Config:

<?php
<?php
/**
 * This is the model class for table "{{config}}".
 *
 * The followings are the available columns in table '{{config}}':
 * @property string $id
 * @property string $param
 * @property string $value
 * @property string $default
 * @property string $label
 * @property string $type
 */
class Config extends CActiveRecord
{
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
 
    public function tableName()
    {
        return '{{config}}';
    }
 
    public function rules()
    {
        return array(
            array('value', 'safe'),
            array('id, param, value, label, type, default', 'safe', 'on'=>'search'),
        );
    }
}

В таблицу кроме полей param и value мы добавили поля default для значения по умолчанию и label для хранения названия настройки. В панели управления от стандартного CRUD оставляем только действие actionUpdate() с возможностью изменять поле value. Операций добавления или удаления там быть не должно, так как содержимое этой таблицы вбивает вручную прямо в базу данных разработчик приложения. Кроме того, имеется атрибут type для указания типа значения (например string, text, checkbox) для вывода нужного типа поля в форме редактирования настроек.

Теперь для удобного чтения параметров нужно сделать компонент:

<?php
<?php
/**
 * @author ElisDN <mail@elisdn.ru>
 * @link https://elisdn.ru
 */
class DConfig extends CApplicationComponent
{
    protected $data = array();
 
    public function init()
    {
        $items = Config::model()->findAll();
        foreach ($items as $item){
            if ($item->param) 
                $this->data[$item->param] = $item->value === '' ?  $item->default : $item->value;
        }
        parent::init();
    }
 
    public function get($key)
    {
        if (array_key_exists($key, $this->data)){
            return $this->data[$key];
        } else {
            throw new CException('Undefined parameter '.$key);
        }
    }
 
    public function set($key, $value)
    {              
        $model = Config::model()->findByAttributes(array('param'=>$key));
        if (!$model) 
            throw new CException('Undefined parameter '.$key);
 
        $this->data[$key] = $value;
        $model->value = $value;
        $model->save();
    }
}

и подключить его к приложению в файле конфигурации:

'components'=>array(
 
    // ...
 
    'config'=>array(
        'class' => 'DConfig'
    ),
),

При инициализации компонента все настройки считаются в массив $data. Для автоматической загрузки компонента в начале работы приложения можно поместить его имя в список preload:

// preloading components
'preload'=>array(
    'log',
    'config'
),

Теперь достаточно вбить в базу данных все параметры и считывать в любом месте приложения вызовом метода get():

Yii::app()->config->get('NEWS_PER_PAGE');

По возможности лучше закешировать чтение из базы в методе init():

$items = Config::model()->cache(3600)->findAll();

Но тогда не забывайте сбрасывать кэш при каждом изменении настроек. Также для экономии памяти при работе с сотнями параметров можно заменить чтение с использованием СActiveRecord::findAll() на запрос DAO.

Небольшой совет: При увеличении числа параметров может возникнуть ситуация, когда нескольким из них нужно дать похожие имена. При этом нужно следить, чтобы имена не совпадали, а это может привести к появлению сложных имён типа NEWS_PER_PAGE, POSTS_PER_PAGE, NEWS_PER_PAGE_IN_HOME. Также при выводе в списке (например, в CGridView) все параметры трудно «красиво» отсортировать. Для решения этих проблем можно называть параметры по шаблону ГРУППА.ПАРАМЕТР вроде NEWS.PER_PAGE, BLOG.PER_PAGE, SHOP.PER_PAGE, NEWS.PER_HOMEPAGE. Это одновременно избавляет от случайного повторения имён и выводит параметры группами при сортировке их имён по алфавиту.

Присутствующий метод set() позволяет при необходимости менять значение любого параметра. Это, например, может пригодиться для изменения курса доллара по планировщику в вашем интернет-магазине:

$current_curs = ... ;
if ($current_curs && Yii::app()->config->get('SHOP.DOLLAR_CURS') != $current_curs) 
    Yii::app()->config->set('SHOP.DOLLAR_CURS', $current_curs);

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

Пойдём дальше и сделаем более полноценную версию компонента (с использованием DAO для выборки и кэшированием):

<?php
<?php
/**
 * @author ElisDN <mail@elisdn.ru>
 * @link https://elisdn.ru
 */
 
class DConfig extends CApplicationComponent
{
    public $cache = 0;
    public $dependency = null;
 
    protected $data = array();
 
    public function init()
    {
        $db = $this->getDbConnection();
 
        $items = $db->createCommand('SELECT * FROM {{config}}')->queryAll();
 
        foreach ($items as $item)
        {
            if ($item['param'])
                $this->data[$item['param']] = $item['value'] === '' ?  $item['default'] : $item['value'];
        }
 
        parent::init();
    }
 
    public function get($key)
    {
        if (array_key_exists($key, $this->data))
            return $this->data[$key];
        else
            throw new CException('Undefined parameter ' . $key);
    }
 
    public function set($key, $value)
    {
        $model = Config::model()->findByAttributes(array('param'=>$key));
        if (!$model)
            throw new CException('Undefined parameter ' . $key);
 
        $model->value = $value;
 
        if ($model->save())
            $this->data[$key] = $value;
 
    }
 
    public function add($params)
    {
        if (isset($params[0]) && is_array($params[0]))
        {
            foreach ($params as $item)
                $this->createParameter($item);
        }
        elseif ($params)
            $this->createParameter($params);
    }
 
    public function delete($key)
    {
        if (is_array($key))
        {
            foreach ($key as $item)
                $this->removeParameter($item);
        }
        elseif ($key)
            $this->removeParameter($key);
    }
 
    protected function getDbConnection()
    {
        if ($this->cache)
            $db = Yii::app()->db->cache($this->cache, $this->dependency);
        else
            $db = Yii::app()->db;
 
        return $db;
    }
 
    protected function createParameter($param)
    {
        if (!empty($param['param']))
        {
            $model = Config::model()->findByAttributes(array('param' => $param['param']));
            if ($model === null)
                $model = new Config();
 
            $model->param = $param['param'];
            $model->label = isset($param['label']) ? $param['label'] : $param['param'];
            $model->value = isset($param['value']) ? $param['value'] : '';
            $model->default = isset($param['default']) ? $param['default'] : '';
            $model->type = isset($param['type']) ? $param['type'] : 'string';
 
            $model->save();
        }
    }
 
    protected function removeParameter($key)
    {
        if (!empty($key))
        {
            $model = Config::model()->findByAttributes(array('param'=>$key));
            if ($model)
                $model->delete();
        }
    }
}

Для активации кэширования настройте кэш приложения и установите нужные значения атрибутам cache и dependency

'components'=>array(
 
    // ...
 
    'config'=>array(
        'class'=>'DConfig',
        'cache'=>3600,
    ),
),

Этот компонент дополнен методами add() и delete() для непосредственного добавления и удаления параметров. Этим методам можно передавать как один параметр:

Yii::app()->config->add(array(
    'param'=>'BLOG.POSTS_PER_PAGE',
    'label'=>'Записей на странице',
    'value'=>'10',
    'type'=>'string',
    'default'=>'10',
));
 
Yii::app()->config->delete('BLOG.POSTS_PER_PAGE');

так и массив:

Yii::app()->config->add(array(
    array(
        'param'=>'BLOG.POSTS_PER_PAGE',
        'label'=>'Записей на странице',
        'value'=>'10',
        'type'=>'string',
        'default'=>'10',
    ),
    array(
        'param'=>'BLOG.POSTS_PER_HOME',
        'label'=>'Записей на главной странице',
        'value'=>'5',
        'type'=>'string',
        'default'=>'5',
    ),
));
 
Yii::app()->config->delete(array(
    'BLOG.POSTS_PER_PAGE',
    'BLOG.POSTS_PER_HOME',
));

Предположим, что разрабатывая нами система должна поддерживать автоматическую установку (и удаление) модулей. Для этого, например, в каждом модуле мы можем создать методы install() и uninstall() и прописать в них добавление и удаление нужных параметров и создание директорий для загрузки файлов:

class BlogModule extends CWebModule
{
    public function init()
    {
        $this->setImport(array(
            'blog.components.*',
            'blog.models.*',
        ));
    }
 
    public function install()
    {
        Yii::app()->config->add(array(
             array(
                 'param'=>'BLOG.POSTS_PER_PAGE',
                 'label'=>'Записей на странице',
                 'value'=>'10',
                 'type'=>'string',
                 'default'=>'10',
             ),
             array(
                 'param'=>'BLOG.POSTS_PER_HOME',
                 'label'=>'Записей на главной странице',
                 'value'=>'5',
                 'type'=>'string',
                 'default'=>'5',
             ),
        ));
 
        $path = Yii::getPathOfAlias('webroot.upload.blog');
 
        if (!is_dir($path))
            @mkdir($path, 755);            
    }
 
    public function uninstall()
    {
        Yii::app()->config->delete(array(
             'BLOG.POSTS_PER_PAGE',
             'BLOG.POSTS_PER_HOME',
        ));
    }
}

В контроллере раздела «Управление модулями» можно производить их установку и удаление вызывая соответствующий метод модуля:

$module = Yii::app()->getModule($moduleName);
$module->install();

или

$module = Yii::app()->getModule($moduleName);
$module->uninstall();

На этом всё. Теперь необходимые каждому модулю параметры будут добавляться в базу автоматически при установке модуля.

Комментарии

 

Евгений

Вываливается ошибка: Fatal error: Class 'DConfig' not found in Z:\home\yii\framework\YiiBase.php on line 219. Расскажите ка избавится.

Ответить

 

Елисеев Дмитрий

Это значит, что системе не удалось найти этот класс. Убедитесь, что класс находится в файле DConfig.php и он доступен для импорта. Для этого его можно положить в папку protected/components и настроить импорт всех классов из неё:

return array(
    'import'=>array(
        'application.components.*',
    ),    
),

или положить в произвольную директорию (например protected/components/config) и указать путь к ней непосредственно в строке подключения

'components'=>array(
    'config'=>array(
        'class'=>'application.components.config.DConfig',
    ),
),
Ответить

 

Евгений

В Вашем листинге в начале отсутствует <?php
Резюме: тупое копирование приводит к вышеописанным результатам.
Спасибо за статью

Ответить

 

Виталий – kivicms.ru

Автор - респект и уважуха. Сайт - супер! Статьи - просто прелесть. Продолжай в том же духе. Сайт однозначно в закладки.
Изложение просто замечательное!!! Молодец!

Ответить

 

Елисеев Дмитрий

Ого)) Спасибо, стараюсь.

Ответить

 

Виталий – kivicms.ru

Дмитрий, не мог бы ты привести описание экшена по редактированию настроек из конфига?

Ответить

 

Елисеев Дмитрий

Ничего специфичного в экшене нет. Обычная работа с ActiveRecord моделью Config. Подойдёт стандартный сгенерированный в gii CRUD контроллер с выводом списка в CGridView и редактированием модели в форме CActiveForm. Только операции create и delete из него нужно удалить.

Отличие только в выводе поля $model->value в форме. Там надо вывести input, textarea или checkbox в зависимости от типа поля $model->type. Например, так:

<?php if (!$model->type || $model->type == 'string'): ?>
    <?php echo $form->textField($model, 'value', array('size'=>60, 'maxlength'=>255, 'placeholder'=>$model->default)); ?>
<?php elseif ($model->type == 'text'): ?>
    <?php echo $form->textArea($model, 'value', array('rows'=>10, 'cols'=>80, 'placeholder'=>$model->default)); ?>
<?php elseif ($model->type == 'checkbox'): ?>
    <?php echo $form->checkBox($model, 'value'); ?>
<?php endif; ?>

Я у себя использую табличный ввод для отображения всех параметров в одной большой форме.

Ответить

 

Виталий – kivicms.ru

Это понятно... Непонятно как использовать совместно с YiiBooster.
Потому как echo $form->textFieldRow($model, 'value', естественно не отображает label поля...
Конечно можно использовать HTML разметку из бутстрапа, но как то... как то не кошерно получается, не по Yii-шному :)

Ответить

 

Дмитрий Елисеев

Понятно. Всё-таки проще вручную label подписать. Но это сделка с совестью :)

<h1>Параметр "<?php echo Chtml::encode($model->label); ?>"</h1>

Пришла мысль, что замечательно было бы построить грид с Ajax редактированием: щёлкаешь по параметру, а его поле выскакивает во всплывающем окне.

Ответить

 

Виталий – kivicms.ru

ну собственно так и сделал:

<?php foreach($model as $i=>$m): ?> 
<div class="control-group ">
	<label class="control-label" for="TestForm_textField"><?php echo $m->label; ?></label>
	<div class="controls">
		<?php 
		if ($m->type == 'string' || $m->type == 'integer')	
			echo CHtml::activeTextField($m,"[$m->param]value",array('placeholder'=>$m->default)); 
		if ($m->type == 'boolean') 
			echo Chtml::activeCheckBox($m,"[$m->param]value");
		?>
	</div>
</div>
<?php endforeach; ?>
Ответить

 

Виталий – kivicms.ru

Кстати на сайте невозможно зарегистрироваться, после активации вот что:

Ошибка 500
Не определено свойство "User.user".

Поправь. У тебя очень интересные статьи, приятно читать...

Ответить

 

Елисеев Дмитрий

C отсутствующей аватаркой проблемы были. Исправил.

Ответить

 

Стас

скажите, а сеттер где добавляется? не получается произвести обновление

Yii::app()->config->set('SHOP.DOLLAR_CURS', $current_curs);

спасибо.

Ответить

 

Дмитрий Елисеев

В смысле? Не работает конструкция

Yii::app()->config->set('SHOP.DOLLAR_CURS', 30.56);

или другая проблема?

Ответить

 

Стас

Дмитрий, есть ли разница где мне установить

Yii::app()->config->set('SHOP.DOLLAR_CURS', 30.56);

- вьюшка, модель, контроллер. и.пр.? (для теста)
я добавил во вьюшку, выдается ошибка подкл. файла.

include(Config.php) [function.include]: failed to open stream: No such file or directory 

по идее должен везде подгружать?

'preload'=>array(
    'config'
),

спасибо

Ответить

 

Дмитрий Елисеев

Разницы никакой нет. Всё доступное по Yii::app() работает везде. Ошибка говорит, что Yii не смог найти ActiveRecord класс модели Config. Вы точно её создали?

Ответить

 

Стас

странно.
данные выводит, но переделывая на set и добавляя новые значения, выдает нет файла!
может проблема в модульности?

'components'=>array(
    'config'=>array(
	'class'=>'application.modules.admin.components.DConfig',
    ),
),

хотя, опять же, данные то выводятся!!!

Ответить

 

Дмитрий Елисеев

Добавьте в начале DConfig.php строку импорта модели, например:

<?php
Yii::import('applications.modules.admin.models.Config');
class DConfig extends CApplicationComponent
{ ...
Ответить

 

Стас

не, так не работатет
Yii::import('applications.modules.admin.models.Config');
, я попробовал перед сеттером установить Yii::app()->getModule('admin');
сработало как нужно.
Спасибо за труд, качественные статьи.

Ответить

 

Денис

Статья супер! Впрочем как и все остальные!

Ответить

 

Дмитрий Елисеев

Спасибо!

Ответить

 

Денис

Здравствуйте! Статья отличная, но у меня возник вопрос: А что делать если я хочу хранить в настройках такие данные как host, bdname,bduser,bdpassword,host?

Ответить

 

Дмитрий Елисеев

Интересный вопрос. Тогда Вы никогда не подключитесь к базе данных...

Ответить

 

Денис

Ну да, тупанул. Придётся при установке просить указать эти настройки. Без последующей возможности изменить их не трогая main.php

Ответить

 

Александр

Отличное решение, спасибо! Вечно мучал этот вопрос. Скажите, а как Вы очищаете кэш при сохранении настроек? Или просто используете dependecies?
П.С. у CApplicationComponent в init надо вроде parent::init вызвать.

Ответить

 

Дмитрий Елисеев

Можно очищать весь кэш вручную в админке или, если один запрос не будет лишним, вообще не кэшировать. Либо использовать тэгирование кэша и в actionUpdate сбрасывать кэш только этого компонента по тегу.

Ответить

 

standalone

А можно как-то задать настройки внутри конфига, например:

urlManager => array(
    'urlFormat'=>Yii::app()->config->get('url_type'),
)

?

Ответить

 

Дмитрий Елисеев

Прямо так присвоить значение не получится, так как в index.php конфигурационный файл считывается до запуска приложения. Но можно вписать туда анонимную функцию в качестве обработчика какого-либо события приложения, и уже в ней производить любые операции:

return array( 
    ...
    'onBeginRequest' => function($event){
        Yii::app()->urlManager->urlFormat = Yii::app()->config->get('url_type');
    },
);
Ответить

 

Виталий Воскобович

Статья отличная!
Скажите, а как лучше выводить эти настройки по группам? Допустим, в разных контроллерах.
Общие настройки, Настройки новостей, Настройка рассылки.

Ответить

 

Дмитрий Елисеев

И меня имена всех параметров имеют вид МОДУЛЬ.ПАРАМЕТР, то есть для блога:

Yii::app()->config->get('BLOG.POSTS_PER_PAGE');

Поэтому при сортировке по алфавиту они у меня сгруппировываются сами. Общие параметры можно «обозвать» как GENERAL или MAIN.

Но можно добавить отдельное поле для групп и сортировать по нему:

Yii::app()->config->get('blog', 'posts_per_page');
Ответить

 

Виталий Воскобович

Дмитрий, благодарю за ответ. Но вы наверное меня не правильно поняли.
В текущей версии у вас все настройки выводятся на одной странице. А если у меня 100 надстроек? Тогда скорее всего нужно в модуле настроек сделать несколько контроллеров BlogController, PostController и т.д. чтобы разбить настройки по страницам. Вариантов осуществить это масса. Но меня интересует как бы поступили вы?

Ответить

 

Дмитрий Елисеев

Именно поля для ввода всех параметров на одной странице выводить не обязательно. Меня бы устроил обычный CGridView с разбивкой на страницы с выпадающем списком-фильтром в столбце «Группа».

Ответить

 

Виталий Воскобович

Хм... понятно. Но я вот хочу доработать ваше решение создав в нем возможность редактировать настройки на разных страницах модуля. Но так как я не опытный yiiст, по скорее всего попрошу вас взглянуть на мое решение, если вам будет интересно=)

Ответить

 

Виталий Воскобович

Вот дела... не могу опубликовать код. Вышлю на почту.

Ответить

 

Dmitry Dy
public function get($key) {
        if (isset($this->data[$key])){
            return $this->data[$key];
        } else {
            throw new CException('Undefined parameter '.$key);
        }
    }


У меня в базе value IS NULL, в $this->data['my_param'] = null; Из-за этого метод всегда выбрасывает исключение. Проверять лучше, в т.ч. из-за скорости, через array_key_exists.

ЗЫ: спасибо за модуль

Ответить

 

Дмитрий Елисеев

Спасибо. Заменил.

Ответить

 

Андрей Кузнецов

Добрый день.
Что-то никак сообразить не могу, а как в параметры в БД засунуть список?
вот такой, например:

    'translatedLanguages' => array(
      'kk'=>'Kaz',
      'ru'=>'Rus',
      'en'=>'Eng',
    ),

чтобы при этом не сильно ломать другой код, где это перечисление используется так:

 <?php foreach (Yii::app()->params['translatedLanguages'] as $key=>$lang): ?>

Спасибо.

Ответить

 

Дмитрий Елисеев

Можно сериализовать, например.

Ответить

 

Андрей Кузнецов

да, спасибо.
я про JSON прочитал. Наверно что-то в этом направлении надо делать.
Я сишник много-много лет :), а с PHP и YII всего месяц занимаюсь - жизнь заставила. Поэтому и вопросы возникают. Идеология программирования совершенно другая :)

Ответить

 

Дмитрий Елисеев

Даже без JSON можно. Обычные serialize() и unserialize() подойдут.

Ответить

 

Роман

Не могли бы вы показать пример кода. А то я не совсем понимаю где должен храниться сериализованный массив и его значение.

Ответить

 

Артем – php-zametki.ru

Дмитрий, спасибо огромное за Ваш ресурс. Искренне желаю Вам успехов ибо на мой взгляд Ваш сайт один из полезнейших ресурсов рунета. Особенно радуют статьи по Yii. А еще радует приятный внешний вид, как Ваш, так и сайта в целом.

Ответить

 

Fizigr – web-sun.ru

Здравствуйте, Дмитрий!
Спасибо за интересную статью. Я изучаю Yii и попробовал реализовать обработку настроек Вашим методом. У меня через раз получается ошибка:

PHP notice
MemcachePool::get():
.....yii\framework\caching\CMemCache.php(149) - return $this->_cache->get($key);
Stack Trace
#0	
+  E:\web2\Apache2\htdocs\partner\yii\framework\caching\CMemCache.php(149): MemcachePool->get("e5af7ddc59018a246ebe1205c68be156")
#1	
+  E:\web2\Apache2\htdocs\partner\yii\framework\caching\CCache.php(104): CMemCache->getValue("e5af7ddc59018a246ebe1205c68be156")
#2	
+  E:\web2\Apache2\htdocs\partner\yii\framework\db\CDbCommand.php(494): CCache->get("yii:dbquerymysql:host=localhost;dbname=partner:root:SELECT * FRO...")
#3	
+  E:\web2\Apache2\htdocs\partner\yii\framework\db\CDbCommand.php(396): CDbCommand->queryInternal("fetchAll", array(2), array())
E:\web2\Apache2\htdocs\partner\protected\components\DConfig.php(18): CDbCommand->queryAll()
$items = $db->createCommand('SELECT * FROM {{config}}')->queryAll();

Подскажите, в чем дело?

С уважением.

Ответить

 

Дмитрий Елисеев

А с CFileCache работает?

Ответить

 

Fizigr – web-sun.ru

Да, на нем и остановился.
Какие расширения для Yii порекомендуете посмотреть для новичка, так сказать маст хэв?

Ответить

 

Andrey

Добрый день, подскажите пожалуйста, где красивее или правильнее писать данные строки

Yii::app()->config->get('NEWS_PER_PAGE');
По возможности лучше закешировать чтение из базы в методе init():
$items = Config::model()->cache(3600)->findAll();

И еще вопрос - что такое NEWS_PER_PAGE ? Вроде как подразумевается параметр для постраничной навигации, но в таблице такого имени поля нет, объясните пожалуйста.

Ответить

 

Дмитрий Елисеев

Пишем прямо там, где используются, например:

$dataProvider = new CActiveDataProvider('Post', array(
    'criteria' => $criteria,
    'pagination' => array(
        'pageSize' => Yii::app()->config->get('BLOG_POST_PER_PAGE'),
    ),
));

Закешировать – заменить первую строку в методе init компонента:

public function init() {
    $items = Config::model()->cache(3600)->findAll();
    ...
}

NEWS_PER_PAGE - это просто я так назвал параметры (в поле param).

Ответить

 

студент

Спасибо, Дмитрий, изучаю Yii по урокам на вашем сайте.
Сделал компонент по примеру, но возник вопрос:
Как использовать поле label и type в форме редактирования?
Об этом ничего не сказали.
Можно делать дополнительные запросы из вьюхи, но это по моему костыль.

Ответить

 

Дмитрий Елисеев
<?= CHtml::label($model->label) ?>
Ответить

 

Игорь

Дмитрий вопрос (пришел сюда из Yii2).

1. Обязательно ли создавать поле id. Может ли поле param выступать в роли первичного ключа?
2. Хочу создать еще одну таблицу config_description (config_id, text) для описания настройки, но делать отдельно чтобы не тянуть это во всем приложении, а запрашивать только в админке для помощи в настройке.

Как правильно написать ограничение внешнего ключа для таблицы config_decription? То есть чтобы удалялся или изменялся при изменении param таблицы config?

Ответить

 

Дмитрий Елисеев

1. Можно любое поле. Просто привычка называть id.

2. С поля config_param на param.

Ответить

 

akulenok

А чем плох такой вариант? правда уже на Yii2
В админке сделал модельку настроек и созхраняю их в файл

file_put_contents(
    Yii::getAlias('@app') . '/config/params.php',
    serialize($model->getAttributes())
);

ну и вывожу потом

$params = unserialize(file_get_contents(Yii::getAlias('@app') . '/config/params.php'));
$model = new Settings();
$model->setAttributes($params);

в конфиге приложения $params = unserialize(file_get_contents(__DIR__ . '/params.php'));

Ответить

 

tarik

Классные статьи, автору спасибо.

Ответить

 

Андрей

Как вот эту строку под Yii2 правильно переписать?
$db = Yii::app()->db->cache($this->cache, $this->dependency);

Ответить

 

Дмитрий Елисеев
$config = Yii::$app->db->cache(function () {
    return Config::find()->all();
}, $this->cache, $this->dependency);
Ответить

 

Андрей

Да и как в Yii2 лучше поступить с
$module = Yii::app()->getModule($moduleName);
$module->install();
и так далее?

Ответить

 

Дмитрий Елисеев

Также Yii::$app->getModule($moduleName).

Ответить

 

Андрей

Правильно ли я вообще понял идею.
Через компонент мы можем получить только value или default по имени параметра? Если нам надо остальные поля, как label и так далее, то придётся через модель действовать? Что-то вроде такого
$result = ConfigModel::findOne(['param' => 'SITE.BASE_ADDR']);
$result->label;

Только начал Yii2 изучать, ещё не всё понятно, но фреймворк понравился)))

Ответить

 

Дмитрий Елисеев

Да, остальное через обычный Activerecord.

Ответить

 

Антон

Дмитрий, спасибо за статью!
А можете рассказать как хранить настройки в Symfony?

Ответить

 

Дмитрий Елисеев

Также сделать сервис Config.

Ответить

 

Антон

А если он нужен почти в каждом контроллере и во многих других сервисах - протаскивать его туда через DI?

Ответить

 

Дмитрий Елисеев

Можно сразу доставать из него значения в контейнере:

services:
    App\Controller\Home:
        $param: '@=service("App\\Config").get("param")'
Ответить

 

Антон

Благодарю!

Ответить

Оставить комментарий

Войти | Завести аккаунт | Войти через


(никто не увидит)





Можно использовать теги <p> <ul> <li> <b> <i> <a> <pre>