yii2 sorting in related model - php

have relation
model Shop.php
public function getShopAddr()
{
return $this->hasOne(SprShopAddr::className(), ['id' => 'shop_addr_id']);
}
model SprShopAddr.php
public function getDivision()
{
return $this->hasOne(SprDivision::className(), ['id' => 'division_id']);
}
model SprDivision.php
public function getShopAddrs()
{
return $this->hasMany(SprShopAddr::className(), ['division_id' => 'id']);
}
view index.php
<?= GridView::widget([
'dataProvider' => $dataProvider,
//'filterModel' => $searchModel,
'summary' =>false,
'columns' => [
'location_code',
[
'label' => 'Дивизион',
'attribute' => 'division_id',
'value' => 'shopAddr.division.division'
],
['class' => 'yii\grid\ActionColumn', 'template' => '{update}{delete}'],
]
]); ?>
sort on gridview for field shopAddr.division.division not working. How to fix it?

for related model you must configure properly the setSort function of the dataProvider
You can find the right information in this tutorial.
The most important part is that you must define the $dataProvider->setSor(...) function in yourModelSearch like this
$dataProvider->setSort([
'attributes' => [
'yuorRelatedFieldName' => [
'asc' => [ $tableRelated . '.yourField' => SORT_ASC ],
'desc' => [ $tableRelated . '.yourField' => SORT_DESC ],
'label' => 'yuorLabel'
],
],
'defaultOrder' => ['yuorDefaultOrderField' => SORT_ASC],
]);

Related

Yii2: display some records at the top of GridView widget

In Yii2 app I have model Document which can belong to user. Belonging is set with owner_id field.
In view I display list of Documents using GridView widget. Default sort is by document_id.
Every user sees all documents (event if specific document doesn't belong to him).
But I need to display documents which belongs to current logged in user at the top of GridView. How can I do this?
I suppose I should make some changes to Document::search() method by can't find out what excactly I should do.
Here is my controller action:
public function actionIndex()
{
$modelFullName = $this->modelFullName;
$model = new $modelFullName();
$dataProvider = $model->search(Yii::$app->request->queryParams);
return $this->render(
'index',
[
'model' => $model,
'dataProvider' => $dataProvider,
]
);
}
Part of view:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $model,
'columns' => [
[
'attribute' => 'document_id',
],
[
'attribute' => 'status',
'format' => 'raw',
'value' => function($model) {
return $model->statusString;
},
],
[
'attribute' => 'title',
],
[
'attribute' => 'date_created'
],
[
'attribute' => 'client_id',
'value' => function($model) {
return $model->client ? $model->client->title : '';
},
'filter' => ArrayHelper::map(Clients::find()->all(), 'client_id', 'title')
],
[
'attribute' => 'project_id',
'value' => function($model) {
return $model->project ? $model->project->title : '';
},
'filter' => ArrayHelper::map(Projects::find()->all(), 'project_id', 'title')
],
[
'class' => yii\grid\ActionColumn::className(),
'template' => '{view} {delete}',
'buttons' => [
'view' => function ($url, $model) {
return $this->context->getBtn('view', $model);
},
'delete' => function ($url, $model) {
if (Yii::$app->user->can('deletePrsSum')) {
return $this->context->getBtn('delete', $model);
}
},
],
'visibleButtons' => [
'update' => Yii::$app->user->can('updateDocument'),
'delete' => Yii::$app->user->can('deleteDocument'),
]
],
],
]);
Current Document::search() implementation:
public function search($params)
{
$query = self::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => ['document_id' => SORT_ASC]
]
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
if ($this->client_id) {
$query->andFilterWhere([
'client_id' => $this->client_id,
]);
}
if ($this->project_id) {
$query->andFilterWhere([
'project_id' => $this->project_id,
]);
}
return $dataProvider;
}
UPDATE
So how I managed to do this:
public function search($params)
{
$userId = Yii::$app->user->identity->user_id;
$query = self::find()->select(
"*, IF(owner_id={$userId},(0),(1)) as sort_order"
)->orderBy([
'sort_order' => SORT_ASC,
'document_id' => SORT_ASC
]);
//further code...
Add a filter in your search function to filter with the id of the logged in person/user:
$query->andFilterWhere(['owner_id' => Yii::$app->user->identity->id]);

kartik\Select2 as filter input in yii2\grid

I've encountered another dummy problem with my Yii2 project. I've got a standard gridView in my view, defined liek this:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'layout' => '{items}{summary}',
'columns' => [
[
'class' => 'yii\grid\SerialColumn',
'contentOptions' => [
'style' => 'vertical-align: middle;'
]
],
[
'attribute' => 'name',
],
[
'attribute' => 'type',
'value' => function($model){
/* #var $model app\models\Object */
return $model->typeNames()[$model->type];
},
'filter' => Select2::widget([
'name' => 'ObjectSearch[type]',
'data' => Object::typeNames(),
'theme' => Select2::THEME_BOOTSTRAP,
'hideSearch' => true,
'options' => [
'placeholder' => 'Wybierz typ obiektu...',
'value' => isset($_GET['ObjectSearch[type]']) ? $_GET['ObjectSearch[type]'] : null
]
]),
],
[
'attribute' => 'countryId',
'value' => 'country.name',
'filter' => Select2::widget([
'name' => 'ObjectSearch[countryId]',
'data' => Country::forWidgets(),
'theme' => Select2::THEME_BOOTSTRAP,
'options' => [
'placeholder' => 'Wybierz państwo...'
]
]),
],
//other columns
],
]); ?>
I've defined a searchModel class:
class ObjectSearch extends Object
{
public function rules()
{
return [
[['type'], 'integer'],
[['name', 'city', 'countryId'], 'string']
];
}
//some other functions
public function search($params)
{
$query = Object::find()->where(['userId' => Yii::$app->user->id]);
$query->joinWith('country');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['countryId'] = [
'asc' => ['countries.name' => 'ASC'],
'desc' => ['countries.name' => 'DESC']
];
if (!$this->load($params) && $this->validate()) {
return $dataProvider;
}
$query->andFilterWhere(['like', 'objects.name', $this->name])
->andFilterWhere(['like', 'city', $this->city])
->andFilterWhere(['=', 'objects.countryId', $this->countryId])
->andFilterWhere(['=', 'type', $this->type]);
return $dataProvider;
}
}
Sorting and searching works fine - I've got correct results. So what's my problem? For standard columns when I type some text in textInput the value of this input stays in it after search. But when I choose some value in Select2 widget search work, but after search the selected value disappear and I've got just a placeholder.
Thanks for your help,
Kamil
You should simply use initValueText param :
initValueText: string, the text to displayed in Select2 widget for the initial value.
e.g. :
Select2::widget([
'name' => 'ObjectSearch[type]',
'data' => Object::typeNames(),
'initValueText' => $searchModel->type,
// ... other params
])
You could also use it as an InputWidget :
Select2::widget([
'model' => $searchModel,
'attribute' => 'type',
'data' => Object::typeNames(),
// ... other params
])

Sort by related model attributes in GridView Yii Framework 2.0

I have Post model and two related models, User and Comments.
Relation with User and Comment model defined in Post model:
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getUserName()
{
return $this->user->name;
}
public function getComments(){
return $this->hasMany(Comment::className(), ['comment_id' => 'id']);;
}
public function countCommentPoints() {
return $this->hasMany(Comment::className(), ['comment_id' => 'id'])->sum('point');
}
My PostSearch model looks like following. I omitted the code andFilterWhere() because it is out of the scope:
class PostSearch extends Post {
public $userName;
public function rules()
{
return ['userName', 'safe'];
}
public function search($params) {
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->setSort([
'attributes' => [
'userName' => [
'asc' => ['user.name' => SORT_ASC],
'desc' => ['user.name' => SORT_DESC],
],
],
]);
if (!($this->load($params) && $this->validate())) {
$query->joinWith(['user']);
return $dataProvider;
}
}
return $dataProvider;
}
View code:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'title',
[
'attribute' => 'userName',
'value' => 'userName',
'label' => 'User Name'
],
[
'attribute' => 'comment',
'value' => function($model){
return $model->countCommentPoints();
},
'label' => 'Points',
],
],
]);
With all the code above I could sort the records by id and title and by userName which is an attribute of the related User model. But I could not sort by the column Points since it is not an attribute of the Comment model but a sum value returned from the getLeadEarningPerWebmaster() method. I have tried to read Yii 2.0 documentation here http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html but the section Sorting Data is still under development. How can I make GridView sort by the Points column?
You can sort GridView columns by related columns that are not necessarily inside the original ActiveRecord.
echo GridView::widget([
'dataProvider' => new ActiveDataProvider([
'query' => $model->joinWith([
'comment' => function ($query) {
$query->select('SUM(point) AS sum')->from(['comment' => '{{%comment}}']);
}
]),
'sort' => [
'attributes' => [
'comment.sum' => [
'asc' => ['comment.sum' => SORT_ASC],
'desc' => ['comment.sum' => SORT_DESC],
]
],
'sortParam' => 'post-sort',
'defaultOrder' => ['comment.sum' => SORT_ASC]
],
]),
That should get you started.

How can I show two attributes values in one column through relation in Yii 2 GridView

i have Gridview in index i want to show width and height both in one column how can i do it
here is the view code
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'fld_id',
'fld_name',
[
'label' => 'Material Name',
'attribute' => 'fld_material_id',
'value' => 'fldMaterial.fld_name',
],
[
'label' => 'Size',
'attribute' => 'fld_size_id',
'value' => 'fldSize.fld_width',
],
// 'fld_size_id',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
i have relation fldSize in model here it is just only displaying fld_width i want to show it in the format fld_width."x".fld_height how can i do it in Yii2
You should simply use value callback, e.g. :
[
'label' => 'Size',
'attribute' => 'fld_size_id',
'value' => function ($model) {
return $model->fldSize->fld_width . 'x' . $model->fldSize->fld_height;
},
],
Sorry that after more than one year, but it works (not a dropdown but Select2).
Here is the code for the form
<?= $form->field($model, 'ID_MACH')->widget(Select2::classname(), [
'data'=> ArrayHelper::map(Maschines::find()->all(),'ID_MACH','fullname'),
'language'=>'ru',
'theme'=>'krajee',
'options'=>['placeholders'=>'suda...',
'prompt'=>'10-'],
'pluginOptions'=>[
'allowclear'=>true
],
Next is the Model for Mashines:
public function getFullName()
{
return $this->customer.','.$this->Manufacturer.','.$this->type.','.$this->serial;}

How do I pass a array as a param for a Yii2 gridview column

I am trying to pass $arr_judete_v2 as a param to a callback function in a gridview and it does not work;
$model['county_id'] returns a number
$arr_judete_v2[1]['nume'] returns a name
my issue:
[
'attribute' => 'county_id',
'label' => Yii::t('diverse', 'Judet'),
'content' => function($model, $arr_judete_v2) {
return $arr_judete_v2[$model['county_id']]['nume'];
},
],
the entire gridview
<?php
echo GridView::widget([
'layout' => "{items}",
'dataProvider' => $dataProvider,
'columns' => [
'id',
[
'attribute' => 'nume',
'label' => Yii::t('companie', 'nume'),
],
'cui',
'email',
[
'attribute' => 'county_id',
'label' => Yii::t('diverse', 'Judet'),
'content' => function($model, $arr_judete_v2) {
return $arr_judete_v2[$model['county_id']]['nume'];
},
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}',
'buttons' => [
'update' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', ['update', 'id' => $model['id']], [
'title' => Yii::t('yii', 'Update'),
'data-pjax' => '0',
]);
}
]
],
],
]);
From the source code for \Yii\grid\Column
#var callable This is a callable that will be used to generated the content of each cell.
The signature of the function should be the following: function ($model, $key, $index, $column)
As Mihai has correctly pointed out you can use use() to include variables into the function's scope as follows:
"content" => function($model, $key, $index, $column) use ($arr_judete_v2) {
return $arr_judete_v2[$model['county_id']]['nume'];
}
Please note that the variables are copied into the function and as such any changes will not affect the variable outside of the function. A better explanation of this is given in this answer.
Use use (), see how the function is defined for the value of the column.
$invoice_status_data = array('' => 'Select a status') + ArrayHelper::map(InvoiceStatus::find()->asArray()->all(), 'id', 'name');
........................
'columns' => [
........................
[
'attribute'=>'Contact.name',
'format'=>'raw',
'value'=>function ($model, $key, $index, $widget) use ($invoice_status_data) {
.............................
$content .=
Html::dropDownList('dropdown'. $model->id, '', $invoice_status_data, [
'class' => 'form-control',
'onchange' => 'javascript: myInvoice.change($(this));',
'data-href' => Url::toRoute(['invoice/change-status', "Invoice_id"=>$model->id])]);
return $content;
},
],

Categories