I’m scratching my head here. I have a join on a query and when I try to display the data I want in gridview, nothing is shown. What am I doing wrong here?
$query = Tickers::find()
->orderBy([
'ticker' => SORT_ASC
])
->leftJoin('sec_type', 'sec_type.id = tickers.type_id');
$dataProvider = new ActiveDataProvider([
'query' => $query
]);
In the view:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'ticker',
'name',
'type_id',
[
'attribute' => 'type',
'value' => 'sec_type.type'
],
'sector_id',
'country_id',
'visible',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
bpanatta
(Bruno Panatta)
February 11, 2021, 2:37am
2
Even doing the join, when you call Tickers::find()
from SQL view is like you are doing this: SELECT tickers.* FROM ...
And you can validate that by doing this, right after building your query:
$query->createCommand()->getRawSql();
In order to “fetch” that data you could add the method addSelect() to your query
OR even better : declare a relation between your records:
public function getSecType() {
return $this->hasOne(SecType::className(), ['id' => 'type_id']);
}
Read more here in Declaring Relations
I do have the relations declared, but I’m not sure how I would use them in this context. What would the query look like?
bpanatta
(Bruno Panatta)
February 11, 2021, 12:33pm
4
You can access that through the Gridview like this:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
[
'label' => Yii::t('app', 'Type'),
'value' => 'secType.type' // Here it will look for the attribute `type` in the relation
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
This will fetch the data.
Unfortunately, this doesn’t work.
Is there something wrong with my query? Or how I’m accessing it in GridView?
Whether I use “sec_type.type” or “secType.type”, the column returns “not set”.
bpanatta
(Bruno Panatta)
February 11, 2021, 3:34pm
6
Which of those methods did you use for fetching the data?
Well, neither. I’d like to use the declaration but I don’t know what that query would look like.
Would it be another separate query or a part of the query I’ve written?
Also, when I try “addSelect()”, it still does not display the type AND eliminates a large number of results.
I tried adding this:
->addSelect('*', 'sec_type.type')
When I change the query to the following:
$query = (new Query())
->select('*')
->from('tickers')
->leftJoin('sec_type', 'sec_type.id = tickers.type_id');
The data is displayed properly, but now the buttons in the action column no longer work.
bpanatta
(Bruno Panatta)
February 11, 2021, 5:40pm
10
bpanatta:
OR even better : declare a relation between your records:
public function getSecType() {
return $this->hasOne(SecType::className(), ['id' => 'type_id']);
}
Do this solution instead! add that method to the Tickers
model and, if you don’t have a SecType
model, create one!
After this is done, just change the GridView to look like in this example:
bpanatta:
<?= GridView::widget([ 'dataProvider' => $dataProvider, 'filterModel' => $searchModel, 'columns' => [ [ 'label' => Yii::t('app', 'Type'), 'value' => 'secType.type' // Here it will look for the attribute `type` in the relation ], ['class' => 'yii\grid\ActionColumn'], ], ]); ?>
bpanatta
(Bruno Panatta)
February 11, 2021, 5:41pm
11
Also change your query to just this:
$query = Tickers::find();
Leave the sorting for the dataProvider: read here about ActiveDataProvider
This was the issue! The relation was there, but named getType(). It was generated by gii, so I didn’t bother checking it.
Thank you so much!!!
Next question…
How do I add filtering on the Type column like the other columns? I’ve added
->andFilterWhere(['like', 'type', $this->secType]);
To the search function, however, the filtering/sorting function does not appear. Any way to get that in there?
bpanatta
(Bruno Panatta)
February 11, 2021, 6:15pm
14
now you use the leftjoin
:
->leftJoin('sec_type', 'sec_type.id = tickers.type_id')
->andFilterWhere(['like', 'sec_type.type', $this->secType]);
If you now some SQL, I recommend you run the following command, so this you can always no what is the SQL command that you are getting:
Hmm, just tried this. The SQL command looks good, but still no filtering.
What else should I check for?
bpanatta
(Bruno Panatta)
February 11, 2021, 6:43pm
16
Please, show me the SQL generated
Here it is…
'SELECT `tickers`.* FROM `tickers` LEFT JOIN `sec_type` ON sec_type.id = tickers.type_id ORDER BY `ticker`'
Looking at it, I see it’s only selecting from tickers. The thing is, when I throw in, “addSelect()” to capture the other columns, it eliminates a number of the results…
bpanatta
(Bruno Panatta)
February 11, 2021, 6:50pm
18
forget the addSelect
, probably the attribute $this->secType
is empty. In this case the andFilterWhere()
wont apply. Check the value for this attribute.
And maybe try changing the andFilterWhere
to andWhere
.
You’re right, it’s empty, but they all are (‘id’, ‘ticker’, etc.). I don’t think that’s where the problem is.
Now, I’m curious to know how GridView processes the ‘filterModel’…
Edit: I think I may know why. The search model is pulling from TickersSearch, which doesn’t have the columns in it from the relationship tables. Question is now, how do I get it to recognize the other columns?
bpanatta
(Bruno Panatta)
February 11, 2021, 8:19pm
20
add them to your TickersSearch, add as class var on to the rules()
.
The logic here is: TickersSearch
must have all attributes for a search over tickers, this means that it might contain attributes that doesn’t exist in the Tickers
model, or it might even not contain attributes that exist in the Tickers
model.