How to retrieve 2nd level many to many relationship with Eloquent? - laravel

I describe a possible E-R picture here:
Entities are : News, Tag, Magazine
A News belongs to many Magazine (Magazine has many news)
A Tag belongs to many News (News has many tags)
Both are many to many relationships.
Starting from Magazine how would I define models in order to access Tags?
like $magazine->news()->tags(); ?

In model Magazine
function news(){
return $this->hasMany(News::class);
}
In model News
function tags(){
return $this->hasMany(Tag::class);
}
function magazine(){
return $this->belongsTo(Magazine::class);
}
In model Tag
function news(){
return $this->belongsTo(News::class);
}
Now
Since magazine has many news it returns a collection
#foreach($magazine->news as $n)
{{ $n->id }}
#foreach($n->tags as $tag)
{{ $t->id }}
#endforeach
#endforeach

Related

Laravel Many to Many relationship for 3 tables

i've 3 tables Branches,Subjects,Teachers
Branches and subjects already many to many.
i've CRUD for teacher,when i create teacher i insert info to user model to add new user with type teacher.
i want to make relation to allow me combine teachers/branches/subjects.
for example when i'm creating teacher i need to select branch/branches and subject/subjects that this teacher related to.
any hint allows me to do this ?
i it convert for you
If I get it right, you have established the many-to-many-relationships between every two of the three models
(Teacher, Branche & Subject).
Instead, you should establish the many-to many between any two models
of your choice and treat the third model as a pivot. For example:
Teacher.php
class Teacher extends Model
{
public function branches()
{
return $this->belongsToMany(Branche::class)->withPivot('subject');
}
}
Branche.php
class Branche extends Model
{
public function teachers()
{
return $this->belongsToMany(Teacher::class)->withPivot('subject');
}
}
view.blade.php
#foreach($teachers as $teacher)
#foreach($teacher->branches as $branc)
{{ $branc->name }} {{ $branc->pivot->subject }}
#endforeach
#endforeach

Laravel relationships (one to many)

I am new to Laravel and maybe somebody can give me an example for this.
I have two tables - Auhors and Books and two views - authors.index and books.index.
I know how to display all the books related to author in authors.index, but the question is, how to display all authors related books in books.index view?
My models and BookController:
Authors
Books
BooksController
You need to use the opposite function belongsTo into your Books model.
public function authors() {
return $this->belongsTo(Authors::class, 'author_id', 'id');
}
You can find more info here

Get a distinct list of all related model instances in Eloquent

I have two Eloquent models (say: Books and Authors) which have a one-to-many-relation (one Author can have many Books, each Book has exactly one Author). The database also contains Authors which have no Book at all. I would like to retrieve a list of all Authors which have a Book - whitout having duplicate authors.
Currently I loop over all Book instances and add the Author to the list if it is not yet in the list:
$books = Books::all();
$list = [];
foreach ($books as $book) {
if (! in_array($book->author, $list) ) {
array_push($list, $book->author);
}
}
I wonder whether there is a smarter way to get this, i.e. a way, which reuduces the number of database queries.
I would like to retrieve a list of all Authors which have a Book - whitout having duplicate authors
Use the has() method:
$authorsWithBooks = Author::has('books')->get();
$books = Books::with('author')->get();

Load relations for a query result separately

Let's say we have two models Book and Author. The Book model defines a relationship to get the author:
public function author()
{
return $this->belongsTo(Author::class, 'author_id','id');
}
If we want to get all of the books that were published in 2000, along with their authors, we can do this:
$books = Book::with('author')->where('publication_year', 2000)->get();
Now what if we want to return the unique Authors who published in 2000 separately from their Books? Let's say Bob published three books and Sally published two books. We'd have one collection that included the 5 books without their authors, and another collection that included Bob and Sally once each.
This is the closest I've gotten (this is a simplified example and may contain typos):
$books = Book::with('author')->where('publication_year', 2000)->get();
$authors = $books->pluck('author')->unique('id');
//this part is bad:
foreach ($books as $book) {
unset($book['author']);
}
Is there a more efficient way to do this, or do I have to set up a manual JOIN?
If you want to get IDs of authors who have written books in 2000, you could use whereHas():
Author::whereHas('books', function($q) {
$q->where('publication_year', 2000);
})->pluck('id');
You can use whereIn as:
$books = Book::where('publication_year', 2000)->get();
$authors_id = $books->unique('author_id')->pluck('author_id');
$authors = Author::whereIn('id', $authors_id)->get();

Eloquent to combine data from 2 x tables?

Table Structure:
games
id | name
awards
id | award name | game_id (fk)
Relationships
A game can have many awards.
An award has one game.
class Games extends Model
{
public $timestamps = false;
public function awards()
{
return $this->hasMany('award');
}
}
I need to get all the games out of my database. I do this using:
Game::all();
I then need to get all of the games out of my database but include data from the awards table.
I want to have an array which I can loop through to output the games, and if the game has an award - output this also.
What would be the correct eloquent statement?
Laravel's relations are brilliant for this kind of thing. Everything you have so far is on the correct path.
// Controller
public function index()
{
$games = Game::all();
return view('games.index', compact('games'));
}
// View
#foreach($games as $game)
{{ $game->name }}
#if(count($game->awards) > 0)
// Game has some awards, lets loop through them
#foreach($game->awards as $award)
{{ $award->name }}
#endforeach
#endif
#endforeach
Using the relation you've setup in your Game model you can instantly access the related data from other tables. Now each time you call $game->awards it will query the database, however using Laravel's Eager Loading you can pull all this information out at the same time rather than on demand.
// Controller
public function index()
{
$games = Game::with('awards')->get();
return view('games.index', compact('games'));
}
and by doing the exact same thing in the view you're no longer running a new query each time you want to get a games awards as they've already be fetched from the database. More on eager loading here http://laravel.com/docs/5.0/eloquent#eager-loading

Resources