whereHas not working as expected - php

I am trying to get all Shops that have one of $item_ids = array('1', '17');.
However, the code below is not doing that as I expected it to - it just hands me all the shops.
$shops = Shop::whereHas('items', function($query) use ($item_ids) {
$query->where('items.id', '=', $item_ids[0]);
foreach(array_slice($item_ids, 1) as $item_id) {
$query->orWhere('items.id', '=', $item_id);
}
})
->get(array('shops.id', 'shops.shop_name', 'shops.lat', 'shops.lng'));
I do I only get the Shops with one of the specified Items?

You should rather use:
$shops = Shop::whereHas('items', function($query) use ($item_ids) {
$query->whereIn('id', $items_ids);
})->get();
or
$shops = Shop::whereHas('items', function($query) use ($item_ids) {
$query->whereIn('id', $items_ids);
})->select('shops.id', 'shops.shop_name', 'shops.lat', 'shops.lng')->get();

Related

Filtering in Laravel using regex

I'm trying to filter products based on query string. My goal is to get products from a collection if it's given, otherwise get every product. Could someone help me what's wrong with the following code?
$products = \App\Product::where([
'collection' => (request()->has('collection')) ? request('collection') : '[a-z]+',
'type' => (request()->has('type')) ? request('type') : '[a-z]+'
])->get();
PS.: I've also tried with 'regex:/[a-z]+', it's not working...
$products = \App\Product::where(['collection' => (request()->has('collection')) ? request('collection') : 'regex:/[a-z]+'])->get();
What you can do is use when eloquent clause, so your where clause for collections will be triggered only when the request('collection') exists, same logis applie to type as well.
$products = \App\Product::
when(request()->has('collection'), function ($q) {
return $q->where('collection', request('collection'));
});
->when(request()->has('type'), function ($q) {
return $q->where('type', request('type'));
})
->get();
Or another way if you have your request values assigned to a variable something like:
$collection = request('collection');
$type= request('type');
$products = \App\Product::
when(!empty($collection), function ($q) use ($collection) {
return $q->where('collection', $collection);
});
->when(!empty($type), function ($q) use ($type) {
return $q->where('type', $type);
})
->get();

Trying to search in a model via eloquent - laravel with optimal parameters

Im trying to figure out why my query is ignoring everything except the title and the description. The search button leading to the controller, is for filtering different type of ads , by category, by region, by price.
For example if now i search for existing ad and its found by title / keyword -> will always show, even if i choose a different region / category/ price range
Im trying to use something that will save me a lot of if statements to check if they exist in the request. Maybe other option si to use https://github.com/mohammad-fouladgar/eloquent-builder to build my query
public function index(Request $request)
{
$keyword = $request['keyword'];
$category_id = $request['category_id'];
$type_id = $request['type_id'];
$region_id = $request['region_id'];
$min_price = $request['min_price'];
$max_price = $request['max_price'];
$result = Ad::when($keyword, function ($q) use ($keyword) {
return $q->where('title', 'like', '%' . $keyword . '%')->orWhere('description', 'like', '%' . $keyword . '%');
})
->when($category_id, function ($q) use ($category_id) {
return $q->where('category_id', $category_id);
})
->when($region_id, function ($q) use ($region_id) {
return $q->where('region_id', '=', $region_id);
})
->when($type_id, function ($q) use ($type_id) {
return $q->where('adtype_id', '=', $type_id);
})
->when($min_price, function ($q) use ($min_price) {
return $q->where('price', '>=', $min_price);
})
->when($max_price, function ($q) use ($max_price) {
return $q->where('price', '<=', $max_price);
})
->paginate(8);
My get param url looks like that:
search?keyword=&category_id=0&region_id=0&type_id=0&min_price=&max_price=
The produced query in mysql when i search for existing ad by its name and i look for a different category is:
select * from `ads` where `title` like '%test test%' or `description` like '%test test%' and `category_id` = '2' limit 8 offset 0
The ad is found, but the actual category is 1, not 2, same for all others optimal parameters.
You can edit your query to look for specific relations, using whereHas. This method will allow you to add customized constraints to a relationship constraint, such as checking the content of a comment.And to check max/min price, use where method. So, you can use it like this:
$result = Ad::when($keyword, function ($q) use ($keyword) {
return $q->where('title', 'like', '%' . $keyword . '%')->orWhere('description', 'like', '%' . $keyword . '%');
})
->whereHas('category_relation_name', function ($q) use ($category_id) {
return $q->where('category_id', $category_id);
})
->whereHas('region_relation_name', function ($q) use ($region_id) {
return $q->where('region_id', $region_id);
})
->whereHas('type_relation_name', function ($q) use ($type_id) {
return $q->where('adtype_id', $type_id);
})
->where('price', '>=', $min_price);
->where('price', '<=', $max_price);
->paginate(8);

issue in laravel relationship with multiple model

user has relation with creater one to one but creater has relation with archive belongsToMany
$creatorQuery = User::query();
$cultivator_id = 2;
$creatorQuery = $creatorQuery->select('id', 'name', 'email', 'role');
$creatorQuery = $creatorQuery->with('creater', function($q) {
$q->whereHas('archive', function($q) use($cultivator_id) {
$query->where('caltivater_id', $cultivator_id);
});
});
$creators = $creatorQuery->get();
showing error mb_strpos() expects parameter 1 to be string, object given
function is supposed to be passed into creater, so you need to change your call to be a key/value array:
$creatorQuery = $creatorQuery->with(['creater' => function($q) use($cultivator_id) {
$q->whereHas('archive', function($q) use($cultivator_id) {
$query->where('caltivater_id', $cultivator_id);
});
}]);
You've said you want to get users by their caltivater_id value defined in Archive model. Use nested whereHas():
$creators = User::whereHas('creator', function($q) use($cultivator_id) {
$q->whereHas('archive', function($q) use($cultivator_id) {
$q->where('caltivater_id', $cultivator_id);
});
})
->with('creators')
->get();
Or use dot notation:
$creators = User::whereHas('creator.archive', function($q) use($cultivator_id) {
$q->where('caltivater_id', $cultivator_id);
})
->with('creators')
->get();

How to include or exclude where statement in Laravel Eloquent

I need the same query for two different user roles. Difference is only in one whereNotIn condition.
So for the Basic user it would be:
$chart2 = DB::connection('mysql2')->table('tv')
->select('*')
->join('epgdata_channel', 'cid', '=', 'channelid')
->where('ReferenceDescription', $campaign->spotid)
->whereNotIn('ChannelName', $sky)
->get();
And for Premium:
$chart2 = DB::connection('mysql2')->table('tv')
->select('*')
->join('epgdata_channel', 'cid', '=', 'channelid')
->where('ReferenceDescription', $campaign->spotid)
->get();
I know I can do it with simple if statement:
if($user->userRole == "Basic"){
//first $chart2
}
else{
//second $chart2}
but I have a lots of queries where I need just to add or remove this whereNotin condition and rewriting the queries (using if statement) is not a nice solution.
Try scope.
In your TVModel.php:
public function scopeConditionalWhereNotIn($query, $doesUse, $col, $val) {
if($doesUse)
$query->whereNotIn($col, $val);
}
Usage:
$condi = true;//or false.
$chart2 = TVModel::select('*')
->join('epgdata_channel', 'cid', '=', 'channelid')
->where('ReferenceDescription', $campaign->spotid)
->conditionalWhereNotIn($condi, 'ChannelName', $sky)
->get();
Inside your model add this:
public function scopeBasicUser($query,$channel){
return $query->whereNotIn('ChannelName', $channel);
}
and in your controller:
$query = DB::connection('mysql2')->table('tv')
->select('*')
->join('epgdata_channel', 'cid', '=', 'channelid')
->where('ReferenceDescription', $campaign->spotid);
if($user->userRole == "Basic")
$query = $query->basicUser($channel);
return $query->get();
$userRole = $user->userRole;
$chart2 = DB::connection('mysql2')->table('tv')
->select('*')
->join('epgdata_channel', 'cid', '=', 'channelid')
->where('ReferenceDescription', $campaign->spotid)
->where(function ($query) use ($userRole){
if($userRole == "Basic"){
$query->whereNotIn('ChannelName', $sky)
}
})
->get();
This code worked for me.

Laravel Eloquent search two optional fields

I'm trying to search two optional tables using eloquent:
$users = User::where('ProfileType', '=', 2)
->where(function($query) {
$query->where('BandName', 'LIKE', "%$artist%");
$query->or_where('Genre', 'LIKE', "%$genre%");
})->get();
This works fine for return all results when a user does an empty search, but I am not sure how to adjust this for to search for bandname when that is present and vise versa.
Just to explain what happens on answer below:
Eloquent does a tricky thing here: When you call User::where(...) it returns a Database\ Query object. This is basically the same thing as DB::table('users')->where(...), a chainable object for constructing SQL queries.
So having:
// Instantiates a Query object
$query = User::where('ProfileType', '=', '2');
$query->where(function($query) {
// Adds a clause to the query
if ($artist = Input::get('artist')) {
$query->where_nested('BandName', 'LIKE', "%$artist%", 'OR');
}
// And another
if ($genre = Input::get('genre')) {
$query->where_nested('Genre', 'LIKE', "%$genre%", 'OR');
}
});
// Executes the query and fetches it's results
$users = $query->get();
Building on Vinicius' answer here's what worked:
// Instantiates a Query object
$query = User::where('ProfileType', '=', '2');
// Adds a clause to the query
if ($artist = Input::get('artist')) {
$query->where('BandName', 'LIKE', "%$artist%");
// Temp Usernamesearch
$query->or_where('NickName', 'LIKE', "%$artist%");
}
// Genre - switch function if artist is not empty
if ($genre = Input::get('genre')) {
$func = ($artist) ? 'or_where' : 'where';
$query->$func('Genre', 'LIKE', "%$genre%");
}
// Executes the query and fetches it's results
$users = $query->get();
Turns out that the second optional field must use or_where only if $artist is not set.
Thanks for your help
I think this is what youre after. Your view would have a form to search artist/genre one or the other can be set, or both, or none.
$users = User::where('ProfileType', '=', 2);
if (Input::has('artist')) {
$users = $users->where('BandName', 'LIKE', '%'.Input::get('artist').'%');
}
if (Input::has('genre')) {
$users = $users->where('Genre', 'LIKE', '%'.Input::get('genre').'%');
}
$users = $users->get();
$query = FormEntry::with('form')->where('domain_id', $id);
$query->where(function($query) use ($search, $start, $limit, $order, $dir) {
$query->where('first_name', 'LIKE', "%{$search}%")
->orWhere('last_name', 'LIKE', "%{$search}%")
->orWhere('email', 'LIKE', "%{$search}%")
->offset($start)
->limit($limit)
->orderBy($order, $dir);
});
$entries = $query->get();
$totalFiltered = $query->count();

Categories