What I want is that when a user visits this link /api/bonus?provider[]=MyCompany
the result will show only bonus provided by providers=[MyCompany].
In my controller:
public function all(Request $request)
{
$size = $request->input('size');
$bonus = Bonus::with('category', 'bonus');
$bonus = Filterer::apply($request, $size, $bonus);
$bonus = Filterer::apply($request, $size, $bonus);
return response()->json([
'code' => 0,
'success' => true,
'data' => BonusResource::collection($bonus),
}
My expected result is to get all the providers that equal the [MyCompany]
But somehow this query doesn't work.
Filterer
public static function apply(Request $filters, $size, $bonus)
{
if ($filters->has('provider')) {
$bonus->whereHas('bonus', function ($query) use ($filters) {
$query->whereIn('providers', $filters->input('provider',[]));
});
}
return $bonus->paginate($size);
}
but at the end I'm getting this result. The data is null [].
I'm wonder why I can't get the data. Which part I had done wrong?
To actually get results you should use some function that gets data from database, for example get, first (depends whether you want to get multiple rows or only first row). Now you only prepare query that should be executed but you never execute it, so yo should change line:
$bonus = Filterer::apply($request, $size, $bonus);
into
$bonus = Filterer::apply($request, $size, $bonus);
$bonus = $bonus->get();
to execute query and get results.
I might be wrong, but based on your code, the function apply didn't return anything, it will always empty. Shouldn't it be return $bonus? and don't forget the get.
public static function apply(Request $filters, $size, $bonus)
{
if ($filters->has('provider')) {
$bonus->whereHas('bonusRelease', function ($bonus) use ($filters) {
return $bonus->whereJsonContains('providers', $filters->input('provider',[]));
});
}
return $bonus->get();
}
Updated my answer
The providers is a json type. You can't just query it with where in (a,b,c). Change to whereJsonContains. Please check this link another case and laravel docs.
First, convert the input into array, here I'm using explode()
and then I loop the converted array and use %% to search the providers. Hope it will help!
if ($filters->has('provider') && trim($filters->input('provider')) != "") {
$bonus_list->whereHas('bonusCompany', function ($query) use ($filters) {
$providers = explode(',', (trim($filters->input('provider'), '[]')));
foreach ($providers as $key => $provider) {
if ($key == 0) {
$query->where('providers', 'LIKE', ['%' . trim($provider) . '%']);
} else {
$query->orwhere('providers', 'LIKE', ['%' . trim($provider) . '%']);
}
}
});
};
Related
In my Laravel 8 project I'm dispatching a Job which runs and collects a bunch of data from the database, the data could be any amount ranging from a few hundred rows of data to potentially thousands, so could be quite memory intensive.
Upon returning the results, they're processed and added to a database table, and I'm hoping to have some kind of progress indication as a percentage that can be reported back to the user whilst the chunking is in progress, I have two tables, a reports and a reports_data table.
I've switched by query over to Laravel's chunk method, and am splitting the data collection into smaller bits as this should improve performance, but for some reason, to use my data as a whole, as if it were a collection I'm pushing it into an empty array called $res, but I'm getting an error so my job failsError: Call to a member function groupBy() on array:
Error: Call to a member function groupBy() on array
I'm wondering what I'm missing...
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$filters = json_decode($this->report->discovery_filters);
$data = [];
// create
foreach ($filters as $findable) {
$resultData = [];
// query data
if (isset($findable->query)) {
$this->setDynamicChartOptions();
$res = [];
$chunkData = DB::table($findable->query->table)
->select($findable->query->columns)
->where($findable->query->filterBy)
->orderBy($findable->query->orderBy->field, $findable->query->orderBy->direction)
->chunk(100, function ($chunkedResults) use ($res) {
foreach ($chunkedResults as $chunk) {
// how to update some kind of progress?
array_push($res, $chunk);
var_dump(count($res));
}
});
// $res expected as a collection? Maybe I can use the `collect` method?
if (isset($findable->query->useGrouping) && $findable->query->useGrouping) {
$results = $res->groupBy(function ($item, $key) use ($findable) {
$date = Carbon::parse($item->{$findable->query->groupBy});
return $date->format($findable->query->groupByFormat);
});
$results = $results->map(function ($item, $key) {
return $item[0];
});
$resultData = $results->flatten();
}
}
$res = [
'componentID' => $findable->componentID ?? 0,
'type' => $findable->type ?? '',
'name' => $findable->name ?? '',
'labelsKey' => $findable->query->labelsKey ?? '',
'dataKey' => $findable->query->dataKey ?? '',
'data' => $resultData ?? [],
'structure' => $this->getStructure($findable, $resultData)
];
array_push($data, $res);
}
// create our report data entry
$this->createReportData($data);
}
UPDATE:
I've tried chunking and grouping, the job fails:
$res = [];
$chunkData = DB::table($findable->query->table)
->select($findable->query->columns)
->where($findable->query->filterBy)
->orderBy($findable->query->orderBy->field, $findable->query->orderBy->direction)
->chunk(100, function ($chunkedResults) use ($res) {
$res[] = $chunkedResults;
foreach($res as $chunk) {
$chunk->groupBy();
}
});
This also fails...
res = [];
$chunkData = DB::table($findable->query->table)
->select($findable->query->columns)
->where($findable->query->filterBy)
->orderBy($findable->query->orderBy->field, $findable->query->orderBy->direction)
->chunk(100, function ($chunkedResults) use ($res) {
$res[] = $chunkedResults;
});
foreach($res as $chunk) {
$chunk->groupBy();
}
And this too, still doesn't seem to work in that it doesn't give back any collection, which is what I need for the rest of my code to work:
$res = [];
$chunkData = DB::table($findable->query->table)
->select($findable->query->columns)
->where($findable->query->filterBy)
->orderBy($findable->query->orderBy->field, $findable->query->orderBy->direction)
->chunk(100, function ($chunkedResults) use ($res) {
foreach ($chunkedResults as $key => $chunk) {
array_push($res, $chunk);
}
});
$res = collect($res);
Because $res = []; is an array, not an instance of eloquent's Illuminate\Support\Collection. Therefore, you can not call $res->groupBy(), as you are trying within the first if-statement.
Remove the ->chunk() method and get your data-chunk by using slice instead for example within a loop that always takes a slice of the data.
Optionally, call collect($res) to turn the array back into a collection. However, when having a Collection already, there is no point in making it into an array first just to cast it back directly afterwords. So I would go with the slice approach.
You could also - withing your chunk callback - do the following:
->chunk(100, function ($chunkedResults) use ($res) {
$res[] = $chunkedResults;
});
And then:
foreach($res as $chunk) {
$chunk->groupBy();
}
I have a function getUnfilledOrders where I get Orders from the database and then use chunk to have them go to checkStatus 10 at a time. If I have 100 orders, the flow I believe would happen is checkStatus get will get called 10 times (since there are 100 orders).
Now once that completes, I want to have access to $totalOrders in getUnfulfilledOrders. Is this possible?
protected function getUnfulfilledOrders()
{
Order::where('order_status', '!=', true)
->where('tracking_number', '!=', null)
->limit(3000)
->chunk(10, function ($unfulfilledOrders) {
$this->checkStatus($unfulfilledOrders);
});
// how to do something now with $totalOrders once ALL Orders are processed 10 at a time;
}
protected function checkStatus($unfilledOrders)
{
$totalOrders = array();
foreach ($unfulfilledOrders as $unfulfilledOrder) {
// logic here
array_push($totalOrders, $unfulFilledOrder->id);
}
}
Like this:
protected function getUnfulfilledOrders()
{
$totalOrders = [];
Order::where('order_status', '!=', true)
->where('tracking_number', '!=', null)
->limit(3000)
// Add use (&$totalOrders)
->chunk(10, function ($unfulfilledOrders) use (&$totalOrders) {
$totalOrders = array_merge($totalOrders, $this->checkStatus($unfulfilledOrders));
});
// how to do something now with $totalOrders once ALL Orders are processed 10 at a time;
}
protected function checkStatus($unfilledOrders)
{
$totalOrders = array();
foreach ($unfulfilledOrders as $unfulfilledOrder) {
// logic here
array_push($totalOrders, $unfilledOrder->id);
}
// Return the generated array
return $totalOrders;
}
Here I initiated an empty array at the start of getUnfulfilledOrders() and merged anything returned by checkStatus() into it.
More on use ($var)
More on passing by reference (&$var)
controller code
if($this->input->post('update'))
{
$n=$this->input->post('pps_pin');
$e=$this->input->post('pps_address');
$m=$this->input->post('stm_shipping_type');
$a=$this->input->post('tsm_time_slot');
$b=$this->input->post('pps_price');
$id=$this->input->post('pps_slid');
$this->Config_model->updaterecords($n,$e,$m,$id,$a,$b);
redirect('Admin_ctrl/config/view_pincode_price');
}
}
model code
function updaterecords($n,$e,$m,$id,$a,$b)
{
$id;
$qr=$this->db->query("UPDATE pincode_price_setup,shipping_type_mst,time_slot_mst SET pps_pin='$n',pps_address='$e',stm_shipping_type='$m',tsm_time_slot='$a',pps_price='$b' WHERE pps_slid='$id'");
return $qr;
}
Delivery Method and Delivery Time Slot data are same
You should modify your code to use codeigniters prepared statements. If I correctly understood relations in your DB, your update records method should looks something like this:
function updaterecords($n, $e, $m, $id, $a, $b)
{
$this->db->set('pps_pin', $n);
$this->db->set('pps_address', $e);
$this->db->set('stm_shipping_type', $m);
$this->db->set('tsm_time_slot', $a);
$this->db->set('pps_price', $b);
$this->db->join('shipping_type_mst', 'pincode_price_setup.pps_shipping_type = shipping_type_mst.stm_sqlid');
$this->db->join('time_slot_mst', 'pincode_price_setup.pps_time_slot = time_slot_mst.tsm_sqlid');
$this->db->where('pps_slid', $id);
$this->db->update('pincode_price_setup');
}
Friendly tip: give your variables some more meaningful names, it would be much easier to work with variable named $pin than $n.
Please try like this
//Controller Code
function update_record($id){
$update_array = array(
'pps_pin' => $this->input->post('pps_pin') ///add fields in array which updated
);
$this->modal_name->update($id,update_array);//pass id & array which want to be update
}
//Modal code
function update($id,$array){
return $this->db->where('id',$id)->update('TABLE_NAME',array);
}
Try This code
function updaterecords($n, $e, $m, $id, $a, $b) {
$this->db->set('pps_pin', $n);
$this->db->set('pps_address', $e);
$this->db->set('stm_shipping_type', $m);
$this->db->set('tsm_time_slot', $a);
$this->db->set('pps_price', $b);
$this->db->where('pps_slid', $id);
$this->db->update('pincode_price_setup');
return ($this->db->affected_rows() != 1) ? false : true;
}
Once codeigniter model is loaded then its default update function works
if($this->input->post('update'))
{
$data = [
'pps_pin' => $this->input->post('pps_pin'),
'pps_address' => $this->input->post('pps_address'),
'stm_shipping_type' => $this->input->post('stm_shipping_type'),
'tsm_time_slot' => $this->input->post('tsm_time_slot'),
'pps_price' => $this->input->post('pps_price'),
'pps_slid' => $this->input->post('pps_slid'),
];
$this->Config_model->id = $id;
$this->Config_model->update($data);
redirect('Admin_ctrl/config/view_pincode_price');
}
}
So I am sure we don't need to define a separate function in model for same purpose.
So as I understand it, you want to update records in your database. I will not write it for you. I will show you an example.
This code may not be perfect but it works for my localhost project.
Create a function to update records in your controller.
Example:
public function update($id){
$id = $this->input->post('id');
//create $data array and add your data to array
$data = array(
'nazov_divizia' => $this->input->post('nazov')
);
//send this $data array with $id to your update function in model
$this->Divizia_model->updateData($id, $data);
//you can create flash message if you want
$this->session->set_flashdata('message', 'Údaje upravené');
//redirect to your controller index function
redirect(base_url().'divizia');
}
Create a function to update the record in your model.
Example:
public function updateData($id, $data)
{
$this->db->where('id_divizia', $id);
$this->db->update('divizia', $data);
}
I have an array that comes to controller's action.
$arrOfTags = $request['position'];
That array looks like :
['manager', 'consultant'];
Next, I am querying the DB for CV's where position is one of these.
$query = Cv::query();
$query->whereIn('position', $arrOfTags);
...
->get();
Now the question :
If $request['position'] = ['manager','consultant']; and whereIn clause finds result just for position = 'consultant' and none for 'manager', how can I programmatically discover that results are found for 'consultant' and/or didn't found for 'manager' ?
EDIT
All my query's code :
$arrOfTags = explode(',', $request['position']);
$query = Cv::query();
$query->whereIn('position', $arrOfTags)
if($request['salary']) {
$query->whereIn('salary', $request['salary']);
}
if($request['skill']) {
$query->join('skills', 'cvs.id', '=', 'skills.cv_id')
->join('allskills', 'skills.allskills_id', '=', 'allskills.id')
->select('cvs.*', 'allskills.name AS skillName')
->whereIn('skills.allskills_id', $request['skill']);
}
if($request['language']) {
$query->join('languages', 'cvs.id', '=', 'languages.cv_id')
->join('alllanguages', 'languages.alllanguages_id', '=', 'alllanguages.id')
->select('cvs.*', 'alllanguages.name as languageName')
->whereIn('languages.alllanguages_id', $request['language']);
}
$cvs = $query->distinct()->get();
Imagine that $arrOfTags values are ['manager', 'consultant', 'sales']
I want somehow to discover that results was found for position =
manager and consultant, and didn't found for position = 'sales'
You can load the data from DB:
$cvs = CV::....;
And then use the partition() method:
list($manager, $consultant) = $cvs->partition(function ($i) {
return $i['position'] === 'manager';
});
Or the where() method:
$manager = $cvs->where('position', 'manager');
$consultant = $cvs->where('position', 'consultant');
Both partition() and where() will not execute any additional queries to DB.
You can do this way too:
$managers = $collection->search(function ($item, $key) {
return $item['position'] === "manager";
});
$consultants = $collection->search(function ($item, $key) {
return $$item['position'] === "consultant";
});
You could use count().
if(($query->count)==($query->where('position','consultant')->count())){
///all are coming for position=consultants
}
Or you could use groupBY-
$query = $query->groupBy('position')->toArray();
And retrieve by-
$consultants = $query['consultant'];
Alright I have a GeneralModel written in CodeIgniter and a friend asked me if I could convert it into Laravel 4.2 for him. I was working on this and I think I have most of it correct but I am getting stuck at the select statement.
In CodeIgniter I have the following:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE){
if($field != FALSE){
// WHERE in case of FIELD / VAL :)
$this->db->where($field, $val);
}
$query = $this->db->get($table);
if($multiple == 1){
// Multiple rows
return $query->result_array();
} else {
// One row
return $query->row_array();
}
}
Does anyone here knows how I can convert this function into Laravel 4.2 syntax?
I currently have:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE){
$result = DB::table($table);
}
I got stuck pretty quickly since I have no idea how I can achieve the same in Laravel 4.2 with splitting up the sections of the query like I did with CodeIgniter.
You can chain methods in the same way:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE)
{
$query = DB::table($table);
if ($field != FALSE) {
// WHERE in case of FIELD / VAL :)
$query->where($field, $val);
}
if ($multiple)
return $query->get();
else
return $query->first();
}
Laravel is similar in that you can use the Fluent Query Builder to build your queries in multiple stages prior to actually making the query. Once you know this, the translation is pretty straightforward:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE)
{
$query = DB::table($table);
if($field){
// WHERE in case of FIELD / VAL :)
$query = $query->where($field, $val);
}
if($multiple) {
return $query->get();
}
return $query->first();
}
I don't think it's really good practice relying on Fluent though inside of an Eloquent model, but there are cases where that can't be helped. If the current objective is to convert the project to Laravel, there's probably calling code relying on the fact that this method exists. Converting the function to use Eloquent rather than Fluent will change the function's signature and cause other parts of the code to break, but it would look like this:
public function getData($multiple = true, $field = false, $val = false)
{
$query = $this;
if($field) {
$query = $query->where($field, $val);
}
if($multiple) {
return $query->get();
}
return $query->first();
}
The calling code itself can be modified to do the exact same function in Laravel like this:
// Instead of...
$result = $model->getData(1, 'field', 'value');
// You can do this:
$result = $model->where('field', 'value')->get();
// Or this if you'd rather not have multiple:
$result = $model->where('field', 'value')->first();
Using this function inside Eloquent (IMHO) in the long run doesn't really save you much, and instead is mostly just clutter.