Create a collection of pages from a structure field

I am not sure how to search for this, so i ask it really quick here:

Is it possible (and how) to create a collection page objects from one page containing a structure field.
An example: There is one event, that can have multiple dates (via structure field) and i want to display each of these dates as an entity with informations from the page (title, descriptions, etc.)
I also need to merge this collection later with pages that have only one date that has no structure field…

thanks in advance for any thoughts…

What is your use case?

I want to create pages for events. Each one has a set of informations (title, description, related pages, and so on).
Each event has also several dates & times, which i want to add through a structure field.

Later, i want to be able to generate calendar, that displays all the events at their dates, linking to the detail page of that event.

Is this a use case?

Yes, that is a perfect use case. But you don’t have to create page collections from non-existing pages for this. You can filter your events by day to populate your calendar.

ok. but how would i do that, if the dates are in the structure fields? can i filter just as if it would be a normal date?

Not quite, but with the filter function (with callback). Within that callback function, you can use pluck() to get an array of all the dates in the structure field, and then check if the current day is in that array,

But this would work only for a very specific day. I wanted to generate a page with all events (and dates) grouped by days… would something like this possible too?

Yes, I don’t see why not. A page with all events grouped by days is no different from a calendar, where you do exactly that, i.e. group events by day. You would create an array of all dates of all events and then find all the events that belong to each group.

I don’t quite see, however, how to create a pages collection from the same page over and over again.

i think i see the point in that. so, your suggestion is, that i first loop through all pages with the structure fields, build an array with all dates and then search for each date for pages that contain that date?

is there an elegant way of doing this?

can i use groupBy() at any point?

groupBy() is a method of the collection object. In your case, you will be dealing with an array of dates, however, so no groupBy(), and you don’t need it. Once you have your array of dates, loop through it and then for each of the dates use a function that collects all the events that belong to that date (then loop through the collection of results). Within that methods, you will have to make a distinction between pages with a single event and pages with multiple events (don’t know if you are using different templates or a toggle field?).

Get array of all dates from all events (with structure field):

// in your controller
$events = page('events')->children()->visible();
foreach($events as $event) {
  $dates = $event->dates()->toStructure()->pluck('date', ',');
  foreach($dates as $date) {
    $dates[] = $date;
  }
}

$dates = array_unique($dates, SORT_NUMERIC);

To get all events per day from events with a structure field of dates, you can use a function like this:

// put this into your controller or into a plugin file
function getEventsPerDate($events, $date) {

  $eventsPerDay = $events->filter(function($child) use($date) {
    $dates = $child->dates()->toStructure()->pluck('date', ',');
    // check if the current day is in dates
    if(in_array($date, $dates)) {
      return $child;
    }
  });
 
  return $eventsPerDay;

}

In your template:

<?php

foreach($dates as $date) {
  // you don't need to define events again, if it is already defined in your controller
  // just putting it here to make it clearer
  $events = page('events')->children()->visible();
  $dayEvents = getEventsPerDate($events, $date);
  foreach($dayEvents as $event) {
    echo $event->title(); 
  }
}

hi,
thanks a lot. i have some troubles to get it to work though. right now, the array with the dates
seems to be always empty (var_dump: array(0) { } array(0) { } )
This seems to result in a:
Undefined variable: dates
on the template side…

Can you explain me what this is doing?:

what is exceptions() ? and which field is being plucked by ->pluck(‘date’, ‘,’) ?

in my content, the infos are sorted like this:

----
Eventdates: 
- 
  eventdate: 2017-11-11
  eventtime: 19:00
- 
  eventdate: 2017-11-30
  eventtime: 20:30

Sorry, exceptions was a leftover from my original function. Should be the name of your structure field that contains the dates, in this case eventdates

 $dates = $child->eventdates()->toStructure()->pluck('eventdate', ',');

It was just an example, you have to adapt it to your data, names of fields etc.

this lead to new error message, so i am trying to work my way through this:

$dates = $event->eventdates()->toStructure()->pluck('eventdate', ',');
this outputs a correct array of 3 dates (as there are in the contents)

		foreach($dates as $date) {
			$dates[] = $date;
		}

this transforms an array(2) to array(4) with strangely the same dates, but double the amount showing up

$dates = array_unique($dates, SORT_NUMERIC);

after this, only one date is left (the last from the previous outputs). now it is an array(1)

when i am using the template code, i get an error: Undefined variable: dates

i’m really sorry, but i am not sure i really get it…

Does your controller return $dates to the template? If you are not familiar with using controllers, you may want to read the docs. Otherwise, for testing, just put it all into the template.

yes, this part works. i am calling all my var_dumps from the controller and get them displayed on that particular page…
but when i call the
foreach($dates as $date) {
loop, i get the error. so somehow this variable doesn’t want to be transferred over?

Hm, I don’t know what’s wrong with the dates.

I just realized that it somehow doesn’t work with evendate (probably because of the SORT_NUMERIC flag, because it doesn’t give you a Unix timestamp as does a date field called date.

i tried and copied the code into the template and that solves the unknown date problem.
but: i get only one event out in the end, when it should be 3 at the moment… so somewhere the array gets cut…

Yes, see my remark above. Should work if you remove the flag from array_unique.

Or transform date to Unix stamp:

foreach($events as $event) {
  $dates = $event->dates()->toStructure()->pluck('eventdate', ',');
  foreach($dates as $date) {
    $dates[] = strtotime($date);
  }
}
$dates = array_unique($dates, SORT_NUMERIC);

removing the flag doesn’t change much…

here are the results from each step:
$dates = $event->eventdates()->toStructure()->pluck('eventdate', ',');
array(2) { [0]=> string(10) “2017-11-11” [1]=> string(10) “2017-11-30” } array(1) { [0]=> string(10) “2017-09-21” }

foreach($dates as $date) {$dates[] = $date;}

array(4) { [0]=> string(10) “2017-11-11” [1]=> string(10) “2017-11-30” [2]=> string(10) “2017-11-11” [3]=> string(10) “2017-11-30” } array(2) { [0]=> string(10) “2017-09-21” [1]=> string(10) “2017-09-21” }

$dates = array_unique($dates, SORT_NUMERIC);
array(1) { [0]=> string(10) “2017-09-21” }

$dates = array_unique($dates);
array(1) { [0]=> string(10) “2017-09-21” }