Trouble understanding Eloquent relationships - laravel

I'm having trouble understanding Eloquent relationships.
Say I have four tables with data
Users
id
...
UserCars
user_id
car_id
color_id
Cars
id
make
model
Colors
id
color
Now I understand how to get the UsersCars for a selected user with
User.php Model
public function cars()
{
$this->hasMany(Car::class);
}
I can then get the User's car in to a view with
public function show(User $user)
{
$cars= $user->cars;
return $cars;
}
So say a given user id 1 has 2 cars, I can get get his cars with $user->cars() which gives me something like in the view
{"id":1, "car_id":3, "color_id": 2}
{"id":1, "car_id":10, "color_id": 4}
But what I'm not getting is how to then further get the actual value of the relevant ids. So once I've passed $users->cars() as $cars in my controller to my view I can then get the actual make and model and color of the users car.
Something like
#foreach ($cars as $car)
{{ $car->make }} : {{ $car->model }}
{{ $car->color }}
#endforeach
So once I call $user->cars() I need the something like
{"id":1, "car_id":3, "make" => "Ford", "model" => "Fiesta", "color_id": 2, "color":"red"}
{"id":1, "car_id":10, "make" => "Volkswagon", "model" => "Golf", "color_id": 4, "color":"blue"}
I hope that makes sense and any help is appreciated, thanks.

You can access all that data through relationships. Simply define them and load them as you need. First let's define every basic relationship in your model files
In Users model:
// User.php
public function user_cars()
{
return $this->hasMany(App\UserCar::class);
}
In UserCars model:
// UserCar.php
public function user()
{
return $this->belongsTo(App\User::class);
}
public function car()
{
return $this->belongsTo(App\Car::class);
}
public function color()
{
return $this->belongsTo(App\Color::class);
}
In Cars model:
// Car.php
public function user_cars()
{
return $this->hasMany(App\UserCar::class);
}
With all that defined, you can access the relationships by just calling upon them. The difference between $car->user_cars() and $car->user_car is the returned object.
$car->user_cars() is an instance HasMany object and $car->user_cars is a Collection instance. It's basically the same as writing $car->user_cars()->get() so you want to go with the later most of the time.
Now let's see your controller method. Technically, you can return the $user and access all relationships in the view but every time you do, that's an additional query to the database. It's something you should avoid by getting all the data eager loaded first. Since you're using Route Model Binding to get the $user, you need to use the load() function. You can even load nested relationships, which is exactly what you're looking for.
public function show(User $user)
{
// This tells eloquent to add the nested relationships to your User instance.
$user->load('user_cars.car', 'user_cars.color');
return $user;
}
Next, you can access them in the view just like you wanted
#foreach ($user->user_cars as $user_car)
{{ $user_car->car->make }}
{{ $user_car->car->model }}
{{ $user_car->color->color }}
#endforeach
Read more on the subject https://laravel.com/docs/5.8/eloquent-relationships

Your have incorrectly defined the relationship on the User to Car.
Since the relationship with users and cars are many-to-many you must use belongsToMany() eloquent relationship.
doc => https://laravel.com/docs/5.8/eloquent-relationships#many-to-many
User Model
public function cars()
{
return $this->belongsToMany(Car::class, 'user_cars', 'user_id', 'car_id');
}
Car Model
public function users()
{
return $this->belongsToMany(User:class, 'user_cars', 'car_id', 'user_id');
}
then you can access cars from the user, or users from the car.

Related

Fetching data from two tables in Laravel in show function in controller?

I have two Model, School, and Student the relationship is, School has Many Student
//Student Model
public function school()
{
return $this->belongsTo('App\School');
}
and same in School Model the following is the function for relationship
public function student()
{
return $this->hasMany('App\Student');
}
Now I have a show Page I like to display the following information. (school_name,school_code) from the school table and student information all from the Student Table.using show function in student controller if I pass as
public function show($id)
{
$student=Student::find($id);
$school=School::find($id);
return View::make('student.show')->with(['school'=> $school,'student'=>$student]);
}
it gets data from school if school_id ==$id but one school has many students it fails if I click to show a button with an ID of 109, how to write the Join query to get school_code and school_name from schools table.
Not sure why you are using the same $id to getting student and school
public function show($id)
{
$student = Student::find($id);
$school = $student->school; //school of the student
return View::make('student.show')->with(['school'=> $school,'student'=>$student]);
}
Use this code
Your model should be like this
public function students()
{
return $this->hasMany('App\Student');
}
You have to change like this.
$student = Student::find($id);
$school = $student->school;
Since you have the relationship setup already, you could use Eloquent to fetch data for single student with the school that he belongs tos as follow:
public function show($id)
{
$student = Student::with('school')->where('id', $id)->first();
return View::make('student.show')->compact('student);
}
Now you can retrieve data show.blade.php as follow:
#foreach($student as $stud)
<li> {{ $stud->student_name}}</li>
<li> {{ $stud->student_code}}</li>
<li> {{ $stud->->school->school->name}}</li>
<li> {{ $stud->school->school_name }}</li>
#ndforeach

laravel model controller retrieve data

I'am new to laravel and had a hard time for eloquent ORM, I like to retrieve Favourite items from the table with specific user id, but seem I don't find a way to display the data correctly.
I refer and copied the favourite model code from here
Model: Favourite
class Favourite extends BaseModel
{
public function favouritable()
{
return $this->morphTo();
}
}
Model: Course
public function favourites()
{
return $this->morphMany(Favourite::class, 'favouritable');
}
public function myFavourite()
{
return $this->favourites()->where('favor_user', '=', auth()->user()->id);
}
Controller: FavouriteController#index
public function index()
{
$course = new Course();
$myfavs = $course->myFavourite();
//dd($myfavs);
$this->vdata(compact('myfavs'));
return view('front.favorites', $this->vdata);
}
In blade view, but return empty/blank data:
#foreach($myfavs as $myfav)
{{ $myfav->$course_name }}
#endforeach
When i dd($myfavs) it display pretty bunches of data that i couldn't find the data that is stored in the favourites table.
I think you have added the conditions but forgot get the results with one of the methods to do so.
Try :
$myfavs = $course->myFavourite()->get();
Or :
$myfavs = $course->myFavourite()->take(<N>)->get;
Or
::all()
etc. take a look at : https://laravel.com/docs/5.8/eloquent#retrieving-models

Laravel One To Many Relationship

I have an Author model and Blog model.
I also set up a table with the author_id and blog_id. The table is called "author_blog".
Below is how I am defining my relationships:
Author Model:
public function blogs()
{
return $this->hasMany('App\Blog', 'author_id');
}
Blog Model:
public function author()
{
return $this->belongsTo('App\Author', 'blog_id');
}
In my view I am trying to do $blog->author->first_name. The first name is a column on the Authors table.
I keep getting
trying to get property on non-object.
Any ideas?
UPDATE:
I have removed the intermediate table and instead put an "author_id" on my blogs table and shortened it as such.
Author Model:
public function blogs()
{
return $this->hasMany('App\Blog');
}
Blog Model:
public function author()
{
return $this->belongsTo('App\Author');
}
In my BlogController, when I define the view, I grab a collection of blogs via $blogs = Blog::all();
In my view I just loop through the blogs to show each individually like...
#foreach ($blogs as $blog)
<div>{{ $blog->author->first_name }}</div>
#endforeach
For one to many relationship you don't need another table to handle your foreign key.
Just add author_id foreign key with your blogs table. then define your relations
like below,
Author Model:
public function blogs()
{
return $this->hasMany('App\Blog', 'author_id');
}
Blog Model:
public function author()
{
return $this->belongsTo('App\Author', 'author_id');
}
view:
before that make sure your query return a valid collection.
#foreach ($blogs as $blog)
<div>#if( $blog->author) {{ $blog->author->first_name }} #endif </div>
#endforeach
For further more details : https://laravel.com/docs/5.8/eloquent-relationships#one-to-many
with belongsToMany relation you can define your middle table(author_blog)
In Author model:
public function blogs()
{
return $this->belongsToMany(Blog::class,'author_blog','author_id','blog_id');
}
author_blog => middle table
author_id => foreignPivotKey
blog_id => relatedPivotKey

Get username from ID

I have a blade template in a Laravel 5.5 app that is returning a user ID integer
I am looking for a way to get the users name from that value within the blade template
The value is just saved in the table and there is no relationship setup, is there a way to get the username without having to set up a relationship?
** UPDATE **
My products controller looks like this...
public function index()
{
$users = User::all();
$products= Product::all();
return view('products.index',compact('products', 'users'));
}
So now I have the users available inside the blade template but now I need to get the user from the id that is contained in produts
In your controller that's passing the user data to the view, you can either pass the entire $user object and print it in your view like {{ $user->name }} or set yourself a variable that holds just the username and pass that in for however you're using it.
I would do the first one though, something like:
public function index()
{
$user = User::where('id',$id)->firstOrFail();
return view('dashboard.index', compact('user'));
}
Or if you're getting all users from the database, an example would be:
public function index()
{
$users = User::all();
return view('dashboard.index', compact('users'));
}
Then in your view you can do
#foreach($users as $user)
{{ $user->name }}
#endforeach
Edit
Since seeing your updated question, you would benefit from making a relationship between your users and your products. So, you would say that a user has many products and that a product belongs to a user.
class User extends Model
{
/**
* Get all of the products for the user.
*/
public function products()
{
return $this->hasMany('App\Product');
}
}
And then
class Product extends Model
{
/**
* Get the user that is assigned to the product
*/
public function user()
{
return $this->belongsTo('App\User');
}
}
Once you have set this up, you can loop through your products and get the username like this:
#foreach($products as $product)
{{ $product->user->name }}
#endforeach
Create helper file: follow this rule to make it : https://laravel-news.com/creating-helpers
and make one function like this:
function getUsername($uerId) {
return \DB::table('users')->where('user_id', $userId)->first()->name;
}
and call this function from your view like this :
{{getUsername($id))}} //it will print user name;
{{\App\User::findOrFail($id)->name}}
Auth::user()->name if user is online. if not you must have controller function like:
$users = User::all();
and in blade
#foerach($users as $user)
{{$user->name}}
#endforeach

hasManyThrough() or similar database model

I have a database setup similar to this:
items
id - integer
user_id - int
users
id - integer
name - string
contacts
id - integer
user_id - integer
name - string
Using Eloquent ORM how would I query for that returns the associated user, and their contacts? I'm currently using
Items::with('user')->get();
Models and relationship:
// User model
class User extends Eloquent {
public function items()
{
return $this->hasMany('Item');
}
public function contacts()
{
return $this->hasMany('Contact');
}
}
// Contact model
class Contact extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
// Item model
class Item extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
Usage:
$items = Item::with('user.contacts')->get(); // Result will be a collection object
$firstItem = $items->first(); // get the first item from collection
// Or this to get first one
$firstItem = $items->get(0); // get the first item from collection
$firstItem->user; // Get related User Model
$firstItem->user->contacts; // get collection of Contact models
If you pass the $items to your view then you may use a loop, for example:
$items = Item::with('user.contacts')->get();
return View::make('viewname')->with('items', $items);
In your view:
#foreach($items as $item)
{{ $item->property_name }}
{{ $item->user->property_name }}
#foreach($item->user->contacts as $contact)
{{ $contact->propertyname }}
#endforeach
#endforeach
It's called loading nested relations - last example on http://laravel.com/docs/eloquent#eager-loading
$items = Items::with('user.contacts')->get();
// then for example:
$item = $items->first();
$item->user; // user Model
$item->user->contacts; // Collection of Contact models
A note: there is no relation to access such relation directly. hasManyThrough won't work in this setup.

Resources