How to handle an empty search query in Laravel 9? - php

I'm currently trying to implement a search functionality in my Laravel 9 API. Unfortunately, when I leave an empty query the API returns absolutely nothing. Any idea what I'm doing wrong?
Route:
Route::get('/products/search/{title?}', 'searchTitle');
public function searchTitle(Request $request, $title = '')
{
$pageSize = $request->page_size ?? 10;
if ($title == '') {
return Product::query()->paginate($pageSize);
} else {
return Product::where('title', 'LIKE', "%$title%")
->paginate($pageSize);
}
}

I suggest you use Conditional Clauses (when), something like this:
return Product::when($title !== '', function (Builder $query, $title) {
return $query->where('title', 'LIKE', "%$title%");
})
->paginate($pageSize);
Or use the object assign to a variable and make the where
$product = Product::query();
if ($title !== '') {
$product->where('title', 'LIKE', "%$title%");
}
return $product->paginate($pageSize);

Related

Filter a collection in Laravel

i want to filter a collection in order to return only items with fullname that is like the one given in parmaters
public function searchFriend($fullName){
return Auth::user()->friends->filter(function ($item) use ($fullName) {
return false !== stristr($item->friend->full_name, $fullName);
});
}
the function actually is not returning the correct results.
Instead of accessing the collection directly, you can do the filtering in SQL.
public function searchFriend($fullName){
return Auth::user()
->friends()
->where('full_name', 'like', '%'.$fullName.'%')
->get();
}
If you, for whichever reason, need to do it on the collection, then the problem with your current code is that $item represents the friend, so you're checking $item->friend->full_name instead of $item->full_name.
public function searchFriend($fullName){
return Auth::user()
->friends
->filter(function ($item) use ($fullName) {
return false !== stristr($item->full_name, $fullName);
});
}
I guess friend is a relationship to the User model so it could be
public function searchFriend($fullName)
{
return Auth::user()->friends()->whereHas('friend', function ($query) use ($fullName) {
$query->where('full_name', 'like', "%{$fullName}%");
})->get();
}
If you have first_name and last_name in User model then you can use concat.
public function searchFriend($fullName)
{
return Auth::user()->friends()->whereHas('friend', function ($query) use ($fullName) {
$query->whereRaw("concat(first_name, ' ', last_name) like ?", ["%{$fullName}%"]);
})->get();
}

How can I select columns by type in a polymorphic relationship?

As the title says, I have a polymorphic relationship of many to many, I want to select certain columns of each model. I have already looked at the documentation of Laravel but I only found this code, which is similar to what I am looking for.
$comments = App\Comment::whereHasMorph(
'commentable',
['App\Post', 'App\Video'],
function (Builder $query, $type) {
if ($type === 'App\Post') {
$query->where('content', 'like', 'foo%');
}
}
)->get();
I want to do something similar but this way:
$comments = App\Comment::with(
'commentable',
['App\Post', 'App\Video'],
function (Builder $query, $type) {
if ($type === 'App\Post') {
$query->select('id', 'title');
}elseif($type === 'App\Video'){
$query->select('id', 'name');
}
}
)->get();
I hope you can understand me and help with this problem thanks
Suppose the polymorphic method in each Model classes looks like this:
public function commentType()
{
return $this->morphOne('App\Comment', 'commentable');
}
An easy way would be to add two methods to the Comment class:
public function getIsPostAttribute()
{
return $this->commentType == 'App\Post';
}
public function getIsVideoAttribute()
{
return $this->commentType == 'App\Video';
}
Then, just:
$comment = App\Comment::find(1)->isPost; // True or False
$comment = App\Comment::find(1)->isVideo; // True or False
Now queries will be easy to do:
$posts = App\Comment::where('isPost', true)->get();
$videos = App\Comment::where('isVideo', true)->get();

transform() must be an instance of App\DigitalCase

public function index(Request $request) {
if ($request->has('show_type') && $request->show_type == 'deleted') {
$digital_cases = DigitalCase::onlyTrashed()->get();
} else {
$digital_cases = DB::table('digital_cases');
if ($request->has('caseName')) {
$digital_cases = $digital_cases->where('name', 'LIKE', $request->caseName . '%');
if ($request->has('addedBy')) {
$addedBy = $request->addedBy;
$digital_cases = $digital_cases->whereIn('added_by', function ($query) use ($addedBy) {
$query->select('id')->from('assistants')->where('firstname', 'LIKE', $addedBy . '%');
});
}
} else if ($request->has('addedBy')) {
$addedBy = $request->addedBy;
$digital_cases = $digital_cases->whereIn('added_by', function ($query) use ($addedBy) {
$query->select('id')->from('assistants')->where('firstname', 'LIKE', $addedBy . '%');
});
}
$digital_cases = $digital_cases->get();
}
$transformation = fractal()->transformWith(new DigitalCaseTransformer())->collection($digital_cases)->toArray();
return response()->json($transformation, 200);
}
I really tired of asking questions. But i have last problem is; i couldnt convert digital_cases to DigitalCase Model instance.
I got an error :
Type error: Argument 1 passed to App\Transformers\DigitalCaseTransformer::transform() must be an instance of App\DigitalCase, instance of stdClass given, called in
If it work in IF condition everything is ok. But when it work in ELSE condition it returns an error. How can i convert digital_cases variable to instance of DigitalCase ?
Laravel 5.6
Using $digital_cases = DB::table('digital_cases'); will not give you an instance (or Collection of) the DigitalCase Model. You need to use DigitalCase. To start a query that you can append conditional clauses to, begin with
$digital_cases = DigitalCase::query();
Then, continue appending clauses in the same way. When you pass a closure (->get(), etc), you'll end up with a Collection of DigitalCase Models (or a single DigitalCase if using ->first()).
You can really simplify and clean up the conditional queries using when:
DigitalCase::when($request->has('caseName'), function ($q) {
return $q->where('name', 'LIKE', request()->caseName . '%');
})->when($request->has('addedBy'), function ($q) {
return $q->whereIn('added_by', function ($query) {
$query->select('id')->from('assistants')->where('firstname', 'LIKE', request()->addedBy . '%');
});
}})->get();
That will yield the same result as all the if () { .. } else if () { .. }

Building complex where statement in Laravel Eloquent using

I have an Eloquent\Builder $query that I want to use additional where() calls on, where the amount of the calls is indefinite and is taken from an array $filter, example below:
$filter = [
'or:email:=:ivantalanov#tfwno.gf',
[
'or:api_token:=:abcdefghijklmnopqrstuvwxyz',
'and:login:!=:administrator',
],
];
The strings, when parsed, produce valid SQL conditions, but the problem lies into sticking them into closures where a group is present (like strings 2 and 3 in the example - the array is their 'group').
I know of Laravel's functionality that allows sticking a Closure function into $query->where() to achieve what I want, but the problem I'm facing is actually building those complex closures. I have to iterate through every string in the group and pass it into the closure generated like so (where $item is the result of parsing a condition string):
$closure = function ($query) use ($item)
{
call_user_func_array(
[$query, $item['function']], [$item['field'], $item['operator'], $item['values']]
);
};
Now the obvious problem with this is while it makes simple closures easily, passing more than one condition is plain impossible.
My question is, what could I use to prepare a complex statement to be executed on a query inside a closure?
Okay, I think I figured it out.
This is the method that will return the end result.
public function parse_filter(Builder &$query, array $filter)
{
$groups = $this->_prepare_groups($filter);
return $this->_parse_groups($query, $groups);
}
These methods will parse the initial array into something more usable.
private function _prepare_groups(array $filter)
{
foreach ($filter as $key => $item) {
if (is_array($item)) {
$groups[] = $this->_prepare_groups($item);
}
if (is_string($item)) {
$simple_filter = $this->_parse_simple_filter($item);
$groups[] = $simple_filter;
$simple_filter = null;
}
}
return $groups;
}
private function _parse_simple_filter(string $filter)
{
$filter_data = explode(':', $filter);
$simple_filter['function'] = $filter_data[0] === 'and' ? 'where' : 'orWhere';
$simple_filter['field'] = $filter_data[1];
$simple_filter['operator'] = $filter_data[2];
$simple_filter['values'] = $filter_data[3];
return $simple_filter;
}
And here is where the most of the magic happens. Closures are recursive calls to this method, as you can see.
private function _parse_groups(Builder &$query, array $groups)
{
foreach ($groups as $operator => $group) {
if (!array_key_exists('function', $group)) {
$closure = function ($query) use ($group)
{
$this->_parse_groups($query, $group);
};
$query->where($closure);
} else {
$query->{$group['function']}($group['field'], $group['operator'], $group['values']);
}
}
return $query;
}
Using this, you can modify an Eloquent\Builder object however you like with deeply nested filters that are declared dynamically (for example, received within a GET/POST request).
I guess this will help for you:
In model create a scope:
public static function scopeGetResultList($query) {
return $query->where(function ($query) use ($item) {
$query->where('group_user_holder_type', '=', 1)
->orWhere('group_user_holder_type', '=', 0);
});
}
OR
Example:
public static function getSearchedUserAuto($search_key, $user_id)
{
$users = DB::table((new User)->getTable().' as U')
->select('U.*', 'CT.city_name', 'C.nicename')
->leftJoin((new Country)->getTable().' as C', 'C.country_id', '=', 'U.user_country')
->leftJoin((new City)->getTable().' as CT', 'CT.city_id', '=', 'U.user_city')
->where(function($query) use ($search_key){
$query->where('U.user_full_name', 'like', '%'.$search_key.'%')
->orWhere('U.user_email', 'like', '%'.$search_key.'%');
})
->where(function($query) use ($search_key){
$query->where('U.user_full_name', 'like', '%'.$search_key.'%')
->orWhere('U.user_email', 'like', '%'.$search_key.'%');
})
->where('U.status', '=', 1)
->where('U.user_id', '!=', $user_id)
->get();
return $users;
}
See if it is work for you.

Laravel Pages with Categories Route Parameters

based on the example from here https://scotch.io/tutorials/simple-and-easy-laravel-routing#blog-pages-with-categories-route-parameters
I want to show entries for specific categories.
By calling this Route:
Route::get('menues/{city?}', 'PagesController#menue');
I want to show all entries for a specific city.
This is my Controller:
public function menue($city = null) {
if ($city) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '=', $city)->get();
} else {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '!=', $city)->get();
}
return view('pages.menues')
->withRestaurants($restaurants)
->withCity($city);
}
The only thing that doesn't work is, by calling a url with a {city} that doesn't exist in the DB I want to display all entries.
With the code above this doesn't happen. I get a blank page.
How can I fix this? My guess was that the code inside my else statement displays all entries, but this isn't the case.
Do the following:
public function menue($city = null) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}]);
if(if(!is_null($city) && !is_null(City::where('name', $city)->first())) {
$restaurants->where('city', '=', $city);
}
$restaurants = $restaurants->get();
return view('pages.menues')
->withRestaurants($restaurants)
->withCity($city);
}
->where('city', '!=', $city) is the problem. If you want to get all articles, remove the condition.
Change the condition to:
if(!is_null($city) && !is_null(City::where('name', $city)->first())
Use Requests $request
public function menue(Request $request) {
if ($request->has('city')) {
I would do something like:
public function menue($city = null) {
if ($city) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '=', $city)->get();
if (restaurants->count() == 0) {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->get();
}
} else {
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}])->where('city', '!=', $city)->get();
}
return view('pages.menues')
->withRestaurants($restaurants)
->withCity($city);
}

Categories