Laravel whereHas and for each of collection - php

I would need something like this:
$user_ids = [1,2,3]; // 1 as logged user
$chats = Chat::whereHas('users', function ($q) { $q->where('users.id','=',1); })->get();
$c = null;
foreach ($chats as $chat) {
if ($chats->users->pluck('id')->diff($user_ids)->count() === 0) {
$c = $chat;
break;
}
}
return $c;
Is there some one-liner or simpler solution in laravel to get chat based on relation collection that equals to array of ids without same order within array?

If I understand you correct, you want the first chat that has exactly these user IDs right? then try this:
$user_ids = [1, 2, 3];
$chat = Chat::has('users', '=', count($user_ids))
->where(function ($query) use ($user_ids) {
foreach ($user_ids as $user_id) {
$query->whereHas('users', function ($q) use ($user_id) {
$q->where('id', $user_id);
});
}
})
->first();

$chat = Chat::whereHas('users', fn ($q) => $q->whereIn('users.id', $user_ids), '=', count($user_ids))
->whereDoesntHave('users', fn ($q) => $q->whereNotIn('users.id', $user_ids))
->first();
This works

Related

How to use a list of IDs in a query

I have a query that filter users to display to admins by ID, now I would like to expand this query to accommodate more IDs like 2,3,4,5 and 6, so how do I arrange it in a list
public function vipusers()
{
$data['title'] = 'Vip Users';
$is_super = !auth()->guard('admin')->user()->is_super;
$data['users'] = Users::when($is_super, function ($q) {
$q->where('id', '!=', 1);
})
->orderBy('id', 'DESC')->get();
return view('admin.dashboard.manage', $data);
}
You can use whereIn :
https://laravel.com/docs/8.x/queries#additional-where-clauses
$ids = [2, 3, 4, 5, 6];
$users = Users::whereIn('id', $ids)->orderBy('id', 'DESC')->get();
...
Extending #Bazaim's answer.
Consider using a function to iterate through all the users, by passing the id from table to the function. Consider using the following snippet.
public function vipusers($id)
{
$data['title'] = 'Vip Users';
$is_super = !auth()->guard('admin')->user()->is_super;
$data['users'] = Users::when($is_super, function ($q) {
$q->where('id', '!=', $id);
})->orderBy('id', 'DESC')->get();
return view('admin.dashboard.manage', $data);
}
This solved what I'm trying to achieve according to https://laravel.com/docs/8.x/queries#where-clauses
public function vipusers()
{
$data['title'] = 'Vip Users';
$is_super = !auth()->guard('admin')->user()->is_super;
$data['users'] = Users::when($is_super, function ($q) {
$q->where('id', '!=', 1)
->where('id', '!=', 2)
->where('id', '!=', 3);
})
->orderBy('id', 'DESC')->get();
return view('admin.dashboard.manage', $data);
}

Foreach loop only returns the latest result from a query in laravel

I want to loop through a collection and do a query for each item of this collection but the foreach loop only returns the latest result. How can I solve this problem?
foreach ($conversations as $conversation) {
if ($conversation->id_participant1 !== Auth::user()->id) {
$users = User::where(function ($query) use ($conversation) {
$query->where('id', $conversation->id_participant1);
})
->get();
} else {
$users = User::where(function ($query) use ($conversation) {
$query->where('id', $conversation->id_participant2);
})
->get();
}
}
you are overwriting in every loop $user variable
you can create empty array on the top of foreach, and push users to that variable
$users = []
foreach ($conversations as $conversation) {
if ($conversation->id_participant1 !== Auth::user()->id) {
$users[] = User::where(function ($query) use ($conversation) {
$query->where('id', $conversation->id_participant1);
})
->get();
} else {
$users[] = User::where(function ($query) use ($conversation) {
$query->where('id', $conversation->id_participant2);
})
->get();
}
}

Removing item from collection change its type - Laravel

I'm using Laravel 5.4. This code retrieves users belonging to a company and return them to the client side.
The following query is used to get the user of the company
$users = User::where('company_id', '=', $idCompany)
->with([
'roles' => function($q) {
$q->whereBetween('level', [50, 999]);
}
])->get();
Situation A
return $users;
$users is an array of objects [{user1}, {user2}]
Situation B
foreach($users as $key=> $user) {
if(count($user->roles) == 0){$users->forget($key);}
}
return $users;
I remove some item from the collection and the
$users is an object of objects {{user1}, {user2}}
Removing an item from the collection seems to change the type of the variable $users
How could I remove some item from the collection while maintaining
the array of object?
EDIT
Here is the correct query
$users = User::whereHas('roles', function ($query) {
$query->whereBetween('level', [50, 999]);
})
->with('roles')
->where('company_id', '=', $idCompany)
->get();
return $users;
After manipulating the collection, you need to add ->all() to get the remaining collection;
return $users->all();
You could also do it this way
$filtered = $users->reject(function ($value, $key) {
return count($user->roles) == 0;
});
return $filtered->all();
As proposed by Alex in the comments, you could use whereHas() instead of with() to get directly all the users having a role between 50 and 999
$users = User::whereHas('roles', function ($query) {
$query->whereBetween('level', [50, 999]);
})
->where('company_id', '=', $idCompany)
->get();

Laravel array whereIn()

I have a form to filter items:
and I'm looking for something similar to this in Laravel 5.3:
// some variables get from request()->input('...')
$mode = ['A'];
$type = ['a', 'b'];
$group = [0, 1];
// desirable query
$results = Item::whereIn([
['mode_id', $mode],
['type_id', $type],
['group_id', $group]
])->paginate(10);
I can do this
$results = Item::whereIn('mode_id', $mode)
->whereIn('type_id', $type)
->whereIn('group_id', $group)
->paginate(10);
but it's not a dynamic way. For example, if a user select nothing in mode, the query returns an empty array.
We can use conditional clauses:
$results = Item::
when(!empty($mode), function ($query) use ($mode) {
return $query->where('mode_id', $mode);
})
->when(!empty($type), function ($query) use ($type) {
return $query->where('type_id', $type);
})
->when(!empty($group), function ($query) use ($group) {
return $query->where('group_id', $group);
})
->paginate(10);
You can do:
$qb = Item::newQuery();
if (!empty($mode))
{
$qb->whereIn('mode_id', $mode);
}
if (!empty($type))
{
$qb->whereIn('type_id', $type);
}
if (!empty($group))
{
$qb->whereIn('group_id', $group);
}
$results = $qb->paginate(10);
Or build your whereIn associative array w/o empty where's before passing it on.

Laravel Eloquent Query: Using WHERE with OR AND OR?

How do I say WHERE (a = 1 OR b =1 ) AND (c = 1 OR d = 1)
For more complicated queries am I supposed to use raw SQL?
Make use of Logical Grouping (Laravel 7.x/4.2). For your example, it'd be something like this:
Model::where(function ($query) {
$query->where('a', '=', 1)
->orWhere('b', '=', 1);
})->where(function ($query) {
$query->where('c', '=', 1)
->orWhere('d', '=', 1);
});
If you want to use parameters for a,b,c,d in Laravel 4
Model::where(function ($query) use ($a,$b) {
$query->where('a', '=', $a)
->orWhere('b', '=', $b);
})
->where(function ($query) use ($c,$d) {
$query->where('c', '=', $c)
->orWhere('d', '=', $d);
});
Incase you're looping the OR conditions, you don't need the the second $query->where from the other posts (actually I don't think you need in general, you can just use orWhere in the nested where if easier)
$attributes = ['first'=>'a','second'=>'b'];
$query->where(function ($query) use ($attributes)
{
foreach ($attributes as $key=>value)
{
//you can use orWhere the first time, doesn't need to be ->where
$query->orWhere($key,$value);
}
});
if you want to use parentheses in laravel 4 and don't forget return
In Laravel 4 (at least) you need to use $a, $b in parentheses as in the example
$a = 1;
$b = 1;
$c = 1;
$d = 1;
Model::where(function ($query) use ($a, $b) {
return $query->where('a', '=', $a)
->orWhere('b', '=', $b);
})->where(function ($query) use ($c, $d) {
return $query->where('c', '=', $c)
->orWhere('d', '=', $d);
});
This is my result:
Simply Use in Laravel Eloquent:
$a='foo', $b='bar', $c='john', $d='doe';
Coder::where(function ($query) use ($a, $b) {
$query->where('a', '=', $a)
->orWhere('b', '=', $b);
})->where(function ($query) use ($c, $d) {
$query->where('c', '=', $c)
->orWhere('d', '=', $d);
})->get();
Will produce a query like:
SELECT * FROM <table> WHERE (a='foo' or b='bar') AND (c='john' or d='doe');
You can also query the first or condition and later you can apply another or condition
$model = Model::where('a',1)->orWhere('b',1);
now apply another condition on that $model variable
$model1 = $model->where('c',1)->orWhere('d',1)->get();
$a, $b, $c, $d can be dynamic values by the query
->where(function($query) use ($a, $b)
{
$query->where('a', $a)
->orWhere('b',$b);
})
->where(function($query) use ($c, $d)
{
$query->where('c', $c)
->orWhere('d',$d);
})
Another way without using Modal
Database: stocks
Columns:id,name,company_name,exchange_name,status
$name ='aa'
$stocks = DB::table('stocks')
->select('name', 'company_name', 'exchange_name')
->where(function($query) use ($name) {
$query->where('name', 'like', '%' . $name . '%')
->orWhere('company_name', 'like', '%' . $name . '%');
})
->Where('status', '=', 1)
->limit(20)
->get();
You can also use query scopes to make things a bit tidier, so you can do something like:
Invoice::where('account', 27)->notPaidAt($date)->get();
Then in your model
public function scopeNotPaidAt($query, $asAt)
{
$query = $query->where(function ($query) use ($asAt) {
$query->where('paid', '=', '0000-00-00')->orWhere('paid', '>=', $asAt);
});
return $query;
}
YourModel::where(function ($query) use($a,$b) {
$query->where('a','=',$a)
->orWhere('b','=', $b);
})->where(function ($query) use ($c,$d) {
$query->where('c','=',$c)
->orWhere('d','=',$d);
});
You can use:
Model::where('table_column', 'value')->orWhere('table_column', 'value')->get()
Best way to use sql brackets use callback function in laravel eloquent.
YourModal::where(function ($q) {
$q->where('a', 1)->orWhere('b', 1);
})->where(function ($q) {
$q->where('c', 1)->orWhere('d', 1);
});
You don't have to use = symbol, it's come as the default
Lest say if you have a query that contain brackets inside a brackets
WHERE (a = 1 OR (b = 1 and c = 5))
YourModal::where(function ($q) {
$q->where('a', 1)->orWhere(function($q2){
$q2->where('b', 1)->where('c', 5);
});
});
lest say you want to make values dynamics
YourModal::where(function ($q) use($val1, $val2) {
$q->where('a', $val1)->orWhere(function($q2) use($val2){
$q2->where('b', $val2)->where('c', $val2);
});
});
ModelName::where(function ($query) use ($a) {
$query->where('a', '=', $a)->orWhereNull('a');
})
->where(function ($query) use ($b,$c) {
$query->where('b', '=', $b)
->orWhere('c', '=', $c);
})->where('d',$d);
OUTPUT QUERY:
SELECT * FROM ModelName WHERE (a='a' or a is null) AND (b='b' or
c='c') AND d='d';
For eloquent query builder the following query will not work:
MODELNAME::where('a', 1)->orWhere('b', 1)->where('c', 1)->orWhere('d', 1);
But you can use this code:
MODELNAME::where(function($a) {
$a->where('a', 1)->orWhere('b', 1);
})->where(function($a) {
$a->where('c', 1)->orWhere('d', 1);
});
You can use the second query and it will work perfectly.
This works for me
$business = Model::where('model_id', $model_id1)->orWhere('model_id', $model_id2)->first();

Categories