Nested Query in Laravel 5.2 - php

I Have a search box that I want to use to search some of columns of a table in the database. Here's the code
$project = Project::findOrFail($id);
$file = \App\File::find($file);
$query = $request->input('q');
$materials = $query
?\App\Material::where('file_id', '=', $file->id)
->where('material_name', 'LIKE', "%$query%" )->get()
:\App\Material::where('file_id', '=', $file->id)->get();
return view('projects.file',compact('project', 'file', 'materials'));
The data as it is when the page loads is filtered to show just the items from this project. But when the search is done, it searches the whole table. How can I make it search only the items from the specific project and not the whole items from the table?

You can nest your search items this way:
public function handle($request, Closure $next)
{
$project = Project::findOrFail($id);
$file = \App\File::find($file);
$materials = \App\Material::newQuery();
// Did it found the file?
if ($file) {
// Search for the file
$materials->where('file_id', '=', $file->id);
}
// AND, does it have a query to search?
if ($search_item = $request->input('q')) {
// Search for the query
$materials->where('material_name', 'LIKE', "%$search_item%");
}
// AND, does it have a project to filter?
if ($search_item = $request->input('project')) {
// Filter the project
$materials->where('project', 'LIKE', "%$search_item%");
}
// Now go get the results
$materials = $materials->get();
// And return to the view
return view('projects.file',compact('project', 'file', 'materials'));
}

Related

Search in data from cache

My question is, if there is data in the cache, I created a condition by saying fetch, and if not, I bring it from the database and refresh the cache for a certain period of time. Normally, if I don't use the cache, I can search the page, but I cannot search by id or nickname with the code below.So when using cache::get can I add a search condition?
public function index(Request $request)
{
$submit = $request->get('submit');
$id = $request->get('id');
$nick_name = $request->get('nick_name');
if (Cache::has('users')) {
$users = Cache::get('users');
return view('admin.users.index', compact('users'));
}
$users = User::when(!empty($id), function ($query) use ($id) {
$query->where('id', $id);
})->when(!empty($nick_name), function ($query) use ($nick_name) {
$query->where('nick_name', $nick_name);
})->orderBy('created_at', 'asc')->get();
Cache::put('users', $users, now()->addMinutes(60));
return view('admin.users.index', compact('users'));
}
Update: Based on the examples on the page below, the problem was solved
https://www.honeybadger.io/blog/caching-in-laravel/
You should add search criteria in your cache key. E.g.
public function index(Request $request) {
$submit = $request->get('submit');
$id = $request->get('id');
$nick_name = $request->get('nick_name');
$cacheKey = User::class . md5(json_encode([$submit, $id, $nick_name]));
if (Cache::has($cacheKey)) {
/* ... */
}
because now your cache writes only first search result and ignores everything else.
Or write to cache all users. Then run that array through array_filter applying filters. But that can be waste of developer time if search is very dynamic.

How to add filter and pagination with Laravel Eloquent

I am trying to create an API that will return all customers record from the database. But this provides pagination and filtering.,
The filtering feature is an optional query parameter. So would not necessary included it inside query parameter.
But i am facing an issues in doing that.
Here is my index methods from CustomerController file:
public function index(Request $request)
{
// Get how many item per page
$itemPerPage = $request->query('per_page');
// SQL Query
$customers = Customer::all();
// Filter data
if (!empty($request->name)) {
$customers = $customers->where('name', '=', $request->name);
}
// Return the result as JSON
return new CustomerCollection($customers->paginate($itemPerPage));
}
Or have any better approach to combine optional filtering feature with pagination?
Thank you.
Your main issue is this line:
$customers = Customer::all();
The all() method immediately returns all customers records as a Collection, which does not have a ->paginate() method: https://laravel.com/docs/9.x/collections#available-methods.
To optionally chain, use the ->query() method, or a ->when() clause:
Using ::query() instead of ::all():
$itemPerPage = $request->query('per_page');
// SQL Query
$customers = Customer::query();
// Filter data
if (!empty($request->name)) {
$customers = $customers->where('name', '=', $request->name);
}
// Return the result as JSON
return new CustomerCollection($customers->paginate($itemPerPage));
Using a ->when() clause:
$itemPerPage = $request->query('per_page');
$customers = Customer::when(!empty($request->name), function ($query) use ($request) {
$query->where('name', '=', $request->name);
});
return new CustomerCollection($customers->paginate($itemPerPage));

Multiline Eloquent query

I'm trying to filter my products based on selected filters and possibly a search term/word. My filters have a relationship with categories, which in their turn have a relation ship with my products. My code below only works (without the if statement checking for a search term/word) when everything is chained together, but when I try to break the query into multiple lines (which I've read is possible, right?) it returns an empty array.
Here's a my code:
// Create array from selected categories/filters
$filter_ids = explode(',', $request->get('cats'));
// Query for active products
$products = Product::where('active', '=', 1);
$products->with(['categories' => function($query) use ($filter_ids) {
// Query for active categories
$query->where('active', 1)->whereHas('filters', function ($query) use ($filter_ids) {
// Query for the selected filters from the request
$query->whereIn('id', $filter_ids);
});
}]);
// Check for search term/word
if ($request->get('q')) {
$q = $request->get('q') ? urldecode($request->get('q')) : null;
$products->where('title', 'LIKE', "%{$q}%");
}
// Limit to 10 items and get results
$products->limit(10)->get();
return response()->json([
'status' => 'success',
'response' => $products
], 200);
I think you could but don't need to query all products with title first, before adding the relationships. But whats wrong here is that you must store the result of get() in a variable before adding it to your json response body:
Try to do something like:
if ($request->get('q')) {
$q = $request->get('q') ? urldecode($request->get('q')) : null;
$products->where('title', 'LIKE', "%{$q}%");
}
$products->with(['categories' => function($query) use ($filter_ids) {
// Query for active categories
$query->where('active', 1)->whereHas('filters', function ($query) use ($filter_ids) {
// Query for the selected filters from the request
$query->whereIn('id', $filter_ids);
});
}]);
$response = $products->limit(10)->get();
return response()->json([
'status' => 'success',
'response' => $response
], 200);
Lukas' answer led me to do some more debugging and eventually solving my problem, though it was not the position of the if statement checking if there's a search term/word.
The problem lies in the following line:
$products->limit(10)->get();
I needed to store the retrieved results from the get(); method in another variable, in my case:
$response = $products->limit(10)->get();
I eventually ended up with the following working code:
// Create array from selected categories/filters
$filter_ids = explode(',', $request->get('cats'));
// Query for active products
$products = Product::where('active', '=', 1);
$products->with(['categories' => function($query) use ($filter_ids) {
// Query for active categories
$query->where('active', 1)->whereHas('filters', function ($query) use ($filter_ids) {
// Query for the selected filters from the request
$query->whereIn('id', $filter_ids);
});
}]);
// Check for search term/word
if ($request->get('q')) {
$q = $request->get('q') ? urldecode($request->get('q')) : null;
$products->where('title', 'LIKE', "%{$q}%");
}
// Limit to 10 items, get results and store in '$response'
$response = products->limit(10)->get();
return response()->json([
'status' => 'success',
'response' => $response
], 200);

Laravel filters won't work when trying to add them

So I'm making a fliter in laravel for a project and me and my teacher are braking our head on a the following thing.
In the code below the general search for a player works but the other statements won't add to it if they are defined and in the POST request;
Controller:
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Input;
class FilterController extends Controller
{
public function filter(Request $request)
{
$player = new \App\Player;
$filters = $player->newQuery();
$query = Input::get('q');
// Search for a player based on their status.
if ($request->has('status')) {
$filters->orwhere('status', $request->input('status'));
}
// Search for a player player on their club.
if ($request->has('club')) {
$filters->orwhere('Club', $request->input('club'));
}
// Search for a player player on their team category .
if ($request->has('Category')) {
$filters->orwhere('Category', $request->input('Category'));
}
// Search for a player player if he is flagged as removed.
if ($request->has('remove')) {
$filters->orwhere('remove', $request->input('remove'));
}
// Search for a player player on their size.
if ($request->has('size')) {
$filters->orwhere('Size', $request->input('size'));
}
// General search for a player
if($request->has('q')){
$filters->orwhere('first_name','LIKE','%'.$query.'%')
->orWhere('last_name','LIKE','%'.$query.'%')
->orWhere('mobile','LIKE','%'.$query.'%')
->orWhere('street_name_nummer','LIKE','%'.$query.'%')
->orWhere('city','LIKE','%'.$query.'%');
}
// Get the results and return them.
$results = $filters->get();
if(count($results) > 0){
return view('lists/ekick')->withDetails($results,$query);
} else return view ('lists/ekick')->with('No Details found. Try to search again !');
}
}
route:
Route::any('lists/ekick', 'FilterController#filter');
output view:
img from view
To pick up on Aaron Sarays answer, you are most likely filtering the wrong way. Normally additional filters are additional conditions each record has to meet in order to be part of the result. If you consider an Excel table and you filter one column, you won't even have all options to filter for in the second column because you already limited the result and you can only limit it further.
Combine this knowledge with an improved way of filtering and you receive a query like this:
public function filter(Request $request)
{
$query = $request->input('q');
$results = \App\Player::query()
->when($request->input('status'), function ($query, $status) {
$query->where('status', $status);
})
->when($request->input('club'), function ($query, $club) {
$query->where('club', $club);
})
->when($request->input('category'), function ($query, $category) {
$query->where('category', $category);
})
->when($request->input('remove'), function ($query, $remove) {
$query->where('remove', $remove);
})
->when($request->input('size'), function ($query, $size) {
$query->where('size', $size);
})
->when($query, function ($query, $q) {
$query->where(function ($query) use ($q) {
$query->where('first_name', 'LIKE', "%$q%")
->orWhere('last_name', 'LIKE', "%$q%")
->orWhere('mobile', 'LIKE', "%$q%")
->orWhere('street_name_number', 'LIKE', "%$q%")
->orWhere('city', 'LIKE', "%$q%");
});
})
->get();
if ($results->isNotEmpty()) {
return view('lists/ekick')->withDetails($results, $query);
} else {
return view ('lists/ekick')->with('No Details found. Try to search again !');
}
}
The function when($condition, $callback) as used in the query above is used to dynamically build queries. You can consider the following two statements equivalent:
// option 1: conditional query (preferred!)
$results = Player::query()
->when($request->input('q'), function ($query, $q) {
$query->where('name', 'LIKE', "%$q%");
})
->get();
// option 2: plain php query building... (not very clean code)
$query = Player::query();
if ($request->input('q')) {
$query->where('name', 'LIKE', '%'.$request->input('q').'%');
}
$results = $query->get();
In order to do what you're doing, I think you want to not use or with your queries. You're basically saying
Give me the Player where status is something or size is something
I think what you mean to say is
Give me the Player where status is something and size is something
Depending on if the requirements exist or not in the filter.
So, you'd want to alter your code using the following as an example:
if ($request->has('status')) {
$filters->where('status', $request->input('status'));
}
// Search for a player player on their club.
if ($request->has('club')) {
$filters->where('Club', $request->input('club'));
}
You can also bypass one step by using this:
$query = \App\Player::getQuery();

Search all method missing where argument in Laravel 5

I'm trying to write a method in my controller to allow searching the results of my query on my view page. The query selects all results from the "ads" table and this method should allow filtering results by the ad's name inputting keywords in the search bar.
The controller code goes like this:
public function index(Request $request)
{
$title = trans('ad.title');
$ads = Ad::paginate(10);
if (!empty($request->input('search_all'))) {
$search_all = urldecode($request->input('search_all'));
$ads->where(function ($query) use ($search_all) {
$query->where('name', 'like', '%'.$search_all.'%')->get();
});
}else {
// Returning to view
return view('admin.ad.list')
->with('ads', $ads)
->with('title', $title);
}
}
However, when I run a search I get the following error: "Missing argument 2 for Illuminate\Support\Collection::where()".
What am I doing wrong?
At the top, when doing $ads = Ad::paginate(10); you have already pulled the results from the database so no more filtering can be done at DB level.
I'd do something like this instead:
public function index(Request $request)
{
$title = trans('ad.title');
$ads = Ad::select();
if ($request->input('search_all')) {
$search_all = urldecode($request->input('search_all'));
$ads->where('name', 'like', '%'.$search_all.'%');
}
// Returning to view
return view('admin.ad.list')
->with('ads', $ads->paginate(10))
->with('title', $title);
}

Categories