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',
// ...
Related
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]);
Basically, I want to make a CRUD page which is the dataProvider that came from Query class.
So, In controller :
public function actionIndex(){
$searchModel = new RequestBisaApproveSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
Then in RequestBisaApproveSearch(); which is the dataProvider :
public function search($params)
{
$karyawan = Karyawan::findOne(['id' => \Yii::$app->user->identity->karyawan_id]);
$dataKaryawan = $karyawan->linkKaryawanPerusahaanBranchDepartementJabatans;
$branches = [];
$perusahaans = [];
$departements = [];
$jabatans = [];
foreach ($dataKaryawan as $data) :
array_push($branches, $data['branch_id']);
array_push($perusahaans, $data['perusahaan_id']);
array_push($departements, $data['departement_id']);
array_push($jabatans, $data['jabatan_id']);
endforeach;
$query = (new Query())
->select("re.id as id, kar.first_name, kar.last_name, re.status, re.header, re.tanggal_permintaan")
->from('ytresnamuda_it.request re')
->join('LEFT JOIN', 'ytresnamuda_hrd.karyawan kar', 're.karyawan_id = kar.id')
->join('LEFT JOIN', 'ytresnamuda_hrd.link_karyawan_perusahaan_branch_departement_jabatan li', 'kar.id = li.karyawan_id');
$query->where(['IN','li.branch_id', $branches]);
$query->andWhere(['IN','li.perusahaan_id', $perusahaans]);
$query->andWhere(['IN','li.departement_id', $departements]);
$query->andWhere(['<','li.jabatan_id', max($jabatans)]);
$query->andWhere(['!=','li.karyawan_id', $karyawan->id ]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
return $dataProvider;
The problem is, when to make a actionColumn.
Yii2 have a function to createUrl in actionColumn like this:
[
'class' => 'kartik\grid\ActionColumn',
'dropdown' => false,
'width' => '150px',
'template' => '{approve} {print-request}',
'vAlign' => 'top',
'urlCreator' => function ($action, $model, $key, $index) {
return Url::to([$action, 'id' => $key]);
},
'buttons' => [
'approve' => function ($url, $model, $key) {
return Html::a( $key, Url::to(['request-bisa-approve/approve', 'id' => $key]),
[
'class' => 'btn btn-sm btn-primary btn-gii-action-customized fa fa-thumbs-o-up',
'role' => 'modal-remote',
'data-toogle' => 'tooltip',
'title' => 'Reminder IT'
]);
},
],
],
If you can see in :
'urlCreator' => function ($action, $model, $key, $index) {
return Url::to([$action, 'id' => $key]);
},
id is $key.So, I check it with another column,
[
'class' => '\kartik\grid\DataColumn',
'width' => '30px',
'attribute' => 'id',
'vAlign' => 'top',
],
The result is : id is valid integer. But $key always 0.
Weird, but if someone have clue, it so much appreciate.
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 ?
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],
];
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.