Laravel simple constraint on eager load - php

I have a user model, which belongs to one site. One site can have many users.
User table
id
name
email
....
company_site_id
Site table
id
name
The relationship is defined in User as follows:
public function site()
{
return User::belongsTo('App\CompanySite', 'company_site_id', 'id');
}
I want to simply get all users assigned to a site (lets say with a site ID of 1).
$users = \App\User::with(array('site' => function($query)
{
$query->where('id', '=', 1);
}))->get();
dd(count($users));
However this is returning all of the users irrespective of their site.

You are getting all the users that is why, with the use of ->get();.
Use the whereHas method. This will query your relationship and return only the models that have the relation results you are wanting/querying;
$users = User::whereHas('site', function($q)
{
$q->where('id', '=', 1);
})->get();
So Users that have site with an id of 1 will be returned in this instance.

Related

Laravel Livewire Filter Number of Transaction by User

I am using Laravel Livewire for my project. In my project there are three tables. Users, Orders, and Order details. Users are allowed to have multiple orders. In my Orders table each order is saved with user_id. I have generated a Users Table and now i am building a filter in which I want to query users tables that which users have more orders. I want to pass an integer value to filter the users.
i.e If I pass 10 then it will filter users who have ordered more than 10 orders
I have also passed the Relation to Orders Model in my User Model Like this
public function orders()
{
return $this->hasMany(Order::class, 'user_id');
}
I am trying like this but its not returning required result
if ($orders_num = ($filters['orders_num'] ?? false))
$user = $user->orders()->count('user_id');
There are several ways.
Use Eloquent withCount(), in combination with condition.
$threshold = 10;
$users = User::withCount('orders')
->get()
->where('orders_count', '>', $threshold);
Use Eloquent has()
$users = User::has('orders', '>', $threshold)
->get();
Use Collection::map()
$users = User::with('orders')
->get()
->filter(function ($user) use ($threshold) {
return $user->orders->count() > $threshold;
});

Problem in building relationships query in Laravel

Suppose we have 3 tables , User , Report and Job. In users table we having 2 columns to use, id and job_id, in report table , we have user_id and job_id'.
So I need all users with report detail, whose job_id and user_id matched User table. I want to do it with relationship.
I made that query.
Problem is how to write multiple where clause with report, (where user_id,job_id).
User:: select(*)->with("report")->paginate(10);
Try this
User model define
public function job()
{
return $this->belongsTo(Job::class);
}
Job model define
public function reports()
{
return $this->hasMany(Report::class);
}
Then use
User::select(*)->with("job.reports")->paginate(10);
Maybe you can do it like
User::whereHas('report', function ($q) use ($id, $sample) {
$q->where('id', $id)
->where('sample', $sample);
})->get();
$id are just sample variable you can pass on to closure, while whereHas able to check if there's existing relationship
or something like,
User::WhereHas('report', function ($q) use ($id, $sample) {
$q
->where('id', $id) // this part here your using where on reports table
->where('sample', $sample);
})
->where('id', $user_id); // the part here your using where on users table
->get();

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

Laravel Eloquent retrieve data from multiple tables

I have four tables
**Articles table**
id
title
body
owner_id
category_id
**Favorite articles table**
id
user_id
article_id
**User table**
id
user_name
user_type
**Category table**
id
category_name
How to get list of favorite articles (article_name,owner_name,category_name) which related to currently logged user from db using laravel eloquent?
Is it possible to do it in single line request? e.g.:
$articles_data=Auth::user()->favorite_articles->article...
EDIT
For the moment i have to use statement below:
$articles_data = FavoriteArticle::where('user_id', Auth::id())->join('articles', 'articles.id', '=', 'favorite_articles.article.id')
->join('users', 'users.id', '=', 'favorite_articles.user_id')
->join('categories', 'categories.id', '=', 'articles.id')
->get()
Which looks a bit complicated and doesn't use eloquent relations.
Completing #zippo_ answer, in the Controller you must reference what tables you want, e.g.
User.php
use Article;
public function article()
{
return $this->hasOne('App\Article');
}
and in the e.g. UserController.php
$user = User::with('article')->get();
EDIT:
if you want to relate User to Article.Category, after create a relation with user and article
Article.php
use Category;
public function category()
{
return $this->hasOne('App\Category');
}
e.g. UserController.php
$user_articles_categories = User::with('article.category')->get();
You can take advantage of laravel eager loading, which are also called as Eloquent relationships.
Eloquent relationships are defined as functions on your Eloquent model classes.
Eg. In Article Model
public function article()
{
return $this->hasOne('App\Model\Category');
}
In this way, you need to define all the relationships in the respective Model classes.
for more info: http://laravel.com/docs/5.1/eloquent-relationships

Laravel Eloquent: Get record that contains two specific relations

I have a project where a user can create conversations with other users. A conversation can belongsToMany users and user can belongsToMany conversations.
I now need to get the conversation in which two specific users participate.
I tried a combination of solutions using whereIn and I tried the following:
$c = Conversation::whereHas('users', function($q)
{
$q->whereIn('user_id', array(1,3));
})
->get();
Here the problem is that whereIn('user_id', [1,3]) gets records that contains EITHER 1 or 3. I need it to return records that contains BOTH 1 and 3.
Conversation Model
class Conversation extends Model {
public function users(){
return $this->belongsToMany('App\User');
}
}
User Model
class User extends Model {
public function conversations(){
return $this->belongsToMany('App\Conversation');
}
}
Tables
conversations:
id | subject
conversation_user:
id | user_id | conversation_id
Data from table conversation_user
Your newest edit makes a lot more sense, this is actually a very easy fix. whereHas takes two additional parameters where it's going to look for the count.
$users = [1, 3];
$c = Conversation::whereHas('users', function($q) use ($users)
{
$q->whereIn('user_id', $users);
}, '>', count($users) )
->get();
This will get all conversations where user's 1 and 3 have participated in, even if there are additional users that have participated in those conversations. If you want only the conversations with only users 1 and 3, change the > to an =.
Edit: I just realized your pivot table has an id column. This method may not work if your pivot table is going to have duplicates. For example, if you have user_id of 1 in there twice with the same conversation_id both times, it will return that conversation even though it technically only has 1 user. I suggest removing the id column and creating a composite primary key of user_id and conversation_id. If there is the possibility of duplicates, it might be safer to use lukasgeiter's solution.
You are currently querying conversations which either user 1 and/or 3 takes part in. To achieve what you want you need two whereHas calls:
$c = Conversation::whereHas('users', function($q)
{
$q->where('user_id', 1);
})
->whereHas('users', function($q)
{
$q->where('user_id', 3);
}
->get();
And if you have more than two users, add them in a loop:
$users = [1, 2, 3, 4, 5];
$c = Conversation::query();
foreach($users as $userId){
$c->whereHas('users', function($q) use ($userId)
{
$q->where('user_id', $userId);
});
}
$c = $c->get();
I hope this will help you...
$userIds = array(1,3);
$c = Conversation::whereHas('users', function($q) use ($userIds)
{
$q->whereIn('user_id', $userIds);
})
->get();

Categories