How to query table by relation table column condition - php

I have model Users
class Users extends Model implements AuthenticatableContract
{
use Authenticatable,HasApiTokens;
protected $primaryKey = 'user_id';
protected $fillable = ['email','password','email_token', 'verified'];
public function user_info()
{
return $this->hasOne('App\Models\UserInfo','user_id');
}
}
In controller I want to query all users where relation table column "kind" equal to 1 .
So Users table has user_info_id(one to one) . User_info has kind_id.
I want query users by relation table column kind_id.
I can do it by left join . But How can I do it with relation?
I tried like this but it doesnt work
$univer_list = Users::with('user_info')->where('is_university',1)
->where('kind_id',1);

You can use whereHas to query based on the existence of a relationship:
$univer_list = Users::where('is_university', 1)
->whereHas('user_info', function ($query) {
$query->where('kind_id', 1);
})->get();
Get only Users, which should be named User, that have a relationship with UserInfo where kind_id is equal to 1.
Laravel 6.x Docs - Eloquent - Relationships - Querying Relationship Existence

You can make this condition in with
$univer_list = Users::with(['user_info' => function($q) {
$q->where('kind_id', 1);
}])->where('is_university', 1)->get();
I assumed that your is_university exists in users table and your kind_id column exists in user_info table.

Related

Laravel Eloquent finding models with more than one relation to another model on another table [duplicate]

This question already has answers here:
laravel BelongsTo relationship with different databases not working
(13 answers)
Closed 2 years ago.
I have two models using different tables on two different connections, User and UserInfo.
User has a UserInfo hasMany relation:
public function userInfo()
{
return $this->hasMany('path\to\UserInfo','User_ID');
}
and UserInfo has a User belongsTo relation:
public function user()
{
return $this->belongsTo('anotherpath\to\User', 'User_ID', 'User_ID');
}
I would like to find the first user with more than one UserInfo, however I believe that because they are on different tables on the database I am having issues.
This call
$patient = Patient::with('UserInfo')
->withCount('UserInfo')
->having('UserInfo_count', '>', 1)
->first();
Works as expected for other relations and is what I am trying to achieve, but not with this one. The difference being that the two models are on different tables. When I call this in Tinker, I get the error:
Illuminate/Database/QueryException with message 'SQLSTATE[42S02]:
Base table or view not found: 1146 Table '(TableName).UserInfo'
doesn't exist (SQL: select `User`.*, (select count(*) from `UserInfo`
where `User`.`User_ID` = `eob`.`User_ID`) as `UserInfo_count `User`
having `UserInfo_count` > 1 limit 1)'
Any ideas? I'm very new to eloquent and Laravel in general, sorry if I've gotten any terminology wrong or am missing something simple. Thanks!
maybe your table names are not defined properly as standard. so you can use table property to bind table name in model.
what is the standard to define table name.
Illuminate/Database/Eloquent/Model.php
/**
* Get the table associated with the model.
*
* #return string
*/
public function getTable()
{
if (isset($this->table)) {
return $this->table;
}
return str_replace('\\', '', Str::snake(Str::plural(class_basename($this))));
}
Example
Table Model
users User
user_profiles UserProfile
Alternative
in your UserInfo model
protected $table = 'your table name';
In more thing you don't need to add with() method and with withCount() method.
$patient = Patient::withCount('UserInfo')->having('UserInfo_count', '>', 1)->first();

Laravel use a pivot field to filter polymorphic many to many relationship

I'm attaching user permissions to several different models using a polymorphic many-to-many relationship - the pivot table is called permissables:
Permissables
- id
- user_id
- permissable_type
- permissable_id
- role
- created_at
- updated_at
This is working well - I can return a list of permitted users for my Project model using:
public function users()
{
return $this->morphToMany(User::class, 'permissable')->withPivot('role')->withTimestamps();
}
If I want to filter this to just owners - ie where the pivot field role is equal to owner - I can do the following in Tinker:
Project::first()->users->where('pivot.role', '=', 'owner')
But if I try this in my model:
public function owners()
{
return $this->users()->where('pivot.role', '=', 'owner');
}
when I call Project->owners in Tinker, I get an error:
>>> Project::first()->owners
[!] Aliasing 'Project' to 'App\Project' for this Tinker session.
Illuminate/Database/QueryException with message 'SQLSTATE[HY000]: General error: 1 no such column: pivot.role (SQL: select "users".*, "permissables"."permissable_id" as "pivot_permissable_id", "permissables"."user_id" as "pivot_user_id", "permissables"."permissable_type" as "pivot_permissable_type", "permissables"."role" as "pivot_role", "permissables"."created_at" as "pivot_created_at", "permissables"."updated_at" as "pivot_updated_at" from "users" inner join "permissables" on "users"."id" = "permissables"."user_id" where "permissables"."permissable_id" = 1 and "permissables"."permissable_type" = App/Project and "pivot"."role" = owner)'
For the first question:
return $this->users->where('pivot.role', '=', 'owner');
This line works because $this->users return the users' collection with pivot(The key name is pivot). And you are using where-method to filter users collection.
For the second question:
$this->users() change the laravel code to raw sql like:
select users.*, permissables.permissable_id as pivot_permissable_id, permissables.user_id as pivot_user_id, permissables.permissable_type as pivot_permissable_type, permissables.role as pivot_role, permissables.created_at as pivot_created_at, permissables.updated_at as pivot_updated_at
from users
inner join permissables on users.id = permissables.user_id
where permissables.permissable_id = 1 and permissables.permissable_type = "App/Project"
So the Intermediate Table name is permissables, not pivot. Mysql cannot found the intermediate's column when applying where('pivot.role', 'owner') to users().
Laravel provide wherePivot method, which will add intermediate table name for you.
public function owners()
{
return $this->users()->wherePivot('role', 'owner'); // change to where pemissables.role = 'owner'
}

Transform Raw Union Query into Eloquent Relationship

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.

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

Has many through

A Venue has many Subscriptions.
A Subscription has many Subscribers (User).
Theres a pivot table, containing the relation between user_id and subscription_id.
How can I get all Subscribers from a Venue?
I have tried with:
class Venue {
/**
* Members
*/
public function members() {
return $this->hasManyThrough('App\User', 'App\Subscription');
}
}
But it fails with MySQL error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'users.subscription_id' in 'on clause' (SQL: select `users`.*, `sub
scriptions`.`venue_id` from `users` inner join `subscriptions` on `subscriptions`.`id` = `users`.`subscription_id` where `
users`.`deleted_at` is null and `subscriptions`.`venue_id` = 1)
How my Subscription model look:
`Subscription`
class Subscription extends Model {
protected $table = 'subscriptions';
/**
* Subscripers
*/
public function subscribers() {
return $this->belongsToMany('App\User');
}
/**
* Venue
*/
public function venue() {
return $this->belongsTo('Venue');
}
}
Simple question: Why are you using a third model for Subscriptions? It sounds like a normal n:m relation between User and Venue, as already written in the comments above.
class User {
public function venues() {
return $this->belongsToMany('App\Venue');
}
}
class Venue {
public function users() {
return $this->belongsToMany('App\User');
}
}
This constellation actually needs three tables, which are (i gave each model a column name):
users
- id
- name
venues
- id
- name
user_venue
- user_id
- venue_id
But to access the relations, you can simply use the Eloquent magic:
// List of all venues (as Venue models) that are in relation with User with id $id
$venues = User::find($id)->venues()->get();
// Returns the alphabetically first user that has a relation with Venue with id $id
$user = Venue::find($id)->users()->orderBy('name', 'asc')->first();
If you need to store additional information in the pivot table (e.g. when the relation has been established), you can use additional pivot fields:
user_venue
- user_id
- venue_id
- created_at
class User {
public function venues() {
return $this->belongsToMany('App\Venue')->withPivot('created_at');
}
}
class Venue {
public function users() {
return $this->belongsToMany('App\User')->withPivot('created_at');
}
}
// Returns the date of the relations establishment for the alphabetically
// first Venue the User with id $id has a relation to
$created_at = User::find($id)->venues()->orderBy('name', 'asc')->first()->pivot->created_at;
I've never tried to do whatever you are trying to do there, because it seems (with the current information) conceptually wrong. I also don't know if it is possible to set up an own model for a pivot table, but I think it should work if the pivot table has an own primary id column. It could probably be helpful if you've a third model that needs to be connected with a connection of two others, but normally that doesn't happen. So try it with pivot tables, like shown above, first.
Alright, I still don't see a good use case for this, but I can provide you a query that works. Unfortunately I wasn't able to get an Eloquent query working, but the solution should be still fine though.
class Venue {
public function members($distinct = true) {
$query = User::select('users.*')
->join('subscription_user', 'subscription_user.user_id', '=', 'users.id')
->join('subscriptions', 'subscriptions.id', '=', 'subscription_user.subscription_id')
->where('subscriptions.venue_id', '=', $this->id);
if($distinct === true) {
$query->distinct();
}
return $query;
}
}
The relation can be queried just as normal:
Venue::find($id)->members()->get()
// or with duplicate members
Venue::find($id)->members(false)->get()

Categories