Group structure by multiple functions

We’re organising a conference that spans over 6 days. The first two are dedicated to subject X, the following three are dedicated to subject Y and the last day is dedicated to subject Z. Each day is made up of n different keynotes.
All this is as of yet wrapped together in a structured field, where each keynote is a specific entry. These entries all have the keynote’s title, location, date, time, etc.
I’d like to display them as such:

Subject X

  • 01.01.1970
    — keynote 1
    — keynote 2
  • 02.01.1970
    — keynote 3
    — keynote 4
    — keynote 5

Subject Y

  • 03.01.1970
    — keynote 6
    — keynote 7
  • 04.01.1970
    — keynote 8
    — keynote 9

So far, I think I’ve normalised the data correctly.

I could of course add all the relevant info to each individual keynote, even the subject it belongs to and its date, and then display them all in nested foreach loops.

But that would be too easy. And redundant too.

See, each date matches a given Subject, and some subjects span over more than one day. In the above example, day 3 == Subject Y. So once you have the keynote’s date, you should be able to deduct its subject. Keeping the subject in each individual keynote is thus redundant and should be avoided.

This is undoubtedly the right way to proceed, and I’ve managed to group the keynotes by date. What I cannot do however is group these dates together under their relevant subjects in one clean and elegant function.

Any ideas?

I’ll gladly share the code I’m using once I get to my computer tomorrow.

Cheers, and thanks a ton!

Just to make. sure I get this right:

So your structure is one big structure field that contains keynotes with some information attached in fields. There are no other pages involved, so we are only dealing with this field. Ok, the days/dates we get from the structure fields (using pluck()), but where are the subjects stored or rather the relation between day and subject? Maybe I’m missing something?

Nevermind, I got it working within minutes this morning; I guess I just had to ask the question to find the answer.

Here’s the code I’m using:

Logic (will probably end up in controller.php)

<?php
$dateYmd = function($d) {return date('Y-m-d', strtotime($d));};

$eventTypes = function($e) { // Group events by type
  $subjX = ['2018-12-03', '2018-12-04'];
  $subjY = ['2018-12-05', '2018-12-06', '2018-12-07'];
  $subjZ = ['2018-12-08'];

  if(in_array($e->date('Y-m-d'), array_map($dateYmd, $subjX))) return 'Subject X';
  if(in_array($e->date('Y-m-d'), array_map($dateYmd, $subjY))) return 'Subject Y';
  if(in_array($e->date('Y-m-d'), array_map($dateYmd, $subjZ))) return 'Subject Z';
};

$eventDates = function($e) { // Group events by date
  return strftime('%A %e %B %Y', $e->date()); // Desired date output format
} ?>

Template

<h1><?= $section->title()->html() ?></h1>
<ul>

<?php foreach($section->events()->toStructure()->group($eventTypes) as $type => $eventsByType): ?>
  <li><h2><?= $type ?></h2>
    <ul>

    <?php foreach($eventsByType->group($eventDates) as $date => $eventsByDate): ?>
      <li><h3><?= $type ?></h3>
        <ul>

        <?php foreach($eventsByDate as $event): ?>
          <li><?php snippet('components/event', ['event' => $event]) ?></li>
        <?php endforeach ?>

        </ul>
      </li>
    <?php endforeach ?>

    </ul>
  </li>
<?php endforeach ?>

</ul>

Anyway thanks for your quick reply!

In your arrays you already use dates in the correct Y-m-d format; unless you are getting your dates from somewhere else, this bit of code seems superfluous and

if(in_array($e->date('Y-m-d'), $subjX)) return 'Subject X';

would achieve the same.

Right you are! Thank you