Laravel relationship between three tables - php

I have 3 tables:
Events
Ages
Books
Which I was relating them in the following way:
ages
id
name
books
id
title
age_book
id
age_id
book_id
events
id
name
event_age
id
event_id
age_id
event_age_book
event_age_id
book_id
Basically, a book can have many ages, an age can have many books, an event can have many ages, an event age can have many books.
My Event Model looks like this and works fine to get all event ages
class Event extends Model
{
public function ages()
{
return $this->belongsToMany(Age::class, 'event_age');
}
}
Age Model:
class Age extends Model
{
public function books(): BelongsToMany
{
return $this
->belongsToMany(Book::class)
->withTimestamps();
}
}
Book Model
class Book extends Model
{
public function ages(): BelongsToMany
{
return $this
->belongsToMany(Age::class, 'book_age', 'book_id','age_id')
->withTimestamps();
}
}
Im having trouble figuring out how to get all edition age books, is it possible to do it on the Event model?

Let's Review The Relationships
Seems you should only need 3 models, and 5 tables.
Books Belong to Ages
Events Belong to Ages
Ages Belongs to Books
Ages Belongs to Events
Your other models are alright, but your age model is missing a relationship to Event:
class Age extends Model
{
public function books(): BelongsToMany
{
return $this->belongsToMany(Book::class)
->withTimestamps();
}
public function events(): BelongsToMany
{
return $this->belongsToMany(Events::class,'event_age')
->withTimestamps();
}
}
That would allow:
$books->ages;
$events->ages;
$ages->book;
$ages->events;
And chaining...
$books = collect();
foreach($event->ages as $age){
$books->merge($ages->books);
}
$books->unique();
Books and Events
So, I gon't think you want age_event_books. I think what you really want is:
Events belong to Books
Books belong to Events
such that
book_events
- id
- book_id
- event_id
- age_id
And you'd have in book:
public function events()
{
return $this->BelongsToMany('App\Event')
->withTimestamps()
->withPivot('age_id');
}
And in event:
public function books()
{
return $this->belongsToMany('App\Book')->withTimestamps()
->withPiviot('age_id')->groupBy('age_id');
}
Giving you:
$event->books
$book->events
On the Front End
[O]n the frontend i'll need to get the most recent event and group books by age and books can belong to more than one age
$event = Event::latest();
$books = $event->books();
Then on the blade
#foreach($books as $age_id => $books)
<h4>{{Age::find($age_id)->name}}</h4>
#foreach($books as $book)
<div>$book->name</div>
#endforeach
#endforeach
Helpful Tip
You are supplying the relation table, which you have to do because you didn't follow the naming convention for joining tables. The convention is that the classes being joined should be listed alphabetically. So age_event instead of event_age.

Related

Eloquent ORM hasManyTrough

i have a hasManyTrough() relation in my database but could not get it to work with eloquent.
the relation in my database
category(id)
entry(id)
category_entries(category_id, entry_id)
i have 3 models
Category
has_many CategoryEntries
Entry
has_many CategoryEntries
CategoryEntry
belongs_to Category
belongs_to Entry
so every category has many entries and every entry has many categories.
in rails i would do the following
Entry
has_many CategoryEntries
has_many Categories, through: :category_entries
i have created the following in eloquent
CategoryEntry
public function category(){
return $this->belongsTo('App\Category');
}
public function entry(){
return $this->belongsTo('App\Entry');
}
Category
public function categoryEntries(){
return $this->hasMany('App\CategoryEntry');
}
Entry
public function categoryEntries(){
return $this->hasMany('App\CategoryEntry');
}
public function categories()
{
return $this->hasManyThrough('App\Category', 'App\CategoryEntry', 'category_id', 'id');
}
but this will create the following sql command:
select `entries`.*, `category_entries`.`category_id` from `entries`
inner join `category_entries` on `category_entries`.`id` = `entries`.`entry_id`
this makes no sence. where is my mistake?
As described in your question, relation is
Category (hasMany) Entry (hasMany) CategoryEntries
So we can add hasManyThrough relation in Category Model not in Entry model
class Category
.......
public function categoryEntries()
{
$this->hasManyThrough(App\CategoryEntry::class, App\Entry::class);
}
UPDATE
if the relation is based on db you have given, then you have Many-Many relation between Category and Entry. then you can have,
class Entry
....
public function categories()
{
return $this->belongsToMany(App\Category::class, 'category_entries');
}

belongsToMany on not primary field

For example i have 4 tables:
buildings
id, title, ...
rooms
id, building_id, title, ...
companies
id, title, ...
companies_to_buildings
company_id, building_id
and i want to get companies from the room model.
From building model i can do something like
class Building extends Model
{
public function companies(){
return $this->belongsToMany('App\Company', 'company_building');
}
}
or
class Building extends Model
{
public function companies(){
return $this->belongsToMany('App\Company', 'company_building', 'building_id', 'company_id');
}
}
but if i do this in room model, it would not work. it will try to find rows in companies_to_buildings table where companies_to_buildings.building_id=room.id. how can i get companies from the room model?
You can make use of hasManyThrough
Example:
public function series()
{
return $this->hasManyThrough('Series', 'Product');
}

Join three table by laravel eloquent model which has only one relation with each other

How to join the three table in Laravel Eloquent model. My table structure is like. It is easy with raw(mysql with left join) query to get the desired result, but it is possible to get via Eloquent.
Customer table
id
title
name
Order table(has customer id)
id
customer_id
Hour table (has order id)
id
order_id
From Hour model I want to get the Customer Details and Order Details. Now I am able to get the Order details like below.
public function order()
{
return $this->belongsTo('App\Models\Order', 'order_id', 'id');
}
How to get the Customer Details?
I tried like below, but not get success
1.return $this->hasManyThrough('App\Models\Customer','App\Models\Order','customer_id','id');
2. return $this->hasManyThrough('App\Models\Customer','App\Models\Order','customer_id','order_id');
Edit 1:
class HourLogging extends Model
{
public function order()
{
return $this->belongsTo('App\Models\Order', 'order_id', 'id');
}
$timeoverview = HourLogging::select('hour_logging.*')->whereRaw("hour_logging.date BETWEEN '".$start_date."' AND '".$end_date."'")->orderBy('date','asc');
$timeoverview->with('order.customer');
return $timeoverview->get();
}
class Order extends Model {
public function customer() {
return $this->belongsTo('App\Models\Customer');
}
}
hasManyThrough works the opposite way to what you're trying to achieve. It would let you get Hour models from your Customer model easily.
In order to get what you need you need to define the relations that go the other way - from Hour to Order to Customer. Add the following relations to your models:
class Hour extends Model {
public function order() {
return $this->belongsTo('App\Models\Order');
}
}
class Order extends Model {
public function customer() {
return $this->belongsTo('App\Models\Customer');
}
}
With those relations in place you should be able to access Order data with $hour->order and Customer data with $hour->order->customer.
One thing to remember: Eloquent offers possibility to eagerly load related data to avoid additional queries. It makes sense to do it when you fetch multiple Hour records at once. You an load all Hour records with related Order and Customer data with the following:
$hours = Hour::with('order.customer')->get();

Relationships using Eloquent

I'm using Eloquent in Laravel 5 and am a bit confused in relations between tables. These are existing tables of a software and cannot be altered.
I have the following tables that shows historical details of a student. All tables have model classes created.
student
-------
student_id (PK)
first_name
last_name
class
-----
class_id (PK)
name
section
year //2012, 2013 etc
student_id (FK)
result
------
result_id (PK)
class_id (FK)
month // jan, feb etc
status //pass or fail
Below are the details of each table
Student studies in a class for a particular year
Each class for that year will have 10 results (1 result for each month in an year)
Each result will contain the state for a test in a month (pass or fail)
I want to access objects based on the below examples. Can you guide on setting up relations in the model classes
student->class(2013)->result(jan)
result(feb)->class(2016)->student
First of all you should define the relationships between your models:
Result.php model
public function class(){
return $this->belongsTo('Class::class');
}
Class.php model
public function results(){
return $this->hasMany('Result::class');
}
public function student(){
return $this->belongsTo('Student::class');
}
Student.php model
public function classes(){
return $this->hasMany('Class::class');
}
Then, you can use some queries. For your first example student->class(2013)->result(jan):
$results = Student::find($student_id)->classes()->where('year', '2013')->results()->where('month', 'jan')->get();
Also, if you will need to search classes by year and results by month a lot of times, you can easily add some methods like this in your models:
Student.php model
public function classesByYear($year){
return $this->classes()->where('year', $year)->get();
}
Class.php model
public function resultsByMonth($month){
return $this->results()->where('month', $month)->get();
}
So the previous example will become:
$results = Student::find($student_id)->classesByYear('2013')->resultsByMonth('jan');
EDIT: Your tables are using a custom identifier, so you must implement protected $primaryKey = 'custom_id'; on each model.

Laravel Eloquent Relationship custom query

I have 2 tables: USERS and SUBJECTS
The relationship between USER and SUBJECT is many to many.
In the User.php and Subject.php models, I defined:
User.php
function subjects() { return $this->belongsToMany('App\User'); }
Subject.php
function users() { return $this->belongsToMany('App\Subject'); }
The pivot table is subject_user and it has 3 columns:
subject_id, user_id, finished
The finished value can only be between 0 and 1.
Now I know that when I want to select all the subjects that an user studied, I have to write $user->subjects.
But what if I want to select all the subjects that an user studied and the finished value in the pivot table is equal to 1?
You need to add "withPivot()" to your relationship definitions, like this:
function subjects() { return $this->belongsToMany('App\User')->withPivot('finished'); }
function users() { return $this->belongsToMany('App\Subject')->withPivot('finished'); }
Then you can do:
$user->subjects()->where('finished', 1)->get();
You will need to eager load that relationship and use the wherePivot method.
$user = User::with(['subjects' => function($q) {
$q->wherePivot('finished', 1);
}])->fine($user_id);

Categories