Filtering Eloquent Collection - laravel

Trying to filter a collection object down based upon any combination of multiple values. This is as far as I've got. Not happening. Any clues for me?
public function search()
{
$posts = Posting::all();
$type_id = Input::get('type_id');
$country_id = Input::get('country_id');
$province_id = Input::get('province_id');
$posts = $posts->filter(function($post)
{
if( !empty($type_id) && $type_id>0 )
{
return $post->where('type_id','=',$type_id);
}
})->values();
$posts = $posts->filter(function($post)
{
if( !empty($country_id) && $country_id>0 )
{
return $post->where('country_id','=',$country_id);
}
})->values();
$posts = $posts->filter(function($post)
{
if( !empty($province_id) && $province_id>0 )
{
return $post->where('province_id','=',$province_id);
}
})->values();
return $posts;
}
Any help appreciated.

First off, you should really do a validation for the id being larger than 0, if they were provided. You shouldn't be manually checking that out.
But anyhow, why are you using filter, when you can just directly use Eloquent (I omitted the check for id being bigger than 0):
$type_id = Input::get('type_id');
$country_id = Input::get('country_id');
$province_id = Input::get('province_id');
$query = Posting::query();
if ( ! empty($type_id)) $query->whereTypeId($type_id);
if ( ! empty($country_id)) $query->whereCountryId($country_id);
if ( ! empty($province_id)) $query->whereProvinceId($province_id);
return $query->get();

First off, you need to return something that makes sense from the closure in your filter:
$posts = $posts->filter(function($post)
{
if( !empty($type_id) && $type_id>0 )
{
return $post->where('type_id','=',$type_id);
}
})
Above returns Eloquent\Builder object, which is evaluated to true, so.. it really doesn't make sense.
This is what you need:
$posts = $posts->filter(function($post)
{
if( !empty($type_id) && $type_id>0 )
{
return $post->type_id == $type_id; // bool
}
})
With such code, you will filter the collection. $posts now will hold only those items, that match the statement in that closure.

Related

Error:You must specify an orderBy clause when using this function

I am getting the following error while trying to migrate. Actually, I have a lot of data so I used the chunk in laravel.
I am using MongoDB not SQL
** You must specify an orderBy clause when using this function.**
My migration file's up function is is
public function up()
{
ini_set('max_execution_time', 250);
ini_set('memory_limit', '1024M');
$product_array = DB::collection('product')->orderBy('created_at','asc');
$product_array->chunk(20, function($product_array)
{
$cotationPercentForecast=0;
$cotationPercent=0;
$quote_tpl = array();
foreach ($product_array as $key => $value) {
if (isset($value['quote_tpl'])) {
$quote_tpl = $value['quote_tpl'];
$defaultScoreCount = 0;
$realScoreCount = 0;
$forecastScoreCount = 0;
foreach ($quote_tpl as $idxPerimetre => $perimetre) {
if (isset($perimetre['families'])) {
foreach ($perimetre['families'] as $idxFamilies => $family) {
if (isset($family['subfamilies'])) {
foreach ($family['subfamilies'] as $idxSubFamilies => $subfamily) {
if (isset($subfamily['items'])) {
foreach ($subfamily['items'] as $idxitem => $item) {
if (isset($item['criterias'])) {
foreach ($item['criterias'] as $idxcriteria => $criteria) {
if (!isset($criteria['inactive']) || $criteria['inactive'] != 'true') {
$defaultScoreCount++;
if (isset($criteria['real_score'])) {
$realScoreCount++;
}
if (isset($criteria['forecast_score'])) {
$forecastScoreCount++;
}
}
} // FOREACH CRITERIA
} // ISSET CRITERIA ###
} // FOREACH ITEM
} // ISSET ITEM ###
} // FOREACH SUBFAMILY
} // ISSET SUBFAMILY ###
} // FOREACH FAMILY
} // ISSET FAMILY ###
}// FOREACH PERIMETER ##
if ($realScoreCount > 0 && $defaultScoreCount > 0) {
$cotationPercentUn = ($realScoreCount / $defaultScoreCount) * 100;
$cotationPercent = round($cotationPercentUn, 2);
}
if ($forecastScoreCount > 0 && $defaultScoreCount > 0) {
$cotationPercentUnForecast = ($forecastScoreCount / $defaultScoreCount) * 100;
$cotationPercentForecast = round($cotationPercentUnForecast, 2);
}
$results = DB::collection('product')->update(['cotation_percent' => $cotationPercent,'forecast_cotation_percent' => $cotationPercentForecast]);
}
}
});
}
I have gone through many answers here and almost all suggest to use orderBy so I used it. But still getting the error.
i have used
Product::chunk(5, function($product_array){}
Any help is appreciated. Thanks in advance.
This warning is added when Laravel internally uses enforceOrderBy which is defined inside Illuminate/Database/Query/Builder.
Whenever you use chunk on a query builder instantiated by DB facade Illuminate\Database\Query\Builder directly, it would ask you :
You must specify an orderBy clause when using this function.
So it will happen if you are doing :
\DB::table('product')->chunk(10, function($product){
...
});
If you manually add an order by to this, it will not throw the error and will work as expected :
\DB::table('product')->orderBy('created_at')->chunk(10, function($product){
...
});
However, its better to use the Eloquent Model directly like which will not enforce you to add an order by clause manually :
Product::chunk(10, function($product){
...
});
Also there is no method DB::collection(), you can use DB::table() instead if you wish, unless you are using mongodb and not MySQL

How to add another array value in codeigniter using getRecords

The orignial code was like this , I want to get landline_no value also in getRecords, How to do that
public function checklead() {
$lead = $_POST['number'];
$check = $this->common_model->getRecords('leads',array("phone_no"=>$lead));
if(count($check) > 0) {
$lead = $this->common_model->getRecored_row('leads',array("phone_no"=>$lead));
if($lead->assignto_self != 0) {
$assignto = $lead->assignto_self;
$key = 'Self Assign';
} else if($lead->assignto_se != 0) {
$assignto = $lead->assignto_se;
$key = '';}
What I have achieved so far,but not getting array values from getRecords
$lead = $_POST['number'];
$check = $this->common_model->getRecords('leads',array("phone_no"=>$lead),array("landline_no"=>$lead));
//echo "<pre>";
//print_r($check);
//echo $check[0]['landline_no'];exit;
if(count($check) > 0) {
$lead = $this->common_model->getRecored_row('leads',array("phone_no"=>$lead,"landline_no"=>$check[0]['landline_no']));
Code for getRecords:
function getRecords($table,$db = array(),$select = "*",$ordercol = '',$group = '',$start='',$limit=''){
$this->db->select($select);
if(!empty($ordercol)){
$this->db->order_by($ordercol);
}
if($limit != '' && $start !=''){
$this->db->limit($limit,$start);
}
if($group != ''){
$this->db->group_by($group);
}
$q=$this->db->get_where($table, $db);
return $q->result_array();
}
// Get Recored row
public function getRecored_row($table,$where)
{
$q = $this->db->where($where)
->select('*')
->get($table);
return $q->row();
}
Check my answer: This code also working well, i have written, but i am not sure , this logic is correct or not kindly check this one.
public function checklead() {
$lead = $_POST['number'];
if($this->common_model->getRecords('leads',array("phone_no"=>$lead)))
{
$check=$this->common_model->getRecords('leads',array("phone_no"=>$lead));
}
else
{
$check=$this->common_model->getRecords('leads',array("landline_no"=>$lead));
}
echo "<pre>";
//echo $check;
//print_r($check); exit;
$p= $check[0]['phone_no'];
$l= $check[0]['landline_no'];
// exit;
if(count($p) > 0 || count($l)>0) {
$lead = $this->common_model->getRecored_row('leads',array("phone_no"=>$p));
$lead1 = $this->common_model->getRecored_row('leads',array("landline_no"=>$l));
if($lead->assignto_self != 0 || $lead1->assignto_self != 0) {
$assignto = $lead->assignto_self;
$key = 'Self Assign';
} else if($lead->assignto_se != 0 || $lead1->assignto_se != 0) {
$assignto = $lead->assignto_se;
$key = '';
}else if($lead->assignto_tl != 0 || $lead1->assignto_tl != 0) {
$assignto = $lead->assignto_tl;
$key = '';
} else if($lead->uploaded_by != 0 || $lead1->uploaded_by != 0) {
$assignto = $lead->uploaded_by;
$key = 'Uploaded by';
}
$user = $this->common_model->getRecored_row('admin',array("id"=>$assignto));
$role = $this->common_model->getRecored_row('role',array("id"=>$user->role));
$this->session->set_flashdata('message', array('message' => 'This Lead Already exist with '.$user->name.' ('.$role->role.') '.' ','class' => 'danger'));
redirect(base_url().'leads');
} else {
redirect(base_url().'leads/add_newlead/'.$lead);
}
}
There does not seem to be any reason to use getRecords(). The $check value has no useful purpose and creating it is a waste of resources.
We don't need $check because getRecord_row() will return the "lead" if found so the only check needed is to see if getRecord_row() returns anything. getRecord_row() uses the database function row() which returns only one row or null if no rows are found. Read about row() here.
If what you want is to find the "lead" that has either a "phone_no" or a "landline_no" equal to $_POST['number'] then you need to use a custom string for the where clause. (See #4 at on this documentation page.) You need a custom string because getRecord_row() does not allow any other way to ask for rows where a='foo' OR b='foo'. Here is what I think you are looking for.
public function checklead()
{
// use input->post() it is the safe way to get data from $_POST
$phone = $this->input->post('number');
// $phone could be null if $_POST['number'] is not set
if($phone)
{
$lead = $this->common_model->getRecored_row('leads', "phone_no = $phone OR landline_no = $phone");
// $lead could be null if nothing matches where condition
if($lead)
{
if($lead->assignto_self != 0)
{
$assignto = $lead->assignto_self;
$key = 'Self Assign';
}
else if($lead->assignto_se != 0)
{
$assignto = $lead->assignto_se;
$key = '';
}
}
}
}
The main difference between getRecords() and getRecord_row() is the number of records (rows of data) to return. getRecord_row() will return a maximum of one record while getRecords() might return many records.
getRecords() accepts arguments that allow control of what data is selected ($db, $select), how it is arranged ($ordercol, $group), and the number of rows to retrieve ($limit) starting at row number x ($start) .

How to get Select max value in codeigniter

Controller:
$next_id = $this->o->next_id();
$data['next_id']=$next_id;
Model:
public function next_id(){
$this->db->select_max('p_ori_id');
$max = $this->db->get('orientation_master');
if($max==0){
$next_id = 1;
}else{
$next_id = 1+$max;
}
return $next_id;
}
Return Error:
Object of class CI_DB_mysqli_result could not be converted to int
Please solve problem..
No offense to #pradeep but you may have some unexpected results if you don't have any rows. I suggest:
public function next_id()
{
$this->db->select_max('p_ori_id', 'max');
$query = $this->db->get('orientation_master');
if ($query->num_rows() == 0) {
return 1;
}
$max = $query->row()->max;
return $max == 0 ? 1 : $max + 1;
}
Hope this will help you:
public function next_id()
{
$this->db->select_max('p_ori_id', 'max');
$query = $this->db->get('orientation_master');
// Produces: SELECT MAX(p_ori_id) as max FROM orientation_master
$max = $query->row()->max;
if($max == 0){
$next_id = 1;
}else{
$next_id = $max+1;
}
return $next_id;
}
For more : https://www.codeigniter.com/user_guide/database/query_builder.html
You are getting that error becuase $max is a result set object and not an integer record value like you're trying to use it.
You can try this function to get the next id.
Modified function:
public function next_id(){
$this->db->select_max('p_ori_id', 'max');
$result = $this->db->get('orientation_master');
$row = $result->row_array();
$next_id = isset($row['max']) ? ($row['max']+1) : 1;
return $next_id;
}
If the column is auto increment, you can use the below code instead.
Alternative:
public function next_id() {
$sql_string = "SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '".$this->db->dbprefix."orientation_master'";
$query = $this->db->query($sql_string);
$row = $query->row_array();
return $row['auto_increment'];
}

Laravel Query Builder dynamic nested where/orWhere

I hope someone can help guide me in the right direction. I am new to Laravel and far from the best php coder. I am trying to build dynamic nested where/orWhere clauses and I am stuck, and by stuck I mean I can't figure it out. The code I have so far is:
public static function runNested($rId, $current_id) {
$insidestuff = DB::table('tableName')
->select('all fields necessary')
...
->get();
$count=1;
foreach ($insidestuff as $inside)
{
$var1 = $inside->var1;
$var2 = $inside->var2;
$var3 = $inside->var3;
$var4 = $inside->var4;
if ($count == 1)
{
$outsideMet = $outsideMet->where(function($query) use ($var1, $var2, $var3, $var4, $id)
{
$query->where($var1, $var2, $var3);
$outsideMet = myClass::runNested($var4, $id);
});
} else {
$outsideMet = $outsideMet->orWhere(function($query) use ($var1, $var2, $var3, $var4, $id)
{
$query->where($var1, $var2, $var3);
$outsideMet = myClass::runNested($var4, $id);
});
}
$count++;
}
}
public static function runOutside($rId) {
$outsideQuery = DB::table('tableName')
->select('all necessary fields')
->get();
$outsideMet = dbTable::select('*');
$outsideMet = $outsideMet->leftJoin('necessary fields');
$outsideCount=1;
foreach ($oursideQuery as $oQuery)
{
$oVar1 = $oQuery->oVar1;
$oVar2 = $oQuery->oVar2;
$oVar3 = $oQuery->oVar3;
$oVar4 = $oVar4;
$oVar5 = $oQuery->oVar5;
if ($outsideCount == 1)
{
$outsideMet = $outsideMet->where(function($query) use ($oVar1, $oVar2, $oVar3, $oVar4, $oVar5)
{
$query->where($oVar1, $oVar2, $oVar3);
$outsideMet = myClass::runNested($oVar4, $oVar5);
});
} else {
$outsideMet = $outsideMet->orWhere(function($query) use ($oVar1, $oVar2, $oVar3, $oVar4, $oVar5)
{
$query->where($oVar1, $oVar2, $oVar3);
$outsideMet = myClass::runNested($oVar4, $oVar5);
});
}
$outsideCount++;
}
$outsideMet = $outsideMet->count();
I hope someone can tell me how to do this properly, and if the above code is even close, what I am doing wrong. Thank you in advance for the help and guidance.

CI pagination double query

I am working in CI Framework. For pagination i use two queries, one for required output using limit, and another to count total number of rows. Is there any other way like both can be done from single query?
My query is:
{
$searchtxt = $this->input->post('searchtxt');
$datefrom = $this->input->post('fromdate');
$todate = $this->input->post('todate');
$status= $this->input->post('order_status');
$sc_id = $this->input->post('sc_id');
if($sc_id){
$this->db->where('('.'o.requested_sc_id = '.$sc_id.' OR o.requesting_sc_id = '.$sc_id.')');
//$this->db->where('o.requesting_sc_id =',$sc_id);
}
if ($status){
$this->db->where('o.order_status =',$status);
}
if ($status != '' && $status == 0 ){
$this->db->where('o.order_status = 0');
}
if($searchtxt){
$this->db->like('o.order_number',$searchtxt);
}
if($datefrom)
{
$this->db->where('o.order_dt >=', date("Y-m-d",date_to_timestamp($datefrom)));
}
if($todate)
{
$this->db->where('o.order_dt <=', date("Y-m-d",date_to_timestamp($todate)));
}
if ($this->session->userdata('usergroup_id')!=1 && $this->session->userdata('usergroup_id')!= 2 && $this->session->userdata('usergroup_id')!=6 ){
$this->db->where('('.'o.requested_sc_id = '.$this->session->userdata('sc_id').' OR o.requesting_sc_id = '.$this->session->userdata('sc_id').')');
//$this->db->where('o.requesting_sc_id = '.$this->session->userdata('sc_id'));
}
$this->db->select('o.order_id,o.order_number,o.order_dt,o.call_id,c.call_uid,o.order_status,o.order_dt,sc.sc_name,e.engineer_name');
$this->db->from($this->table_name.' AS o');
$this->db->join($this->mdl_callcenter->table_name.' AS c','c.call_id=o.call_id','left');
$this->db->join($this->mdl_servicecenters->table_name.' AS sc' ,'sc.sc_id=o.requested_sc_id','left');
$this->db->join($this->mdl_engineers->table_name.' AS e', 'e.engineer_id = o.engineer_id','left');
$this->db->order_by('o.order_status ASC,o.order_dt DESC,o.order_created_ts DESC');
if(isset($page['limit'])){
$this->db->limit((int)$page['limit'],(int)$page['start']);
}
$result = $this->db->get();
//echo $this->db->last_query();
if ($status){
$this->db->where('o.order_status =',$status);
}
if ($status != '' && $status == 0 ){
$this->db->where('o.order_status = 0');
}
if($sc_id){
$this->db->where('o.requesting_sc_id =',$sc_id);
}
if($searchtxt){
$this->db->like('o.order_number',$searchtxt);
}
if($datefrom)
{
$this->db->where('o.order_dt >=', date("Y-m-d",date_to_timestamp($datefrom)));
}
if($todate)
{
$this->db->where('o.order_dt <=', date("Y-m-d",date_to_timestamp($todate)));
}
//if ($this->session->userdata('global_admin')!=1){
if ($this->session->userdata('usergroup_id')!=1 && $this->session->userdata('usergroup_id')!= 2 && $this->session->userdata('usergroup_id')!=6 ){
$this->db->where('o.requested_sc_id = '.$this->session->userdata('sc_id').' or o.requesting_sc_id = '.$this->session->userdata('sc_id'));
}
$this->db->select('o.order_id');
$this->db->from($this->table_name.' AS o');
$this->db->join($this->mdl_callcenter->table_name.' AS c','c.call_id=o.call_id','left');
$this->db->join($this->mdl_servicecenters->table_name.' AS sc' ,'sc.sc_id=o.requested_sc_id','left');
$this->db->join($this->mdl_engineers->table_name.' AS e', 'e.engineer_id = o.engineer_id','left');
$result_total = $this->db->get();
$orders['list'] = $result->result();
$orders['total'] = $result_total->num_rows();
return $orders;
}
Here is some explanation for this.
function($limit,$offset){
$this->db
->select("SQL_CALC_FOUND_ROWS emp", FALSE)
->select("*")
->from('tbl1')
->limit($limit, $offset);
$data["query_result"] = $this->db->get()->result_array();
$query = $this->db->query('SELECT FOUND_ROWS() AS `Count`');
$data["total_rows"] = $query->row()->Count;
return $data;
}
Here you see you are forced to get total count using another query.
Of course this is not what you want but it is impossible with single query using mysql.
But here is a php way.
function($limit,$offset){
$this->db
->select("*")
->from('tbl1');
$data["query_result"] = $this->db->get()->result_array();
$data["total_rows"] = array_slice($data["query_result"], $offset, $limit);
return $data;
}
This can be achieved with single query but involves php to get the desired result.

Resources