Yii2 "has no relation named" at search model even the function it is defined in the main model

open-ecommerce.org picture open-ecommerce.org · Mar 2, 2017 · Viewed 8.8k times · Source

I am having a yii2 error : common\models\Book has no relation named "favorite".

When I try to add:

public function search($params) {
    $query = Book::find();
    $query->joinWith(['author', 'profile', 'favorite']);

In the book model I do have the public function:

public function getFavoritedIcon() {
    if (isset($this->favorite)) {
        return '<i class="glyphicon glyphicon-asterisk books-form"></i>';
    } else {
        return '';
    }
}

And also this extra function to get the icon

public function getFavoritedIcon() {
    if (isset($this->favorite)) {
        return $icon;
    } else {
        return '';
    }
}

And this works fine in the grid where I want to add sorting and filter:

[
    'label' => 'Favorites',
    'attribute' => 'favorite',
    'value' => 'favoritedIcon',
    'hAlign' => 'center',
    'vAlign' => 'middle',
    'format' => 'raw',
    'width' => '50px',
],

I do some different things from another models I am using:

  • in the grid i get the value as an icon from the book model but i used this before.
  • the other thing is that the Favorite model has not the same name that the table but it work fine in the grid

abstract class Favorite extends \yii\db\ActiveRecord {

    public static function tableName()
    {
        return 'user_favorite';
    }


    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['user_id', 'book_id'], 'required'],
            [['user_id', 'book_id'], 'integer'],
            [['selectedTime'], 'safe']
        ];
    }

Any clues what I am doing wrong ?

======================================================

UPDATE after Pedro del Sol answer

There was some errors in the code but the main one was answered by Pedro, I do had a favorite function in the Book model but not favorites with multiple output.

So now it is working like that:

In the Book model

    public function getFavorite() {
    $userID = Yii::$app->user->identity->id;
    return Favorite::find()->where(['user_id' => $userID, 'book_id' => $this->id])->one();
}

public function getFavorites() {
    $userID = Yii::$app->user->identity->id;
    return $this->hasMany(Favorite::className(), ['book_id' => 'id'], ['book_id' => $this->id]);
}
public function getFavoritedIcon() {
    if (isset($this->favorite)) {
        return '<i class="glyphicon glyphicon-asterisk books-form"></i>';
    } else {
        return '';
    }
}

In the BookSearch model:

    public function search($params) {
    $query = Book::find();
    $query->joinWith(['favorites']);

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);

    $dataProvider->setSort([
        'attributes' => [
            'title',
            'author_id',
            'rights_owner_id',
            'user_favorite.user_id',
        ]
    ]);

and the grid view :

        [
        'label' => 'Favorites',
        'attribute' => 'user_favorite.user_id',
        'value' => 'favoritedIcon',
        'hAlign' => 'center',
        'vAlign' => 'middle',
        'format' => 'raw',
        'width' => '50px',
    ],

Answer

Pedro del Sol picture Pedro del Sol · Mar 2, 2017

Having a method to getFavoritedIcon() is not the same as declaring a relation to getFavorite()

I assume that in your Book model class you have the methods getAuthor() and getProfile() which will return queries linking a Book with an Author and a Profile. You'll need something similar with Favorite(s) but I suspect the multiplicities will be different.

I think to declare your relation you'll need something like

/**
 * @return \yii\db\ActiveQuery
 */
public function getFavorites()
{
    return $this->hasMany(Favorite::className(), ['book_id' => 'ID']);
}

if the relation between Books and Favorites is one to many (most likely) or

/**
 * @return \yii\db\ActiveQuery
 */
public function getFavorite()
{
    return $this->hasOne(Favorite::className(), ['book_id' => 'ID']);
}

if the relation is one to one.

You can then use joinWith() with either 'favorite' or 'favorites' depending on the multiplicities of your relation.