Fetch data when you have multiple search queries in laravel - php

I have this type of modal for search data from the database.
Image
I want to search the data if the user only types company name and CIN or *company name only or
company state and company district user can choose any field. So I want to fetch the data only on selected fields.
Is there any simplest way to do this
I have coded multiple if-else statements.
My Code
else if ($req->state && $req->district) {
$data = tbl_company::query()
->where(
"state",
"LIKE",
"%{$req->state}%"
)->where(
"district",
"LIKE",
"%{$req->district}%"
)
->paginate(100);
}
// Filter using only state and city
else if ($req->city && $req->district && $req->state == null) {
$data = tbl_company::query()
->where(
"city",
"LIKE",
"%{$req->city}%"
)->where(
"district",
"LIKE",
"%{$req->district}%"
)
->paginate(100);
}
// company status only
else if ($req->company_status && $req->city == null && $req->district == null && $req->state == null) {
$data = tbl_company::query()
->where(
"company_status",
$req->company_status
)
->paginate(100);
}

use Conditional Clauses
$data = tbl_company::query()->when($req->state && $req->district, function ($query, $req) {
$query->where("state", "LIKE", "%{$req->state}%")
->where("district", "LIKE", "%{$req->district}%");
})->when($req->city && $req->district && $req->state == null, function ($query, $req) {
$query->where("city", "LIKE", "%{$req->city}%")
->where("district", "LIKE", "%{$req->district}%");
})->paginate(100);
Updates
use loop
$data = tbl_company::query()->where(function ($query)use($req){
foreach ($req->only('state','district','city','company_status') as $filterField=>$filterFieldValue){
if(!empty($filterFieldValue)&&is_array($filterFieldValue)){
$query->wherein($filterField,$filterFieldValue);
}elseif (!empty($filterFieldValue)){
$query->where($filterField, "LIKE", "%{$filterFieldValue}%");
}
}
})->paginate(100);

I found the answer. I solved this problem using Pipeline Design Pattern
$query = tbl_company::query();
if ($req->has('state')) {
$query->whereIn('state', $req->input('state'));
}
if ($req->has('district')) {
$query->whereIn('district', $req->input('district'));
}
if ($req['date_of_registration']['start'] && $req['date_of_registration']['end']) {
$from = Carbon::parse($req['date_of_registration']['start']);
$to = Carbon::parse($req['date_of_registration']['end']);
$query->whereBetween(
DB::Raw("STR_TO_DATE(date_of_registration,'%d-%m-%Y')"),
[$from, $to]
);
}
if ($req['authorized_capital']['start'] && $req['authorized_capital']['end']) {
$query->whereBetween(
"authorized_capital",
[$req['authorized_capital']['start'], $req['authorized_capital']['end']]
);
}
//finally
$data = $query->paginate(100);

Related

Laravel complicated filter query

I need to write API query which consists of "status", "category_id", "city_id" fields, and there are a lot of cases:
1) status is an array => ['OPEN','CLOSED'] OR category_id is an array => [1,2,4] AND city_id = 7 (could be any integer)
2) status is an array => ['OPEN','CLOSED'] OR category_id is an integer => 2 AND city_id = 7 (could be any integer)
3) status is a string => 'OPEN' OR category_id is an array => [1,2,4] AND city_id = 7 (could be any integer)
4) status is an array => ['OPEN','CLOSED'] AND city_id = 7 (could be any integer)
5) category_id is an array => [1,2,4] AND city_id = 7 (could be any integer)
6) status is a string => 'OPEN' AND city_id = 7 (could be any integer)
7) category_id is an integer => 1 AND city_id = 7 (could be any integer)
I have already tried to write this query, however, confused in the number of statements (the code is not working correctly, there is also district_id, but for simplicity of example I did not mention it):
$cat = cleanString(request()->get('category_id'));
$status = cleanString(request()->get('status'));
$city = cleanString(request()->get('city_id'));
$dist = cleanString(request()->get('district_id'));
if ($cat != null && $status != null) {
if (is_array($cat) && is_array($status)) {
$issues = $issues->whereIn('category_id', $cat)->orWhereIn('status', $status)->where('city_id', $city)->where('district_id', $dist);
} elseif (is_array($cat)) {
$issues = $issues->whereIn('category_id', $cat)->where('status', $status)->where('city_id', $city)->where('district_id', $dist);
} elseif (is_array($status)) {
$issues = $issues->whereIn('status', $status)->where('category_id', $cat)->where('city_id', $city)->where('district_id', $dist);
} elseif (is_string($cat) && is_string($status)) {
$issues = $issues->where('category_id', $cat)->where('status', $status)->where('city_id', $city)->where('district_id', $dist);
}
} elseif ($cat == "" || $cat == []) {
$issues = $issues->where('status', $status)->where('city_id', $city)->where('district_id', $dist);
} elseif ($status == "" || $status == []) {
$issues = $issues->where('category_id', (int)$cat)->where('city_id', $city)->where('district_id', $dist);
}
$issues = $issues->get();
Is there any way not to use so many if-else cases and make code looks cleaner and work properly?
Thanks everyone for answers in advance!
I wrote better version of query, however the disadvantage is I have to pass status or category_id as an array like this + if city_id AND/OR district_id is null, then no data returns:
{
"city_id" : 5,
"district_id" : 9,
"category_id" : [5,4],
"status" : ["REJECTED"]
}
And here is code:
if ($cat != null && $status != null) {
$issues = $issues->where('city_id', $city)->where('district_id', $dist)
->where(function ($q) {
$q->whereIn('category_id', cleanString(request()->get('category_id')))
->orWhereIn('status', cleanString(request()->get('status')));
});
} elseif ($cat == "" || $cat == []) {
$issues = $issues->where('city_id', $city)->where('district_id', $dist)
->where(function ($q) {
$q->whereIn('status', cleanString(request()->get('status')));
});
} elseif ($status == "" || $status == []) {
$issues = $issues->where('city_id', $city)->where('district_id', $dist)
->where(function ($q) {
$q->whereIn('category_id', cleanString(request()->get('category_id')));
});
}
Force convert to array
$filters = [
'category_id' => (array) cleanString(request()->get('category_id', [])),
'status' => (array) cleanString(request()->get('status', [])),
];
$filters = array_filter($filters);
foreach($filters as $key => $val) {
$issues->orWhereIn($key, $val);
}

Laravel Pagination after sending parameters through form (GET)

at the moment Iam really struggeling with filtering and the pagination of Laravel. On http://snkrgllry.herokuapp.com/ you can try to sort the images with the Filter Modal for example likes ascending, if you go now to the second page it says that view[2] is not found.
I send the parameters for filtering through a form to a controller which makes a query and will send all those data back to the view. Everything fine so far, but the second page is not working at all.
Here is my code on the Blade
<div class="container">
<div class="col-xs-12 row-centered">
{{ $images->appends(request()->input())->links()}}
</div>
</div>
This is the controller function, please excuse my bad programming its my first web-/laravel project.
public function filter(Request $request)
{
$brand = $request->brand;
$color = $request->color;
$style = $request->style;
$material = $request->material;
$year = $request->year;
$shape = $request->shape;
$sorting = $request->sort;
$page = $request->page;
$user_id = $request->user_id;
$sortingMethod = 'desc';
$sortingParameter = 'created_At';
//Abfrage wie sortiert werden soll
if ($sorting == 'uploadDesc') {
$sortingMethod = 'desc';
$sortingParameter = 'created_At';
} else if ($sorting == 'uploadAsc') {
$sortingMethod = 'asc';
$sortingParameter = 'created_At';
} else if ($sorting == 'leer') {
$sortingMethod = 'desc';
$sortingParameter = 'created_At';
} else if ($sorting == 'likesAsc') {
$sortingParameter = 'count';
$sortingMethod = 'asc';
} else if ($sorting == 'likesDesc') {
$sortingParameter = 'count';
$sortingMethod = 'desc';
}
//$imagesQuery = DB::table('images')->select('brand', 'color', 'style', 'material', 'shape', 'year', 'id', 'path', 'created_at')->where('contest', 'true');
$imagesQuery = DB::table('images')
->leftJoin('likes', 'images.id', '=', 'likes.image_id')
->select('images.*', DB::raw("count(likes.image_id) as count"))
->groupBy('images.id', 'images.brand', 'images.user_id', 'images.color', 'images.style', 'images.material', 'images.shape', 'images.year', 'images.desc', 'images.path', 'images.name', 'images.model', 'images.contest', 'images.remember_token', 'images.created_at', 'images.updated_at')
->orderBy($sortingParameter, $sortingMethod);
$brands = DB::table('images')->select('brand')->groupBy('brand')->get();
$colors = DB::table('images')->select('color')->groupBy('color')->get();
$styles = DB::table('images')->select('style')->groupBy('style')->get();
$materials = DB::table('images')->select('material')->groupBy('material')->get();
$years = DB::table('images')->select('year')->groupBy('year')->get();
$shapes = DB::table('images')->select('shape')->groupBy('shape')->get();
if ($brand !== 'leer') {
$imagesQuery->where('brand', '=', $brand);
}
if ($year !== 'leer') {
$imagesQuery->where('year', '=', $year);
}
if ($color !== 'leer') {
$imagesQuery->where('color', '=', $color);
}
if ($style !== 'leer') {
$imagesQuery->where('style', '=', $style);
}
if ($material !== 'leer') {
$imagesQuery->where('material', '=', $material);
}
if ($shape !== 'leer') {
$imagesQuery->where('shape', '=', $shape);
}
if ($year !== 'leer') {
$imagesQuery->where('year', '=', $year);
}
if ($page == 'contest') {
$imagesQuery->where('images.contest', '=', 'true');
$brands->where('contest', 'true');
$colors->where('contest', 'true');
$styles->where('contest', 'true');
$materials->where('contest', 'true');
$years->where('contest', 'true');
$shapes->where('contest', 'true');
}
if ($page == 'profile') {
$imagesQuery->where('images.user_id', '=', $user_id);
$user = User::find($user_id);
}
$images = $imagesQuery->paginate(12);
return view($page)->with(compact('images', 'brands', 'colors', 'styles', 'materials', 'years', 'shapes', 'user'));
}
And this is my route which will called, if I submit the filter form.
Route::get('/indexFilter', 'ImagesController#filter');
Are there any suggestions from your side how to fix this problem. I read a lot about it but I still didnt get it done.
I would really appreciate you help!
Best regards Lars
You pass page as a parameter:
return view($page)
So it is '2' for the second page. Just pass template name, not page number. Use another name for passed page variable, it is used for pagination.
Nice shoes! :)
The problem is in your frontend code. When you click the next page, the request param of page is 2 instead of index
Here's the HTML code: 2
Thanks a lot I will not managed it to solve it until tomorrow (contribution of the project to our Prof. at University) but now I know my mistake and I "fixed" it so it will work out for me. I'll try my best to fix the issue with your solution!!

Laravel: Join Closure Inside where closure. Eloquent

I'm trying to select some registries in my "properties" table using a filter search function.
In my controller I receive the filters and process them with an advanced where, inside it I need to look registries related by other table when the filter "room" is used. For this I'm trying to do a join inside the where closure, but the join is not working at all, the search is done ignoring the join.
Controller:
$filter_type= Input::has('filter_type') ? Input::get('filter_type') : NULL;
$filter_val= Input::has('filter_val') ? Input::get('filter_val') : NULL;
$state= NULL;
$sub_category= NULL;
$cat_operation= NULL;
$room= NULL;
if($filter_type == 'state'){
$state = $filter_val;
}
if($filter_type == 'sub_category'){
$sub_category = $filter_val;
}
if($filter_type == 'cat_operation'){
$cat_operation = $filter_val;
}
if($filter_type == 'room'){
$room = $filter_val;
}
$properties = Property::where(function($query) use ($state, $sub_category, $cat_operation, $room){
if (isset($state)){
$query->where('state_id', $state);
}
if (isset($sub_category)){
$query->where('sub_category_id', $sub_category);
}
if (isset($cat_operation)){
$query->where('cat_operation_id', $cat_operation);
}
if(isset($room)){
$query->join('properties_control', function($join) use ($room)
{
if($room == 5){
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '>=', $room);
}else{
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '=', $room);
}
});
}
})->paginate(20);
The join statement is not running at all.
It's possible include a join closure in a where closure like I am trying to do here? There is another way to accomplish this?
The main reason why your join closure is not working, is because it is enclosed in an advanced where closure.
Here's the laravel (right) way to write the code above:
$filter_type= Input::get('filter_type',null);
$filter_val= Input::get('filter_val',null);
//Start the query builder
$queryProperties = Property::newQuery();
//Switch on type of filter we received
switch($filter_type)
{
case 'state'
$queryProperties->where('state_id',$filter_val);
break;
case 'sub_category':
$queryProperties->where('sub_category_id', $filter_val);
break;
case 'cat_operation':
$queryProperties->where('cat_operation_id', $filter_val);
break;
case 'room':
$queryProperties->join('properties_control', function($join) use ($filter_val)
{
if($room == 5){
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '>=', $filter_val);
}else{
$join->on('properties.id', '=', 'properties_control.property_id')
->where('properties_control.category_feature_item_id', '=', 75)
->where('properties_control.category_feature_item_value', '=', $filter_val);
}
});
break;
}
$properties = $queryProperties->paginate(20);

Concatenate queries using Eloquent Builder

How can I concatenate queries using Eloquent Builder?
I am building queries based on criteria (where clause) and taking limit and offset from URL. These queries are then passed to ->get() method to fetch result. I want to do it using Eloquent and not Query builder.
This is how you build a query in eloquent(I have given an example of using multiple where clauses):
$result = ModelName::where('key_1', '=' , 'value_1')
->where('key_2', '>', 'value_2')
->take(4)
->offset(2)
->get()
The take() method will limit the number of results to 4 with offset 2.
http://laravel.com/docs/5.0/eloquent
Update
Based on OP's question over here https://laracasts.com/discuss/channels/general-discussion/eloquent-query-builder , I am updating my answer.
You could do something like this:
if($params)
{
$query = $this->model;
foreach($params['search'] as $param)
{
$query = $query->where($param['where'],'=',$param['value']);
}
if (isset($params['start']))
{
$query = $query->offset($params['start'] );
}
if(isset($params['count']))
{
$query = $query->take($params['count']);
}
if (isset($params['sortColumn']))
{
$ascending = $params['ascending'] == 'true' ? 'ASC' : 'DESC';
$query = $query->orderBy($params['sortColumn'], $ascending);
}
}
$query->get();
What you need is assigning result of functions again to the model.
You had:
if($params)
{
foreach($params['search'] as $param)
{
$this->model->where($param['where'],'=',$param['value']);
}
if (isset($params['start']))
{
$this->model->offset($params['start'] );
}
if(isset($params['count']))
{
$this->model->take($params['count']);
}
if (isset($params['sortColumn']))
{
$ascending = $params['ascending'] == 'true' ? 'ASC' : 'DESC';
$this->model->orderBy($params['sortColumn'], $ascending);
}
}
$this->model->get();
and you need to use:
if($params)
{
foreach($params['search'] as $param)
{
$this->model = $this->model->where($param['where'],'=',$param['value']);
}
if (isset($params['start']))
{
$this->model = $this->model->offset($params['start'] );
}
if(isset($params['count']))
{
$this->model = $this->model->take($params['count']);
}
if (isset($params['sortColumn']))
{
$ascending = $params['ascending'] == 'true' ? 'ASC' : 'DESC';
$this->model = $this->model->orderBy($params['sortColumn'], $ascending);
}
}
$data = $this->model->get();

Laravel dynamic queries with premade string

How to insert strings as query in Laravel? I have to handle a dynamic value for "book formats" (such as "pdf", "epub", "physical", "") and this formats are separated by comma. Here is my code:
$formats_sql = '';
$format_filter_count = 0;
$format_filter = explode(',', $format_filter);
foreach ($format_filter as $format_filter_tmp) {
if ($format_filter_count == 0) {
$formats_sql .= "where('format', '=', '{$format_filter_tmp}')";
} else {
$formats_sql .= "->orWhere('format', '=', '{$format_filter_tmp}')";
}
$format_filter_count += 1;
}
if ($price_filter == 'paid') {
$books = Book::where('book_id', '=', $category_book->book_id)->$formats_sql->where('sell_price', '>', '0')->where('status', '=', '1')->get();
}
But makes this problem:
Undefined property: Illuminate\Database\Eloquent\Builder::$where('format', '=', 'pdf')->orWhere('format', '=', 'epub')
Your over complicating this. You should be using whereIn where you need to search for an array of values.
You whole code above can be condensed to:
if ($price_filter == 'paid') {
$formats = explode(',', $format_filter);
Book::where('book_id', $category_book->book_id)->whereIn('format', $formats)->where('sell_price', '>', '0')->where('status', '1')->get();
}

Categories