Understanding Eloquent in Laravel - php

Previously I have worked with bog standard PHP and have recently made the move over to Laravel. One thing I cannot grasp is SQL queries in Laravel Eloquent.
For instance I have a roles and a users table. The roles table contains roles and IDs for each role. The users table contains various user details as well as a role_id to reference the role of the user.
What I have tried in my user model
public function role()
{
// return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
return $this->hasOne('App\Role', 'id', 'role_id');
}
What I have tried in my role model
public function users()
{
return $this->hasMany('App\User', 'role_id', 'id');
}
Then in my controller
public function index()
{
$var = User::find()->role->get();
return view('article',
array(
'var' => $var
));
}
But now how do I access the fields in both tables as I would in ordinary PHP? I would rather use standard SQL but am trying to properly learn this framework.
Any advice?

You can access table fields via eloquent model attributes.
If you have fields like name, email you can fetch them like
$user = User::find(1);
$name = $user->name;
$email = $user->email;
$roleName = $user->role->name;
Note that you do not really have to call get() method on relation. Accessing it will call it automatically.
Laravel docs are pretty helpful in this matter. Laravel 5.2 Eloquent: Getting Started and Laravel 5.2 Eloquent: Relationships

Try it with eager loading
$var = User::with('role')->find($userId)->get();

Related

Filtering Laravel Eloquent call by something in the with clause

I'm building an app based off of the Laravel bootcamp app and I'm trying to add additional filtering based off of the with statement.
Some probably obvious things:
each user has a city
each call has a user referenced by user_id
public function index()
{
$user = auth()->user();
$city = $user->city;
return Inertia::render('Calls/Index', [
'calls' => Call::with('user:id,name,city,state,email')->latest()->get(),
]);
}
I need to only get calls whose user has the same location as them. Is there something obvious I'm missing?
When retrieving model records, you may wish to limit your results based on the existence of a relationship, there is where you can use whereHas
I presume you have a relation in your Interia Model refer to User model:
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
now you can make you code like this:
return Inertia::render('Calls/Index', [
'calls' => Call::with('user:id,name,city,state,email')->whereHas('user',function ($q) use ($city) {
$q->where('city',$city);
})->latest()->get(),
]);

Get single column from many-to-many relationship in laravel

I created many-to-many relationship between User model and Role model with the pivot table 'role_user'. I want to retrive a single column 'role_name' for the authenticated user as an array.
Here's my configuration for User and Role model:
User.php:
public function roles()
{
return $this->belongsToMany(Role::class);
}
Role.php:
public function users()
{
return $this->belongsToMany(User::class);
}
AuthController.php:
public function details()
{
$user = Auth::user();
$user['role'] = $user->roles;
return response()->json(['success' => $user], 20);
}
To which laravel responds with the following:
{"user":{"id":4,"first_name":"Jill","last_name":"mclane","email":"jill#g.co","role":[{"id":1,"role_name":"vendor","pivot":{"user_id":4,"role_id":1}}]}}
I want to get role_name column as an array for a selected user. eg. role:['vendor','admin']. I used select method but it returns pivot along with other columns:
$user['role'] = $user->roles()->select('role_name')->get();
//returns {"user":{"id":4,"first_name":"Jill","last_name":"mclane","email":"jill#g.co","role":[{"role_name":"vendor","pivot":{"user_id":4,"role_id":1}}]}}
You can use the pluck method on the Collection to do this:
$user['role'] = $user->roles->pluck('name');
You have loaded the roles relationship when accessing $user->roles though. Though it is not showing in your current output.
This method also exists for Query Builder.
$user['role'] = $user->roles()->pluck('name');
This would not load the relationship.
Laravel 7.x Docs - Collections - Available Methods pluck
Laravel 7.x Docs - Queries - Retrieving Results - Retrieving A List Of Column Values pluck
use first() function to get single record
$user['role'] = $user->roles()->first()->role_name;
An easy and good way to approach something like this would be to use API resources. That way you can customize the JSON response from the controller.
See: https://laravel.com/docs/7.x/eloquent-resources

Laravel : Use Pivot table to get group with their respective roles

I'm trying to get All roles in a user group in eloquent style.
//this function is defined in the ModelUserGroup
public function roles(){
return $this->hasMany(ModelGroupRole::class, 'group_id','id');
}
I'm trying to get all roles like this:
ModelUserGroup::with('roles')->get(),
I also tried ->hasManyThrough but it is not working for me.
I need all roles data like id,name, etc. using with.
Looks like you need a belongsToMany relationship.
In your UserGroup model.
public function roles()
{
// Assuming your role model is named ModelRole...
return $this->belongsToMany(ModelRole::class, 'group_role', 'group_id', 'role_id');
}
Now you can do the following:
$group = ModelUserGroup::with('roles')->first();
dd($group->roles); // will be a collection of ModelRole's
Answered on my phone so there may be syntax errors.
As stated here in the many to many section, you have got to define the relationships as the follwing:
in User_Group :
public function roles(){
return $this->belongsToMany('App\Pathto\Role', 'group_role','group_id','role_id');
}
in Role:
public function user_groups(){
return $this->belongsToMany('App\Pathto\UserGroup', 'group_role', 'role_id', 'group_id');
}
Edit: ModelUserGroup::with('roles')->get() should work just fine then.
(of course, change pathto with your path to the models.)

Fetch multiple tables through hasManyThrough Laravel Eloquent

Database
I'm kind of new to databases and I made this small database, but I have problems fetching data from it.
Im trying to get all the racers from the logged in user, and it works properly, but if I enter $pigeons = $user->racer I only get back the racer table. I would like to know the attributes of the racers from the pigeons table aswell. I've made it work with query builder left joining the tables but I'm not sure why I set up this relationship if I can't use Laravel inner method.
In the User model I have these relationships:
public function pigeons(){
return $this->hasMany('App\Pigeon');
}
public function racers(){
return $this->hasManyThrough('App\Racer', 'App\Pigeon');
}
This is the Pigeon model:
public function user(){
return $this->belongsTo('App\User');
}
public function racer(){
return $this->hasMany('App\Racer');
}
}
And this is the Event model:
public function race(){
return $this->hasOne('App\Race');
}
public function racers(){
return $this->hasMany('App\Racer');
}
And this is what my EventsController looks like with the working alternative method and the commented not working.
public function upcoming(){
$id = auth()->user()->id;
$user = User::find($id);
$pigeons = DB::table('racers')->leftJoin('pigeons', 'racers.pigeon_id', '=', 'pigeons.id')->where('pigeons.user_id', '=', $id)->get();
//$pigeons = $user->racers;
return view('events.upcoming')->with('pigeons', $pigeons);
}
This is what I get with $user->racers or $user->racers()->get():
[{"id":1,"pigeon_id":14,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null},{"id":2,"pigeon_id":15,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null},{"id":3,"pigeon_id":16,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null}]
And this is what I want to get, its not correct either since I should get id:1 but I want to pass to view these additional datas aswell like gender, color, ability (but they are in pigeons table not in racers).
[{"id":14,"pigeon_id":14,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"hen","color":"blue","ability":38},{"id":15,"pigeon_id":15,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"hen","color":"blue","ability":48},{"id":16,"pigeon_id":16,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"cock","color":"blue","ability":11}]
To get the pigeons, what you would have to do is $pigeons = $user->racers()->get();. You can see an example of this in Laravel's official documentation https://laravel.com/docs/5.5/eloquent-relationships#introduction.

Laravel - How to chain Eloquent relationship - Eager Loading

I'm using Laravel 5.4, Laravel Roles from here and Eloquent relationships.
I'm trying to retrieve the users of a company along with their roles.
User::find(1)->roles gets me the user's roles whose id =1
Company::find(1)->users gets me all the users that belongs to the company whose id =1 (without the roles of users).
Company::find(1)->users->roles returns an error Property [roles] does not exist on this collection instance.
Questions
Is it possible to do what I want to do ?
If so, how should I do it ?
User.php
class User extends Authenticatable
{
use HasRoleAndPermission;
public function company()
{
return $this->belongsTo('App\Company');
}
public function user()
{
return $this->belongsTo(User::class);
}
}
HasRoleAndPermission.php
trait HasRoleAndPermission
{
public function roles()
{
return $this->belongsToMany(config('roles.models.role'));
}
}
Company.php
class Company extends Model
{
public function users() {
return $this->hasMany('App\User');
}
}
$company = Company::with('users.roles')->find(1);
Will load all the users, and all the roles for each user.
Update
According to your comment, you don't want the company data. Just users and roles Using eager loading and relationship existence.
$users = User::with('roles')
->whereHas('company' => function($query){
$query->where('name', '=', 'company'); //If you don't have the company ID
})->get();
Without relationship existence
$users = User::where('company_id', 1)->with('roles')->get();
1 company has many users.
1 users has many roles.
You are trying to get the roles of a collection of users (the property only exists for one user) thus, the property doesn't exists for the collection.
If you want to get all the roles of all users in the company, you might try the above code:
$roles = [];
Company::find(1)->users->foreach(function($user) {
$roles = array_merge($roles, $user->roles);
});
--------- edit ---------
For eager loading the roles of users, you must use with, as suggested by #Ohgodwhy, but I'd refactor a little:
$users = User::with('roles')->where('company_id', $companyId)->get();
Now you have the array of users eager loading their roles. You still can't access directly $users->roles, you must first get a user, only then get its roles.

Categories