Yii фреймворк: установка дефолтных параметров для виджетов

Владимир | | PHP, Web разработка, Yii.

yii widget parameters

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

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

Например, у нас есть файлы.
protected/components/MyWidget.php – класс виджета
и
protected/components/views/myWidget.php – представление.

Класс виджета может выглядеть примерно так.

class MyWidget extends CWidget {

	public function run() {
		$this->render('myWidget');
	}
}

А в представлении можно записать что-то вроде

<h1>Привет!</h1>

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

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

При этом, передавать их в представление удобнее всего если они сохранены в виде ассоциативного массива, т.к. метод render принимает во втором параметре именно массив.

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

Т.е. код выглядит приблизительно так

class MyWidget extends CWidget {
	public $params = array(
		'parameter 1'=>'value 1',
		'parameter 2'=>'value 2',
		'parameter 3'=>'value 3',
	);

	public function run() {
		$this->render('myWidget', $this->params);
	}
}

Теперь взгляните на код вставки виджета на страницу.

$this->widget('application.components.MyWidget');

Тут все отлично, но что если мы захотим изменить 'parameter 3'? Во втором параметре метода widget мы можем передать наши значения.

$this->widget('application.components.MyWidget', array(
	'params'=>array(
		'parameter 3'=>'new value 3',
	);
));

Но такой вызов перезапишет весь массив $params, т.е. 'parameter 1' и 'parameter 2' будут стерты.

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

Лучше решить проблему так.

1) Делаем массив $params приватным.

private $params = array(
...
);

2) Добавляем метод setParams в класс виджета (название образуется с из названия атрибута класса, значение которого нужно установить (в данном случае Params), и приставки set). Этот метод в первом параметре получит новое значение атрибута. В этом примере – массив с измененным параметром. Нам остается только объединить массивы.

public function setParams($params) {
	$this->params = array_merge($this->params, $params);
}

Этот же прием можно использовать для проверки параметров или их предварительной обработки.

Если есть замечания или вопросы, пишите, постараюсь ответить 😉

Удачи!

Интересно почитать

Предлагаем авоськи оптом из любых органических тканей

  • BuCeFaL

    Насколько я понял, это возможно потому что CWidget наследует CComponent, а у того есть «сетеры и гетеры».

    http://yiiframework.ru/doc/cookbook/ru/core.getters.setters

    • Гость

      2BuCeFaL
      не может быть такого 🙂

      • BuCeFaL

        Кэп залогинился под моим профилем и запостил то.

        • Гость

          Мне кажется, что автор топика знает, что такое гетТеры и сетТеры, раз уж он их использовал. возможно, я ошибаюсь.

    • Насчет геттеров и сеттеров все правильно. Особенность заключается в использовании области видимости атрибута для того, чтобы гарантировать вызов сеттера.Все очевидно, если устанавливать атрибуты напрямую, но в данном случае запись выполняет метод CWidgetFactory->createWidget.CMap::mergeArray() удобно использовать если нужно объединять многомерные массивы, т.к. она рекурсивная. В данном случае, в этом необходимости не было, к тому же native функции работают быстрее.

      • Интересно, чем CMap::mergeArray отличается от native php функций array_merge_recursive/array_merge?
        Судя по тому, что CMap::mergeArray не тупо вызывает внутри себя array_merge_recursive, смысл видимо есть…

        • Посмотрел код к CMap::mergeArray и описание к array_merge_recursive. По-моему, работают одинаково.

  • Насчет геттеров и сеттеров все правильно. Особенность заключается в использовании области видимости атрибута для того, чтобы гарантировать вызов сеттера.

    Все очевидно, если устанавливать атрибуты напрямую, но в данном случае запись выполняет метод CWidgetFactory->createWidget.

    CMap::mergeArray() удобно использовать если нужно объединять многомерные массивы, т.к. она рекурсивная. В данном случае, в этом необходимости не было, к тому же native функции работают быстрее.

  • SpiLLeR

    Я бы в сеттер добавил опцию, по которой можно не мержить массивы, а просто применить, который передали.

    • Чтобы сбросить не указанные параметры?

      • SpiLLeR

        Да, чтобы можно было передать полный конфиг файл и не надо было обнулять не нужные атрибуты.

        • Код будет примерно такой

          public function setParams($params) {
          if (isset($params['updateAll']) && $params['updateAll'] === true) {
          $this->params = $params;
          } else {
          $this->params = array_merge($this->params, $params);
          }
          }

        • SpiLLeR

          Я бы сделал public function setParams($params, $updateAll='false') {…}, но это скорее вкусовшина.

      • Yirwert

        23342634623642

  • Очень не хватает поддержки тем (themes) в Yii виджетах

    • Можно сделать несколько представлений для виджета и передавать нужное в параметре.

  • Спасибо за статью.
    Хоть я гуглил и другое, и суть статьи гласит не о том, что я искал, но она мне помогла решить мою проблему)

  • Pasechnikbs

    Мне кажется проще сделать так
    $this->widget('application.components.MyWidget', array(
    'parameter_1'=>'value 1',
    'parameter_2'=>'value 2',
    'parameter_3'=>'new value 3',
    ));
    Использовать так $this->parameter_1 и т.д.
    Параметры которым мы не хотим давать разрешение на переопределение просто сделать private. Да и использование в коде проще..

    • Тоже вариант. Но в моем случае значения параметров передавались в виде массива, поэтому удобнее было использовать array_merge, чем устанавливать каждый параметр отдельно.

  • Pasechnikbs

    Мне кажется проще сделать так
    $this->widget('application.components.MyWidget', array(
    'parameter_1'=>'value 1',
    'parameter_2'=>'value 2',
    'parameter_3'=>'new value 3',
    ));
    Использовать так $this->parameter_1 и т.д.
    Параметры которым мы не хотим давать разрешение на переопределение просто сделать private. Да и использование в коде проще..

  • Pasechnikbs

    Мне кажется проще сделать так
    $this->widget('application.components.MyWidget', array(
    'parameter_1'=>'value 1',
    'parameter_2'=>'value 2',
    'parameter_3'=>'new value 3',
    ));
    Использовать так $this->parameter_1 и т.д.
    Параметры которым мы не хотим давать разрешение на переопределение просто сделать private. Да и использование в коде проще..