How to fix laravel collection chunk loop once? - php

I have a problem with laravel collection with chunk result. It run only one time in loop.
I have 204 elements in array and I want to split it as 100 each by using laravel collection helper. It must run in three times but I got only once.
private function __migrateDistricts()
{
DB::beginTransaction();
try {
$file = 'resources/csv/districts.csv';
$csv = array_map('str_getcsv', file($file));
$table = 'districts';
$collection = collect($csv);
$arr_districts = array();
foreach ($collection->chunk(100) as $districts) {
foreach ($districts as $dist) {
array_push($arr_districts, $this->__transformDistricts($dist));
}
DB::table($table)->insert($arr_districts);
DB::commit();
}
} catch (\Exception $e) {
DB::rollBack();
}
}
private function __transformDistricts($district)
{
$code = substr($district[3],0,2);
$pro = DB::table('provinces')->where('code', $code)->first();
return [
'province_id' => $pro->id,
'name_kh' => $district[1],
'name_en' => $district[2],
'code' => $district[3],
];
}
After I run the I got only 100 records in table. It should be 204 records in table. What is wrong with my code? Thanks

In your code...
$arr_districts = array();
foreach ($collection->chunk(100) as $districts) {
foreach ($districts as $dist) {
array_push($arr_districts, $this->__transformDistricts($dist));
}
DB::table($table)->insert($arr_districts);
DB::commit();
}
in each inner loop, you add the data to $arr_districts, which on the second time of your outer loop, will still contain the data from the first loop.
You should reset this array for each main loop to clear the data out...
foreach ($collection->chunk(100) as $districts) {
$arr_districts = array(); // Move to here
foreach ($districts as $dist) {
array_push($arr_districts, $this->__transformDistricts($dist));
}
DB::table($table)->insert($arr_districts);
DB::commit();
}

Related

Larvel Update Data from Array with foreachloop

Hello There I need Help To Update on Vehicle Wies on Specific Dates.I'm Attaching Form image and Here is my Controller code.
public function add_vehicle_expense(Request $request)
{
$veh = array('veh_reg_num' => $request->veh_reg_num);
foreach ($veh as $data) {
print_r($request->date[$data]);
dd();
$veh = Sale_report::where('date',$request->date[$data])->where('veh_reg_num', $request->veh_reg_num[$data])->update(['diesel_qty'=> $request->qty[$data], 'diesel_rate'=> $request->rate[$data], 'diesel_amount'=> $request->total_amount[$data], 'other_expense'=> $request->other_exp[$data]]);
}
if ($veh) {
return redirect()->back()->with('Data Store Successfully');
}
//$veh = Sale_report::where('date',$request->date)->where('veh_reg_num', $request->veh_reg_num)->update(['diesel_qty'=> $request->qty, 'diesel_rate'=> $request->rate, 'diesel_amount'=> $request->total_amount, 'other_expense'=> $request->other_exp]);
/* foreach ($request->date as $reg_num => $key ) {
$s = Sale_report::where('date',$request->date[$reg_num])->where('veh_reg_num',$request->veh_reg_num[$reg_num])->first();
$s->diesel_qty = $request->qty[$reg_num];
$s->diesel_rate = $request->rate[$reg_num];
$s->diesel_amount = $request->total_amount[$reg_num];
$s->other_expense = $request->other_exp[$reg_num];
$s->update();
} */
}
I have try to Update Data by matching Each Vehicle Number with Date Some times it Show ErrorException Attempt to read property on int,ErrorException Undefined array key "data"
I have Found The Solution of this Problem.
I've use implode(',' , $request->veh_reg_num) Then I use $datas = explode() function then I use foreach() With exploded Vairable as foreach($datas as $data => $value){
match the each row that with $data array then I Update the values to data base }

Laravel flatten won't flatten array error

In my Laravel project I'm trying to flatten an array to ensure consistency, for some reason, the attached screenshot showing my data format returned from my project won't flatten with the flatten() method.
I get an error:
Error: Call to a member function flatten() on array
Which is quite generic, I've tried using ->toArray() before flattening but this doesn't give me any data, what am I doing wrong here?
The logic exists within a Laravel job, thus the console log
/**
* Group data
*
* #return void
*/
public function groupData(
$data,
$groupBy,
$groupByFormat,
$additionFromField = ''
) {
$results = $data->groupBy(function ($item, $key) use ($groupBy, $groupByFormat) {
$date = Carbon::parse($item->{$groupBy});
return $date->format($groupByFormat);
});
// grouping by some kind of total
if (!empty($additionFromField)) {
$results = $results->map(function ($item, $key) use ($additionFromField) {
$totals = 0;
foreach ($item as $key => $value) {
$totals += $value->{$additionFromField};
}
return [
'items' => count($item),
'total' => $totals ?? 0
];
});
$calcedData = [];
foreach ($results as $key => $result) {
array_push($calcedData, [
'period_to' => $key,
'items' => $result['items'],
'total' => $result['total']
]);
}
return $calcedData;
}
// standard grouping of data
$results = $results->map(function ($item, $key) {
return $item[0];
});
return $results;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$filters = json_decode($this->report->discovery_filters, true);
$data = [];
foreach ($filters as $findableKey => $findable) {
/*
** If there are datasets on the findable objec, then we assume
** that we can build up a chart or some data structure.
*/
if (isset($findable['datasets'])) {
$pushableDatasets = [];
foreach ($findable['datasets'] as $datasetKey => $dataset) {
// query data
if (isset($dataset['query'])) {
$additionFromField = $dataset['query']['additionFromField'] ?? '';
$res = DB::table($dataset['query']['table'])
->select($dataset['query']['columns'])
->where($dataset['query']['filterBy'])
->orderBy($dataset['query']['orderBy']['field'], $dataset['query']['orderBy']['direction'])
->get()
->chunk(100);
$res = $res->flatten();
if (isset($dataset['query']['useGrouping']) && $dataset['query']['useGrouping'] == 'yes') {
$results = $this->groupData(
$res,
$dataset['query']['groupBy'],
$dataset['query']['groupByFormat'],
$additionFromField
);
var_dump($results); // shown in the screenshot
$resultData = $results->flatten();
array_push($pushableDatasets, $this->getStructure($findable, $datasetKey, $resultData));
}
}
}
$findable['datasets'] = $pushableDatasets;
}
array_push($data, $findable);
}
}
Error: Call to a member function flatten() on array
The error message is quite accurate and descriptive. flatten is a member function of an object (in this case, the Laravel Collection object) and an array is not an object.
You need to convert the array to a collection first, then you can flatten it:
$flattened = collect($results)->flatten();
$new = collect($results)->flatten();
In your case you can also use array_flatten() I guess. Here is the documentation https://laravel.com/docs/5.1/helpers#method-array-flatten

Laravel chunk Call to a member function groupBy() on my variable

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

Request too heavy

I try to retrieve for each region the number of cities with current events.
So I started doing this:
$regionCities = [];
foreach ($regions as $region) {
$regionCities[$region->getId()] = $cityRepository->getCitiesByRegion($region);
}
dump($regionCities);
$regionCitiesNumber = [];
foreach ($regionCities as $index => $region) {
foreach ($region as $city) {
$regionCitiesNumber[$index] = count($city->getCurrentEvents());
}
}
My dump returns me this:
dump
The problem is, it crashes my script, and I suddenly get a blank page when I dump regionCitiesNumber.
getCurrentEvents is a method of my City entity that will retrieve all current events.
public static function createCurrentEventsCriteria(): Criteria
{
return Criteria::create()
->where(Criteria::expr()->gte('endDate', new DateTime('00:00:00')))
->orderBy(['id' => 'DESC'])
;
}
public function getCurrentEvents(): Collection
{
$criteria = EventRepository::createCurrentEventsCriteria();
return $this->events->matching($criteria);
}
Use error logs or try using "Try Catch" wrapper
$regionCities = [];
foreach ($regions as $region) {
$regionCities[$region->getId()] = $cityRepository->getCitiesByRegion($region);
}
//dump($regionCities);
try {
$regionCitiesNumber = [];
foreach ($regionCities as $index => $region) {
foreach ($region as $city) {
$regionCitiesNumber[$index] = count($city->getCurrentEvents());
}
}
} catch (\Throwable $t) {
dd($t);
}
So I tried:
return $this->events->matching($criteria)->count();
And I dumped on regionCitiesNumber, it gave me a totally wrong result:
For example for the ARA region, I end up with 0 as a result while there are 1895 events distributed over all the departments ...
As a result, most regions result in 0, sometimes 1, sometimes 2 ...
In addition, it takes a long time to load my page, isn't there a softer solution?

how to add array or row to array while foreach looping laravel 5.8

I need to get all products for category and sub categories when click on parent category
so i make loop or recursive loop to get all id for category and subcategory to search for its products
public function tree($category, $cats = array())
{
$items = category_model::select('id')->where('parent_id', $category)->get();
foreach ($items as $key=>$value)
{
//$cats = $value;
$cats = Arr::add($cats, 'id', $value);
self::tree($value, $cats);
}
return $cats;
}
public function allproduct(Request $request)
{
return self::tree($request->id);
}
I have tried this code but looping with our result
I need to add this all id to make search for products through this array
You can improve your own code and make it work by taking all the category ids at once, instead of making a for each loop there.
Also, you are missing a terminating condition which is a must when using recursive functions.
Also, you don't need to process the same ids again and again if they have already been processed.
Taking all those points in mind, do something like this:
public function tree($cats, $alreadyProcessedCats = [])
{
if (empty($cats)) {
return [];
}
$newCatIds = [];
foreach ($cats as $catId) {
//do not process it if it was alreadt processed
if (in_array($catId, $alreadyProcessedCats)) {
continue;
}
//fetch all the categories id where parent id is one of the id which is present in the $cats
$items = category_model::where('parent_id', $category)->pluck('id');
if (empty($items)) {
continue;
}
$items = $items->toArray();
$newCatIds = array_merge($newCatIds, $items);
}
//terminal condition
if (empty($newCatIds)) {
return $cats;
}
$newCats = array_merge($cats, $newCatIds);
return self::tree($newCats, $cats);
}
public function allproduct(Request $request)
{
$allCategoriesIds = [$request->id];
$allCategoriesIds = self::tree($allCategoriesIds);
}
Fix your foreach loop.
foreach ($items as $key=$value)
should be
foreach ($items as $key => $value)
I can't comment on that static Arr function (a Laravel thing I guess? due to the misuse of statics everywhere?)

Categories