Hey folks,
imagine the following database setup (PK’s are bold)
-
Table user (id, name)
-
Table song (id, interpret, title)
-
Table user_song_rating (user_id, song_id, rating)
The last table saves user specific ratings about a song (i.e. how much the user likes a song on a scala from 1 to 10).
Now, in the view I’ve a GridView which displays a list of Songs and I want it to display a rating bar column in case that a user is logged in. So i basicaly declared this relation in my Song model:
public function getUserSongRating()
{
return $this->hasOne(UserSongRating::className(), ['song_id' => 'id'])
->andOnCondition('{{%user_song_rating}}.[[user_id]] = :user_id', [':user_id' => Yii::$app->user->id]);
}
So far, so good. This is working as expected.
In my experience with Yii 1 I’ve made some not-so-good experience of using the user component within a model, (primarily because it is available to web applications only, but also because it lead to unexpected results if the application had multiple modules were the user’s id was refering to different tables and so on…) and I really want to try to avoid using it in Yii 2 models.
So on a second try I was modifing the relation to pass the userid as a parameter
public function getUserSongRating($userId)
{
return $this->hasOne(UserSongRating::className(), ['song_id' => 'id'])
->andOnCondition('{{%user_song_rating}}.[[user_id]] = :user_id', [':user_id' => $userId]);
}
Now, while this works and this “feature” is also mentioned in the guide, it actually has a drawback which i couldn’t find a solution for, yet:
When using this relation with a GridView I stumbled upon multiple problems:
[list=1]
[*]When creating the dataprovider within the controller, I want to eager load the relation by using joinWith(‘userSongRating’). (I use joinWith() in favor of with() because I also need to configure a yii\data\Sort Object in order to allow the user to sort the songs depending on his ratings). However, I did not found a way to pass the userId to the relation. Looking at the source I’ve also found that there is now way to do it either (other then using a default parameter). What I am hoping for is a good workaround for it.
[*]The same problem pops up in the column configuration of the GridView, because it cannot load the relation without failing (because of the missing parameter)
[/list]
So, the question is: Is there a good way to do what I want to achieve? And: Do you access components which are usualy only available in either console (e.g. \yii\console\Request) or web (e.g. \yii\web\User) in your models? If not: What pattern do you use to avoid it with respect to the DRY principle?