Fill missing array elements with zero values Codeigniter - php

I am fetching data from database which have dates that need to be sent to the view to create a chart. Some months might not have transactions which I need them to be autofilled with 0.
Model
function get_chart_data()
{
$this->db->order_by('month','asc');
$this->db->select('COUNT(*) as no_payments, SUM(amount) as total_payment_amount, YEAR(`date_paid`) AS year, MONTH(`date_paid`) AS month');
$this->db->group_by(array("year", "month"));
$this->db->where('tbl_payments.payment_type', "PAYMENT");
return $this->db->get('tbl_payments');
}
When I print_r in my controller the data is
Array ( [0] => stdClass Object ( [no_payments] => 1 [total_payment_amount] => 450 [year] => 2016 [month] => 1 ) [1] => stdClass Object ( [no_payments] => 5 [total_payment_amount] => 1162 [year] => 2016 [month] => 5 ) [2] => stdClass Object ( [no_payments] => 2 [total_payment_amount] => 1700 [year] => 2016 [month] => 6 ) )
How can I fill in the missing months and data with zero i.e the data to be
Array ( [0] => stdClass Object ( [no_payments] => 1 [total_payment_amount] => 450 [year] => 2016 [month] => 1 ) [1] => stdClass Object ( [no_payments] => 0 [total_payment_amount] => 0 [year] => 2016 [month] => 2 ) [2] => stdClass Object ( [no_payments] => 0 [total_payment_amount] => 0 [year] => 2016 [month] => 3 ) )

You could add them manually:
$months = array();
$query = $this->db->get('tbl_payments')->result();
foreach($query as $q)
{
$months[] = $q->month;
}
for($i = 1; $i <= 12; $i++)
{
if(!in_array($i, $months))
{
$new_data = new stdClass();
$new_data->no_payments = 0;
$new_data->total_payment_amount = 0;
$new_data->year = 2016;
$new_data->month = $i;
$query[] = $new_data;
}
}
That is asuming you will only need the filling months for current year. If you query other years, you may add that to the logic and include it in another loop.

Related

PHP Create array using Loop and add days with zero orders

I have a mysql query output that give the number of loads for each day of the month.
Array
(
[0] => Array
(
[day] => 01
[Loads] => 9
)
[1] => Array
(
[day] => 02
[Loads] => 7
)
[2] => Array
(
[day] => 03
[Loads] => 12
)
[3] => Array
(
[day] => 04
[Loads] => 5
)
[4] => Array
(
[day] => 06
[Loads] => 1
)
[5] => Array
(
[day] => 07
[Loads] => 4
)
[6] => Array
(
[day] => 08
[Loads] => 9
)
[7] => Array
(
[day] => 09
[Loads] => 19
)
[8] => Array
(
[day] => 10
[Loads] => 11
)
[9] => Array
(
[day] => 11
[Loads] => 5
)
[10] => Array
(
[day] => 12
[Loads] => 2
)
[11] => Array
(
[day] => 14
[Loads] => 7
)
[12] => Array
(
[day] => 15
[Loads] => 9
)
[13] => Array
(
[day] => 16
[Loads] => 11
)
[14] => Array
(
[day] => 17
[Loads] => 9
)
[15] => Array
(
[day] => 18
[Loads] => 6
)
[16] => Array
(
[day] => 19
[Loads] => 3
)
)
You can see from the output not all days have loads. Day 5 and Day 13 are missing. I want to loop and create a new array and if there are no loads for that day add the day with zero loads.
I have been struggling with this. It seems that it would be simple but I can't seem to get it. Can someone here please help me?
I am extremely thankful.
Here is what I have so far:
$dayCountArr = [];
for ($i = 1; $i <= 31; $i++) {
$tempArr = [];
foreach ($dayO as $d) {
if ($d['day'] == $i) {
$day = $d['day'];
$loads = $d['Loads'];
} else {
$day = $i;
$loads = 0;
}
$dayCountArr[] = [$day, $loads];
}
}
Here is query. It returns the above output
SELECT
DATE_FORMAT(r.ship_date, '%d') AS day,
COUNT(DISTINCT(r.order_number)) AS 'Loads'
FROM table r
WHERE YEAR(r.ship_date) = '2022'
&& MONTH(r.ship_date) = 3
&& r.team = 'TEAM-2'
&& (r.order_status = 'Progress' || r.order_status = 'Delivered')
GROUP BY DATE_FORMAT(r.ship_date, '%d')
I assume your sql array is in $dayO and days are in preceding 0 format, I created load array for available days and assigned them to new dayCountArray. I applied str_pad to avoid keys 1(numeric) and use 01(string)
$dayCountArr = array();
foreach($dayO as $day){
$load[str_pad($day['day'], 2, "0", STR_PAD_LEFT)] = $day['Loads'];
}
for ($i = 1; $i <= 31; $i++) {
//Generating keys ('01','02',..,'31')
$key = str_pad($i, 2, "0", STR_PAD_LEFT);
//Assign 0 if Loads not available for $key
$dayCountArr[] = array('day' => $key,'Loads' => isset($load[$key])?$load[$key]:0);
}
print_r($dayCountArr);

PHP push missing weekdays with 0 total into array

I need to buildup a graph with total sales for each day for last week, I did not get all 7 days data, rather getting 3 days data from database, I need to push rest of the 4days with total sales 0,
I have the following array of 3 days
Array
(
[0] => Array
(
[SalesDate] => Jun09
[total] => 4
)
[1] => Array
(
[SalesDate] => Jun11
[total] => 2
)
[2] => Array
(
[SalesDate] => Jun14
[total] => 1
)
)
but I need all 7days data from Jun09 to Jun15 like this
Array
(
[0] => Array
(
[SalesDate] => Jun09
[total] => 4
)
[1] => Array
(
[SalesDate] => Jun10
[total] => 0
)
[2] => Array
(
[SalesDate] => Jun11
[total] => 2
)
[3] => Array
(
[SalesDate] => Jun12
[total] => 0
)
[4] => Array
(
[SalesDate] => Jun13
[total] => 0
)
[5] => Array
(
[SalesDate] => Jun14
[total] => 1
)
[6] => Array
(
[SalesDate] => Jun15
[total] => 0
)
)
I have tried with following code, but not getting the required data.
<?php
$sales =array(array('SalesDate' => 'Jun09',
'total' => 4
),
array
(
'SalesDate' => 'Jun11',
'total' => 2
),
array
(
'SalesDate' => 'Jun14',
'total' => 1
)
);
$final_array = array();
foreach($sales as $sale)
{
for($i=7;$i>0;$i--)
{
$current_weeks =[];
if($sale['SalesDate'] ==date('Md', strtotime("-".$i." days")))
{
$week_days['SalesDate'] = $sale['SalesDate'];
$week_days['total'] = $sale['total'];
}
else
{
$week_days['SalesDate'] = date('Md', strtotime("-".$i." days"));
$week_days['total'] = 0;
}
$final_array[] =$week_days;
}
}
You could first create a 'skeleton' array that matches your source array $arr, but with all the previous seven days $prevSevenDays. The date format matches the source array's, the totals are all set to 0.
// build empty skeleton
$prevSevenDays = [];
for ($i = 7; $i > 0; $i--) {
$prevSevenDays[$i]['SalesDate'] = date('Md', strtotime("-$i days"));
$prevSevenDays[$i]['Total'] = 0;
}
All you have to do is cycle through this array to replace the entries with available data in your source array $arr.
foreach ($arr as $sales) {
foreach ($prevSevenDays as $key => $day) {
if ($sales['SalesDate'] === $day['SalesDate']) $prevSevenDays[$key]['Total'] = $sales['Total'];
}
}
demo

PHP usort 2 dimensional array not working (sort by integer)

I have this array: $attachments = array();
Which is populated like this:
if (have_rows('attachments_items')):
while ( have_rows('attachments_items') ) : the_row();
$attachment_id = get_sub_field('fileattachment',false);
$year = get_sub_field('year',false);
if(is_null($year) || $year == 0){
$year=2018;
}
$attachments[$i]['year'] = (int)$year;
$attachments[$i]['id'] = $attachment_id;
$i++;
endwhile;
endif;
I want to sort it by year so I tried that:
usort($attachments,function($first,$second){
return $first->year < $second->year;
});
But its not working:
Before
unsorted:Array (
[0] => Array ( [year] => 2018 [id] => 14689 )
1
=> Array ( [year] => 2017 [id] => 14690 )
2 => Array ( [year] => 2018 [id] => 14688 )
[3] => Array ( [year] => 2018 [id] => 14687 ) .....)
After
sorted:Array (
[0] => Array ( [year] => 2018 [id] => 14689 )
1
=> Array ( [year] => 2018 [id] => 16323 )
2 => Array ( [year] => 2018 [id] => 21545 )
[3] => Array ( [year] => 2017 [id] => 14690 )
[4] => Array ( [year] => 2018 [id] => 12711 )
.....)
I think you are trying to sort arrays but you are using the fields as object properties $first->year.
Try using
usort($attachments, function ($first, $second) {
return $first["year"] < $second["year"];
});
print_r($attachments);
Demo

Find duplicate values in a multidimensional array and create new multidimensional array that contains no dupes

I have the following array taken from a database:
Array
(
[0] => Array
(
[facility_name] => AFC Clayton Juniors
[day] => 15
[month] => Apr
[year] => 2016
[start_time] => 20
[end_time] => 21
)
[1] => Array
(
[facility_name] => AFC Clayton Juniors
[day] => 15
[month] => Apr
[year] => 2016
[start_time] => 22
[end_time] => 23
)
[2] => Array
(
[facility_name] => Chorlton Runners
[day] => 15
[month] => Apr
[year] => 2016
[start_time] => 10
[end_time] => 11
)
[3] => Array
(
[facility_name] => Chorlton Runners
[day] => 15
[month] => Apr
[year] => 2016
[start_time] => 19
[end_time] => 20
)
)
And I need it to be nested as follows::
Array
(
[0] => Array
(
[facility_name] => AFC Clayton Juniors
[dates] => Array
(
[date1] => Array
(
[date] => 15 Apr 2016
[timeslots] => Array
(
[timeslot1] => Array
(
[start_time] => 20
[end_time] => 21
)
[timeslot2] => Array
(
[start_time] => 22
[end_time] => 23
)
)
[date2] => 16 Apr 2016 //etc
)
)
[1] => Array
(
[facility_name] = Chorlton Runners
[dates] => Array //etc
)
)
To elaborate: I need to have NO duplicate names in my array, and the dates that exist for the same name to be entered as new keys to the dates array that match the same name, and the same thing for time slots. How can I do this?
For this solution let's say the array taken from the databse is named $facilities. The code would be:
$noDupes = array();
foreach ($facilities as $fac) {
$facilityIndex = -1; // The index of the facility name, -1 indicates it wasn't found.
$dateIndex = ''; // The index of the date string, an empty string indicates it wasn't found.
$timeslotIndex = ''; // The index of the timeslot, an empty string indicates it wasn't found.
$facDate = "{$fac['day']} {$fac['month']} {$fac['year']}"; // The date string (dd mmm aaaa)
foreach ($noDupes as $f => $facility) {
if ($fac['facility_name'] == $facility['facility_name']) {
// If the facility name was found we take the corresponding index (0, 1, 2, etc.).
$facilityIndex = $f;
foreach ($facility['dates'] as $d => $date) {
if ($facDate == $date['date']) {
// If the date string was found we take the corresponding index (date1, date2, date3, etc.).
$dateIndex = $d;
foreach ($date['timeslots'] as $t => $timeslot) {
if ($fac['start_time'] == $timeslot['start_time'] && $fac['end_time'] == $timeslot['end_time']) {
// If the timeslot was found we take the corresponding index (timeslot1, timeslot2, timeslot3, etc.).
$timeslotIndex = $t;
break; // end timeslot loop
}
}
break; // end date loop
}
}
break; // end facility loop
}
}
if ($facilityIndex == -1) {
// Take the new index for the date and timeslot if-statements
$facilityIndex = count($noDupes);
$noDupes[] = array(
'facility_name' => $fac['facility_name'],
'dates' => array()
);
}
if ($dateIndex == '') {
// Calculate the new index for the date (date1, date2, etc.)
$dateNum = count($noDupes[$facilityIndex]['dates']) + 1;
$dateIndex = "date{$dateNum}";
$noDupes[$facilityIndex]['dates'][$dateIndex] = array(
'date' => $facDate,
'timeslots' => array()
);
}
if ($timeslotIndex == '') {
// Calculate the new index for the timeslot (timeslot1, timeslot2, etc.)
$timeslotNum = count($noDupes[$facilityIndex]['dates'][$dateIndex]['timeslots']) + 1;
$timeslotIndex = "timeslot{$timeslotNum}";
$noDupes[$facilityIndex]['dates'][$dateIndex]['timeslots'][$timeslotIndex] = array(
'start_time' => $fac['start_time'],
'end_time' => $fac['end_time']
);
}
}
Using JSON array will make your task very easy, and is supported in PHP

Array montlhy reporting but not from 1st of month

I have a large array of booking dates and amount, like so :
Array
(
[0] => Array
(
[date] => 2014-04-04
[total] => 30.00
)
[1] => Array
(
[date] => 2014-04-05
[total] => 47.00
)
[9998] => Array
(
[date] => 2014-08-21
[total] => 52.00
)
... ++ a lot of dates associated to numbers.
and process it to get monthly reports :
$months = array();
foreach($myarray as $k=>$v) {
list($y,$m) = explode("-",$v['date']);
$months[$y."-".$m][] = $v['total'];
}
which gives me a nice array :
Array
(
[2014-04] => Array <-- Every amount made in April
(
[0] => 30.00
[1] => 47.00
[2] => 47.00
...
)
[2014-05] => Array <-- Every amount made in May
(
[0] => 68.00
[1] => 42.00
....
)...
However I'm trying to find a way the same thing but starting from a specific day, say 5 for example, in order to get (dates labelled for clarity):
Array
(
[from January 5 to February 4] => Array
(
[0] => 30.00
[1] => 47.00
[2] => 47.00
)
[from February 5 to March 4] => Array
(
[0] => 30.00
[1] => 47.00
[2] => 47.00
)...
So every amount made each month, but starting from the 5th of each month.
Something like this should work. I hate saying should, but I don't have the data to test with. Let me know if anything's wrong:
$months = array();
foreach($months as $k => $v) {
list($y, $m, $d) = explode("-", $v['date']);
if($d < 5) {
if($m == 1) {
$y--;
$m = 12;
} else {
$m--;
}
}
$months[$y . "-" . $m][] = $v['total'];
}

Categories