Apply reduce method for all properties of an object - laravel

I have an object in Laravel that represent a monthly report.
0 => array:20 [▼
"id" => 43
"operation_id" => 1
"meter_id" => 3
"period" => "monthly"
"total_conso" => "103.42"
"total_autoconso" => "59.47"
"total_grid" => "43.95"
"bill" => "31.95"
"grid_fee" => "26.97"
"solar_turpe_tax_fee" => "4.99"
"savings" => "4.41"
"total_prod" => null
"total_surplus" => null
"autoconso_rate" => "57.5"
"autoprod_rate" => null
"surplus_rate" => null
"date" => "2019-08-24T00:00:00.000000Z"
"created_at" => "2019-08-24T00:00:00.000000Z"
"updated_at" => "2020-10-01T15:03:38.000000Z"
I have a array with 12 objects of these, one per month.
I am calculating the yearly report values, and I have to sum all 12 month for each field.
I can do it with reduce field by field with:
$totalConso = $reports->reduce(function ($sum, $report) {
return $sum + $report->total_conso;
}, 0);
What I am looking for is a way to do it for all fields. Is it possible ? It would allow me not to duplicate 10 times the same reduce function
Thanks !

You could do something like this:
[$totalConso, $totalAutoConso] = collect(['total_conso', 'total_autoconso'])->map(fn ($property) => $reports->sum($property));
If you would prefer an array with each total:
$totals = collect(['total_conso', 'total_autoconso'])->mapWithKeys(fn ($property) => [$property => $reports->sum($property)]);
This would give you a collection with all the totals.
If you don't like hardcoding the list of total_* attributes, you can get them dynamically from the list of fillable attributes of your model (this assumes you use the fillable property):
$totals = collect(Report::make()->fillable)
->filter(fn ($property) => strpos($property, 'total_') === 0)
->mapWithKeys(fn ($property) => [$property => $reports->sum($property)]);
Demo: https://laravelplayground.com/#/snippets/ec3c662f-0ab9-4de8-8422-7bed2f054677

Use the collect helper and sum method:
$total = collect($reports)->sum('total_conso');

Related

Laravel Excel Row Validation with conditions depends on another field input

I need to validate every rows from excel user upload in laravel which already converted to numeric array.
The validation i wanted is :
to make sure that the 1st field (0) is not blank,
then check whether the input is 'PRODUCTION-PROJECT' or not, if yes, then the 2nd field is required (1).
how to achieve this ?
My Controller Import class
$file = $request->file('file');
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$reader->setLoadSheetsOnly(['Upload']);
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load($file->getRealPath());
$sheet = $spreadsheet->getActiveSheet();
$array = $sheet->toArray();
The array looks like this :
array:8 [
0 => array:11 [
0 => "PRODUCTION-PROJECT"
1 => "Consumable equipment expenses"
2 => "2022-07"
3 => "2022-08"
4 => "Forstr"
5 => "DOMESTIC"
6 => "ABCDE"
7 => "IDR"
8 => 2000
9 => 1
10 => "Enim temporibus est quis."
],
1 => array:11 [
0 => "PRODUCTION-PROJECT"
1 => null
2 => "2022-08"
3 => "2022-08"
4 => "RX"
5 => "DOMESTIC"
6 => "FGHIJ"
7 => "USD"
8 => 2000
9 => 1
10 => null
],
];
The validation i've tried so far like so :
$validatedData = Validator::make($array, [
'*.0' => 'required',
'*.1' => Rule::requiredIf('*.0' === 'PRODUCTION-PROJECT')
];
and the validation didn't show any error
The params of Rule::requiredIf should be a callback function that you need to custom the rule and input.
It's better to change Rule::requiredIf('*.0' === 'PRODUCTION-PROJECT') to 'required_if:*.0,PRODUCTION-PROJECT"'
so the correct code is :
$validatedData = Validator::make($array, [
'*.0' => 'required',
'*.1' => 'required_if:*.0,PRODUCTION-PROJECT'
];

How to use groupBy Month and Sum in laravel MongoDB

Query to get monthly orders (total orders per month(count) or total sales per month(sum)):
Tried this query, but it is not working. Also tried with other results from StackOverflow, but I didn't understand how it is done with MongoDB query. This is the link to that question : select-sum-column-and-group-by-with-mongodb-and-laravel
$monthly_orders = Order::select(
DB::raw('sum(total_amount) as sum'),
DB::raw('YEAR(created_at) year, MONTH(created_at) month'),
)
->groupBy('month')
->get();
When I try to get total amount by using group by customer ID , it is returning sum as null
$monthly_orders = Order::selectRaw('sum(total_amount) as sum, customer_id')
->groupBy('customer_id')
->pluck('sum', 'customer_id');
Result :
Illuminate\Support\Collection {#2123 ▼
#items: array:4 [▼
"6098e5ff5977a25ee96a2a42" => null
"60dbf87f7d8ffb7cdb2233d2" => null
"605af409195d8e59e34893f2" => null
"60ddae4a66fb69678e45f056" => null
]
}
Try using raw and aggregate
$monthly_orders = Order::raw(function ($collection) {
return $collection->aggregate([
[
'$group' => [
"_id" => '$customer_id',
'customer_id' => ['$first' => '$customer_id'],
'sum' => ['$sum' => '$total_amount']
]
],
]);
});
you can use pluck
$monthly_orders->pluck('sum','customer_id')
Group by month
$monthly_orders = Order::raw(function ($collection) {
return $collection->aggregate([
[
'$group' => [
"_id" => ['$month'=>'$created_at'],
'customer_id' => ['$first' => '$customer_id'],
'sum' => ['$sum' => '$total_amount']
]
],
]);
});

How to create a single array using two iterating loop and than update_batch

How do I take id on every iteration from check_seeds array and add on each itteration into seeded[] array.
In more simple words, I want to take an item from the first iteration and add into the first iteration, take an item from the second iteration and add into the second iteration and so on...
Actually, on update_batch we need third parameter (primary key, index) to update array values in database rows where id from database rows matches with the id in update_batch.
$check_seeds = $this->tournament_model->get_seeds($tournament_id);
$seeds = $this->input->post('seed');
foreach ($seeds as $key => $value){
if(!empty($key) && !empty($value)){
$seeded[] = array(
'id' => (Add id here),
'tournament_id' => $tournament_id,
'stage_id' => $stage_id,
'seed_id' => $value,
'team_name' => $key,
);
$this->db->update_batch('tournament_seed', $seeded, 'id');
redirect('organizer/tournaments);
}
}
print_r($check_seeds)
Array
(
[0] => Array
(
[id] => 3
[tournament_id] => 713161746
[stage_id] => 3
[seed_id] => 3
[team_name] => -V-ATTAX
)
[1] => Array
(
[id] => 4
[tournament_id] => 713161746
[stage_id] => 3
[seed_id] => 3
[team_name] => -V-ATTAX
)
[2] => Array
(
[id] => 5
[tournament_id] => 713161746
[stage_id] => 3
[seed_id] => 3
[team_name] => -V-ATTAX
)
)
in your model function get_seeds() you can query the current max value of id as an alias and return it together with the query result:
function get_seeds($tournament_id) {
$this->db->select_max('id', 'max_id');
$this->db->where('tournament_id', $tournament_id);
$result = $this->db->get('tournament_seed');
return $result->result();
}
then in your controller's for_each() you increment that value:
$i=0;
foreach ($seeds as $key => $value){
$i++;
$seeded[] = array(
'id' => $value->max_id + $i,
//....
);
}
Codeigniter docs: Selecting Data, scroll down to select_max(), as there is no internal bookmark

Convert an array of array onto Collection Laravel

I have an array of array which results from several sql requests.
First I make a sql request in a foreach in order to have all the datas i need
foreach ($users as $user) {
// Two different Eloquent requests
$todo = User::select().....where('users.id' = $id);
$done = User::select().....where('users.id' = $id);
// I have operation on Collection that work fine ...
$totalTimes = $todo->toBase()->sum('dureeformation') ;
$spendTimes = $done->toBase()->sum('dureeformation') ;
$remainingTimes = $totalTimes - $spendTimes;
$all[] = ['user_id' => $id, 'totalTime' => $totalTimes, 'spendTime' => $spendTimes,'remainingTime' => $remainingTimes ];
}
My issue is the following... Outside the foreach i display the values and i have this array of array ...
array:16 [▼
0 => array:4 [▼
"user_id" => 1
"totalTime" => 465
"spendTime" => 0
"remainingTime" => 465
]
1 => array:4 [▼
"user_id" => 3
"totalTime" => 375
"spendTime" => 0
"remainingTime" => 375
]
I would need to have a Collection instead ... I tried to make $all = Collect(....) but i doesn't give me the expected result.
I need a collection because i have to create a Collection with this created collection and another one from another request.
Concerning this part i already had this case and i can solve it.
Thanks for your help
try this helper function :
$collection = collect($all);
This function will convert your array to collection.

sorting and filtering not working in custom admin module

I am trying to implement an admin module in magento which has a grid in the first page and grids in the tabs while editing the grid entities.
The main grid works fine, but the grids in the tabs are not working fine.
The problem I found while I debugged the code is that, I am loading the collection in the grid with field filtering, ie I am filtering the collection with filter that is the user id. I did this because I need only data of a single user from the table. This made the entire problem, the data in the grid is coming correctly, but the filtering,sorting and searching feature inside grid is not working and returning a 404 not found error page. I tried removing the field filter I added while getting the collection, then it works fine but all the data in the table is coming which is the opposite to my requirement.
Is there any possible solution to this. Here is the way I am trying to do:
protected function _prepareCollection() {
$collection = Mage::getModel('merchant/subscriptions')->getCollection()->addFieldToFilter('user_id', Mage::registry('merchant_data')->getId());
$this->setCollection($collection); //Set the collection
return parent::_prepareCollection();
}
Thanks in advance.
ok My problem is solved there is a mistake in my code. In the grid file the function below was wrong.
public function getGridUrl() {
return $this->getUrl('*/*/transactiongrid', array('user_id',Mage::registry('merchant_data')->getId(), '_current' => true));
}
The correct method was
public function getGridUrl() {
return $this->getUrl('*/*/transactiongrid', array('user_id'=> Mage::registry('merchant_data')->getId(), '_current' => true));
}
Filter action is dependent on your below method:
public function getGridUrl() {
return $this->getUrl('*/*/grid', array('user_id' => Mage::registry('merchant_data')->getId(),'_current'=>true));
}
now this is how you will prepare collection:
protected function _prepareCollection()
{
$regData = Mage::registry('merchant_data');
if(isset($regData))
$regData = $regData->getId();
else
$regData = $this->getRequest()->getParam('user_id');
$collection = Mage::getModel('merchant/subscriptions')->getCollection()->addFieldToFilter('user_id',$regData);
...
When I dumped $regData I got this:
Cubet_Merchant_Model_Merchant Object
(
[_eventPrefix:protected] => core_abstract
[_eventObject:protected] => object
[_resourceName:protected] => merchant/merchant
[_resource:protected] =>
[_resourceCollectionName:protected] => merchant/merchant_collection
[_cacheTag:protected] =>
[_dataSaveAllowed:protected] => 1
[_isObjectNew:protected] =>
[_data:protected] => Array
(
[user_id] => 3
[firstname] => Robin
[lastname] => Cubet
[email] => robin#cubettech.com
[username] => robincubet
[password] => 51a7f45eb11fc49b5967a0039193c3ad:HSX8JkSO5lr3uaRHrzd86i7gb0RATeDb
[created] => 2013-12-12 08:34:28
[modified] => 2013-12-16 09:03:56
[logdate] =>
[lognum] => 0
[reload_acl_flag] => 1
[is_active] => 1
[extra] => N;
[rp_token] =>
[rp_token_created_at] =>
)
[_hasDataChanges:protected] =>
[_origData:protected] => Array
(
[user_id] => 3
[firstname] => Robin
[lastname] => Cubet
[email] => robin#cubettech.com
[username] => robincubet
[password] => 51a7f45eb11fc49b5967a0039193c3ad:HSX8JkSO5lr3uaRHrzd86i7gb0RATeDb
[created] => 2013-12-12 08:34:28
[modified] => 2013-12-16 09:03:56
[logdate] =>
[lognum] => 0
[reload_acl_flag] => 1
[is_active] => 1
[extra] => N;
[rp_token] =>
[rp_token_created_at] =>
)
[_idFieldName:protected] => user_id
[_isDeleted:protected] =>
[_oldFieldsMap:protected] => Array
(
)
[_syncFieldsMap:protected] => Array
(
)
)

Resources