0
votes

I've got a problem I've not faced before with Eager Loading in Laravel.

I have the following table structure

- Letter
    id,
    sentence_id

- Sentence
    id,
    paragraph_id

- Paragraph
    id,
    book_id

- Book
    id

belongsTo/belongsToMany:

  • letter->belongsToMany('Sentence')
  • sentence->belongsTo('Paragraph')
  • paragraph->belongsTo('Book')

has/hasMany:

  • book->hasMany('Paragraph')
  • paragraph->hasMany('Sentence')
  • sentence->hasMany('Letter')

This all works great. However, if I want to get all the letters in the book, I have can't seem to figure out the correct way to do this.

I've tried hasManyThrough but quickly realized that does not serve the purpose I'm trying to achieve.

I then thought I could use Eager Loading WITH hasManyThrough something to the effect of.

public function sentences(){
    return $this->hasManyThrough('Sentence', 'Paragraph');
}

Which I could then do something like:

Book::sentences()->with(['letters' => function($q) use (&$letters){
    $letters = $q->get()->unique();
}]);

However this does not seem to establish the relationship correctly.

What is the best way to access D through A?

1

1 Answers

1
votes

To load letters relationship into Book you should do something like that with standard relationships:

Relationships:

Book:

paragraps -> hasMany

Paragraph:

sentences -> hasMany

Sentence:

letters -> hasMany

Getting book with letters

$bookId = 1; // sample book id
$book = Book::with('paragraphs.sentences.letters')->find($bookId);

And now to display all letters you could use:

foreach ($book->paragraphs as $paragraph)  {
     foreach ($paragaph->sentences as $sentence) {
         foreach ($sentence->letters as $letter) {
            echo $letter->id;
         }
     }      
}

I don't know what for you use this structure, but depending on usage, maybe you should also duplicate somehow information in your database. For example for letters maybe you should also add book_id column and then you could get all books letters using simple $book->letters but everything depends on how you use your application.