Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Array values in a loop in PHP

I have an Array $data composed as following :

$data[$k]['id'] = $row['iddevice'];
$data[$k]['temp_00'] = $row['temp_00'];
$data[$k]['temp_01'] = $row['temp_01'];
$data[$k]['temp_02'] = $row['temp_02'];
$data[$k]['temp_03'] = $row['temp_03'];
$data[$k]['temp_04'] = $row['temp_04'];

I have only two elements in this Array, so echo count($data); return 2

I am using Morris.js to create a line chart, below an example of working code :

$(function() {

    Morris.Line({
  element: 'morris-area-chart',
    data: [
  { y: '00h', 1:57, 2:41},
  { y: '01h', 1:62, 2:98},
  { y: '02h', 1:44, 2:43},
  { y: '03h', 1:67, 2:84},
  ],
  xkey: 'y',
  parseTime:false,
  ykeys: [1,2,3],
  pointSize: 2,
  hideHover: 'auto',
  labels: ['Capteur X', 'Capteur Y']
});

Morris.js Line Chart

My problem is as soon as I try to use PHP to use the values from my $data it doesn't work, the chart doesn't load any values.

   Morris.Line({
  element: 'morris-area-chart',
    data: [
    { y: '00h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_00'],2); $i++; }?>},
    { y: '01h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_01'],2); $i++; }?>},
    { y: '02h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_02'],2); $i++; }?>},
    { y: '03h', <?php $i = 0; while ($i <= count($data)-1) { echo $data[$i]['id'].":".round($data[$i]['temp_03'],2); $i++; }?>},

  ],

For me, the algorithm is fine :

  • $i equal 0
  • while $i is lower or equal to count($data)-1 (so 2-1 = 1 so we should stay in the loop two times)
  • Display the ID and temperature values for this elements
  • Increment $i by one

What am I thinking or doing wrong here ?

Also when I initialize $i to one rather than zero, I can get the values for the second entry in my $data Array

Morris.js Chart 2

(I prefer to say that I am not a developer so this code might not be the cleanest I agree)

EDIT :

  • Pastebin to the var_dump of $data : http://pastebin.com/dYNtLxqX

  • Screenshot when using Forbs' solution (Chart doesn't load at all) : Morris.js Chart 3

  • The SQL query I am using to populate $data Array :

    select iddevice, data.ip, type, description,
       avg(case when hour(date) = 00 then temp end) as temp_00,
       avg(case when hour(date) = 01 then temp end) as temp_01,
       avg(case when hour(date) = 02 then temp end) as temp_02,
       ...
       avg(case when hour(date) = 22 then temp end) as temp_22,
       avg(case when hour(date) = 23 then temp end) as temp_23
    from data, device
    where date >= '2017-03-20' and
      date < '2017-03-21' and
      device.ip = data.ip
    group by ip
    order by iddevice;
    
  • The Array is populate with this query using a while loop

    $results = $conn->query($sql);
    $k = 0;
    $data = array();
    while ($row = $results->fetch_assoc()) {
        $data[$k]['temp_00'] = $row['temp_00'];
        $data[$k]['temp_01'] = $row['temp_01'];
        $data[$k]['temp_02'] = $row['temp_02'];
        $data[$k]['temp_03'] = $row['temp_03'];
        ...
        $k++;
    }
    
like image 534
Will Avatar asked Dec 30 '25 13:12

Will


1 Answers

This is my suggestion for a different way to do this. It cuts down on the repeated code, and minimizes the PHP/JS mixing.

First, build your array a little differently as you fetch the rows from your query:

while ($row = $results->fetch_assoc()) {
    // Loop over each of the temp_x columns
    for ($i=0; $i < 4; $i++) {
        $x = str_pad($i, 2, '0', STR_PAD_LEFT);
        // add the value for each temp_x to a temporary array, using time for a key
        $temp = is_null($row["temp_$x"]) ? 'null' : round($row["temp_$x"], 2);
        $times[$x][] = $row['iddevice'] . ':' . $temp;
    }
}

Next, format the values of each array in the temporary array

foreach ($times as $time => $temps) {
    $data[] = "{ y: '{$time}h', " . implode(', ', $temps) . '}';
}

Then convert the $data array to a string:

$data = implode(",\n", $data);

That way, all the PHP you'll need in the JS part is:

Morris.Line({
  element: 'morris-area-chart',
  data: [ <?php echo $data ?> ]

There may be a better way using json_encode. If you change the code inside the while loop that fetches rows from your database just slightly:

for ($i=0; $i < 4; $i++) {
    $x = str_pad($i, 2, '0', STR_PAD_LEFT);
    $temp = is_null($row["temp_$x"]) ? null : round($row["temp_$x"], 2);
    $times[$x]['y'] = $x.'h';
    $times[$x][$row['iddevice']] = $temp;
}

Then $data can be formed using json_encode. (The array_values is used to reindex the array with numeric indexes so it will render as an array in the JSON output instead of an object.)

$data = json_encode(array_values($times));

And in the JS:

Morris.Line({
  element: 'morris-area-chart',
  data: <?php echo $data ?>
  // note: no [] brackets around $data in this version

Whether or not this will work depends on whether or not it's okay for all the keys to be strings, because JSON keys are strings, so you'll get output like

{ "y": "01", "1": 17.62, "2": 19.52 }

instead of

{ y: '01', 1: 17.62, 2: 19.52 }

I think it should probably work anyway.

like image 192
Don't Panic Avatar answered Jan 01 '26 02:01

Don't Panic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!