[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.
Related
I successfully displayed the 3 columns in the gridview. the attr1, attr2, and the sum of the 2 attributes. attr1 and attr2 are from the database and the 3rd column is their sum. How do I make the sorting and filtering work?
Here is the gridview.
[
'label' => 'Number of Enquiries',
'value' => function ($model) {
return $model->countEnquire + $model->countPhone + $model->countTrial;
},
'enableSorting' => true,
]
How add sorting for this column?
OK, I don't have your full source code to go by but can help with a basic example.
Ideally you should start by creating your model and CRUD files using Gii like I have for in my example below.
Here is my basic database table, record:
I added some test data:
Then I created the model and CRUD files using Gii, which I then modified to show you an example of the custom summing/sorting you wish to achieve. See below.
#app/models/Record.php
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "record".
*
* #property integer $record_id
* #property integer $attr1
* #property integer $attr2
* #property integer $sum
*/
class Record extends \yii\db\ActiveRecord
{
public $sum;
public function getSum()
{
$this->sum = 0;
if (is_numeric($this->attr1) && is_numeric($this->attr2)) {
$this->sum = $this->attr1 + $this->attr2;
}
return $this->sum;
}
/**
* #inheritdoc
*/
public static function tableName()
{
return 'record';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['record_id', 'attr1', 'attr2'], 'required'],
[['record_id', 'attr1', 'attr2', 'sum'], 'integer'],
[['sum'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'record_id' => 'Record ID',
'attr1' => 'Attr1',
'attr2' => 'Attr2',
'sum' => 'Sum',
];
}
/**
* #inheritdoc
* #return RecordQuery the active query used by this AR class.
*/
public static function find()
{
return new RecordQuery(get_called_class());
}
}
#app/models/RecordSearch.php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Record;
/**
* RecordSearch represents the model behind the search form about `app\models\Record`.
*/
class RecordSearch extends Record
{
/**
* #inheritdoc
*/
public function attributes()
{
// add related fields to searchable attributes
return array_merge(parent::attributes(), ['sum']);
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['record_id', 'attr1', 'attr2', 'sum'], 'integer'],
[['sum'], '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)
{
// find records, additionally selecting the sum of the 2 fields as 'sum'
$query = Record::find()->select('*, (`attr1` + `attr2`) AS `sum`');
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// enable sorting for the related columns
$dataProvider->sort->attributes['sum'] = [
'asc' => ['sum' => SORT_ASC],
'desc' => ['sum' => SORT_DESC],
];
$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;
}
// grid filtering conditions
$query->andFilterWhere([
'record_id' => $this->record_id,
'attr1' => $this->attr1,
'attr2' => $this->attr2,
]);
// if the sum has a numeric filter value set, apply the filter in the HAVING clause
if (is_numeric($this->sum)) {
$query->having([
'sum' => $this->sum,
]);
}
return $dataProvider;
}
}
#app/views/record/index.php
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use yii\widgets\Pjax;
/* #var $this yii\web\View */
/* #var $searchModel app\models\RecordSearch */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Records';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="record-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<p>
<?= Html::a('Create Record', ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?php Pjax::begin(); ?> <?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'record_id',
'attr1',
'attr2',
'sum',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
I hope this helps!
I have a table that have a relation like this :
Now i get a problem coz if you see,
My work in table in deal_komisi.
But in my searchModel, I want my user can search based in table : item_Layanan.nama_item
This is My model
class DealKomisi extends \yii\db\ActiveRecord {
...... //Common code
/* Related to list_harga */
/**
* #return \yii\db\ActiveQuery
*/
public function getListHarga() {
return $this->hasOne(ListHarga::className(), ['id' => 'list_harga_id']);
}
So, in my DealKomisiSearch, I just use this :
public function search($params) {
$query = DealKomisi::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$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,
'list_harga_id' => $this->list_harga_id,
'komisi' => $this->komisi,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]);
$query->joinWith('listHarga');
$query->andFilterWhere(['like', 'created_by', $this->created_by])
->andFilterWhere(['like', 'updated_by', $this->updated_by])
;
return $dataProvider;
}
What Should I do, P.S
I also created the list_harga model which is, the relation to **item_layanan ** is definite like this.
class ListHarga extends \yii\db\ActiveRecord
public function getItemLayanan()
{
return $this->hasOne(ItemLayanan::className(), ['id' => 'item_layanan_id']);
}
Please advise.
Any help it so appreciated
I would like to get data of a user and his roles but it returns an error of:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'auth_item.user_id' in 'on clause'
The SQL being executed was: SELECT COUNT(*) FROM `tblusers` LEFT JOIN `auth_item` ON `tblusers`.`id` = `auth_item`.`user_id`
I have tried:
Search model
$query = User::find()->joinWith('role');
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['id'=>SORT_ASC]],
'pagination' => ['pageSize' => $pageSize]
]);
return $dataProvider;
Relationship on the user model
public function getRole()
{
// User has_one Role via Role.user_id -> id
return $this->hasOne(Role::className(), ['user_id' => 'id']);
}
Relationship on the role model
public function getUser()
{
return $this->hasMany(User::className(), ['id' => 'user_id']);
}
This is the full search:
public function search($params, $pageSize = 10)
{
$query = User::find()->joinWith('role');
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['id'=>SORT_ASC]],
'pagination' => ['pageSize' => $pageSize]
]);
return $dataProvider;
die();
// if user is not 'theCreator' ( You ), do not show him users with this role
// if user is not 'theCreator' ( You ), do not show him users with this role
if (Yii::$app->user->can('theCreator')) {
$query->where(['!=', 'item_name', 'theCreator']);
}
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['id'=>SORT_ASC]],
'pagination' => ['pageSize' => $pageSize]
]);
// make item_name (Role) sortable
$dataProvider->sort->attributes['item_name'] = [
'asc' => ['item_name' => SORT_ASC],
'desc' => ['item_name' => SORT_DESC],
];
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'status' => $this->status,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]);
$query->andFilterWhere(['like', 'username', $this->username])
->andFilterWhere(['like', 'email', $this->email])
->andFilterWhere(['like', 'item_name', $this->item_name]);
return $dataProvider;
}
This is the authitem model
<?php
namespace app\rbac;
use yii\db\ActiveRecord;
use Yii;
class AuthItem extends ActiveRecord
{ public static function tableName()
{
return '{{%auth_item}}';
}
public static function getRoles()
{
if (Yii::$app->user->can('theCreator'))
{
return static::find()->select('name')->where(['type' => 1])->all();
}
else
{
return static::find()->select('name')
->where(['type' => 1])
->andWhere(['!=', 'name', 'theCreator'])
->all();
}
}
}
THIS IS THE CODE UPDATE:
On this line
$query = User::find()->joinWith('role');
it actually relates to auth assignment as below:
<?php
namespace app\rbac;
use app\models\User;
use yii\db\ActiveRecord;
use Yii;
class Role extends ActiveRecord
{
public static function tableName()
{
return '{{%auth_assignment}}';
}
public function rules()
{
return [
[['item_name'], 'required'],
[['item_name'], 'string', 'max' => 64],
];
}
public function attributeLabels()
{
return [
'item_name' => Yii::t('app', 'Role'),
];
}
public function getUser()
{
// Role has_many User via User.id -> user_id
return $this->hasMany(User::className(), ['id' => 'user_id']);
}
}
Why does it return that error?
If you are using the default rbac models/module from yii2 could be you are relating the wrong model/table .. because the auth_itme model don't contain user_id column
/**
* This is the model class for table "auth_item".
*
* #property string $name
* #property integer $type
* #property string $description
* #property string $rule_name
* #property string $data
* #property integer $created_at
* #property integer $updated_at
Could be instead that you want relate the auth_assignment table which contain relation between auth_item and user
/**
* This is the model class for table "auth_assignment".
*
* #property string $item_name
* #property string $user_id
* #property integer $created_at
*
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.
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.