I have the following tables:
occupations <- occupation_user -> users
occupations <- occupation_vacancy -> vacancies
And I want to find all vacancies that the current user shares occupations with...
I have it working by querying the occupation_user table to retrieve the users occupations and then using whereIn with the resulting array on the vacancies table.
I have a nagging feeling there may be a better way but I can't see it?
Can anyone advise?
public function scopeFilteredForUser($query, $user_id, $university_id) {
$query->with('occupations')->select('id','university_id','title','employer_name','remuneration','city','state','country','commencement_date','num_positions','expire','contract_type','contract_hours')
->whereDoesntHave('users', function($q) use($user_id) {
$q->where('user_id', $user_id);
})
->withOccupationsFilter($user_id);
}
public function scopeWithOccupationsFilter($query, $user_id) {
$user_occupations = DB::table('occupation_user')
->select('occupation_id')
->where('user_id', '=', $user_id)
->lists('occupation_id');
if (empty($user_occupations)) {
return $query;
}
return $query->whereIn('id', function ($query) use ($user_occupations)
{
$query->select('vacancy_id')
->from('occupation_vacancy')
->whereIn('occupation_id', $user_occupations);
});
}
Related
I want to retrieve all the offices ( with the desks eager loaded) but I only want offices where the user possess all the desks in the office
I have the following models and relationships between them :
I came up with the following query which seems to almost work :
<?php
Office::query()
->whereHas('desks', function ($query) {
$query->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
});
})
->with(['desks'])
->get();
The current query seems to return a result where if a user own a single desk in the office then the office is returned in the query. Am I missing something ? Is there a way to be more strict in the whereHas to have some kind of and instead of a or
Thanks in advance for your help ;)
Edit :
Thanks to Tim Lewis's comment I tried this with not more result :
<?php
Office::query()
->withCount('desks')
->whereHas('desks', function ($query) {
$query
->whereHas('possessedDesks', function ($query) {
$query->where('user_id', auth()->id);
})
->has('possessedDesks', '=', 'desks_count');
})
->with(['desks'])
->get();
Edit 2 :
I managed to get exactly what I need, outside of an Eloquent query. The problem is still persist since I need it to be in an Eloquent query because I need this for a query string request (Search engine).
<?php
$offices = Office::query()
->with(['desks'])
->get();
$possessedDeskIds = auth()->user->with('possessedDesks.desk')->possessedDesks()->get()->pluck('desk.id');
$fullyOwnedOffices = [];
foreach($offices as $office) {
$officeDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($officeDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneAromaIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$fullyOwnedOffices[] = $office;
}
}
Edit 3 :
Ok, With the previous edit and the need to have some kind of one line query (for the query string of a search engine) I simplified the request since the nested whereHas where hard to make sense of.
It's not the prettiest way to do it, It add more query for the process, but with the code from the Edit2 I can generate an array of Ids of the Office where all the Desk are possessed by the user. With that I can just say that when this option is required in the search engine, I just select the ones my algorithm above gave me and no more logic in the query.
If some genius manage to find a way to optimize this query to add the logic back inside of it, I'll take it but for now it works as expected.
Thanks Tim for your help
<?php
class SearchEngineController extends Controller
{
public function index(Request $request) {
$officesWithAllDesksPossessed = collect([]);
if ($request->has('with_possessed_desks') && $request->input('with_possessed_desks')) {
$publicOffices = Office::query()
->isPublic()
->with(['desks'])
->get();
$possessedDeskIds = currentUser()
->possessedDesks()
->with('desk')
->get()
->pluck('desk.id');
foreach($publicOffices as $office) {
$publicOfficesDeskIds = $office->desks()->pluck('id');
$atLeastOneDeskIsNotPossessed = false;
foreach($publicOfficesDeskIds as $officeDesk) {
if ($possessedDeskIds->doesntContain($officeDesk)) {
$atLeastOneDeskIsNotPossessed = true;
break;
}
}
if (!$atLeastOneDeskIsNotPossessed) {
$officesWithAllDesksPossessed->push($office);
}
}
$officesWithAllDesksPossessed = $officesWithAllDesksPossessed->pluck('id');
}
return Inertia::render('Discover', [
'offices'=> OfficeResource::collection(
Office::query()
->isPublic()
->with(['desks'])
->when($request->input('search'), function ($query, $search) {
$query->where('name', 'like', "%{$search}%");
})
->when($request->input('with_possessed_desks'), function ($query, $active) use($officesWithAllDesksPossessed) {
if ($active === 'true') {
$query->whereIn('id', $officesWithAllDesksPossessed);
}
})
->paginate(10)
->withQueryString()
),
'filters' => $request->only(['search', 'with_possessed_desks']),
]);
}
}
I have the User model, I also have the Post model.
I would like to get 4 users through the newest posts of my entire Post model (taking into account that even a single user could have n number of newest posts) and then get the posts of each user (two for each user) obtained through of the relationship, something like that in case it is not understood very well
I have no problem getting the relationship from the blade, but what I can't get are the 4 users with the newest posts
User model
public function posts()
{
return $this->hasMany(Post::class);
}
Post model
public function user()
{
return $this->belongsTo(User::class);
}
This is the query I was doing, but this will simply return any 4 users (I guess by their id) and each user with their 2 newest posts, which is not what I need
User::query()
->whereHas('posts', function ($query){
$query->where('state', PostStateEnum::PUBLISHED)
->orderBy('updated_at')
->take(2);
})
->take(4)
->get();
ADD:
I have tried with join() but I get the same user
My code:
return User::query()
->join('posts', 'posts.user_id', '=', 'users.id')
->where('posts.state', '=', PostStateEnum::PUBLISHED)
->orderByDesc('posts.updated_at')
->select('users.*')
->with('posts', function ($query) {
$query->where('state', PostStateEnum::PUBLISHED)
->orderByDesc('updated_at')
->take(2)
->get();
})
->take(4)
->get();
that return 4 users, but all are the same user
I found subquery ordering
public function getUsersByNewerPosts()
{
return User::query()
->whereHas('posts', function ($query) {
$query->where('state', PostStateEnum::PUBLISHED);
})
->orderByDesc(
Post::select('updated_at')
->whereColumn('user_id', 'users.id')
->where('state', PostStateEnum::PUBLISHED)
->orderByDesc('updated_at')
->limit(1)
)
->take(4)
->get();
}
I have two models with relations as defined below
Order
public function owner()
{
return $this->belongsTo(User::class, 'owner_id');
}
User
public function company(){
return $this->belongsTo(Company::class, 'company_id');
}
company table have 'title' field.
what I want is to get all the orders sorted/order by company title. I've tried different solution but nothing seems to work. Any help or hint would be appreciated.
Recent solution that I tried is
$query = OrderModel::whereHas('owner', function($q) use ($request){
// $q->orderBy('owner');
$q->whereHas('company',function ($q2) use ($request){
$q2->orderBy('title',$request->get('orderByDirection') ?? 'asc');
});
});
but I am not getting user and company relation in query results. also the result remains same for 'ASC' and 'DESC' order.
You could sort the query after adding join like:
return Order::join('users', 'users.id', '=', 'owner_id')
->join('companies', 'companies.id', '=', 'users.company_id')
->orderBy('companies.title')
->select('orders.*')
->get();
You can define new relations in User and Company models.
User
public function orders()
{
return $this->hasMany(Order::class);
}
Company
public function users()
{
return $this->hasMany(User::class);
}
Now you can fetch companies that are in asc order and with the use of relation, you can fetch users and orders. So the ORM like be,
$companies = Company::with('users.orders')->orderBy('title', 'ASC')->get();
So these are the company-wise orders. You can use this too.
i have a question about the code above , i want to search with criteria from 2 extra tables
I want 'charge' from charges table , 'name' from user table and also 'name' from customer table
all has binds the above query runs but the doesnt fetch data from customers->name any idea how to make it work?
public function scopeSearch($query, $val){
return $query->has('customer')
->whereHas('user', function($query) use ($val) {
$query->where('tasks','like','%'.$val.'%')
->Orwhere('name','like','%'.$val.'%');
})
->with('user')
->with('customer');
}
You can follow the documentation about adding stuff to your relation query (whereHas).
So, you should have this:
public function scopeSearch($query, $val){
return $query->with(['user', 'customer'])
->whereHas('user', function($query) use ($val) {
$query->where('tasks','like','%'.$val.'%')
->Orwhere('name','like','%'.$val.'%');
})
->whereHas('customer', function($query) use ($val) {
$query->where('name','like','%'.$val.'%');
});
}
See that you had only used whereHas for users but not customers...
Finally worked! after some research i found that the problem was my using of or statement
the code above works for me:
public function scopeSearch($query, $val){
return $query->whereHas('user', function($query) use ($val) {
$query->where('tasks','like','%'.$val.'%')
->orWhere('name','like','%'.$val.'%');
})
->orWhereHas('customer', function($query) use ($val) {
$query->where('name', 'LIKE', '%'.$val.'%');
})
->with('user', 'customer');
}
I am using 2 tables upon displaying my users in my users>index.blade
these 2
USER table
and COLLECTOR_MEMBERS table
The result is this
Now my problem is I want to connect to the other table called
COMMISSIONS table
to achieve this result
MODELS
COMMISSIONS Model
USER
COLLECTOR MEMBER
USER Controller index function
public function index(Request $request)
{
$users = User::all();
$admins = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'admin');
})->get();
$collectorList = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'collector');
})->with('collectorList')->get();
$borrowers = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'borrower');
})->get();
$userProfile = Auth::user()->id;
if (Auth::User()->hasRole(['borrower','collector'])){
return redirect('dashboard/profile/'.$userProfile);
}
return view('dashboard.users.index', compact('users','profile'))
->with('admins',$admins)
->with('borrowers',$borrowers)
->with('collectorList',$collectorList);
// ->with('collectorBorrowers',$collectorBorrowers);
}
How wan I display the commission_amount column from commissions table? to make my list like this
You could use sum aggregate function, your code should look like this.
$collectorList = User::whereHas('roles', function ($q) {
$q->where('roles.name', '=', 'collector');
})->with(['collectorCommission' => function($query) {
$query->sum('commission_amount');
}])->get();
Assuming that you have this relationship in your user model
public function collectorCommission() [
return $this->hasMany('App\Commissions', 'user_id');
}
You cant use belongsToMany relationship since this relationship
requires you an intermediary table in your second argument.
You should use hasMany relationship considering that one user has many commissions.