1

I have the following $MessagesArray PHP bidimensional indexed array of one-dimensional associative inner arrays:

Array
(
    [0] => Array
        (
            [id] => 1
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2016/11/27
            [time] => 11:00
            [ampm] => AM
            [specialcontent] => none
            [content] => Hello
        )

    [1] => Array
        (
            [id] => 2
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2016/11/27
            [time] => 11:00
            [ampm] => AM
            [specialcontent] => none
            [content] => How are you?
        )

    [2] => Array
        (
            [id] => 3
            [from] => Person 2
            [to] => Person 1
            [platform] => Instagram Direct Messaging
            [date] => 2016/11/27
            [time] => 6:00
            [ampm] => PM
            [specialcontent] => none
            [content] => Oh, hey there. I'm fine
        )

    [3] => Array
        (
            [id] => 4
            [from] => Person 2
            [to] => Person 1
            [platform] => Instagram Direct Messaging
            [date] => 2016/11/27
            [time] => 6:01
            [ampm] => PM
            [specialcontent] => none
            [content] => What about you?
        )

    [4] => Array
        (
            [id] => 5
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2016/11/28
            [time] => 8:00
            [ampm] => AM
            [specialcontent] => none
            [content] => It's been a while.
        )

    [5] => Array
        (
            [id] => 6
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2016/11/30
            [time] => 2:00
            [ampm] => PM
            [specialcontent] => none
            [content] => Hello?
        )

    [6] => Array
        (
            [id] => 7
            [from] => Person 2
            [to] => Person 1
            [platform] => Instagram Direct Messaging
            [date] => 2016/12/01
            [time] => 3:00
            [ampm] => PM
            [specialcontent] => none
            [content] => Sorry, I'm traveling 'till next year.
        )

    [7] => Array
        (
            [id] => 8
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2016/12/05
            [time] => 1:00
            [ampm] => PM
            [specialcontent] => none
            [content] => Fine by me.
        )

    [8] => Array
        (
            [id] => 9
            [from] => Person 2
            [to] => Person 1
            [platform] => Instagram Direct Messaging
            [date] => 2017/01/04
            [time] => 3:00
            [ampm] => PM
            [specialcontent] => none
            [content] => I'm back.
        )

    [9] => Array
        (
            [id] => 10
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2018/01/15
            [time] => 1:00
            [ampm] => PM
            [specialcontent] => none
            [content] => I'm back too, one year later too.
        )

)

Whose actual code is (although I actually created the previous array from a database in a XML file):

<?php
    $MessagesArray = array(
        array(
            "id" => "1",
            "from" => "Person 1",
            "to" => "Person 2",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/11/27",
            "time" => "12:00",
            "ampm" => "AM",
            "specialcontent" => "none",
            "content" => "Hello"
        ),
        array(
            "id" => "2",
            "from" => "Person 1",
            "to" => "Person 2",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/11/27",
            "time" => "11:00",
            "ampm" => "AM",
            "specialcontent" => "none",
            "content" => "How are you?"
        ),
        array(
            "id" => "3",
            "from" => "Person 2",
            "to" => "Person 1",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/11/27",
            "time" => "6:00",
            "ampm" => "PM",
            "specialcontent" => "none",
            "content" => "Oh, hey there. I'm fine"
        ),
        array(
            "id" => "4",
            "from" => "Person 2",
            "to" => "Person 1",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/11/27",
            "time" => "6:01",
            "ampm" => "PM",
            "specialcontent" => "none",
            "content" => "What about you?"
        ),
        array(
            "id" => "5",
            "from" => "Person 1",
            "to" => "Person 2",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/11/28",
            "time" => "8:00",
            "ampm" => "AM",
            "specialcontent" => "none",
            "content" => "It's been a while."
        ),
        array(
            "id" => "6",
            "from" => "Person 1",
            "to" => "Person 2",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/11/30",
            "time" => "2:00",
            "ampm" => "PM",
            "specialcontent" => "none",
            "content" => "Hello?"
        ),
        array(
            "id" => "7",
            "from" => "Person 2",
            "to" => "Person 1",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/12/01",
            "time" => "3:00",
            "ampm" => "PM",
            "specialcontent" => "none",
            "content" => "Sorry, I'm traveling 'till next year."
        ),
        array(
            "id" => "8",
            "from" => "Person 1",
            "to" => "Person 2",
            "platform" => "Instagram Direct Messaging",
            "date" => "2016/12/05",
            "time" => "1:00",
            "ampm" => "PM",
            "specialcontent" => "none",
            "content" => "Fine by me."
        ),
        array(
            "id" => "9",
            "from" => "Person 2",
            "to" => "Person 1",
            "platform" => "Instagram Direct Messaging",
            "date" => "2017/01/04",
            "time" => "3:00",
            "ampm" => "PM",
            "specialcontent" => "none",
            "content" => "I'm back."
        ),
        array(
            "id" => "10",
            "from" => "Person 1",
            "to" => "Person 2",
            "platform" => "Instagram Direct Messaging",
            "date" => "2018/01/15",
            "time" => "1:00",
            "ampm" => "PM",
            "specialcontent" => "none",
            "content" => "I'm back too, one year later too."
        )
    );
?>

And I'd like to somehow have a code that automatically creates HTML, with the following example:

<div class="year">
  2016
  <div class="month">
    Month 11
    <div class="day">
      Day 27
    </div>
    <div class="day">
      Day 28
    </div>
    <div class="day">
      Day 30
    </div>
  <div class="month">
    Month 12
    <div class="day">
      Day 01
    </div>
    <div class="day">
      Day 05
    </div>
  </div>
  </div>
</div>
<div class="year">
  2017
  <div class="month">
    Month 01
    <div class="day">
      Day 04
    </div>
  </div>
</div>
<div class="year">
  2018
  <div class="month">
    Month 01
    <div class="day">
      Day 15
    </div>
  </div>
</div>

As you can see, it isn't really that hard, I'm just having a problem figuring out how to use nested foreach functions.

The code should produce a <div> HTML element for each unique year, then its corresponding <div> HTML element for each unique month of that year, and then at the same time its corresponding <div> HTML element for each day month of that month of that year.

I think we need to use nested foreach functions. Suppose we have the code foreach ($MessagesArray as $item) {}, then, inside the function, we could get the year, month, and day as $year = substr($item['date'], 0, 4);, $month = substr($item['date'], 5, 2);, and $day = substr($item['date'], 8, 2);, respectively. I also think we need to someone know the value of the previous iteration.

alejnavab
  • 1,136
  • 1
  • 12
  • 30
  • Can you do a `var_export()` of your array? Will make it easier to copy/help you. – Blue Aug 05 '18 at 02:46
  • Additionally, you should be able to do something like [this post](https://stackoverflow.com/a/12706456/4875631) to convert your array into something more meaningful to you. Then loop through your array. – Blue Aug 05 '18 at 02:47
  • 1
    @ggorlen I just added it to my post! – alejnavab Aug 05 '18 at 02:58
  • @FrankerZ Do you mean to add the actual code of the array to my post? If so, I just did it // With the post you linked, do you mean that I sort the array by its IDs? – alejnavab Aug 05 '18 at 03:00

3 Answers3

2

Yes, you will need to write code that is aware of the previous row's data. This can be accomplished with a single loop and some logically positioned condition statements.

Code: (Demo)

$MessagesArray = [
    ["date" => "2016/11/27"],
    ["date" => "2016/11/27"],
    ["date" => "2016/11/27"],
    ["date" => "2016/11/27"],
    ["date" => "2016/11/28"],
    ["date" => "2016/11/30"],
    ["date" => "2016/12/01"],
    ["date" => "2016/12/05"],
    ["date" => "2017/01/04"],
    ["date" => "2018/01/15"]
];
$yr = null;
$mo = null;
$dy = null;

foreach ($MessagesArray as $row) {
    if ($row["date"] == "$yr/$mo/$dy") {
        continue;  // if repeat of previous date, move to next iteration
    }
    [$y, $m, $d] = explode("/", $row["date"]);
    if (($m != $mo || $y != $yr) && $mo !== null) {
        echo "</div>";
    }
    if ($y != $yr) {
        if ($yr !== null) {
            echo "</div>";
        }
        echo "<class='year'>$y";
    }
    if ($m != $mo || $y != $yr) {
        echo "<div class='month'>Month $m";
    }
    echo "<div class='day'>Day $d</div>";
    $yr = $y;
    $mo = $m;
    $dy = $d;
}
if (sizeof($MessagesArray)) {
    echo "</div></div>";
}

Output:

<div class='year'>2016
    <div class='month'>Month 11
        <div class='day'>Day 27</div>
        <div class='day'>Day 28</div>
        <div class='day'>Day 30</div>
    </div>
    <div class='month'>Month 12
        <div class='day'>Day 01</div>
        <div class='day'>Day 05</div>
    </div>
</div>
<div class='year'>2017
    <div class='month'>Month 01
        <div class='day'>Day 04</div>
    </div>
</div>
<div class='year'>2018
    <div class='month'>Month 01
        <div class='day'>Day 15</div>
    </div>
</div>
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • This is also the most accurate. I don't really know which one to choose. – alejnavab Aug 05 '18 at 06:01
  • Hahaha, perhaps I ask another question and you answer it? It is a complement of this one, except that it includes echo-ing the messages. – alejnavab Aug 05 '18 at 06:03
  • I'll be rechecking all three answers and check which one is the best of the best. – alejnavab Aug 05 '18 at 06:09
  • **Dude!** There is one problem, your code is repeating days from the same month of the same year, which I dont want. However I think I can fix that myself. – alejnavab Aug 05 '18 at 06:46
  • Thats as simple as just checking days as well as month/year. – Blue Aug 05 '18 at 11:19
  • @alej27 whoops, that was silly of me. I didn't read the question closely enough. I've corrected my code logic. – mickmackusa Aug 05 '18 at 11:39
  • Do you actually want this to be saved as a concatenated string to be `return`ed instead of echoed? Are you running this inside of a custom function or something? I can adjust again. – mickmackusa Aug 05 '18 at 11:49
1

Reformat your array:

$formatted = [];

foreach ($MessagesArray as $Message) {
    $year = substr($Message['date'], 0, 4);
    $month = substr($Message['date'], 5, 2);
    $formatted[ $year ][ $month ][] = $Message;
}

print_r($formatted);

Then it's a simple as looping through:

foreach ($formatted as $year => $months) {
    //Echo year text
    foreach ($months as $month => $messages) {
        //Echo month text
        foreach ($messages as $message) {
            //Echo each text
        }
    }
}

See this php playground.

Blue
  • 22,608
  • 7
  • 62
  • 92
1

Here's a naive approach:

$messages = [
    ["date" => "2016/11/27"],
    ["date" => "2016/11/27"],
    ["date" => "2016/11/27"],
    ["date" => "2016/11/27"],
    ["date" => "2016/11/28"],
    ["date" => "2016/11/30"],
    ["date" => "2016/12/01"],
    ["date" => "2016/12/05"],
    ["date" => "2017/01/04"],
    ["date" => "2018/01/15"]
];

$parsed = [];

foreach ($messages as $k => $v) {
    [$y, $m, $d] = explode("/", $v["date"]);
    $parsed[$y][$m][$d] = 1;
}

$html = [];

foreach ($parsed as $y => $v) {
    $html[] = "<div class='year'>$y";
    
    foreach ($v as $m => $v) {
        $html[] = "<div class='month'>Month $m";

        foreach ($v as $d => $v) {
            $html[] = "<div class='day'>Day $d</div>";
        }
      
        $html[] = "</div>";
    }

    $html[] = "</div>";
}

echo implode($html);

Output:

<div class="year">2016<div class="month">Month 11<div class="day">Day 27</div><div class="day">Day 28</div><div class="day">Day 30</div></div><div class="month">Month 12<div class="day">Day 01</div><div class="day">Day 05</div></div></div><div class="year">2017<div class="month">Month 01<div class="day">Day 04</div></div></div><div class="year">2018<div class="month">Month 01<div class="day">Day 15</div></div></div>

Explanation:

Parse the structure in one loop, then loop over it again to generate the HTML. Note that I simplified your data structure but it'll work the same on any other as long as the "date" key exists. Also, the HTML is minified but identical--if you would like a pretty version, that's not much trouble.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • Why do you create a `$html` array? Why not simply just echo it out? – Blue Aug 05 '18 at 03:38
  • Why would you echo it? OP asked to create the HTML, not echo it. I'd rather not write code with side effects unless specifically asked to--keeping it in array or string format gives OP the most options for what to do next, like send it with some JSON or XML to the front end, for example. – ggorlen Aug 05 '18 at 03:44