Reverse contains() in laravel? - php

I'm new to laravel,
I'm trying to get a row from a table according to it's Many-to-Many relationship with another table.
You know when you pass multiple ids in contain() to check if they have relationship with that row or not, like this:
$row->contains([4,6,9]);
i want to reverse this, where i can use the ids [4,6,9] to get any row from the other table linked with them.

Let's say you have this two models: User and Role that makes many-to-many relationship.
If you defined your relationships properly:
/** User.php */
public function roles()
{
return $this->belongsToMany(Role::class);
}
-
/** Role.php */
public function users()
{
return $this->belongsToMany(User::class);
}
Then you could use the relationship to accomplish what you are trying to do.
From the related object:
$user = User::find(1);
// getting all the roles attached with a user:
$roles = $user->roles;
// getting all the roles attached with a user that has certain ids:
$roles = $user->roles()->whereIn('id', [2, 4, 6])->get();
Also, you could find your desired related model using the collection instance that return the relationship:
$user = User::find(1);
// getting all the roles attached with a user:
$roles = $user->roles;
// getting a specific role attached to a user:
$specific_role = $roles->where('id', 6)->first();

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

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 5.* - Eloquent Many to Many Relationships

I have the following tables
USERS = username | email | name
FOLLOWERS = user_id | follower_id
When a logged-in user clicks on "follow" my code saves his id inside followers.follower_id, and the id of user who he wants to follow is saved inside followers.user_id.
To see how many followers a user has and how many users a user is following I use:
$followers = Follower::where('user_id', $user->id)->count();
$following = Follower::where('follower_id', $user->id)->count();
This works well, but I would like to show information about the followers of one user. I've tried the following:
$first_follower = $followers[0]->user->username;
But it return the user followed not the follower.
I am wondering how I can get information about the follower
User Model
protected $fillable = ['username','email','name'];
public function follow() {
return $this->hasMany('Shop\Follower');
}
Follower Model
protected $fillable = ['user_id','follower_id'];
public function user() {
return $this->belongsTo('Shop\User');
}
An example how you should implement relations, is above. It's many users to many users thru followers table. You probably dont need a follower model, cause you already have a user model. Your code will work after some analyze and enhancements, but i will highly recomend you to make something like this inuser model instead:
public function followers()
{
return $this->belongsToMany('App\User','followers','user_id','follower_id');
}
public function following_users()
{
return $this->belongsToMany('App\User','followers','follower_id','user_id');
}
Than you can access a followers $user->followers (this will return eloquent collection and you will be able to do whatever you want with this according to laravel docs collection api) and a certain one like $user->followers[0]
Hope i get your answer rigth.
If I get this right the followers are instances of the User class/model, so you don't need a Follower model. You can just define a Many To Many Relationship
In your User model you can add:
public function followers()
{
return $this->belongsToMany('Shop\User', 'followers', 'user_id ', 'follower_id');
}
public function following()
{
return $this->belongsToMany('Shop\User', 'followers', 'follower_id', 'user_id');
}
Than you can access the user followers just by $user->followers which will return a Laravel Collection and with $user->following you can access the ones that the user is following.
//Get the count of all followers for $user
$count = $user->followers()->count();
//Get the count of all followed by $user
$count = $user->following()->count();
//Get the username of the first follower
$follower = $user->followers()->first();
echo $follower->username;
//Loop trough all followers
foreach ($user->followers as $follower) {
echo $follower->username;
}
Defining this relation can help you save/delete followers just by using the attach() and detach() methods
// The $user will be followed by an user with $followerId
// A record in the `followers` table will be created with
// user_id = $user->id and follower_id = $followerId
$user->followers()->attach($followerId);
// The $user will stop be followed by an user with $followerId
$user->followers()->detach($followerId);
A side note:
There is a difference between calling the followers() method and calling the followers property. The first will return BelongsToMany relation and you can call all the Eloquent query builder method on it and the later will return a Collection
/** #var Illuminate\Support\Collection */
$user->followers;
/** #var Illuminate\Database\Eloquent\Relations\BelongsToMany */
$user->followers();

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