Laravel Eloquent where and order conditions only if needed - php

Please look at following code. This code I have written with Codeigniter. What I need to highlight it where condition and order conditions works only if those post requests are set. Otherwise it i just select * from student.
Codeigniter Code
$this->db->select('*');
$this->db->from('student');
if($this->input->post('first_name') != NULL){
$first_name = $this->input->post('first_name');
$this->db->where('first_name', $first_name);
}
if($this->input->post('last_name') != NULL){
$last_name= $this->input->post('last_name');
$this->db->where('last_name', $last_name);
}
if($this->input->post('order_by') != NULL){
$order_by= $this->input->post('order_by');
$this->db->order_by($order_by);
}
$query = $this->db->get();
Laravel Code
I am going do the same thing with laravel.
$first_name = $request->input('first_name');
$last_name = $request->input('last_name');
$order_by = $request->input('$order_by');
$students = Student::orderBy($order_by)
->where('first_name',$first_name)
->where('last_name',$last_name);
->paginate(10);
I able to run above code. The code works when there all post requests.
But if there is no first_name post request I need to remove ->where('first_name',$first_name).
If there i no order_by post request, I need to remove orderBy($order_by).
How to do it with above Laravel code.

you can use like,
$students = Student::latest();
if (isset($request->input('order_by'))) {
$students->orderBy($order_by)
}
if (isset($request->input('first_name'))) {
$students->where('first_name',$first_name);
}
if (isset($request->input('last_name'))) {
$students->where('last_name',$last_name);
}
$students->paginate(10);

An approach would be to check if the name is set and then add it to the query builder like so:
$first_name = $request->input('first_name');
...
$students = Student::orderBy($order_by)
if ($first_name) {
$students->where('first_name',$first_name)
}
$students->paginate(10);
However you can clean that up! Since Laravel 5.2.27 you can do as follows:
$students = Student::orderBy($order_by)
->when($request->input('first_name'), function($query) use ($request){
return $query->where('first_name', $request->input('first_name'));
})
->paginate(10);
To make that even more readable you can use a custom macro for if-statements:
$students = Student::orderBy($order_by)
->if($request->input('first_name'), 'first_name', '=', $request->input('first_name'))
->paginate(10);
And the macro:
use Illuminate\Database\Query\Builder;
Builder::macro('if', function ($condition, $column, $operator, $value) {
if ($condition) {
return $this->where($column, $operator, $value);
}
return $this;
});
Source: https://themsaid.com/laravel-query-conditions-20160425
I hope this helps!

You can do it like,
$first_name = $request->input('first_name');
$last_name = $request->input('last_name');
$order_by = $request->input('order_by');
$query = DB::table('student');
if($request->first_name){
$query->where('first_name',$first_name)
}
if($request->last_name){
$query->where('last_name',$last_name);
}
if($request->order_by){
$query->orderBy($order_by);
}
$students = $query->paginate(10);
Hope you understand.

Same approach:
$first_name = $request->input('first_name');
$last_name = $request->input('last_name');
$order_by = $request->input('$order_by');
$query = Student::orderBy($order_by);
if ($first_name) {
$query->where('first_name',$first_name);
}
if ($last_name) {
$query->where('last_name',$last_name);
}
$students = $query->paginate(10);
return $students;

$query = Student::where('last_name',$last_name);
if ($request->has('first_name')) {
$query->where('first_name',$first_name);
}
if ($request->has('order_by')) {
$query->orderBy($order_by);
}
$students = $query->paginate(10);

Related

Laravel default pagination breaking with filter on the same table

I am using Laravel 9 and am displaying some data using the paginate method on the database. I also have a search field above my table and use it to filter out the result. While filtering, I filter the data and call the paginate method on it too. That's where the issue arises. Let's say I was on page number 6 before filtering and after filtering the result sums up in two page, but the paginate method redirect me to page 6 which in turn will show no results.
Below is my code example:
For the first time page:
$modelData = Model::orderBy('id', 'DESC')->paginate(20);
After filtering:
$search = $_GET['searchField'];
$modelData = Model::where("name", "LIKE", "%{$search}%")->paginate(2);
I was expecting it to take me to the first page of the result, but it takes me the the page where i searched my list from.
EDIT:
My Complete function:
public function index()
{
$sortData = $searchData = NULL;
//CHECKS FOR SORTING, SEARCH AND BOTH
if (isset($_GET['sort']) && !empty($_GET['sort']) && isset($_GET['searchField']) && !empty($_GET['searchField'])) {
$search = $_GET['searchField'];
$modelData = Model::where("name", "LIKE", "%{$search}%")->orderBy($_GET['sort'], $_GET['direction'])->paginate(10);
$sortData = $_GET;
$searchData = $search;
} elseif (isset($_GET['sort']) && !empty($_GET['sort'])) {
$modelData = Model::orderBy($_GET['sort'], $_GET['direction'])->paginate(10);
$sortData = $_GET;
} elseif (isset($_GET['searchField']) && !empty($_GET['searchField'])) {
$search = $_GET['searchField'];
$modelData = Model::where("name", "LIKE", "%{$search}%")->paginate(10);
$searchData = $search;
} else {
$modelData = Model::orderBy('id', 'DESC')->paginate(10);
}
return view('content.view.list', compact(
'modelData',
'sortData',
'searchData'
));
}
I think you should not use $_GET
$request->query('sort')
$request->query('direction')
Since you use !empty(), you don't need to use isset().
You don't need $search, because
$search = $_GET['searchField'];
...
$searchData = $search;
So
$searchData = $_GET['searchField'];
You don't need $searchData,too. Because $sortData = $_GET.
You already have whole $_GET, why do you want to define one of it's element again? $sortData['searchField']
I think the English meaning of searchData is better than sortData. Becuar sortData means the data needed to sort, to order by. While searchData means the data needed to do the search task, do the filtering work. So searchData should be the $_GET.
I suggest:
public function index()
{
$searchData= $request->query(); // This is $_GET
// See what is your $_GET
//echo "<pre>".print_r($searchData, 1)."</pre>"; exit;
$model = Product::query(); //Initialize query builder
if(!empty($searchData['searchField']))){
$model->where('name', 'LIKE', '%'.$searchData['searchField'].'%');
}
if(!empty($searchData['sort']))){
$sort = $searchData['sort'];
}else{
$sort = 'id'; // default use id
}
if(!empty($searchData['direction'])){
$direction = $searchData['direction'];
}else{
$direction = 'DESC'; // default use desc
}
$model->orderBy($sort, $direction);
// This can see the SQL content, and it should before result like paginate() or get(). I think...
if(!empty($searchData['debug'])){
$debugData['sql'] = $query->toSql();
$debugData ['bidings'] = $query->getBindings();
echo "<pre>".print_r($debugData , 1)."</pre>"; exit;
}
if(!empty($searchData['limit'])){
$limit = $searchData['limit'];
}else{
$limit = 10;
}
$modelData = $model->paginate($limit)->appends($queries);
return view('content.view.list', compact(
'searchData',
'modelData',
));

How to filter products in e-commerce shop by many inputs when some values can be empty

enter image description here
I have several inputs in order to filter products in the online shop. My question is, how can I filter products if some inputs are left without being filled/chosen. How should I query?
public function find()
{
$categories = Category::all();
if (isset($_GET['submit'])) {
if (!empty($_GET['brand'])) {
$selectedBrand = $_GET['brand'];
echo 'You have chosen: ' . $selectedBrand;
} else {
echo 'Please select the value.';
}
$date = Request::get('date');
$name = Request::get('name');
$selected = $_GET['type'];
$data = DB::table('product')->where('product.type', $_GET['type'])
->where('product.name', $name)
->join('shop', 'product.id', '=', 'shop.product_id')
->where('shop.releasedate', $date)
->get();
return view('pages/catalog')->with(['product' => $data, 'categories' => $categories]);
}
}
You can first check if your fields are filled and continue to query your model with when method
Logic
$date = null;
if($request->filled('date)){
$date = $request->date;
}
// your other values can go here like above
$data = DB::table('product')->where('product.type', $_GET['type'])
->where('product.name', $name)
->join('shop', 'product.id', '=', 'shop.product_id')
->when($date, function ($query, $transmission) {
// this query runs only if $date is `true` (has a value and not empty)
return return $query->where('shop.releasedate','=', $date);
->orderBy('shop.created_at','desc);
}, function ($query) {
// something you want to return if the $date is `false` (empty)
})
->get();

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();

Is it possible to split query builder in Laravel?

Is it possible to split queries somehow like this?
public function getStatuses($dates)
{
$query = DB::table('tickets');
if ($dates['from'])
$query = $query->where('from', $dates['from']);
if ($dates['to'])
$query = $query->where('to', $dates['to']);
$query = $query->select('Active');
return $query->get()->toArray();
}
Yes, it's possibile. But don't reassign to the same variable or you risk messing it up:
public function getStatuses($dates)
{
$query = DB::table('tickets');
if ($dates['from'])
$query->where('from', $dates['from']);
if ($dates['to'])
$query->where('to', $dates['to']);
$query->select('Active');
return $query->get()->toArray();
}
In Laravel 4, its necessary to assign the get method to a variable
public function scopeGetPosts($query, $this_user = NULL){
$results = DB::table('post')
->select('*')
->where('post_status','=','publish');
if( $this_user != NULL ){
$results->where('post_author','=',$this_user->user_id);
}
$data = $results->orderBy('created_at', 'desc')
->get();
if( empty( $results ) )
$data = 'no results';
return $data;
}
In Laravel Eloquent :
$query = ModelName::where('status',1);
if($userId){
$query->where('user_id',$userId);
}
if($limit){
$query->limit($limit);
}
$result = $query->get();

This query show me with this active record

I am having trouble getting two tables and passing them to controller:
IN A MODEL:
function get_all_entries() {
$query = $this->db->get('entry');
return $query->result();
$this->db->select('entry_id , count(comment_id) as total_comment');
$this->db->group_by('entry_id');
$comment = $this->db->get('comment');
return $comment->result();
}
IN A CONTROLLER:
$data['query'] = $this->blog_model->get_all_entries();
$this->load->view('blog/index',$data);
How do I return $query and $comment variables to controller? I think I am doing it wrong.
Use this because you are not allowed to return twice in the same method
function get_all_entries()
{
$query = $this->db->get('entry');
$data[] = $query->result();
$this->db->select('entry_id , count(comment_id) as total_comment');
$this->db->group_by('entry_id');
$comment = $this->db->get('comment');
$data[] = $comment->result();
return $data;
}
EDITS:
In controller
function index(){
$this->load->model('mymodel');
$result = $this->mymodel->get_all_entries();
$entries = $result[0] ;
$comments = $result[1] ;
$data['entries'] = $entries;
$data['comments '] = $comments;
}
Your issue is that you're returning $query->result() in first place, return function halts the current function, so the next steps are not being processed.
Best way would be to create two methods for either $query get and $comment get.
An alternative to your issue would be
function get_all_entries() {
$query = $this->db->get('entry');
$this->db->select('entry_id , count(comment_id) as total_comment');
$this->db->group_by('entry_id');
$comment = $this->db->get('comment');
return array($query->result(),$comment->result());
}
Then in your controller
list($data['query'],$data['comment']) = $this->blog_model->get_all_entries();
$this->load->view('blog/index',$data);

Categories