V
V
Vitaly Khvan2018-09-27 11:18:47
Yii
Vitaly Khvan, 2018-09-27 11:18:47

Yii2 dependent tables, how do you do without an additional model?

In general, there are 2 tables
book and genre
and there is a many-to-many relationship between them, so I add a pivot table genre-book
and in order to make standard calls I have to call forever $model->genres, this is if I call from the book model, but what if I have to look for books from genres, I will pass the function some( Book $item ) to the widget and it turns out that the model of the dependent GenreBook table
comes there and I have to write $model->book->title
how can I bypass the book call while having the right data?
example excerpt from my RecommendedBook code:

public function renderItem($item)
    {
        $title = $item->book->title();
        $cardContent = '';
        $imgSrc = '/img/book-thumb/'.rand(1,100).'.jpg';
        $author = $item->book->author()[0]['first-name'].' '.$item->book->author()[0]['last-name'];
        $cardContent .= Html::img($imgSrc,['class' => 'card-img-top']);
        $cardContent .= Html::tag('h4',$title,['class' => 'card-title']);
        $cardContent .= Html::tag('small',$author,['class' => 'text-muted']);

        $cardDiv = Html::tag('div',$cardContent,['class' => 'card-block']);

        return Html::a($cardDiv,['book/'.$item->book->url],$this->cardOptions);
    }

Compiling dataProvider:
$model = Book::find()->where( [ 'url' => $url ] )->limit( 1 )->one();
        foreach ( $model->genres() as $genre ) {
            $search = new GenreBookSearch();
            $dataProvider[$genre['@attributes']['title']] = $search->search(Yii::$app->request->queryParams);
            $dataProvider[$genre['@attributes']['title']]->query->andWhere(['genre_id' => $genre['@attributes']['id']]);
        }

actually the question is, if I use this muck like $model->book->title(),
then when I try to pass the author of the book, I will have to make exact copies of the dependencies, is this correct and how can I realize all this.
Thank you in advance!

Answer the question

In order to leave comments, you need to log in

3 answer(s)
D
dtBlack, 2018-09-27
@xRites

Your question is very difficult to understand.
As I understand it, you want to write shorter and clearer?
Moreover, to avoid errors, you will probably have to write not $item->book->title, but something similar to !empty($item->book)?$item->book->title:''
As I understand it, you have a problem in building a model and perhaps not knowing what hasMany and hasOne are (the link to the documentation and examples of use was discussed on the same site ), and you may not know such a phenomenon as magic methods , and specifically __get ().
So you should have something like this:

class Genre extends ActiveRecord
{
    public function getBooks()
    {
        return $this->hasMany(Book::className(), ['id' => 'book_id'])
            ->viaTable('genre_book', ['genre_id' => 'id']);
    }
}

And then you will have a list of books in this genre in the $genre->books attribute.

V
vyrkmod, 2018-09-27
@vyrkmod

You here , specifically viaTable(). The result should be for both $book->genres books and $genre->books genres. And to create a separate model for a linking table that does not carry additional information is usually not constructive.

A
Antarit, 2018-09-27
@Antarit

It's not entirely clear what the question is... If you want to do without calling $item->book inside the renderItem function, do it like this

public function renderItem($book)
    {
//какой-то код...
        $title = $book->title();
        $author = $book->author()[0]['first-name'].' '.$book->author()[0]['last-name'];
//какой-то код...
}

and call yourself calmly . Otherwise, you just somehow renderItem($item->book)
make your life very difficult...
In general, you should deal with the hasOne() and hasMany() relations and not write scary data providers... And all such questions will disappear by themselves...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question