Transform Raw Union Query into Eloquent Relationship - php

i've a question about Laravel Relationships.
I've a raw union query and i want to translate into a eloquent relationship.
First of all... i have 4 tables involved:
roles
id|name
permissions
id|name|code|description
permission_role
role_id|permission_id
users
id|...........|role_id
permission_user
user_id|permission_id
Inside my User model, i've this method:
/**
* #TODO: Transform this into a eloquent relationship
*
* #return Collection
*/
public function permissions()
{
$query = sprintf('
(
SELECT permissions.*
FROM permissions
INNER JOIN permission_role ON permission_role.permission_id = permissions.id
WHERE permission_role.role_id = %s
) UNION
(
SELECT permissions.*
FROM permissions
INNER JOIN permission_user ON permission_user.permission_id = permissions.id
WHERE permission_user.user_id = %s
)', $this->role_id, $this->id);
return Permission::hydrate(DB::select($query));
}
The point is, i want to fetch all permissions by the role that the user is associated, and the separated permissions associated to the user.
Can i transform this in some eloquent relationship like hasMany, belongsToMany, etc... ?

The "merge" function in Laravel collection might be able to help you.
The big differnt is that I close off the query with ->get() in advance, and I use merge() instead of union()
// In Controller
public function GetUsersWithPermission()
{
$permissionByRole = User::with('permission_role.permission')->get();
$permissionByUser = User::with('permission_user.permission')->get();
$result = $permissionByRole->merge($permissionByUser);
}
// User Model : get PermissionRole By User
public function permission_role() {
return $this->hasOne('App/Model/permission_role', 'role_id', 'role_id'); }
public function permission_user() {
return $this->hasOne('App/Model/permission_user', 'user_id', 'id'); }
// permission_role Model : get Permissions By Role
public function permission(){
return $this->hasMany('App/Model/Permissions', 'id', 'permission_id'); }
// permission_user Model : get Permissions By User
public function permission(){
return $this->hasMany('App/Model/Permissions', 'id', 'permission_id'); }
Note: I don't have your data so I can't proof it work, but it least it work on my data so should worth your try. and it return all data like: all user details, and permissions so you can use select() function to get Specific Columns.

Related

How to search in another table in Laravel with Eloquent?

I have two models:
Order
Customer
I have customer_id in orders table. Customer details (name, phone, email etc) in customerstable. But I am writing query for orders table.
Now, I want to search with Customer Name on Orders but in Orders table I just have customer_id.
How will I link up with customers table so that I can search with Customer Name. I want to do that with Eloquent.
How is this possible?
There are multiple ways of doing relationship filtering with Eloquent.
You can achieve it with whereHas or using an advanced join / left join query.
I suggest you do a research about Eloquent filtering on Laravel documentation, everything you need for your task should be there.
https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence
https://laravel.com/docs/8.x/queries#advanced-join-clauses
In models define relationships
Customer model
public function orders()
{
return $this->hasMany(Orders::class);
}
Order model
public function customer()
{
return $this->belongsTo(ustomer::class, 'foreign Key', 'id');
}
Then you can call relationships and search what you want
Customer::whereHas('orders')
First you need to create relationship in the orders model, you can use either belongsTo or hasOne relationship.
belongsTo relationship will be like as below
public function customer()
{
return $this->belongsTo(ustomer::class, 'foreign Key', 'id');
}
and the hasOne relationship will be like as below
public function customer()
{
return $this->hasOne(Customer::class, 'foreign_key', 'local_key');
}
The search function will be like as below
public function OrderSearch(Request $request){
try {
/**
* Fetching data with orders relationship
*/
$orders = OrdersModel::with(['customer'])
if(!empty($request->search)){
/**
* Searching the name key inside
* the customer relationship
*/
$orders->where(fn($query)=>
$query->whereHas('customer',fn($query2) =>
$query2->where('name','LIKE','%'.$request->search.'%'));
);
}
/**
* Returning the response
*/
return $orders->get();
} catch (\Throwable $th) {
throw $th;
}
}
Kindly refer the laravel eloquent-relationships documentation : eloquent-relationships

Property [users] does not exist on this collection instance

This error has been posted here several times but I'm encountering something a little different. I have two Tables named users and user_type. And users uses a foreign key from user_type. I have to fetch all users and their types, I'm using Laravel's Eloquent ORM to define relationships, this is a one to one relation.
Users Model:
/**
* Get the user type that user has.
*/
public function users(){
return $this->belongsTo('App\Models\UserType', 'ut_id', 'id');
}
UserType Model:
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'ut_id';
/**
* Get the user associated with the user type.
*/
public function users(){
return $this->hasOne('App\Models\Users', 'user_type_id', $this->primaryKey);
}
Fetching Controller:
$users = Users::all()->users;
According to Laravel ORM one-to-one I can access this method as a property, but it's showing me the defined error. I've also tried to access it as a method but it's saying:
Method Illuminate\Database\Eloquent\Collection::users does not exist.
I've also tried to fetch them by join() but it's returning only a few users, I don't know why:
$users = Users::where('id', '>', '0')
->join('user_type', 'user_type.ut_id', '=', 'users.id')
->select([
'user_type.ut_name',
'users.*'
])->get();
Can someone tell me what I'm doing wrong?
P.s: I just want to show all the users with their respective types
You had missed the exact foreign key between your users table and usertypes table.
First, you defined the that the foreign key of your user table is 'ut_id' base of what you had in your belongsTo relationship. On this one
/**
* Get the user type that user has.
*/
public function users(){
return $this->belongsTo('App\Models\UserType', 'ut_id', 'id');
}
Second is that, in your user type model, you used a foreign key to user table named 'user_type_id', which is at first you named it as 'ut_id' in your users table. On this one
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'ut_id';
/**
* Get the user associated with the user type.
*/
public function users(){
return $this->hasOne('App\Models\Users', 'user_type_id', $primaryKey);
}
You have to match this foreign keys you used to solve your problem.
Now, to fetch your all user with their types, your query should look like this.
$users = Users::with('users')->get();
assuming that your user table has this relationship
public function users(){
return $this->belongsTo('App\Models\UserType', 'ut_id', 'id');
}
and your user types model has this relationshio
public function users(){
return $this->hasOne('App\Models\Users', 'ut_id', $this->primaryKey);
}
in User model
public function type(){
return $this->hasOne(UserType::class, 'id');
}
in UserType Model
public function users(){
return $this->belongsToMany(User::class, 'id');
}
Your relations seem to be wrong.
Users links to UserType with id to ut_id, but userType links to User with id to user_type_id
I'm pretty sure that it should be this for userTypes
/**
* Get the user associated with the user type.
*/
public function users(){
return $this->hasMany('App\Models\Users', 'id', 'user_type_id');
}
and then this for Users
public function userTypes(){
return $this->belongsTo('App\Models\UserType', 'user_type_id', 'id');
}
Then you can eager load for all the results you want...
$users = Users::where('id', '>', '0')
->with('userTypes')
->get();

Join query that gets members of a group, and then gets groups as query in Laravel

I have a website build in Laravel.
I have two tables - Groups and Group members.
For each group_member, the row in the table has id, group_id and user_id.
The groups have a name and a description.
When a user joins a group, a row is created in the group_member table.
But I now need to get the groups that a user is part of.
So if I have user_id = 5, I need to get all the rows in group_member where user_id = 5, and then get the corresponding group, so I can query the groups.
I need to do something like $groups = Groups::whereGroup_member ...
But I cant query the model like that, because in Groups there is no where it specificies who the members are, it is just the group details - the members are specificed in group_member table.
How do I get the groups, which a member is part of using the laravel query standards?
In your User.php Model
public function group_member(){
return $this->hasMany(GroupMember::class,'user_id','id;);
}
In your GroupMember.php Model
public function group(){
return $this->belongsTo(Group::class,'group_id','id');
}
Your query will be
$users = User::with('group_member.group')->find($user_id);
You should use Many-to-Many relation:
class Group
...
public function members() {
return $this->belongsToMany(User::class); // Users (members) that belongs to Group
}
class User
...
public function groups() {
return $this->belongsToMany(Group::class, 'group_member', 'user_id', 'group_id'); // Groups that User belongs to
}
And at controller, when You have user id:
$groups = User::where('id', $user_id)->groups;
More about this written at official docs: https://laravel.com/docs/5.4/eloquent-relationships#many-to-many

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

Eloquent Users in Same Group

I have the usual users, groups and group_user tables. I know the raw SQL that I want:
SELECT group_user.group_id, users.* FROM users
INNER JOIN group_user ON users.id = group_user.user_id
WHERE group_user.group_id IN
(SELECT group_id FROM group_user WHERE user_id=?)
ORDER BY group_user.group_id;
where ? is replaced current user's id.
but, I want to use Eloquent (outside of laravel) for this. I have tried using a User model with a groups method
public function groups() {
return $this->belongsToMany('\Smawt\User\Group');
}
and a Membership model with a users method
public function users($group_id) {
return $this->where('group_id', '=', $group_id)->get();
}
and then I loop through the groups and then loop through all its members. Finally, I append all the data to get one $users object at the end, to pass through to my view.
$thisMembership = new Membership;
$myGroups = $app->auth->groups;
$users = [];
foreach ($myGroups as $myGroup) {
foreach ($thisMembership->users($myGroup->id) as $myUser) {
$thisUser = $app->user->where('id', '=', $myUser->user_id)->first();
$thisUser->group_id = $myGroup->id;
array_push($users, $thisUser);
}
}
Then in my view I loop through my $users as normal. Although this method works, it will not be very efficient as I am unable to work out how to use Eager Loading with it.
Is there a simpler more 'Eloquent' way of getting an object of users who are in the same group as the current user? I don't want just want a list, or an array, as I want to use the other methods defined in my user model.
I have been able to construct the following Eloquent query, although I am not sure this is the 'best' way:
$users = User::join('group_user', 'users.id', '=', 'group_user.user_id')
->whereIn('group_user.group_id', function($query) {
$query->select('group_id')
->from('group_user')
->where('group_user.user_id', '=', $_SESSION['user_id']);
})->orderBy('group_id', 'asc')
->get();
The Eloquent way for the relationship and use of it:
Tables: users, groups
Models: User Group
Pivot Table: group_user (id, user_id, group_id)
In User Model:
public function groups()
{
// pivot table name and related field
// names are optional here in this case
return $this->belongsToMany('Group');
}
In Group Model:
public function users()
{
// pivot table name and related field
// names are optional here in this case
return $this->belongsToMany('User');
}
Use Case (Example):
$usersWithGroup = User::with('groups')->find(1); // or get()
$groupWithUsers = Group::with('users')->find(1); // or get()
For more information check Eloquent section on documentation.
Update:
If user belongsto any group
$usersWithGroup = User::has('groups')->with('groups')->find(1);
Also using if a user belongs to specific group:
$someGroup = 'general';
$usersWithGroup = User::whereHas('groups', function($q) use($someGroup) {
$q->where('group_name', $someGroup);
})
->with('groups')->find(1);

Categories