Add the same page to a collection multiple times

Hi friends :slight_smile:

is it true, that i cant add the same page to a collection multiple times?

What i want to do:

i am creating an event calendar and some events have multiple dates. To avoid having to add the event multiple times in the panel, i added a field where you can add all event dates.

The output of my calendar first shows the month (August 2024) and then all events in this period. So when an event series takes place in august and september, i want the event to be shown in both months.

Here is what i did:

  $articles = $page
    ->children()
    ->listed()
    ->filterBy('template', 'event')
    ->filterBy('isEventSeries', false)
    ->filter(function ($child) {
      $compareDate = mktime(0,0,0,date('m'),date('d'),date('Y'));
      return $child->published()->toDate() <= time() && ( $child->eventdate()->toDate() >= $compareDate || $child->eventdateend()->toDate() >= $compareDate );
    });

  $articlesSeries = $page
    ->children()
    ->listed()
    ->filterBy('template', 'event')
    ->filterBy('isEventSeries', true)
    ->filter(function ($child) {
      $compareDate = mktime(0,0,0,date('m'),date('d'),date('Y'));
      return $child->published()->toDate() <= time() && ( $child->eventdate()->toDate() >= $compareDate || $child->eventdateend()->toDate() >= $compareDate );
    });
    
  foreach($articlesSeries as $articleItem) {
    $months = [];
    
    foreach($articleItem->eventSeriesList() as $eventDate) {
      $month = $eventDate->seriesEventdate()->toDate('M');

      if(in_array($month, $months) === false) {
        array_push($months, $month);

        $newItem = $articleItem->update([
          'id' => $articleItem->title() . '-' . $month,
          'title' => $articleItem->title() . '-' . $month,
          'eventdate' => $eventDate->seriesEventdate()->toDate()
        ]);
        $articles->add($newItem);
      }
    }
  }

so basically i first get all events that ar not an event-series, then i collect all events which are and compare their dates from the list. for each month i wanted to add the item to my articles collection, but the event is only added once. I also tried to create a new page object which then should be added but the output stays the same. it only appears one time.

Im happy for all ideas. Thanks in advance!

True, you cannot add the same page to the collection multiple times using add().

If you use append() however, you can assign a new key (for example, by adding the date to the the key) and add the page to the collection with this new key.

thank you so much Sonja!

I dont quite understand what offset means in the example. And in my specific problem: how can i add the date to the key? Sorry im not very familiar with those functions…

Ignore the offset, that’s just an example. You are looping through $articleSeries, modify the loop to read:

foreach($articlesSeries as $key => $articleItem) {
    // bla bla bla

  $articles->append($key . '-' . $eventDate->seriesEventdate()->toDate(), $articleItem);
}

thanks again! It worked like it should.

I only need one more thing for this to work. Can i change the data of the newly added item inside the collection? So for the appended item i want to change the field “eventdate” to the date found in the loop. i tried this with the page->update() method but this adds the pages inside the content folder, which i want to avoid. i read the docs for the update method which said it will not create a new page but it does so.

I guess you misunderstood something. What the documentation says is that you cannot modify the $page variable without storing the result in a new variable. But update() always writes to the content file.

What you can do, is create a new property (eventDate) in a page model, then add a setter and getter for this property.

In your loop, assign a value to this property.

we are almost there :slight_smile:

i tried your solution with the page model and now i have the correct amount of articles inside my collection. I try to update the event date with a function inside the model, because i need the updated event date for filtering.

i helped myself with the cloning method to get a new instance of the article each time and then setEventdate for the clone.

problem now is, that all articles i appended have the same date, which is the last date inside the loop. Unfortunately i cannot find the error.

here is the loop for the collection:

foreach($articlesSeries as $key => $articleItem) {
      $months = [];
      
      foreach($articleItem->eventSeriesList() as $eventDate) {
        $month = $eventDate->seriesEventdate()->toDate('M');
  
        if(in_array($month, $months) === false) {
          array_push($months, $month);
          $newDate = $eventDate->seriesEventdate()->toDate(t('date-format', 'dd.MM.yyyy'));

          $addItem = $articleItem->clonePage();
          $addItem->setEventDate($newDate);

          $articles->append($key . '-' . $month, $addItem);
        }
      }
    }

and here is my page model:

<?php
    class EventPage extends Page {
        protected $seriesEventDate;

        public function setEventDate($date) {
            $this->update([
                'eventdate' => $date
            ]);
        }

        public function getEventDate() {
            return $this->eventDate();
        }

        public function clonePage() {
            return clone $this;
        }
    }
?>

The problem is that you are actually updating the page, i.e. write to file. I mean set the value

public function setEventDate($date) {
            $this->eventdate = $date
            ]);
        }

And you need to define this property:

        protected $eventDate;

hmm but i thought when i first copy the page and then use the update on the cloned page. it would only affect the clone and not the existing page.

is it possible to have the same property inside the model and also defined in the blueprint? i really need to use the same date since most articles are not affected by this

Why the same property? Here we are adding a new property directly to the page object, what you have in the content file is part of the content object.

Hm, but if it doesn’t work as expected, give it another name.

i guess i did not make myself clear what i try to achieve. let my try again:

i have over 100 events in the list, most of them just have a single date and it works fine filtering and paginating them.
Then there are event series, which start on date 1 and have like 10 other dates defined in the structure field eventSeriesList. To make them visible in the list of all events, i wanted to create a temporary copy of the event, change the event date of the copy and add it to my collection. This collection will then be sorted, filtered and paginated.

so i thought it would be easy to just modify the event date for each temporary copy and add them in the list. then everything else would work like with the single date events.

i dont want to create a new property because that would mean a lot of extra work. But maybe this is the only solution i guess.

Sorry for the circumstances :confused:

I did understand your use-case very well.

And what I suggested will work fine.

Here is a simple example, which assumes you have a field eventDate in your content file, and a property eventDate (or whatever you want to call it with a setter and a getter for this property.

$new = new Pages();
foreach ($page->children()->listed() as $p) {
    $p->setEventDate('2024-06-08');
    $new->add($p);
}

foreach ($new as $pp) {
   // so here I get the eventDate from the content file, or if empty, fall back to the page property set above
    echo($pp->content()->get('eventDate')->or($pp->getEventDate()));
	
}

IMO, this does exactly what you are after.