Laravel: Join Closure Inside where closure. Eloquent - php

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

Related

Fetch data when you have multiple search queries in laravel

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

I need help to turn some raw SQL into Eloquent code

As the title says, I'm having trouble turning my SQL code into Eloquent.
Here's the raw SQL:
select * from `students`
where (
select status_student.id from `status_student`
WHERE
status_student.id = (SELECT MAX(status_student.id) from `status_student`
WHERE
status_student.student_id = students.id)
AND
status_student.status_id = 6
)
IS NOT NULL;
and here's the code so far:
$status = $this->request->get('status');
if ($status !== "0") {
dd($query = Student::where(function($q) use($status){
$q->where('status_student.id', function($q2) use ($status) {
$q2->selectRaw('MAX(status_student.id)')
->where('status_student.student_id', '=', 'students.id')
->where('status_student.status_id', '=', $status);
});
})->toSql());
}
which translates into SQL:
"select * from `students` where (`status_student`.`id` = (select MAX(status_student.id) where `status_student`.`student_id` = ? and `status_student`.`status_id` = ?))
so it's not working properly yet.
I'm having trouble introducing that IS NOT NULL clause and doing
select status_student.id from 'status_student'
instead of just
status_student.id =
How should I modify my code to get the desired SQL?
Thanks.
$status = request()->get('status');
if ($status !== "0") {
dd($query = Student::where(function($q) use($status){
$q->where([['status_student.id' => function($q2) use ($status) {
$q2->selectRaw('MAX(status_student.id)')
->where('status_student.student_id', '=', 'students.id')
->where('status_student.status_id', '=', $status);
}],
['status_student.id', '<>', null]
]);
})->toSql());
}
Generated SQL query:
SELECT *
FROM `students`
WHERE (((`status_student`.`student_id` = ?
AND `status_student`.`status_id` IS NULL)
AND `status_student`.`id` IS NOT NULL))
Not sure if I understanded you correctly but I assume you just didn't get the syntax right
try this one:
$status = $this->request->get('status');
if ($status !== "0") {
// log the queries:
\DB::enableQueryLog();
$query = Student::with([
'statusStudent' => function($q1) use($status) {
$q1->where('status_student.id', function($q2) use ($status) {
$q2->selectRaw('MAX(status_student.id)')
->where('status_student.student_id', '=', 'students.id')
->where('status_student.status_id', '=', $status);
});
}
])
->get();
$pureQuery = \DB::getQueryLog();
dd($pureQuery);
}
If you would like to join in eloquent, you must use with() or load() to do that.

SQL: Query returns 1 using count

I have a query in PHP(MySQL). I am fetching records from a table and returning them to a datatable.
The problem is it always returns 1 when I use count() with the query.
However, if I count the elements of the array, then the result is as expected. It returns all 8 records.
Following is my code:
public function job_order_detail_del($arr=array()) {
$count = 0;
$start = isset($arr['start'])?$arr['start']:0;
$length = isset($arr['length'])?$arr['length']:0;
$search = isset($arr['search'])?$arr['search']:'';
$orderBy = isset($arr['orderBy'])?$arr['orderBy']:'';
$orderDir = isset($arr['orderDir'])?$arr['orderDir']:'';
$aufnr = isset($arr['aufnr'])?$arr['aufnr']:0;
$aufpl = isset($arr['aufpl'])?$arr['aufpl']:0;
$type = isset($arr['type'])?$arr['type']:'';
$whr = array('h.stats' => '', 'h.bukrs' => Session::get('company'), 'h.delstats' => '');
if ($aufnr > 0)
$whr['a.aufnr'] = $aufnr;
if ($aufpl > 0)
$whr['a.aufpl'] = $aufpl;
$a = DB::table('zpp_afpo_h as h')
->leftjoin('zpp_afpo as a ', function($join) {
$join->on('a.aufnr', '=', 'h.aufnr')
->where('a.bukrs', '=', Session::get('company'))
->where('a.stats', '=', '');
})
->leftjoin('zpp_afvc as b ', function($join) {
$join->on('a.aufnr', '=', 'b.aufnr')
->on('a.aufpl', '=', 'b.aufpl')
->where('b.bukrs', '=', Session::get('company'))
->where('b.stats', '=', '');
})
->leftjoin('zpp_afru as c ', function($join) use($type) {
$join->on('c.aufnr', '=', 'b.aufnr')
->on('c.rueck', '=', 'b.rueck');
})
->where('c.type', '=', $type)
->where('c.bukrs', '=', Session::get('company'))
->where('c.stats', '=', '')
->where('c.delstats', '=', '')
->select('h.idat2', 'a.matnr', 'b.arbpl', 'a.gamng as total', 'b.rueck', 'h.priority', 'b.vornr', 'b.prev_startper', 'b.scrap', 'h.dispatch_date', 'h.order_start_dt', 'h.requirement_dt', 'h.ktxt', 'c.rmzhl', 'c.budat', 'c.aufnr', 'c.rework_lmnga', DB::raw('sum(c.lmnga) as sum_cnfrm'));
if ($aufnr == '') {
$a->where('h.idat2', '=', '0000:00:00');
}
$a->where($whr)
->groupby('b.rueck')
->groupby('c.rmzhl')
->groupby('c.counter');
if($orderBy!=''){
$a->orderBy($orderBy,$orderDir);
}
if($search!=''){
$dt_srch = implode('-',array_reverse(explode('-',$search)));
$a->where(function($query) use ($search,$dt_srch){
$query->where('c.aufnr','LIKE','%'.$search.'%')
->orWhere('a.matnr','LIKE','%'.$search.'%')
->orWhere('c.budat','LIKE','%'.$dt_srch.'%')
->orWhere('b.arbpl','LIKE','%'.$search.'%')
->orWhere('a.gamng','LIKE','%'.$search.'%');
});
}
if($length>0){
$get_rec = $a->skip($start)->take($length)->get();
}else{
$get_rec = $a->get();
$count = count($get_rec);
// $count = $a->count(); //Problem is here
return $count;
}
$arr = array();
foreach($get_rec as $l){
if($length>0 || Input::get('open') == 1 || Input::get('open') == 2){
$arr = DB::table('maras')
->where('matnr','=',$l->matnr)
->where('bukrs','=',Session::get('company'))
->where('stats','=','')
->where('delstats','=','')
->select(DB::raw('GROUP_CONCAT(distinct(matnr)) as mat'),DB::raw('GROUP_CONCAT(distinct(mdesc)) as mat_desc'))
->groupby('matnr')
->first();
$l->matnr = $arr->mat;
$l->mat_desc = $arr->mat_desc;
}
}
return $get_rec;
}
Please let me know the problem. Thanks in advance.
You are using count on groupBy element and count is returning only the grouped count. That's why it is returning only single row or 1. You could count the returned collections in this case like-
$count = $get_rec->count();

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