Yii2 Grid view syntax to access data from related model - php

for example I can retrieve the data in the view with this command:
<?=$model->instructor->manager->location['location_title']?>
I have a relation defined in Instructor model like:
/**
* #return mixed
*/
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
/**
* #return mixed
*/
public function getManager()
{
return $this->hasOne(Manager::className(), ['user_id' => 'manager_id']);
}
and in Manager Model relations are defined like this:
/**
* #return mixed
*/
public function getLocation()
{
return $this->hasOne(Location::className(), ['id' => 'location_id']);
}
/**
* #return mixed
*/
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
Now How I can retrieve the same data in grid-view as also add filter for the same.
Thanks.
update: Gridview Code
echo GridView::widget(
[
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
//'id',
'first_name',
'last_name',
// 'username',
// 'auth_key',
// 'password_hash',
// 'password_reset_token',
'email:email',
// 'phone',
//'user_role',
['attribute' => 'created_at', 'label' => 'Last Login', 'value' => function ($data) {
return $data->getLast($data);
},
'contentOptions' => ['style' => 'width:100px']
],
['attribute' => 'created_at', 'label' => 'Create Date', 'contentOptions' => ['style' => 'width:100px'], 'value' => function ($data) {return date('M d, Y', $data->created_at);}
],
// 'updated_at',
['attribute' => 'status', 'value' => function ($data) {
return $data->getStatus($data);
},
'filter' => ['10' => 'Active', '0' => 'Deactive'],
'contentOptions' => function ($data) {
$clr = $data->status == 10 ? 'green' : 'red';
return ['style' => 'width:80px;font-weight:bold;color:' . $clr];
}
]
]
]
);
Update-1
public function actionInstructor()
{
$cond = "user_role='instructor' ";
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams, $cond);
return $this->render(
'instructor', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider
]
);
}
update-2
public function getInstructor()
{
return $this->hasOne(Instructor::className(), ['user_id' => 'id']);
}

You can specify relations either as a string of relation names concatenated with . like below. Make sure you have the relations defined in the respective models the below is for the $dataProvider from the UserSearch model and your User Model should have the relation getInstructor() defined
[
'intructor.manager.location.location_title'
]
or
[
'label' => 'Manager Location',
'value' => function($model){
return $model->instructor->manager->location->location_title;
}
]
if I have the $dataProvider for the UserSearch model below should be the gridview code.
<?=GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
//'id',
'first_name',
'last_name',
[
'label'=>'Manager Location'
'attribute'=>'manager_id'.
'value'=>function($model){
return $model->instructor->manager->location->location_title;
}
]
// 'username',
// 'auth_key',
// 'password_hash',
// 'password_reset_token',
'email:email',
// 'phone',
//'user_role',
['attribute' => 'created_at', 'label' => 'Last Login', 'value' => function ($data) {
return $data->getLast($data);
},
'contentOptions' => ['style' => 'width:100px'],
],
['attribute' => 'created_at', 'label' => 'Create Date', 'contentOptions' => ['style' => 'width:100px'], 'value' => function ($data) {return date('M d, Y', $data->created_at);}],
// 'updated_at',
['attribute' => 'status', 'value' => function ($data) {
return $data->getStatus($data);
},
'filter' => ['10' => 'Active', '0' => 'Deactive'],
'contentOptions' => function ($data) {
$clr = $data->status == 10 ? 'green' : 'red';
return ['style' => 'width:80px;font-weight:bold;color:' . $clr];
},
],

Related

GridView filter model in Yii2

I have a gridview with a dataprovider which has joined two tables as query:
$applicationDataProvider = new ActiveDataProvider([
'query' => Application::find()->with('applicantInfo')
->where(['job_posting_id' => $jobPosting->id,
'deleted_flag' => 0])->orderBy('created_at desc'),
'pagination' => [
'pageSize' => 5
]
]);
and here is my GridView:
<?= GridView::widget([
'dataProvider' => $applicationDataProvider,
'filterModel'=>$searchModel,
'columns' => [
'id',
[
'class' => yii\grid\DataColumn::className(),
'headerOptions' => ['style' => 'color:#337ab7'],
'header' => 'სახელი',
'label'=>'name',
'value' => function ($data) {
return $data->applicantInfo->first_name . ' ' . $data->applicantInfo->last_name;
}
],
'applicantInfo.email',
'applicantInfo.phone',
'created_at:date',
[
'class' => 'yii\grid\ActionColumn',
'headerOptions' => ['style' => 'color:#337ab7'],
'template' => '{view}',
'buttons' => [
'view' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, [
'title' => Yii::t('app', 'გახსნა'),
]);
}
],
'urlCreator' => function ($action, $model, $key, $index) {
if ($action === 'view') {
$url = '/app-info/?id=' . $model->id;
return $url;
}
}
...
in a search model I have email field only because I want to gridview has just only email search field.
class ApplicationSearch extends Application
{
public function rules()
{
return [
[['email'], 'safe'],
];
}
but here is not drawn search field for email, how can I fix it?
You need to add email attribute to ApplicationSearch to store value from filter:
class ApplicationSearch extends Application {
public $email;
public function rules() {
return [
[['email'], 'safe'],
];
}
}
Use this attribute for filtering:
$applicationDataProvider = new ActiveDataProvider([
'query' => Application::find()->with('applicantInfo')
->where(['job_posting_id' => $jobPosting->id, 'deleted_flag' => 0])
->andFilterWhere(['like', 'applicantInfo.email', $this->email])
->orderBy('created_at desc'),
'pagination' => [
'pageSize' => 5
]
]);
And use value from relation in grid:
// ...
[
'attribute' => 'email',
'value' => function ($data) {
return $data->applicantInfo->email;
},
],
'applicantInfo.phone',
// ...

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]);

GridView search filters don't appear Yii2

I've created GridView widget in my view with following params:
<?= GridView::widget([
'dataProvider' => $provider,
'filterModel' => $searchModel,
'summary' => '<br>',
'showOnEmpty' => false,
'columns' => [
[
'attribute' => 'name',
'value' => function ($model) {
return substr($model->name, 0, 50);
},
],
[
'label' => "Ім'я користувача",
'attribute' => "user.name",
'value' => function ($model) {
return substr($model->user->name, 0, 50);
},
],
[
'label' => 'Назва предмету',
'attribute' => "subjects.name",
'value' => function ($model) {
return substr($model->subjects->name, 0, 50);
},
],
[
'class' => 'yii\grid\ActionColumn',
'template' => '{view} {delete}'
]
],
]) ?>
My controller has such code:
$searchModel = new DocumentsSearch();
$provider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'provider' => $provider,
'searchModel' => $searchModel
]);
Also I'm using DocumentSearch model that has following description:
class DocumentsSearch extends Documents
{
public $username;
public $subject_name;
public function rules()
{
return [
[['username', 'subject_name'], 'safe']
];
}
public function search($params)
{
$query = Documents::find()
->joinWith(['user', 'subjects']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pagesize' => 30,
],
]);
$dataProvider->sort->attributes['user.name'] = [
'asc' => ['user.name' => SORT_ASC],
'desc' => ['user.name' => SORT_DESC],
];
$dataProvider->sort->attributes['subjects.name'] = [
'asc' => ['subjects.name' => SORT_ASC],
'desc' => ['subjects.name' => SORT_DESC],
];
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andWhere('user.name LIKE "%' . $this->name . '%" ');
$query->andWhere('user.name LIKE "%' . $this->username . '%" ');
$query->andWhere('subjects.name LIKE "%' . $this->subject_name . '%" ');
return $dataProvider;
}
}
DocumentSearch extends Document model. And I've next relations:
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'owner_id']);
}
public function getSubjects()
{
return $this->hasOne(Subjects::className(), ['id' => 'subject_id']);
}
All these things give me next result:
Before asking I've tried to create inputs by myself using filter param for each column like 'filter'=>Html::input('text','DocumentSearch[subjects.name]')
It triggers JS to send the request but if (!($this->load($params) && $this->validate())) method obvious returns false.
Try using the correspondenting name in rules
[
'label' => "Ім'я користувача",
'attribute' => "username",
'value' => function ($model) {
return substr($model->user->name, 0, 50);
},
],
[
'label' => 'Назва предмету',
'attribute' => "subject_name",
'value' => function ($model) {
return substr($model->subjects->name, 0, 50);
},
],
see this guide http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html#filtering-data
// only fields in rules() are searchable
Or you must extend you search model for calculated or related field adding eventually the proper value in rules

Yii2 ActiveDataProvider sort using count in relational

Yii2 ActiveDataProvider sort using count in relational ?
I've 3 tables, bellow :
And I displaying data from table inventory_device_type, here is the code :
Controller :
<?php
namespace app\controllers\inventory;
use Yii;
use yii\base\Action;
use app\models\tables\InventoryDeviceType;
class DeviceInventory extends Action
{
public function run()
{
$model = new InventoryDeviceType();
$dataProvider = $model->search(Yii::$app->request->post());
return $this->controller->render('device-inventory',[
'dataProvider' => $dataProvider,
]);
}
}
Model :
<?php
namespace app\models\tables;
use yii\db\ActiveRecord;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;
class InventoryDeviceType extends ActiveRecord
{
public static function tableName()
{
return 'inventory_device_type';
}
public function rules()
{
return [
[['name','id_device_vendor'],'required'],
['name','unique']
];
}
public function attributeLabels()
{
return [
'id_device_vendor' => 'Device Vendor',
];
}
/** queries **/
public function findData($id)
{
if(($data = self::findOne($id)) == null){
throw new NotFoundHttpException;
}else{
return $data;
}
}
public function getNormal()
{
return $this->getList()->where(['inventory_device_list.device_condition' => 'normal'])->count();
}
public function getBroken()
{
return $this->getList()->where(['inventory_device_list.device_condition' => 'broken'])->count();
}
public function getSold()
{
return $this->getList()->where(['inventory_device_list.device_condition' => 'sold'])->count();
}
public function getTotal()
{
return $this->getList()->where(['!=','inventory_device_list.device_condition',''])->count();
}
public static function getVendorList($sort=[])
{
return InventoryDeviceVendor::find()->orderBy($sort)->all();
}
public function search($params, $spesific=[],$sort=[])
{
$query = self::find();
$query->where($spesific);
$query->joinWith(['list']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => ['defaultOrder' => $sort]
]);
$dataProvider->sort->attributes['vendor_name'] = [
'asc' => ['inventory_device_vendor.name' => SORT_ASC],
'desc' => ['inventory_device_vendor.name' => SORT_DESC],
];
/** sort on page device-inventory **/
$dataProvider->sort->attributes['device_vendor'] = [
'asc' => ['inventory_device_vendor.name' => SORT_ASC],
'desc' => ['inventory_device_vendor.name' => SORT_DESC],
];
/** sort on page device-inventory end **/
return $dataProvider;
}
/** queries end **/
/** relation **/
public function getListLeft()
{
return InventoryDeviceList::find();
}
public function getList()
{
return $this->hasMany(InventoryDeviceList::className(),['id_device_type' => 'id']);
}
public function getVendorLeft()
{
return InventoryDeviceVendor::find();
}
public function getVendor()
{
return $this->hasOne(InventoryDeviceVendor::className(),['id' => 'id_device_vendor']);
}
/** relation end **/
}
and here is the view :
<?=
GridView::widget([
'dataProvider' => $dataProvider,
'layout' => '<div class="table-responsive">{items}</div> {summary} {pager}',
'columns' => [
[
'class' => 'yii\grid\SerialColumn',
'headerOptions' => ['width' => 50]
],
'name',
[
'attribute' => 'device_vendor',
'class' => 'yii\grid\DataColumn',
'value' => function($data){
return $data->vendor->name;
}
],
[
'attribute' => 'normal',
'class' => 'yii\grid\DataColumn',
'format' => 'html',
'value' => function($data){
return Html::a($data->getNormal(),'#',['class' => 'label label-success']);
},
],
[
'attribute' => 'sold',
'class' => 'yii\grid\DataColumn',
'format' => 'html',
'value' => function($data){
return Html::a($data->getSold(),'#',['class' => 'label label-warning']);
},
],
[
'attribute' => 'broken',
'class' => 'yii\grid\DataColumn',
'format' => 'html',
'value' => function($data){
return Html::a($data->getBroken(),'#',['class' => 'label label-danger']);
},
],
[
'attribute' => 'Total',
'class' => 'yii\grid\DataColumn',
'format' => 'html',
'value' => function($data){
return Html::a($data->getTotal(),'#',['class' => 'label label-primary']);
},
],
],
]);
?>
and how to sort it, like normal, broken, and, sold ?
here is : the result view :
the header normal, sold, broke and all not sortable, i can sort by relation if not using count like this code (like Device Vendor):
$dataProvider->sort->attributes['device_vendor'] = [
'asc' => ['inventory_device_vendor.name' => SORT_ASC],
'desc' => ['inventory_device_vendor.name' => SORT_DESC],
];

YII2 SqlDataProvider doesn't work relation table value

This is my model Riders:
<?php
namespace backend\models;
use Yii;
class Riders extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'riders';
}
public function rules()
{
return [
[['cagories_category_id', 'rider_firstname', 'rider_no_tlpn', 'rider_ucinumber', 'countries_id', 'rider_province', 'rider_city', 'rider_dateofbirth', 'rider_gender'], 'required'],
[['user_id', 'countries_id'], 'integer'],
[['rider_dateofbirth', 'cagories_category_id'], 'safe'],
[['rider_gender', 'rider_status'], 'string'],
[['rider_firstname', 'rider_lastname', 'rider_nickname', 'rider_province', 'rider_city'], 'string', 'max' => 45],
[['rider_email', 'rider_sponsor', 'rider_birthcertificate_url', 'rider_parental_consent_url'], 'string', 'max' => 100],
[['rider_no_tlpn'], 'string', 'max' => 15],
[['rider_ucinumber'], 'string', 'max' => 11]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'rider_id' => 'rider_id',
'cagories_category_id' => 'Category Name',
'user_id' => 'User Team',
'rider_firstname' => 'Rider Firstname',
'rider_lastname' => 'Rider Lastname',
'rider_nickname' => 'Rider Nickname',
'rider_email' => 'Rider Email',
'rider_no_tlpn' => 'Rider No Tlpn',
'rider_ucinumber' => 'Rider Ucinumber',
'countries_id' => 'Country Name',
'rider_province' => 'Rider Province',
'rider_city' => 'Rider City',
'rider_sponsor' => 'Rider Sponsor',
'rider_dateofbirth' => 'Rider Dateofbirth',
'rider_gender' => 'Rider Gender',
'rider_birthcertificate_url' => 'Rider Birthcertificate Url',
'rider_parental_consent_url' => 'Rider Parental Consent Url',
'rider_status' => 'Rider Status',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getRegistrations()
{
return $this->hasMany(Registrations::className(), ['riders_rider_id' => 'rider_id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getCagoriesCategory()
{
return $this->hasOne(Categories::className(), ['category_id' => 'cagories_category_id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']) -> from(user::tableName() . 'ud');
}
/**
* #return \yii\db\ActiveQuery
*/
public function getUserDesc()
{
return $this->hasOne(UserDesc::className(), ['desc_id' => 'user_id']) -> from(['ud' => userDesc::tableName()]);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getCountries()
{
return $this->hasOne(Countries::className(), ['id' => 'countries_id']);
}
}
This my Controller actionIndex:
$searchModel = new RidersSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$totalCount = Yii::$app->db->createCommand('SELECT COUNT(*) FROM riders WHERE user_id = :user_id',
[':user_id' => Yii::$app->user->identity->id])->queryScalar();
$dataProvider = new SqlDataProvider([
'sql' => 'SELECT * FROM riders WHERE user_id = :user_id',
'params' => [':user_id' => Yii::$app->user->identity->id],
'totalCount' => $totalCount,
'key' => 'rider_id',
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => [
'cagories_category_id',
'rider_id',
'rider_firstname',
'rider_email:email',
'rider_no_tlpn',
]
]
]);
$models = $dataProvider->getModels();
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
This is my view index:
<?= GridView::widget([
'dataProvider' => $dataProvider,
// 'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
[
'label' => 'Category Name',
'attribute'=>'cagories_category_id',
'value' => 'cagoriesCategory.category_name', <---Can't work again
],
[
'label' => 'BIB',
'attribute'=>'rider_id',
],
'rider_firstname',
'rider_email:email',
'rider_no_tlpn',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
Before I use sqldataprovider, it can call from model function have relation, after use sqldataprovider can't work. How to get relation table value???
then before use it, i can to merge rider_firstname and rider_lastname with return $model->rider_firstname . " " . rider_lastname; after use sqldataprovider can't work too??
SqlDataProvider returns data as an array so You can't able to access related object with $dataProvider->models()
either you have to use ActiveDataProvider or change your Sql of SqlDataProvider with join condition
sql='sql' => 'SELECT * FROM riders inner join '. Categories::tableName() .' as c on c.category_id=riders.cagories_category_id WHERE user_id = :user_id'

Categories