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

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

Related

Return only specific columns of a polymorphic relationship? Laravel

is there any way that I can only get specific columns back of my polymorphic relationship?
I want to make an Api Call to retrieve a Customer but I dont want to retrieve all the data of the User just the id and the username of it.
Here ary my Models:
User:
public function userable()
{
return $this->morphTo(__FUNCTION__, 'model_type', 'model_id');
}
Customer:
public function user()
{
return $this->morphOne(User::class, 'model');
}
I dont want to work with hidden inside of the User Model because for other Api Calls i need all information of the User.
You can use this method to get the value of attributes in polymorphic relations:
$customer = new Customer();
$customer->user()->value('your_key');

Laravel Many To Many Get element that I dont have a relationship with

In laravel Many to Many relationship like the one in the Laravel Documentation example.
https://laravel.com/docs/9.x/eloquent-relationships#many-to-many
users
id - integer
name - string
roles
id - integer
name - string
role_user
user_id - integer
role_id - integer
In the Users model I have
public function roles()
{
return $this->belongsToMany(Role::class);
}
In the Roles model I have
public function users()
{
return $this->belongsToMany(User::class);
}
How can I get all Role that I don't have a relationship to.
I tried thing like
$this->availableRoles = Role::doesntHave('users')->get();
But this give me all the Role that no user at all have
Any hint on this.
If you already have a User instance (I assume that is what $this is?), then you can simply filter the relationship:
$this->availableRoles = Role::whereDoesntHave('users', function ($subQuery) {
return $subQuery->where('users.id', $this->id);
})->get();
This should return all Role elements, unless that Role has an association with the User ($this, $user, auth()->user(), etc.; adjust as required).
An alternative approach, filter out Role based on existing Roles:
$this->availableRoles = Role::whereNotIn('id', $this->roles->pluck('id'))->get();
This approach get's the roles.id for the User instance.
You can take a look at query efficiency and use the one that works best, but either approach should work fine.
Note: If $this is not a User instance, adjust:
$user = User::find($userId); // or `auth()->user()`, etc.
$availableRoles = Role::whereDoesntHave('users', function ($subQuery) use ($user) {
return $subQuery->where('users.id', $user->id);
})->get();
// OR
$availableRoles = Role::whereNotIn('id', $user->roles->pluck('id'))->get();

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.

Understanding Eloquent in Laravel

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();

Laravel Object queries - 3 tables

I have three tables like this:
**Users**
id
**Posts**
id
user_id
**Favorites**
id
user_id
post_id
Currently, I made it so when I query my posts for display, it pulls all the related user data who created the post with that row which is great! But what I'm trying to do now is also add to see if the user Authorized (Logged in) has favorited the post (row) so I can display to that they already favorited it. I don't want to re-query for every post (i think its called the N+1 problem?). I'm using Laravel4
Post model
class Post extends Eloquent{
public function user(){
return $this->belongsTo('User');
}
User model
public function posts(){
return $this->hasMany('Post');
}
PostsController
public function index()
{
$posts = Post::with('user')->paginate(25);
return View::make('index', compact('posts'));
}
Step 1. Add favorites relationship in Post model.
public function favorites() {
return $this->hasMany('Favorite');
}
When querying the Model.
$auth_user_id = Auth::user()->id;
$posts = Post::with(array('user', 'favorites' => function($query) use ($auth_user_id){
$query->where('user_id', '=', $auth_user_id);
}))->get();
For more information refer to the eager load constraints,
http://laravel.com/docs/eloquent#eager-loading
Adding a many-to-many relationship using the favorites table as pivot would be one approach.
Add favorites relationship in User model:
public function favorites() {
return $this->belongsToMany('Post', 'favorites');
}
You should then be able to get all favorites by simply accessing
Auth::user()->favorites
To find whether the current post is a favorite, use
$isFavorite = Auth::user()->favorites->has($post->id);

Categories