Create zero values for missing items in foreach loop - php

I have an application that extracts some information from mysql between two dates and returns an associative array. I am producing a graph with this information but have dates missing for the dates in the database that have no information to return. I cannot fix this on the mysql side as I only have read only access to the database.
My database method retrieves an associative array like the below:
[0] => Array
(
[number_of_calls] => 151
[total_call_time] => 00:01:30
[average_call] => 00:02:00
[DATE(calldate)] => 2016-03-18
[direction] => outbound
)
What I am hoping to do is create a daterange from my form like below:
//create data range array
$begin = new DateTime( $datefrom );
$end = new DateTime( $dateto );
$end = $end->modify( '+1 day' );
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval ,$end);
And then use a foreach loop to iterate through the selected dates of the daterange and pull the value from the associative array where the dates match and if not insert zero values like below:
[number_of_calls] => 0
[total_call_time] => 00:00:00
[average_call] => 00:00:00
I also need the final array to end up in date order. Can anybody help me with this please?

You can transform your $result array to use DATE(calldate) as keys.
$keys = [];
foreach ($result as $item) {
$keys[] = $item['DATE(calldate)'];
}
$result = array_combine($keys, $result);
And your array will look like that:
[2016-03-18] => Array
(
[number_of_calls] => 151
[total_call_time] => 00:01:30
[average_call] => 00:02:00
[DATE(calldate)] => 2016-03-18
[direction] => outbound
)
And you can check if date is presented by simple command:
$key = $datevalue->format('Y-m-d');
if (isset($result[$key])) {
// date exists, use it
} else {
// date not exists, create empty value
}

This is what I ended up doing
// helper function to recursively search array
function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
foreach ($daterange as $datevalue) {
$key = recursive_array_search($datevalue->format('Y-m-d'), $result);
// if date is found write values from data to output array
if ($key !== False) {
$output_array[] = array("number_of_calls" => $result[$key]['number_of_calls'],
"total_call_time" => $result[$key]['total_call_time'],
"average_call" => $result[$key]['average_call'],
"DATE(calldate)" => $datevalue->format('Y-m-d'),
"direction" => "outbound" );
}
// else write zeros
else {
$output_array[] = array("number_of_calls" => "0",
"total_call_time" => "00:00:00",
"average_call" => "00:00:00",
"DATE(calldate)" => $datevalue->format('Y-m-d'),
"direction" => "outbound" );
}
}
$this->chart_data = $output_array;
}

Related

Loop through array results within last hour

I have a script that queries an API and finds records within the last day.
I'd like to then loop through these results and solely get those within the last hour.
Can someone explain how I do this?
This is my array of daily results:
array(2) {
[0]=>
array(36) {
["CallRef"]=> string(10) "1234567891"
["CallStartTime"]=> string(8) "08:18:30"
}
[1]=>
array(36) {
["CallRef"]=> string(10) "1234567892"
["CallStartTime"]=> string(8) "14:04:20"
}
}
It's 14:40 here in the UK so my script should just grab the 2nd item from the array.
How about this?
$apiElements = [
['CallRef' => '1234567891', 'CallStartTime' => '08:18:30'],
['CallRef' => '1234567892', 'CallStartTime' => '14:04:20'],
];
$currentFormatted = (new DateTime())->format('H');
$startOfHour = DateTime::createFromFormat('H:i:s', $currentFormatted . ':00:00');
$endOfHour = DateTime::createFromFormat('H:i:s', $currentFormatted . ':59:59');
$callsInHour = array_filter($apiElements, function($element) use ($startOfHour, $endOfHour) {
$dt = DateTime::createFromFormat('H:i:s', $element['CallStartTime']);
return $dt >= $startOfHour && $dt <= $endOfHour;
});
Totally untested, but give it a try.
Next time, please post what code you tried...
Theres multiple ways to do this. You can get a Unix timestmap from a hour ago: strtotime('-1 hour'). You can explode the time on every : in the time and take the 2nd result from the explode result.
foreach ($array as $value){
$exploded=explode(":",$value['CallStartTime']);
if(date('H')-1>$exploded[1]){
//This means it's an hour ago.
}
}
Replace $allResults and try this:
date_default_timezone_set('UTC');
$hourAgo = strtotime(date('H:i:s')) - 3600;
foreach ($allResults as $result){
if(strtotime($result["CallStartTime"]) > $hourAgo){
var_dump($result);
}
}
More flexible solution:
First you need a function to convert time to seconds
function convertTimeToSeconds($hhmmss)
{
//correct format if needed
list($hours, $minutes, $seconds) = explode(':', $hhmmss);
return $hours * 3600 + $minutes * 60 + $seconds;
}
And then you just can use array_filter function
$now = date('H:i:s');
$nowSeconds = convertTimeToSeconds($now);
$filterFunction = function ($value) use ($nowSeconds) {
return ($nowSeconds - convertTimeToSeconds($value['CallStartTime'])) < 3600; //3600 seconds = hour
};
$filteredList = array_filter($array, $filterFunction);
All together https://3v4l.org/icAmp
I suppose you have this array
Array
(
[0] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 21:04:20
)
[1] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 09:08:08
)
[2] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 08:11:08
)
[3] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 20:59:08
)
)
And so i tried this
<?php
$arr = array(
"0" => array (
"CallRef" => 1234567892,
"CallStartTime" => "21:04:20"
),
"1" => array (
"CallRef" => 1234567892,
"CallStartTime" => "09:08:08"
),
"2" => array (
"CallRef" => 1234567892,
"CallStartTime" => "08:11:08"
),
"3" => array (
"CallRef" => 1234567892,
"CallStartTime" => "20:59:08"
)
);
//echo "<pre>";print_r($arr);die;
date_default_timezone_set('Asia/kolkata');//set your timezone
$currentTime = date('H:i:s');//getting current time
$lastHourTime = date('H:i:s', strtotime('-1 hour'));//getting last hour time
$result = array();
foreach ($arr as $singlearr){
if(strtotime($singlearr['CallStartTime']) >= strtotime($lastHourTime) && strtotime($singlearr['CallStartTime']) <= strtotime($currentTime)){
$result[] = $singlearr;
}else{
}
}
echo "<pre>";print_r($result);die;//this gives me last hour records only
Check Demo When you check demo All records which have time > last hour will return otherwise it will return empty array
May be it can help!

Grouping with hyphenate not working with i18N for weekdays

I am working on a snippet for displaying opening hours and it works fine in english language and when I change the keys of array to another language it doesn't hyphenate the letters instead it does separation by comma.
What am I doing Wrong?
Below is the PHP code with 2 arrays with 1 commented which is in english and which works fine. Another is an italian langugage weekdays
<?php
/*
// english weekdays
$openHours = array(
'Mon' => '9am-7pm',
'Tue' => '9am-7pm',
'Wed' => '9am-7pm',
'Thu' => '9am-10pm',
'Fri' => 'closed',
'Sat' => '9am-10pm',
'Sun' => '9am-10pm'
);
*/
// italian weekdays
$openHours = array(
'lunedì' => '9am-7pm',
'martedì' => '9am-7pm',
'mercoledì' => '9am-7pm',
'giovedì' => '9am-10pm',
'venerdì' => 'closed',
'sabato' => '9am-10pm',
'domenica' => '9am-10pm'
);
$new_array = array();
foreach($openHours as $key => $value)
{
if(in_array($value,$new_array))
{
$key_new = array_search($value, $new_array);//to get the key of element
unset($new_array[$key_new]); //remove the element
$key_new = $key_new.','.$key; //updating the key
$new_array[$key_new] = $value; //inserting new element to the key
}
else
{
$new_array[$key] = $value;
}
}
foreach ($new_array as $days=>$time){
$daylist = explode(',',$days);
if ($time!='closed'){
if (count($daylist)>2){
$limit = count($daylist)-1;
$first = $daylist[0];
$last = $daylist[$limit];
//loop will go here.
if (date('D', strtotime('+'.$limit.' days', strtotime($first)))==$last){
echo $first.'-'.$last.' '.$time.'<br>';
} else {
$sep = '';
foreach ($daylist as $sepdays){
echo $sep.$sepdays;
$sep = ',';
}
echo ' '.$time.'<br>';
}
} else {
echo $days.' '.$time.'<br>';
}
} else {
$daylist = explode(',',$days);
foreach ($daylist as $sepdays){
echo $sepdays.' '.$time.'<br>';
}
}
}
?>
RESULT
Current Result what am getting with italian language.
lunedì,martedì,mercoledì 9am-7pm
venerdì closed
giovedì,sabato,domenica 9am-10pm
Expected RESULT
This is what I'm expecting.
lunedì-mercoledì 9am-7pm
venerdì closed
giovedì,sabato,domenica 9am-10pm
You are using your array's keys within date and strtotime functions to do your comparisons, both functions works for English. If you need to do it on other languages you should use setlocale and strftime, it will be a lot more complicated process. My suggestions:
Use numeric representation of the days of the week (0-6) and on display, replace the number with the value for the desired language.
Use multidimensional arrays including the numeric day of the week and the opening hours.

Search nested multidimensional array

I have a function that fills an array:
foreach ($request->get('ids') as $id) {
$pdfArray['other']++; // Yes this is initialized
$pdfArray['rows'][$i]['id'] = $schedule->getId();
$pdfArray['rows'][$i]['date'] = $schedule->getStart()->format('d.m.Y');
$pdfArray['rows'][$i]['dateSort'] = $schedule->getStart()->format('Y-m-d H:i');
$pdfArray['rows'][$i]['from'] = $schedule->getStart()->format('H:i');
$pdfArray['rows'][$i]['to'] = $schedule->getEnd()->format('H:i');
$pdfArray['rows'][$i]['desc'] = $schedule->getDescription();
}
What I want to do
On each loop, I want to check if the array (so far) already has a desc entry equal to the current $schedule->getDescription() AND the same date as $schedule->getStart()->format('d.m.Y') (actually more, but let's keep it simple)
What I tried
public function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value OR (is_array($value) && $this->recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
Source
I use it like that:
if ($this->recursive_array_search($schedule->getDescription(), $pdfArray['rows']) &&
$this->recursive_array_search($schedule->getStart()->format('d.m.Y'), $pdfArray['rows'])){
$pdfArray['ma'][$schedule->getId()]++;
}
but this is true when ANY of the start or desc are SOMEWHERE in the current array.
How would I check if desc is found and start is in the SAME $i level?
EDIT for example
Let's say I have 10 $ids to loop through. After 2 loops, the $pdfArray looks like this:
Array
(
[other] => 2
[rows] => Array
(
[0] => Array
(
[id] => 1
[date] => 13.07.2016
[dateSort] => 2016-07-13 08:00
[from] => 08:00
[to] => 09:00
[desc] => TEST
)
[1] => Array
(
[id] => 2
[date] => 12.07.2016
[dateSort] => 2016-07-12 08:00
[from] => 08:00
[to] => 09:00
[desc] => TEST
)
)
)
The next iteration has the following:
$schedule->getStart()->format('d.m.Y') => 12.07.2016
$schedule->getDescription() => TEST
So I want to have the info that the combination already exists in the array.
BUT
$schedule->getStart()->format('d.m.Y') => 12.07.2016
$schedule->getDescription() => TEST2
should NOT return true upon checking of it exists.
To test for a "duplicate" you can use this function:
function testPresence($pdfArray, $desc, $date) {
foreach ($pdfArray["rows"] as $row) {
if ($row["desc"] == $desc && $row["date"] == $date) return true;
}
}
Example use:
echo testPresence($pdfArray, "TEST2", "12.07.2016") ? "Found" : "Not found"; // Not found
echo testPresence($pdfArray, "TEST", "12.07.2016") ? "Found" : "Not found"; // Found
In your original loop, you can use it as follows:
foreach ($request->get('ids') as $id) {
if (testPresence($pdfArray, $schedule->getDescription(),
$schedule->getStart()->format('d.m.Y')) {
// We have a duplicate. Maybe skip this entry?:
continue;
}
$pdfArray['other']++;
$pdfArray['rows'][$i]['id'] = $schedule->getId();
$pdfArray['rows'][$i]['date'] = $schedule->getStart()->format('d.m.Y');
$pdfArray['rows'][$i]['dateSort'] = $schedule->getStart()->format('Y-m-d H:i');
$pdfArray['rows'][$i]['from'] = $schedule->getStart()->format('H:i');
$pdfArray['rows'][$i]['to'] = $schedule->getEnd()->format('H:i');
$pdfArray['rows'][$i]['desc'] = $schedule->getDescription();
}
try this at your validation function
public function array_search($needle1, $needle2 ,$haystack) {
foreach($haystack as $singleArray){
if (in_array($needle1, $singleArray) && in_array($needle2, $singleArray))
return true;
else
continue;
}
return false;
}
and invoke your recursive_array_search like this
if ($this->array_search($schedule->getStart(), $schedule->getDescription(), $pdfArray['rows'])
continue;//Or any other kind of logic you want. At this place you know that description and date staet exist in at your array level
$pdfArray['other']++; // Yes this is initialized
$pdfArray['rows'][$i]['id'] = $schedule->getId();
$pdfArray['rows'][$i]['date'] = $schedule->getStart()->format('d.m.Y');
$pdfArray['rows'][$i]['dateSort'] = $schedule->getStart()->format('Y-m-d H:i');
$pdfArray['rows'][$i]['from'] = $schedule->getStart()->format('H:i');
$pdfArray['rows'][$i]['to'] = $schedule->getEnd()->format('H:i');
$pdfArray['rows'][$i]['desc'] = $schedule->getDescription();
Function version:
/**
* Find matches for $item into pdfArray.
* Returns an index array, possibly empty if no matches.
* #param $item item to find
* #param $rows rows where to search
*/
function findPdfArrayMatches(array $item, array $rows) {
return array_keys(
array_filter(
$rows,
function ($entry) use ($item) {
// These are the matching criteria. More than one row may match.
return $entry['desc'] == $item['desc']
&& $entry['date'] == $item['date']
;
}
)
);
}
You could do like this, in the loop:
$item = [
'id' => $schedule->getId(),
'date' => $schedule->getStart()->format('d.m.Y'),
'dateSort' => $schedule->getStart()->format('Y-m-d H:i'),
'from' => $schedule->getStart()->format('H:i'),
'to' => $schedule->getEnd()->format('H:i'),
'desc' => $schedule->getDescription(),
];
$matches = findPdfArrayMatches($item, $pdfArray['rows']);
if (!empty($matches)) {
...do something with the matches:
foreach ($matches as $match) {
$pdfArray['rows'][$match]['Duplicate'] = true;
}
}
// Add new item
$pdfArray['rows'][$i] = $item;

Make an Array from another array with using implode()

I have an array.
my array:
while($rowop = mysql_fetch_array($resultop))
{
$info[] = array(
'status'=>$rowop[2],
'day' => $rowop[3],
'from'=>$rowop[4],
'to' => $rowop[5],
'mon'=>$rowop[6],
'tue' => $rowop[7],
'wed'=>$rowop[8],
'thu' => $rowop[9],
'fri'=>$rowop[10],
'sat' => $rowop[11],
'sun'=>$rowop[12]
);
}
value of $rowop[6],$rowop[7],$rowop[8],$rowop[9],$rowop[10],$rowop[11],$rowop[12] can be 'on' or 'off'. I want to show only those rows which contain 'off' value. array will be same as:
'status'=>'ok',
'day' =>'all',
'from'=>'12pm',
'to' => '8am',
'off day'=>'tue,wed,thu,sat,sun'
Any one please give me Idea.if possible give example
Try this, ( assuming your array name is $info ) :
$result = array();
foreach($info as $key=>$value){
$result[$key]['status'] = $value['status'];
$result[$key]['day'] = $value['day'];
$result[$key]['from'] = $value['from'];
$result[$key]['to'] = $value['to'];
$off=array();
foreach ($value as $k => $v) {
if($v=="off") $off[]=$k;
}
if($off) $off_days = implode (", ", $off);
$result[$key]["off day"] = $off_days;
}
print_r($result);
What about this?
$days = ['mon','tue','wed','thu','fri','sat','sun'];
for($offs=[],$i=6,$i<=12,$i++) if($rowtop[$i]=='off') $offs[]= $days[$i-6];
$info[] = array(
'status'=>$rowop[2],
'day' => $rowop[3],
'from'=>$rowop[4],
'to' => $rowop[5],
'off day' => implode(',', $offs)
);
How about following code
I didn't test it. Fix if there are any errors
$days = array('mon','tue', 'wed', 'thu', 'fri', 'sat', 'sun');
$selected = array();
$final = array();
foreach($days as $day)
{
if(isset($info[$day]))
if($info[$day] == 'off')
$selected[] = $info[$day];
}
$all_days = implode(',', $selected);
$final['status'] = $info['status'];
$final['day'] = $info['day'];
$final['from'] = $info['from'];
$final['to'] = $info['to'];
$final['off day'] = $all_days;
This can be achieved in multiple steps:
Find all keys with off status using array_filter() and store it in array $result
Remove all the "week keys", i.e. mon, tue, wed etc. using array_diff_key()
Implode $result array to get a comma-separated string, and use that to create a new array element
Code:
// find all keys with 'off' status
$status = 'off';
$result = array_keys(array_filter($info,
function($element) use ($status) {
return $element == $status;
}
));
// remove all week keys
$keys = array('mon','tue','wed','thu','fri','sat','sun');
$info = array_diff_key($info, array_flip($keys));
// create a new array item with the comma-separated key string
$info['off_days'] = implode(',', $result);
print_r($info);
Output:
Array
(
[status] => ok
[day] => all
[from] => 12pm
[to] => 8am
[off_days] => tue,wed,thu,sat,sun
)
Demo.
An example using array_filter
$days = array('mon','tue', 'wed', 'thu', 'fri', 'sat', 'sun');
while($rowp ....) { //
$offs = implode (
',',
array_keys(
array_filter(
array_intersect_key($oneRow, array_flip($days)),
function($i) {return $i == 'off'}
)
)
);
//...
}
where $oneRow is what you are filling the $info array with.
Hope it helps

Sum time if date already exists or has a duplicate

I have this array
$date = array{"2013-09-17 00:21:00",
"2013-09-23 00:12:00",
"2013-09-23 00:41:00",
"2013-09-20 00:13:00",
"2013-09-19 00:34:00",
"2013-09-17 00:38:00"}
I'm trying to sum the time inside the array that have the same date.
This is my expected output:
$date = array{"2013-09-17 00:59:00",
"2013-09-23 00:53:00",
"2013-09-20 00:13:00",
"2013-09-19 00:34:00"}
Now this is what I have tried so far
foreach($date as $key => $value)
{
$lf_date[] = date("Y-m-d",strtotime($value));
$lf_time[] = date("H:i:s",strtotime($value));
if(isset($lf_date[$key]))
{
$output[] += $lf_time[$key];
}
else
{
$output[] = $lf_time[$key];
}
}
This gives me a 0 output T_T.. I already tried searching on google and it says that I have to use isset and array_key_exists but I can't get it to work. :(. Thanks for anyone who could help me.
Use:
<?php
$date = array("2013-09-17 00:21:00",
"2013-09-23 00:12:00",
"2013-09-23 00:41:00",
"2013-09-20 00:13:00",
"2013-09-19 00:34:00",
"2013-09-17 00:38:00");
$array = array();
foreach($date as $key => $value)
{
$lf_date = date("Y-m-d",strtotime($value));
$lf_time = date("H:i:s",strtotime($value));
$midnight = strtotime("0:00");
if(!isset($array[$lf_date]))
$array[$lf_date] = 0;//check is array index exists
$array[$lf_date] += strtotime($lf_time) - $midnight;
}
foreach($array as $key => $value)
{
$midnight = strtotime("0:00");
$array[$key] = $key." ".date("G:i:s", $midnight + $value);
}
$result = array_values($array);
print_r($result);
?>
Output:
Array
(
[0] => 2013-09-17 0:59:00
[1] => 2013-09-23 0:53:00
[2] => 2013-09-20 0:13:00
[3] => 2013-09-19 0:34:00
)

Categories