Обращение к модели из View ? Грех ?
Здесь подразумевается обращение к БД, а это грех и большой. Из представления не должно быть запросов к БД.
Хотя, надо сказать, что Yii 2 не способствует такой чистой архитектуре. Те же виджеты созданы только как некие отрисовщики внутренних представлений, а не независимые полноценные куски кода. Поэтому для превращения в независимые полноценные куски кода с виджетами обычно делают всякие извращения, что приводит к обращению к БД из представления. Вот, например, как это сделано в одном из известных пакетов для Yii 2:
Код: Выделить всё
//controller
public function actionAssignments($id)
{
/** @var User $user */
$user = $this->userQuery->where(['id' => $id])->one();
return $this->render(
'_assignments',
[
'user' => $user,
'params' => Yii::$app->request->post(),
]
);
}
Код: Выделить всё
//view
<?= AssignmentsWidget::widget(['userId' => $user->id, 'params' => $params]) ?>
Код: Выделить всё
//widget view
<?php $form = ActiveForm::begin(
[
'enableClientValidation' => false,
'enableAjaxValidation' => false,
]
) ?>
<?= Html::activeHiddenInput($model, 'user_id') ?>
<?= $form->field($model, 'items')->widget(
SelectizeDropDownList::class,
[
'items' => $availableItems,
'options' => [
'id' => 'children',
'multiple' => true,
],
]
) ?>
Код: Выделить всё
//widget
public function run()
{
$model = $this->make(Assignment::class, [], ['user_id' => $this->userId]);
if ($model->load($this->params)) {
$this->make(UpdateAuthAssignmentsService::class, [$model])->run();
}
return $this->render(
'/widgets/assignments/form',
[
'model' => $model,
'form' => $this->form,
'availableItems' => $this->getAvailableItems(),
]
);
}
Как видите, здесь контроллер просто передает POST-запрос обратно в представление, где он передается параметром в виджет и уже виджет производит операции с моделью/БД и потом отрисовывает результат, что приводит к обращениям у БД из представления. Чтобы не заниматься такими извращениями, лучше сделать свой класс Widget, где создания/запуск и рендеринг будут разделены. Тогда мы можем конфигурировать виджеты в контроллере и выполнять их, рендерить уже в представлении. Выглядеть это будет примерно так:
Код: Выделить всё
public function actionIndex()
{
$widgetManager = new WidgetManager();
$widgetManager->addWidget(MyFirstWidget::class, [
'class' => MyFirstWidget::class,
//... config
])->addWidget('second-widget-alias', [
'class' => MySecondWidget::class,
//... config
])->addWidget(MyThirdWidget::class, [
'class' => MyThirdWidget::class,
//... config
], 'top')->build()->run(['request' => Yii::$app->getRequest(), 'user' => Yii::$app->getUser()]);
$widgets = $widgetManager->getWidgets();
$topWidgets = $widgetManager->getWidgets('top');
return $this->render('index', [
'widgets' => $widgets,
'topWidgets' => $topWidgets
]);
}
Выводим в представлении
Код: Выделить всё
//отдетные виджеты
$widgets->render('second-widget-alias');
$widgets->render(MyFirstWidget::class);
//группу виджетов
$widgets->getGroup('top')->renderAll();
//тоже самое другим способом
$topWidgets->renderAll();
Также можно хранит конфиг виджетов в файле
Код: Выделить всё
public function actionIndex()
{
$widgetManager = new WidgetManager();
$widgetManager->loadFromFile('my-file.php')->build()->run(['request' => Yii::$app->getRequest(), 'user' => Yii::$app->getUser()]);
$widgets = $widgetManager->getWidgets();
$topWidgets = $widgetManager->getWidgets('top');
return $this->render('index', [
'widgets' => $widgets,
'topWidgets' => $topWidgets
]);
}
или в базе данных (полезно, когда виджеты настраиваются в админке)
Код: Выделить всё
public function actionIndex()
{
$widgetManager = new WidgetManager();
$widgetManager->loadFromDb('post/index')->build()->run(['request' => Yii::$app->getRequest(), 'user' => Yii::$app->getUser()]);
$widgets = $widgetManager->getWidgets();
$topWidgets = $widgetManager->getWidgets('top');
return $this->render('index', [
'widgets' => $widgets,
'topWidgets' => $topWidgets
]);
}