Вывод Из Бд В Главный Лейаут

Доброго времени суток! Начал изучать Yii и возникла проблема, на всех страницах нужно выводить имя авторизованного юзера. Это нужно как-то вытащить из бд и вставить в layouts/main.php, но я не понимаю, как это сделать.

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

Что касается конкретно авторизованного юзера, то его данные можно на этапе логина сохранять, а потом извлекать через getState (см документацию про авторизацию и аутентификацию) прямо в лейауте. <?= Yii::app()->user->… ?>

Теперь про передачу общесайтовых данных вообще. Вариантов несколько:

  1. Использовать виджеты. Виджет - это такой мини-контроллер, со своей логикой и представлением. Допустим, меню таким образом удобно делать.

  2. Отнаследоваться от некоего промежуточного контроллера, в котором создать переменную для хранения. Заполнять ее в каком-нибудь хуке, beforeRender, например. Примерно так сделан вывод $title в лейауте.

  3. … будет дополнено…

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

Неужели нельзя как-нибудь так:


<span><?php echo $username; ?></span>

а в самом начале лейату построить нужные запросы к бд и поместить все в нужные переменные

Ну я помимо виджетов еще два способа указал.

А что вам мешает сделать метод в модели?

Например берем модель User:




public static function getUsername($id)

{

   $user=User::model()->findByPk($id);

   if ($user!==NULL){

       return $user->name;  

   } else return false;

}



В layout:




<?=User::getUsername(Yii::app()->user->id);?>



Можно так, кажется что это и есть 3й способ.

Несмотря на то, что Yii технически разрешает такие вещи, вызывать модель из вьюхи как-то… ну, не очень.

MVC, там, все дела.

Плюс не сработает в случае использования другого шаблонизатора.

Если нет класса WebUser, нужно его создать в папке components и в нем




Class WebUser extends CWebUser {

    private $_identity;

    public $identityClass;


    public function getIdentity()

    {

        if ($this->id !== null && $this->_identity === null) {

            $this->_identity = CActiveRecord::model($this->identityClass)->findByPk($this->id);

        }

      return $this->_identity;

    }

}



в config/main.php




'components'=>array(

...

        'user' => array(

            'allowAutoLogin' => true,

            'class' => 'WebUser',

            'identityClass' => 'User',//user model

        ),

...

)




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




Yii::app()->user->identity->id // id пользователя

Yii::app()->user->identity->email // email пользователя



и так далее

Насчет шаблонизатора эт я не понял).

Собственно да это плохой способ, действительно лучше всего хранить в identity. Осознал свою ошибку, еще 1 минус +1 запрос к базе на каждой странице.

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




$form->CheckBoxList($model,'modules',CHtml::listData(Modules::model()->findAll(),'id','title')); ?>



По сути мы нарушаем MVC, но ведь так удобно и я думаю многие так делают или все передают массивы из контроллера и я один такой?

Ну, я не уверен, но к Yii вроде можно прикрутить twig и smarty, и из их шаблонов уже до модели не достучаться.

Прошу прощения, если ошибаюсь, я никогда не пытался отойти от дефолтного php-шного движка.

Я из контроллера передаю массив. Тут ведь вот какая штука: для создания выпадающих списков AR-то не нужен, поэтому круто было бы не просто findAll() сделать, а, к примеру, выгрести только два поля (id, name) - ну, чтобы лишние данные не гонять туда-сюда. В идеале - еще и в объект не маппить, а сразу массивом. Поэтому результирующий код может быть несколько громоздким, и его наличие внутри селекта будет сильно давить на мозг.

Вот в Yii2, кстати, есть офигенная штука - asArray(). Устанавливает флажок, выключающий маппинг в объект.

То есть, вот так делать можно например:


Model::find()->select(['id', 'name'])->asArray()->all()

На выходе сразу массив, безо всяких лишних объектов. Прямо PDO, завернутое в удобную форму.

Что же касается нарушений MVC - ну, это тема для отдельного разговора, да. Те же виджеты - это что за фигня вообще? :) HMVC?

Тогда уж кошерней всего добавить метод, который будет возвращать данные для списка, а уж id, name или какие другие поля там используются - не важно :)




Model::listData()



О, кстати да.

На правах оффтопа… Я считаю, что большая часть методов ActiveRecord нужна только для использования внутри класса модели. К ним относятся все find*, кроме find() и findAll(), причём передавать извне критерий в качестве аргумента тоже не следует. Вот тогда будет настоящий MVC :)

Т.е. если нам где-то нужны модели с условием "active = 1", то правильней делать scope либо findActive(). Хотя удобство AR именно в том, что и логика модели, и методы для доступа к БД собраны вместе (и в то же время недостаток).

Ну не, это уже хардкор :)

С теми же скопами по-разному бывает: active не требует параметра, а какой-нибудь last - удобнее, чтобы требовал.

Ну, чтобы не плодить кучу скопов, делающих одно и то же.

Мне, кстати, безумно нравится как в yii2 сделано: сначала собирается ActiveQuery, а AR уже на последнем этапе подключается, и то - по желанию.

В scopes можно передавать параметры, и ->last(5) лучше, чем ->findAll(array(‘limit’=>5))