Skip to content

Instantly share code, notes, and snippets.

@vhood
Last active May 31, 2023 10:38
Show Gist options
  • Save vhood/b867846db9216f2491999fde91ee3d8b to your computer and use it in GitHub Desktop.
Save vhood/b867846db9216f2491999fde91ee3d8b to your computer and use it in GitHub Desktop.
Yii2 without SearchModel example

Yii2 without SearchModel

This is an architecture example how to create Yii2 a typical page with widgets and a DataProvider.

Popular solution

An action should handle query params, provide a DataProvider and a SerachModel dependent on those params, and return a page.

A typical solition is creating a SearchModel with properties, validation rules and the search() method wich should return the DataProviderInterface.

Better solution

Delegate a DataProvider creating to a factory and provide query params as an argument for the factory method.

Create a model from yii\base\model to work with filters.

<?php
class ArticlesController extends Controller
{
private ArticlesFilterForm $form;
private ArticlesFactory $factory;
/**
* @param string $id
* @param Module $module
* @param array $config
* @param ArticlesFilterForm $form
* @param ArticlesFactory $factory
* @return void
*/
public function __construct(
$id,
$module,
$config = [],
ArticlesFilterForm $form,
ArticlesFactory $factory
) {
parent::__construct($id, $module, $config);
$this->form = $form;
$this->factory = $factory;
}
/**
* @return string
*/
public function actionIndex()
{
$formModel = $this->form;
$params = Yii::$app->request->queryParams;
$dataProvider = $formModel->load($params) && $formModel->validate()
? $this->factory->createArticlesDataProvider($params[$formModel->formName()])
: null;
return $this->render('@view/articles/index', compact('formModel', 'dataProvider'));
}
}
<?php
class ArticlesFactory
{
/**
* @param array $params
* @return DataProviderInterface
*/
public function createArticlesDataProvider(array $params): DataProviderInterface
{
$query = (new Query)
->select(['a.title', 'u.name', 'a.created_at'])
->from(['a' => Articles::tableName()])
->innerJoin(['u' => User::tableName()], 'a.author_id = u.id')
->where(['a.isDeleted' => 0]);
if (isset($params['createdAt'])) {
$query->andWhere(['DATE_FORMAT(created_at, "%d.%m.%Y")' => $params['createdAt']]);
}
return new ActiveDataProvider([
'query' => $query,
'sort' => ['attributes' => ['created_at']]
]);
}
}
<?php
class ArticlesFilterForm extends Model
{
public $createdAt;
public $authorId;
public $authorName;
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['createdAt'], 'required'],
[['createdAt'], 'date', 'format' => 'd.m.Y'],
[['authorId'], 'integer'],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'createdMinDate' => Yii::t('articles', 'Created at'),
'authorId' => Yii::t('articles', 'Author'),
];
}
/**
* {@inheritdoc}
*/
public function load($data, $formName = null)
{
$result = parent::load($data, $formName);
if ($this->authorId) {
$author = ArticleRepository::findAuthorById($this->authorId);
$this->authorName = $author->name;
}
return $result;
}
}
<?php $activeForm = ActiveForm::begin([
'id' => 'articles-filter-form',
'action' => Url::to(['articles/index']),
'method' => 'get'
]) ?>
<?= Html::tag(
'div',
Html::tag('label', Yii::t('articles', 'Created at')) .
DatePicker::widget([
'type' => DatePicker::TYPE_INPUT,
'form' => $form,
'model' => $formModel,
'attribute' => 'createdAt',
'options' => [
'value' => $formModel->createdAt ?: date('01.m.Y')
],
'pluginOptions' => [
'format' => 'dd.mm.yyyy',,
'todayHighlight' => true,
'endDate' => date('d.m.Y')
],
]),
['class' => 'form-group']
)
?>
<?= $activeForm
->field($formModel, 'authorId')
->widget(Select2::class, [
'data' => [$formModel->authorId => $formModel->authorName],
'addon' => [
'prepend' => ['content' => $formModel->getAttributeLabel('authorId')]
],
'pluginOptions' => [
'allowClear' => true,
'placeholder' => '',
'ajax' => [
'url' => Url::toRoute(['/api/users']),
'dataType' => 'json',
'processResults' => new JsExpression('(response) => response.data')
],
],
])
->label(false)
?>
<div class="mt-5">
<?= Html::submitButton(Yii::t('global', 'Apply'), [
'class' => 'btn btn-primary',
]) ?>
</div>
<?php $activeForm->end() ?>
<div>
<div class="panel panel-default text-secondary">
<h1 class='panel-title h2 mb-4'>
<?= $this->title ?>
</h1>
<div class='panel-body'>
<?= Accordion::widget([
'options' => ['class' => 'mb-4'],
'itemToggleOptions' => ['class' => 'btn-block'],
'items' => [
[
'label' => Yii::t('global', 'Filter'),
'content' => $this->render('form', compact('formModel')),
],
],
]); ?>
<?php Pjax::begin(['timeout' => 0]) ?>
<?php if ($dataProvider) : ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'condensed' => true,
'resizableColumns' => true,
'columns' => [
[
'attribute' => 'name',
'label' => Yii::t('articles', 'Author'),
],
[
'attribute' => 'title',
'label' => Yii::t('articles', 'Title'),
],
[
'attribute' => 'created_at',
'label' => Yii::t('articles', 'Created at'),
'format' => ['datetime', 'php:d.m.Y'],
],
]
]) ?>
<?php endif; ?>
<?php Pjax::end() ?>
</div>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment