I am trying to get information from two models that are related, displayed in one view.
So what I am trying to accomplish is have the index view to show the list of people, if I then go into detail view of that particular person I want a list of attributes relevant to that person to appear.
I have the database setup so that when I create a new person a default row gets inserted into the attributes table with the id of the person under the column called person_id.
See my two model classes
People:
class People extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'people';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['dob', 'CURDATE'], 'safe'],
[['age'], 'integer'],
[['firstname', 'surname'], 'string', 'max' => 50]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'firstname' => 'Firstname',
'surname' => 'Surname',
'dob' => 'Dob',
'age' => 'Age',
'CURDATE' => 'Curdate',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getId0()
{
return $this->hasOne(Attributes::className(), ['person_id' => 'id']);
}
}
Attributes:
class Attributes extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'attributes';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['haircolor', 'eyecolor', 'weight', 'height', 'person_id'], 'required'],
[['weight', 'height', 'person_id'], 'integer'],
[['haircolor', 'eyecolor'], 'string', 'max' => 50]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'haircolor' => 'Haircolor',
'eyecolor' => 'Eyecolor',
'weight' => 'Weight',
'height' => 'Height',
'person_id' => 'Person ID',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getPeople()
{
return $this->hasOne(People::className(), ['id' => 'person_id']);
}
}
I have generated CRUD through Gii for both of these models.
What I would like to know is how to setup my people controller and people view so that this may work properly.
Just to recap, my index.php view will just show the list of people, if a record exists, you can view that specific record, if you view the record - which will be the view.php file, I want to show the attributes(These will be the default values) of that particular person where the id of the person is the same as the person_id in the attributes table
The user will then be able to update the attributes relating to that person.
Kind Regards.
Here an example :
public function actionCreate()
{
$user = new User;
$profile = new Profile;
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post()) && Model::validateMultiple([$user, $profile])) {
$user->save(false); // skip validation as model is already validated
$profile->user_id = $user->id; // no need for validation rule on user_id as you set it yourself
$profile-save(false);
return $this->redirect(['view', 'id' => $user->id]);
} else {
return $this->render('create', [
'user' => $user,
'profile' => $profile,
]);
}
}
More informations :
http://www.yiiframework.com/forum/index.php/topic/53935-solved-subforms/page__p__248184
http://www.yiiframework.com/doc-2.0/guide-input-tabular-input.html
To display related information in a view, you get the best performance with eager loading. I'll provide an example:
public function actionView($id)
{
$model = Person::find()
->where(['id' => $id])
->with('id0')
->one();
return $this->render('view', [
'model' => $model,
]);
}
Now i see that your relation in Person Model is called getId0, you can for readability change that to getAttribs(), and change to ->with('attribs') but that is just a digression :)
EDIT: as #soju commented, attributes is not possible to use as a relation name, and that is why gii has given it the name getId0. Attribs or something more informative can be helpful on readability.
If you want to show the results in a widget, like GridView or ListView, you can follow the guide here:
http://www.ramirezcobos.com/2014/04/16/displaying-sorting-and-filtering-model-relations-on-a-gridview-yii2/
EDIT2: as #soju commented, guide is possibly outdated. Read official documents aswell.
http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html#working-with-model-relations
If you want to create your own view, you can access the values with $model->id0->haircolor or, if you rename the relation, $model->attribs->haircolor just like you would any other attribute.
Remember: using GridView / ListView requires the table name from the db when displaying, like 'attributes.eyecolor', but the $model->id0 requires the relation name from the model, without the 'get' in front, and with lower case.
Related
I'm kinda new to Laravel and I hope someone we'll be able to give me some help.
I apologize for my english
So I'm trying to develop an application with some friends to manage our food by sending alert when the peremption date is near.
I'm developing the API, the actual structure is this way:
A user,
A product,
A basket containing the user_id, the product_id and of course the peremption date.
So now when I make a call to get the User 'stock' on my API I wish I could get something like this:
{
'id' : 1,
'peremption_date': XX-XX-XX,
'product' : {
'id' : 3,
'name': bblablabala,
'brand' : blablabala
},
'id' : 2,
'peremption_date': XX-XX-XX,
'product' : {
'id' : 4,
'name': bblablabala,
'brand' : blablabala
},
}
So I took a look on resources and saw that if I define the right relations, this could do the stuff for my output.
I'll link you my actual class declarations and their resources:
User:
//user.php
class User extends Authenticatable
{
use Notifiable, HasApiTokens;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function baskets()
{
return $this->hasMany(Basket::class);
}
}
Product:
//Product.php
class Product extends Model
{
protected $table = 'products';
protected $fillable = ['code_barre', 'product_name', 'generic_name', 'brand', 'quantity'];
public function basket()
{
return $this->belongsToMany(Basket::class);
}
}
//productResource.php
class ProductResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'code_barre' => $this->code_barre,
'product_name' => $this->product_name,
'generic_name' => $this->generic_name,
'brand' => $this->brand,
'quantity' => $this->quantity,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at,
];
}
}
Basket:
//Basket.php
class Basket extends Model
{
protected $table = 'baskets';
protected $fillable = ['user_id', 'product_id', 'dlc_date'];
public function user()
{
return $this->belongsTo(User::class);
}
public function product()
{
return $this->hasOne(Product::class);
}
}
//BasketResource.php
class BasketResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'dlc_date' => (string) $this->dlc_date,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at,
'product' => $this->product
];
}
}
So when I try to store a new basket in my store method:
//BasketController.php
public function store(Request $request)
{
$this->product->storeProduct($request->input('code_barre'));
$att = DB::table('products')
->where('code_barre', '=', $request->input('code_barre'))
->first();
$basket = Basket::create([
'user_id' => $request->user()->id,
'product_id' => $att->id,
'dlc_date' => $request->input('dlc_date')
]);
return new BasketResource($basket);
}
I get the following error (this one)
saying than products.id_basket does not exist and its right, it's not supposed to exist. This is Basket who have a product_id. so I know this is coming from the relationship I declared but I can't figure how to do it right.
Can someone come and save me ???
Thanks a lot, I hope you understood me !
Wish you a good day
As I look at your Basket model, it seems you have to change your:
public function product()
{
return $this->hasOne(Product::class);
}
to:
public function product()
{
return $this->belongsTo(Product::class);
}
Because you have product_id in your baskets table. To use hasOne() relation, you will need to remove product_id from baskets table and add basket_id to products table, because hasOne() relation is something like hasMany(), only calling ->first() instead of ->get()
I want to change what is shown in my yii2 app's history view, so that I don't show a person's ID but his first and last name.
This is a part of my data grid
[
'attribute' => 'oldPerson.Id',
'label' => Yii::t('app', 'Previously In Charge'),
'value' => function($model){
return $model->person->FirstName . ' ' . $model->person->LastName; }
],
but this isn't good since my $model is a history object, which contains a person's ID. I somehow need to obtain the entire person object based on that ID, but I don't know how.
This is my Person model:
namespace app\models;
use Yii;
use \app\models\base\Person as BasePerson;
/**
* This is the model class for table "person".
*/
class Person extends BasePerson
{
public $created_at;
public $created_by;
public $updated_at;
public $updated_by;
public $id;
/**
* #inheritdoc
*/
public function rules()
{
return array_replace_recursive(parent::rules(),
[
[['FirstName', 'LastName', 'Title', 'CitizenNumber', 'Employment', 'Contact'], 'required'],
[['FirstName'], 'string', 'max' => 20],
[['LastName'], 'string', 'max' => 40],
[['Title'], 'string', 'max' => 50],
[['CitizenNumber'], 'string', 'max' => 13],
[['Employment', 'Contact'], 'string', 'max' => 100],
[['CitizenNumber'], 'unique']
]);
}
}
Normally you can get the model based on id this way
public function findModel($id)
{
if (($model = Person ::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
$model contain the Person info related to $id
its also working fine
$model=Modelname::findOne($id);
I'm having trouble understanding how relations work in yii 2
I have 2 tables in a mysql database, author and book.
book has a column named author which links to the id of the author table via foreign key.
I've generated CRUD using gii, and I want the author name to appear in the list view, as well as dropdowns for the author name in the create and update views.
But I cant seem to get the relation working even in the list view.
Here's my code
Book Model:
<?php
namespace app\models;
use Yii;
use app\models\Author;
/**
* This is the model class for table "book".
*
* #property integer $id
* #property string $name
* #property integer $author
*/
class Book extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'book';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name', 'author'], 'required'],
[['author'], 'integer'],
[['name'], 'string', 'max' => 11]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'author' => 'Author',
];
}
public function getAuthor()
{
return $this->hasOne(Author::className(), ['id' => 'author']);
}
}
BookSearch Model:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Book;
/**
* BookSearch represents the model behind the search form about `app\models\Book`.
*/
class BookSearch extends Book
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id', 'author'], 'integer'],
[['name'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = Book::find();
$query->joinWith('author');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
var_dump($dataProvider);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'author' => $this->author,
]);
$query->andFilterWhere(['like', 'name', $this->name]);
return $dataProvider;
}
}
Also, here's the view file:
<?php
use yii\helpers\Html;
use yii\grid\GridView;
/* #var $this yii\web\View */
/* #var $searchModel app\models\BookSearch */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Books';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="book-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<p>
<?= Html::a('Create Book', ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'name',
[
'attribute' => 'author',
'value' => 'author.name',
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
</div>
Author Model:
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "author".
*
* #property integer $id
* #property string $name
*/
class Author extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'author';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name'], 'required'],
[['name'], 'string', 'max' => 200]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
];
}
}
I think I may have to change something somehwhere in the author/authorSearch model.
Can someone help
thanks
You can also add columns to a gridview with value from an anonymous function as described here http://www.yiiframework.com/doc-2.0/yii-grid-datacolumn.html#$value-detail. For example you can show an author's name like this in a gridview:
<?= GridView::widget([
'dataProvider'=>$dataProvider,
'filterModel'=>$searchModel,
'columns'=>[
[
'attribute'=>'author.name',
'value'=>function ($model, $key, $index, $column) {
return $model->author->name;
},
],
//...other columns
]);
?>
you can also return a html-link to the detail-view of an author like this:
//...
'columns'=>[
[
'attribute'=>'author',
'value'=>function ($model, $key, $index, $column) {
return Html::a($model->author->name, ['/author/view', 'id'=>$model->author->id]);
},
],
//...
],
//...
You can access relation table data in any crud view file using their relation name. $model->relName->attribute_name.
And You can access relation table data in gridview at following way :
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
[
'attribute' => 'author',
'value'=>'author.author_name', //relation name with their attribute
]
],
]);
First you need a get function in your model, but you have.
This is :
public function getAuthor()
{
return $this->hasOne(Author::className(), ['id' => 'author']);
}
Now you just need do one more thing.
Go to the index file, and to GridView, and columns.
Write this into columns:
[
'attribute' => 'author',
'value' => 'author.name',
],
In the value, the first parameter is your Get function, what named is : getAuthor, and . after your column name.
Hello in your BookSearch Mode please add below code like this.
$query->joinWith(array('author'));
$query->andFilterWhere(['id' => $this->id,])
->andFilterWhere(['like', 'author.author_name', $this->author]);
And in your view file please use below given code below code is for view file inside grid attrubute.
[
'attribute' => 'author',
'value' => 'author.name',
]
i hope this will helps you. and i hope in author table name is stored in name column.
This worked for me - inside the BookSearch Model:
public function search($params)
{
$dataProvider = new \yii\data\SqlDataProvider([
'sql' => 'SELECT book.id as id ,book.author_fk, book.name as book_name , author.name as author_name' .
' FROM book ' .
'INNER JOIN author ON (book.author_fk = author.id) '
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
return $dataProvider;
}
Only issue now is getting the ActionColumn to work correctly, they're currently linking to the wrong IDs, help anyone.
[EDITED 2]
I'm having hard time to sort by the 'topicCount' which is defined as a relational getter on a model 'Tag'.
A Topic can have a lots of Tag, and wish to sort the Tags by how many Topics containing that Tag.
In my models/Tag.php:
public function getTopicCount()
{
return TopicTag::find()->where(['tag_id' => $this->id])->count();
}
And in my views/tag/index.php:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'name',
[
'attribute'=>'topicCount',
'value' => 'topicCount',
],
'created_at',
['class' => 'yii\grid\ActionColumn','template' => '{view}',],
],
]); ?>
And in my controllers/TagController.php:
public function actionIndex()
{
$dataProvider = new ActiveDataProvider([
'query' => Tag::find(),
'sort'=> [
'defaultOrder' => ['id'=>SORT_DESC],
'attributes' => ['id','topicCount'],
],
'pagination' => [
'pageSize' => 100,
],
]);
return $this->render('index', [
'dataProvider' => $dataProvider,
]);
}
And in my models/TagSearch.php:
<?php
namespace common\models;
use Yii;
/**
* This is the model class for table "tags".
*
* #property integer $id
* #property string $name
* #property string $created_at
* #property string $updated_at
*/
class TagSearch extends Tag
{
public $topicCount;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['topicCount'], 'safe']
];
}
public function search($params)
{
// create ActiveQuery
$query = Tag::find();
$query->joinWith(['topicCount']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['topicCount'] = [
'asc' => ['topicCount' => SORT_ASC],
'desc' => ['topicCount' => SORT_DESC],
];
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andFilterWhere([
//... other searched attributes here
])
->andFilterWhere(['=', 'topicCount', $this->topicCount]);
return $dataProvider;
}
}
And in the index view I can see the correct topicCount:
but on clicking the topicCount column I get the error:
exception 'PDOException' with message 'SQLSTATE[42703]: Undefined column: 7 ERROR: column "topicCount" does not exist
LINE 1: SELECT * FROM "tags" ORDER BY "topicCount" LIMIT 100
Thanks for any guidance..!
[EDIT]
Following Lucas' advice, I've set my dataProvider query in my $dataProvider like this:
'query' => $query->select(['tags.*','(select count(topic_tags.id) from topic_tags where topic_tags.tag_id=tags.id) topicCount'])->groupBy('tags.id'),
and I got error:
exception 'PDOException' with message 'SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "tags"
so I reformulated like this:
'query' => $query->from('tags')->leftJoin('topic_tags','topic_tags.tag_id = tags.id')->select(['tags.*','(select count(topic_tags.id) from topic_tags where topic_tags.tag_id=tags.id) topicCount'])->groupBy('tags.id'),
and now I get the result:
apparently the topicCount column is not set, so when I try to sort by it, it returns the error:
exception 'PDOException' with message 'SQLSTATE[42703]: Undefined column: 7 ERROR: column "topicCount" does not exist
but when I try the SQL directly on the DB, it works fine:
so I suppose the problem is in the way Yii handles the alias 'topicCount'?
2nd EDIT
Still the same result without the topicCount set in the Grid view.
I show my TagSearch model, TagController and views/tag/index view file below:
TagSearch
<?php
namespace common\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use common\models\Tag;
/**
* TagSearch represents the model behind the search form about `common\models\Tag`.
*/
class TagSearch extends Tag
{
public $topicCount;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id', 'topicCount'], 'integer'],
[['name', 'created_at', 'updated_at', 'topicCount'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = Tag::find();
$dataProvider = new ActiveDataProvider([
'query' => $query->from("tags")->select(["tags.*","(select count(topic_tags.id) from topic_tags where topic_tags.tag_id=tags.id) topicCount"])->groupBy("tags.id"),
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
$query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'topicCount' => $this->topicCount,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]);
$query->andFilterWhere(['like', 'name', $this->name]);
return $dataProvider;
}
}
Tag model
<?php
namespace common\models;
use Yii;
/**
* This is the model class for table "tags".
*
* #property integer $id
* #property integer $topicCount
* #property string $name
* #property string $created_at
* #property string $updated_at
*/
class Tag extends \yii\db\ActiveRecord
{
public $topicCount;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'tags';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['topicCount'], 'integer'],
[['name'], 'string'],
[['created_at', 'updated_at'], 'required'],
[['created_at', 'updated_at'], 'safe']
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'topicCount' => 'TC',
'created_at' => 'Created At',
'updated_at' => 'Updated At',
];
}
}
TagController
public function actionIndex()
{
$searchModel = new TagSearch();
$myModels = $searchModel->search([]);
return $this->render('index', [
'dataProvider' => $myModels,
]);
}
tags/index
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'name',
'topicCount',
'created_at',
'updated_at',
['class' => 'yii\grid\ActionColumn','template' => '{view}',],
],
]); ?>
What am I missing?
So resolved following this wiki:
Since in my case I don't use SUM('amount'), I changed to the following and works perfectly:
Tag model:
public function getTopicCount()
{
return $this->hasMany(TopicTag::className(), ["tag_id" => "id"])->count();
}
TagSearch model:
$query = Tag::find();
$subQuery = TopicTag::find()->select('tag_id, COUNT(tag_id) as topic_count')->groupBy('tag_id');
$query->leftJoin(["topicSum" => $subQuery], '"topicSum".tag_id = id');
Just encountered a problem with the generated SQL:
exception 'PDOException' with message 'SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "topicsum"
This might be a Postgres-specific issue, had to arrange the code so that the generated SQL becomes like this:
SELECT COUNT(*) FROM "tags"
LEFT JOIN (SELECT "tag_id", COUNT(*) as topic_count FROM "topic_tags" GROUP BY "tag_id") "topicSum"
ON "topicSum".tag_id = id
note the double-quotation in "topicSum".tag_id part.
Hope this might be of help for someone using Postgres on Yii2.
You should alter your query to group and select the count instead of working with relations.
$query->groupBy('tags.id')->select(['tags.*','(select count(topic_tag.id) from topic_tag where topic_tag.tag.id=tags.id) topicCount']);
This will add topicCount as a result object in your query, which will make it behave like an ordinary column.
Also as a side note, for a method to act a relation in Yii2, it must return an ActiveQuery object. Your getTopicCount() is returning the count as an int, instead of the query, therefore Yii2 will not treat it like a relation.
Based on this Wiki and #arogachev's answer. I put select property to get tags count
public function search($params)
{
$query = SomeModels::find()
->select('subQueryName.field_count, someModels.*');
// ....
so it will give SQL like this SELECT subQuery.field_count, someModels.* ...
at view (grid),
[
'attribute'=> 'field_count',
],
Thank you #arogachev , you saved me :)
light solution is just reate view in PostgreSQL
and generate model via gii generator using as model and order & find work.
For update & delete use table model for search & index use view model.
For example
for actions update & delete use Tag model
for actions index & view use TagView model.
I am trying to setup the filter for related model in Yii2's GridView widget, but I am keep getting the error like the filter value must be an integer.
I have followed this question. Now, I have a two models Services.php and ServiceCharge.php.
In ServiceCharge.php the relation is setup like:
public function getServiceName()
{
return $this->hasOne(Services::className(),['id'=>'service_name']);
}
In the ServiceChargeSearch.php the code is like this:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\ServiceCharges;
/**
* ServiceChargesSearch represents the model behind the search form about `app\models\ServiceCharges`.
*/
class ServiceChargesSearch extends ServiceCharges
{
/**
* #inheritdoc
*/
public function attributes()
{
// add related fields to searchable attributes
return array_merge(parent::attributes(), ['serviceName.services']);
}
public function rules()
{
return [
[['id'], 'integer'],
[['charges_cash', 'charges_cashless'], 'number'],
[['id', 'serviceName.services', 'room_category'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = ServiceCharges::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['serviceName.services'] = [
'asc' => ['serviceName.services' => SORT_ASC],
'desc' => ['serviceName.services' => SORT_DESC],
];
$query->joinWith(['serviceName']);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
// 'service_name' => $this->service_name,
'room_category' => $this->room_category,
'charges_cash' => $this->charges_cash,
'charges_cashless' => $this->charges_cashless,
])
->andFilterWhere(['LIKE', 'serviceName.services', $this->getAttribute('serviceName.services')]);
return $dataProvider;
}
}
and in my Gridview it is setup like this:
[
'attribute'=>'service_name',
'value'=>'serviceName.services',
],
Which is showing the services name from the related model correctly.
I am not able to see what I am doing wrong, but the filter field for the attribute for service is not showing at all.
Actually it is much simpler than it seems.
add the column_name to safe attribute.
Note: this should be relation Name
add the join with query - like - $query->joinWith(['serviceName','roomCategory']);
add the filter condition like:
->andFilterWhere(['like', 'services.services', $this->service_name])
->andFilterWhere(['like', 'room_category.room_category', $this->room_category]);
if like to add sorting add the code like:
$dataProvider->sort->attributes['service_name'] = [
'asc' => ['services.services' => SORT_ASC],
'desc' => ['services.services' => SORT_DESC],
];
$dataProvider->sort->attributes['room_category'] = [
'asc' => ['room_category.room_category' => SORT_ASC],
'desc' => ['room_category.room_category' => SORT_DESC],
];
5 you should also set the relation name say public $roomCategory
That's it. Both sorting and filtering for related table works perfectly.
Note: Remove default validation like integer for related column and default filtering generated by gii otherwise it will generate an error.
Update on Latest version:
Adding Public $attribute is not needed.
Adding safe attribute for relation is also not needed.
but the attribute in your current model, which you want filter is
to added to safe attribute that is a must.
and most importantly in your gridview, the related attribute has to
be in closure format.
that is example
[
'attribute=>'attribute_name',
'value=function($data){
return $data->relationname->related_table_attribute_name
}
],
remember it you are using relation_name.related_table_attribute_name filter somehow doesn't work for me.
There is a fairly comprehensive set of instructions on the Yii Framework website. The only thing to note is that the search model complains about the following lines, but everything appears to work as intended without them:
$this->addCondition(...);
For a model, PaymentEvent (table: subs_payment_event), which has a currency_id field linked to model Currency, this is the complete set of additional code (using the Basic template):
In the main model, PaymentEvent.php:
public function getCurrencyName()
{
return $this->currency->name;
}
In the search model, PaymentEventSearch.php:
public $currencyName;
In its rules:
[['currencyName'], 'safe'],
In the attributes of its setSort statement, include:
'currencyName' => [
'asc' => ['subs_currency.name' => SORT_ASC],
'desc' => ['subs_currency.name' => SORT_DESC],
'label' => 'Currency'
],
Before the grid filtering conditions:
$query->joinWith(['currency' => function ($q) {
$q->where('subs_currency.name LIKE "%' . $this->currencyName . '%"');
}]);
Finally, in the GridView columns array in the view (including my usual link across to the related model records):
[
'attribute' => 'currencyName',
'label' => 'Currency',
'format' => 'raw',
'value' => function ($data) {
return Html::a($data->currency->name, ['/currency/' . $data->currency_id]);
},
],