I have being struggling with related model data for a while and can't seem to pin point the problem, I have been reduced to using a very simple example.
I have two models Dog and Owner, which have the following relations.
Owner:
public function getDogs()
{
return $this->hasMany(Dog::className(), ['owner_id' => 'id']);
}
Dog:
public function getOwner()
{
return $this->hasOne(Owner::className(), ['id' => 'owner_id']);
}
As a simple test I want to get the dog to disaply from the grid view in the index page in Owner view
This is my index.php in the Owner view
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'name',
[
'attribute' => 'type',
'value' => 'dog.type',
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
I must be missing something fundamental here?
You cannot display multiple related items like this, but you could simply use a callback, e.g. :
[
'label' => 'Dog types',
'value' => function($model) {
return join(', ', yii\helpers\ArrayHelper::map($model->dogs, 'id', 'type'));
},
],
Related
Using gii, I created a model based on a database table and then CRUD for the model. One of the columns is showing either 1 or 2 as they are stored in the database. To create new, it was easy using a ActiveForm->dropDownList() widget:
<?= $form->field($model, 'type')->dropDownList(['1'=>'Role', '2'=>'Permission'], ['prompt'=>'Select Auth Item Type']) ?>
How to use GridView and show Role instead of 1 and Permission instead 2?
In gridview you can use value
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
.........
[
'attribute' => 'type',
'label' => 'Type',
'format' => 'raw',
'value' => function ($model) {
if ( $model->type == 1) {
return 'Role';
} else {
return 'Permission';
}
},
],
I want to show staff has many hobbies from table hobbies in detail view and gridview.
But I got an error exception Trying to get property of non-object
Here's my schema code model:
app\model\TblDataStaff
....
public function getTblDataHobis()
{
return $this->hasMany(TblDataHobies::className(), ['id_staff' => 'id']);
}
view code: view.
<?= DetailView::widget([
'model' => $model,
'attributes' => [
...
['attribute'=>'namHob','value'=>$model->tblDataHobis->id],
...
],
]) ?>
index:
<?= GridView::widget([
'dataProvider' => $dataProvider,
//'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
......
['attribute'=>'namHob','value'=>function($namHob){return $namHob->tblDataHobis->name_hobby;},],
.....
['class' => 'yii\grid\ActionColumn'],
],]);?>
How to show many hobbies of staff ?
Nothing strange, you have a Trying to get property of non-object error simply because $model->tblDataHobis return an array of TblDataHobies objects.
You could simply try this :
// display hobbies names separated with commas
echo implode(', ', \yii\helpers\ArrayHelper::map($model->tblDataHobis, 'id', 'name_hobby'));
For DetailView :
'value' => implode(\yii\helpers\ArrayHelper::map($model->tblDataHobis, 'id', 'name_hobby')),
For GridView :
'value' => function($model) {
return implode(\yii\helpers\ArrayHelper::map($model->tblDataHobis, 'id', 'name_hobby')),
},
Try with:
<?= DetailView::widget([
'model' => $model,
'attributes' => [
[
'header' => 'number of hobbies',
'value' => function($data) {
return $data->getTblDataHobis()->count();
}
]
]) ?>
Just get the item data, and after that create a simple yii2 query.
For example my 'worker' has city id, with this id we can find city name by this id.
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
'name:ntext',
'surname:ntext',
'fathers',
[
'attribute' => 'city_id',
'value'=> function($data){
$city = City::find()->where(['id'=>$data->city_id])->one();
$info = $city->name;
return $info;
},
'format'=>'html',
],
'status',
'street',
'in_company',
],
]) ?>
I have 3 tables and i have made relation to What table by using Field table. i want to show name row from What table in Gridview.but it shows me row of data seperated by comma. i want each data in different column. like sql query result with repeated field.
this is my tbon.php model:
public function getWhat()
{
return $this->hasMany(What::className(), ['idw' => 'idw'])
->viaTable('Field', ['id' => 'id']);
}
public function getField()
{
return $this->hasMany(Field::className(), ['id' => 'id']);
}
and in TbonSearch.php i have added these codes:
public $what;
public $field;
and
[['field','what'],'safe']
and in search method, i have added:
$query = Tbon::find()
->joinWith(['field'])
->joinWith(['what']);
and for sorting:
$dataProvider->sort->attributes['what'] = [
'asc' => ['what.name' => SORT_ASC],
'desc' => ['what.name' => SORT_DESC],
];
and add search filter:
->andFilterWhere(['like', 'what.name', $this->what]);
in index i have added this code and here is the problem, i think:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'label'=>'Name',
'attribute' => 'what',
'value' => function ($data) {
$str = '';
foreach($data->what as $name) {
$str .= $name->name.',';
}
return $str;
},
],
data is like this: a,b,c,d for field of name! but i want ID and a then in next row ID and b and etc.
any help will be appreciated!
I dont know your code and I dont get the meaning, but I can answer in general.
A GridView is used to view Data in a Grid. A row in a GridView represents a dataset and presenting data in the form of a table.
foreach($data->what as $name) {
$str .= $name->name.',';
}
I assume you want to display the Name attribute from the relation what. You can simply achieve this with the tablename.columnname syntax.
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'label'=>'Name',
'attribute' => 'what.name',
],
If you want to display the ID column additionally:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'label'=>'Name',
'attribute' => 'what',
'value' => function ($data) {
$str = '';
foreach($data->what as $name) {
$str .= ' ';
$str .= $name->id.'';
$str .= $name->name.',';
}
return $str;
},
],
To be more precise (in Terms of your Problem). We have a datamodel with a junction table like the following simple book database.
Example:
If you want to display the names of the authors on the standard CRUD generated index Gridview, you can do something like this:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'book_name',
[
'label'=>'Author(s)',
'value' => function ($dataProvider) {
$str = '';
foreach($dataProvider->authors as $name) {
$str .= ' ';
$str .= $name->id.' ';
$str .= $name->author_name.',';
}
return $str;
},
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
with the result:
In addition, you can edit the Detail View to display such an information in an extra Gridview. The result can look like this.
To achieve this you have to:
add a data provider to your controller and pass the provider to the view
add a gridview widget in your view and connect the data provider
add a method to your model which crawls the data
view.php aka the view
use yii\grid\GridView;
// other code
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
[
'attribute' => 'author.author_name',
'header' => 'Author(s)',
],
],
]); ?>
BookController.php aka the controller
public function actionView($id)
{
$dataProvider = Book::getAllAuthors($id);
return $this->render('view', [
'model' => $this->findModel($id),
'dataProvider' => $dataProvider,
]);
}
Book.php aka the model
use \yii\data\ActiveDataProvider;
// other code
public static function getAllAuthors($id) {
$query = BookAuthor::find()->where(['book_id' => $id]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
return $dataProvider;
}
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;}
I have two database tables 'user' and 'role'. I used Yii framework 2.0 Gii to create CRUD with User model and UserSearch model. By default, Gii uses GridView::widget for the index page for the 'user' model.
In the search($params) method inside of the UserSearch model, I used the following code to join the above tables together
$query = User::find()->with('role');
Everything works fine with the query.
By default Gii does not include the data from the joined table 'role' in the GridView::widget inside of the views/user/index.php page. With the join query above I could retrieve data from both tables. In the views/user/index.php page I have injected the GridView::widget with the following code so that it also includes the data and column names from the joined table (role).
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'userid',
'username',
'role.role_name',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
Everything works fine with the role data 'role_name included in the GridView::widget. But the problem is that there is no search box for the role_name. The GridView::widget creates search box for the User properties only. Is there any way to add search box for the properties of the joined table 'role' because I also would like to search through 'role_name' as well as through other properties of the User model.
Try this way:
In your UserSearch model add
UserSearch extends ...
{
public $roleFilterInputName; //the name of the filter search input
//important
function rules()
{
//add roleFilterInputName as safe
return [
[['xxx', 'roleFilterInputName'], 'safe'], //!!!!
];
}
}
in your grid:
'columns':
[
//...
[
'attribute' => 'roleFilterInputName',
'value' => 'role.role_name'
],
//...
]
in UserSearch::search()
$query->andFilterWhere(['like', 'role.role_name', $this->roleFilterInputName])
But I guess you'll have to use 'joinWith' instead of 'with'.
Inside CGridView add below code. It will enable filter with dropDownList.
[
'attribute' => 'act_role_id',
'label' => 'Actor Role',
'value' => 'actRole.role_name',
'filter' => yii\helpers\ArrayHelper::map(app\models\ActorRole::find()->orderBy('role_name')->asArray()->all(),'act_role_id','role_name')
],
CGridView code Snippet is as below:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'userid',
'username',
[
'attribute' => 'act_role_id',
'label' => 'Actor Role',
'value' => 'actRole.role_name',
'filter' => yii\helpers\ArrayHelper::map(app\models\ActorRole::find()->orderBy('role_name')->asArray()->all(),'act_role_id','role_name')
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
Try it with
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'userid',
'username',
//'role.role_name',
['attribute' => 'role', 'value' => 'role.role_name'],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
I just have tried it in my code, so I'm not sure if this works also with your code. But if so, I don't know why it has to be defined this way.
I guess the answer of rajesh ujade also includes this definition, however, for Yii 1.
This worked for me
Table = Lead (id , year_id)
Table = Year (id, text)
Added text in lead (index.php)
Year::find()->all() = This code pull all value from table/ all years.
[
'attribute'=> 'year_id',
'format' => 'html',
'value' => 'year.value',
'label' => 'Year',
'filter' => Html::activeDropDownList($searchModel, 'year', yii\helpers\ArrayHelper::map(Year::find()->all(), 'year_id', 'value'), ['class' => 'form-control', 'prompt' => '---']),
],
Also it shows dropdown as well sorting.
image Showing Dropdown in Grdiview
#Ekonoval is going in right way.
Just add following in serch function of UserSearch:
After initializing ActiveDataProvider object like this:
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 5,
],
]);
$dataProvider->sort->attributes['roleFilterInputName'] = [
'asc' => ['role.role_name' => SORT_ASC],
'desc' => ['role.role_name' => SORT_DESC]
];
You may write query in your UserSearch model like
if($this->role)
{
$query->join('LEFT JOIN','role','role.user_id = user.id')->andFilterWhere(['role.item_name' => $this->role]);
}