can't get my head round this php array

Joined
12 Feb 2006
Posts
17,355
Location
Surrey
i think i've just over complicated things for myself, but i'm struggling to figure out the way to store this in a php array.

essentially i am trying to display the total hours worked by shift staff, broken down by week. This is showing just 1 staff member at a time.

the data that is stored in a mysql database is the date + hours worked.

I first grab all the dates for x staff member, going back 12 weeks from todays date.

using a php while loop for each entry, I check what week number of the year that date is within.

I want to do the following:

if it's the same week as the last entry, add those hours to the total hour count for that week in an array and then store the date and hours so that later I can break down the array to show something like this.

Week 43 - Total Hours 7
12/10 - 4 hours
11/10 - 3 hours

Week 42 - Total hours 20
09/10 - 10 hours
06/10 - 6 hours
05/10 - 4 hours

Week 40 - Total Hours 2
22/09 - 2 hours

etc etc.

I just can't figure out how to store this in an array. The week isn't guaranteed to be worked within, and the amount of entries per week is different each week too.

I know i could just display the data as I do the while loop, however i want the count of total hours above the date/hours lines.
 
I'd create a second array for the weekly totals. PHP arrays don't need to be consecutively numbered so it'll store find with missing values, and you can write a simple function:

PHP:
function hoursWorkedInWeek($weekNumber) {
  if (isset($weeklyHours[$weekNumber]))
    return $weeklyHours[$weekNumber];

  return 0;
}

to return the number of hours for a given week.
 
If the dataset isn't huge then i would look at a multidimensional array, under the week number (as an index), store the date and hours and create a summed totalHours integer as you iterate through the DB results -
PHP:
Array[WeekNumber] => array(
    'totalHours' => 7,
    'staffHours' => array(
        '12/10/23' => 4,
        '11/10/23' => 3
    );
);

So if you assume $row is your DB results and workedDate and workedHours are your columns, then you would have something like (this is quick, rough and dirty code and i haven't tested it) -
PHP:
$outputArray = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    // Date Variables
    $workedDate = new DateTime($row['workedDate']);
    $workedDateWeekNumber = $workedDate->format('W');
    $workedDateDMY = $workedDate->format('d/m/Y');  

    // !Exist, Create
    if (!isset($outputArray[$workedDateWeekNumber])) {
        $outputArray[$workedDateWeekNumber] = array(
            'totalHours' = 0;
            'staffHours' = array();
        );
    }  

    // Add Data
    $outputArray[$workedDateWeekNumber]['staffHours'] += array($workedDateDMY => $row['workedHours']);
    $outputArray[$workedDateWeekNumber]['totalHours'] += (int) $row['workedHours'];
}

Performance is the big issue if your dataset is large as you'll eat memory. If it is, then i would either paginate the output or iterate through the returned data once, summing total hours as you go, and then push logic to the frontend to handle displaying the data how you want (to be honest, this might be the better way from the get-go).

Edit - https://onlinephp.io/c/3ce0d
 
Last edited:
Dataset isn't large at all. For admin view it goes back 1 year for these weekly paid staff, and so maximum 200 entries.
You'll be fine then although i would still sort (and/or filter) via the DB query (as long as you have decent indexes) rather than using array sorting functions.

Forgot to add to my initial reply, for rendering out you just need to iterate the array for the week number and total hours worked and then, iterate the 'inner' staffHours array for individual date and worked hours. You end up with something a bit like (at the bottom) - https://onlinephp.io/c/be5e1.
 
PHP:
$outputArray = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    // Date Variables
    $workedDate = new DateTime($row['workedDate']);
    $workedDateWeekNumber = $workedDate->format('W');
    $workedDateDMY = $workedDate->format('d/m/Y');

    // !Exist, Create
    if (!isset($outputArray[$workedDateWeekNumber])) {
        $outputArray[$workedDateWeekNumber] = array(
            [U][B]'totalHours' = 0;[/B][/U]
            'staffHours' = array();
        );
    }

    // Add Data
    $outputArray[$workedDateWeekNumber]['staffHours'] += array($workedDateDMY => $row['workedHours']);
    $outputArray[$workedDateWeekNumber]['totalHours'] += (int) $row['workedHours'];
}

thanks. this seems pretty much what i want. playing with it now

EDIT

worked a trick. it's storing the data perfectly, however my issue is now getting to use the data :p

I thought the below would work but it just says "Notice: Undefined offset: 0 "

PHP:
$keys = array_keys($outputArray);

for($i = 0; $i < count($outputArray); $i++) {
    echo "<tr>";
    echo "<td>".$outputArray[$keys[$i]][0]."</td>";
    echo "<td>".$outputArray[$keys[$i]][1]."</td>";
    echo "</tr>";
    
}
 
Last edited:
EDIT

worked a trick. it's storing the data perfectly, however my issue is now getting to use the data :p

I thought the below would work but it just says "Notice: Undefined offset: 0 "

PHP:
$keys = array_keys($outputArray);

for($i = 0; $i < count($outputArray); $i++) {
    echo "<tr>";
    echo "<td>".$outputArray[$keys[$i]][0]."</td>";
    echo "<td>".$outputArray[$keys[$i]][1]."</td>";
    echo "</tr>";
 
}

As @Mr Jack says, that won't work if you're using an array structure similar to what i posted as the index(es) you're requesting (during the loop) doesn't exist. Instead, iterate the array with foreach with key value, similar to the example posted (https://onlinephp.io/c/be5e1), eg -
PHP:
// array AS key => value
foreach ($outputArray as $weekNumber => $array) {
    // 'Initial' iteration for week number and total (week) hours
    print '<tr><td>Week ' . $weekNumber . ' - Total Hours ' . $array['totalHours'] . '</td></tr>';
    // Iterate 'staffHours' for individual hours - array AS key => value
    print '<tr';
    foreach ($array['staffHours'] as $workedDate => $workedHours) {
        print '<td>' . $workedDate . ' - ' . $workedHours . '</td>';
    }
    print '</tr>';
}

Edited - Just to make explanation and code clearer.
 
Last edited:
ok thanks guys. it's now all working, with 2 issues i've since realised.

one is minor. i used to also store the database row id for the times so that i could click each row to edit it, and also, the username of the person who submitted the time for each row. these are called:

$row['whoSubmit']
$row['timesId']

the bigger issue i've realised is that if 2 different times are added for the same date. this adds up fine for the total amount of times per week, and also gets stored in the array, but when the for loop goes round to display the data, it skips if there is more than 1 entry per date.
 
ok thanks guys. it's now all working, with 2 issues i've since realised.

one is minor. i used to also store the database row id for the times so that i could click each row to edit it, and also, the username of the person who submitted the time for each row. these are called:

$row['whoSubmit']
$row['timesId']

the bigger issue i've realised is that if 2 different times are added for the same date. this adds up fine for the total amount of times per week, and also gets stored in the array, but when the for loop goes round to display the data, it skips if there is more than 1 entry per date.
Nest another array with the date, hours and who created that entry under the row ID (as long as your row ID is unique then it'll also solve your conflict issue with data) instead of date(s); ie -

PHP:
Array[WeekNumber] => array(
    'totalHours' => 7,
    'staffHours' => array(
        [rowID] => array(
            'date' => '12/10/2023',
            'hours' => 4,
            'whoSubmit' => 'Rasmus Lerdorf'
        )
    );
);

You iterate the staffHours as before but you would get the row ID as the key, instead of the date, and then the value would be an array, rather than a integer of hours, that you can grab date, hours etc from, eg - foreach ($array['staffHours'] as $rowID => $array) and then $array['date'], $array['whoSubmit'] etc.
I would look at renaming some of the variables i've used though to make it clearer as it is a bit messy.
 
Last edited:
thanks that's all sorted. arrays are one of those things that I get for about 30 minutes and then totally get confused 30 minutes later.
Once you start nesting then arrays can get complicated quickly although i find doodling structures massively helps to visualise the array as well help break it down for iterating.
Glad it's sorted though :)
 
You can(kind of) think of arrays like folders containing files, which can also hold folders with other files, and so on (like on your PC). Or a bag holding items, which might also contain more bags with items. At a basic level it's one bag/folder holding a group of items, with each item inside having an index(key) starting from 0, until you start using associative/named keys, but it's a very basic and widely used means of creating a group of things(data).

Start dumping/printing your data into something readable so you can see your data structure.
Code:
printf( '<pre>%s</pre>'. PHP_EOL, print_r( $your_var_here, true ) );
 
Last edited:
back again with this array mumbo jumbo

different issue but i'm sure easy to solve that i just can't figure out.

i have the below array. it used to have name, price, qty, total etc, but i've decided to remove that.

that now leaves the array looking simpler like this
PHP:
  $products_info=[

    ["name"=>"One-Off Clean"],
    ["name"=>"Oven Valet"],
    ["name"=>"Carpet Clean"],
    ["name"=>"Inside Windows"],
  ];

what i want to do is be able to simply add new lines to this array with some if statements, e.g.

PHP:
if ($quote_prop > 0) {
    $generalcleaning = true;
    $products_info += [ "name" => "General Cleaning" ];
}

nothing makes sense. nothing i read about adding to an existing array matches exactly what i'm after. i know i could simplify this array already, but it's part of something else that allows me to have more options in the future, and if i changed this array i'd need to change that code too, and i'd rather keep it as is for now and leave the ability for it to come back in the future

thanks
 
Last edited:
You could also use array_push(); e.g. array_push($products_info, [ "name" => "General Cleaning" ]);

It sounds like you're still finding arrays a headache. Are you using print_r to debug them regularly? It's a really useful function for looking at the contents of an array all nested in a very readable format.
 
Back
Top Bottom