Filter collection by date parameter in period between two dates

Hi
I would like to know how to get each dates values between two dates. The topic https://forum.getkirby.com/t/group-function-with-two-values/6592 could help me but this doesn’t get each values.

I have my events stored in the “projects” folder. Each folder have a date_from and date_to fields. Now I want to get every dates between these two dates.
Example : for the project A from 01.02.2017 to 03.02.2017, I want to get this : 01.02.2017/02.02.2017/03.02.2017.
After that, some project can have only one date, for exemple from 01.02.2017 to 01.02.2017

My final project consist to link these values to the calendar plugin by Bastien instead of using the MolocLab plugin calendar (that is not necessary for my back end).
My feeling is that I could use a “controller” system (like filters) but I don’t know how to.

Thank you in advance

This stackoverflow thread has some solutions: http://stackoverflow.com/questions/4312439/php-return-all-dates-between-two-dates-in-an-array

Thank you. I found an elegant solution with DatePeriod (PHP > 5.3)

<?php 
     $begin = new DateTime($project->date_from('Y-m-d') );
     $end = new DateTime($project->date_to('Y-m-d'));
     $interval = DateInterval::createFromDateString('1 day');
     $period = new DatePeriod($begin, $interval, $end);
          foreach ( $period as $dt )
               echo $dt->format( "Y-m-d" );     
?>

I could get every duration between two dates.

How can I store them to display into my calendar ? Like a filtering system, do I need to build a controller ? I just want to get every events by clicking on the day link of my calendar

<a href="#">
     <div class="content">
          <?php echo ($day->isToday()) ? '<strong>' . $day->int() . '</strong>' : $day->int() ?>
     </div>
</a>

Is my question was not well explained or do you want me to open a new topic ? Does anybody has some advices ?

I must admit that I don’t quite understand what you mean. There seem to be two things, one is storing the dates (but you have already stored the dates, haven’t you) and the other filtering.

Oh, ok well.
Because an example is more explicit

I want to filter every date and display each events corresponding.
In my calendar snippet, $day return the day.

 <a href="<?php echo url('/' . url::paramsToString(['date' => $day])) ?>">
                                <div class="content">
                                    <?php echo ($day->isToday()) ? '<strong>' . $day->int() . '</strong>' : $day->int() ?>
                                
                                </div>
                            </a> 

And my controller now

  $events = page('projects')->children()->visible()->filter(function($child) {
            return $child->date(null, 'date_from') > time() || $child->date(null, 'date_to') > time();
          });
  return $events->date();

};

But as you can see, it does’nt work as expected. How can I do ?

So I take it if you click on a day in the calendar, you want to get events for that day.

Your filter only gets events in the future, so what you would have to do is get the parameter from the URL and then get events for that day.

if($date = param('date')) {
// filter by that date
}

Ok I’m trying to integer your code is that correct ?

if($date = param('date')) {
        $events = page('projects')->children()->visible()->filter(function($child) {
            return $child->date(null, 'date_from') > time() || $child->date(null, 'date_to') > time();
        });
    }
    return $events->date();

How can I return the project by date and fetch all date used into my projects ?

No, you would have to use the param in your filter, I don’t have the time now, but will get back to you later.

Your day filter should actually look similar to this (change the variables to fit yours):

// using the date format from your URL http://octaverimbertriviere.com/Clermont/date:2017-02-24
$projects = $page->children()->visible();
if($date = param('date')) {
  $projects = page('projects')->children()->visible()->filter(function($child) use($date) {
    return $child->date('Y-m-d', 'date_from') == $date || $child->date('Y-m-d', 'date_to') == $date;
  });
}

Note that you have to use use($date) in the filter function, otherwise the $date variable would be undefined within the callback function.

Using the $date variable, I lose the date from url and get http://…/date:

calendar.php (controller)

<?php
return function($site, $pages, $page) {
$projects = page('projects')->children()->visible();
if($date = param('date')) {
  $projects = page('projects')->children()->visible()->filter(function($child) use($date) {
    return $child->date('Y-m-d', 'date_from') == $date || $child->date('Y-m-d', 'date_to') == $date;
  });
}    
};
?>

calendar.php (snippet)

 <a href="<?php echo url('/' . url::paramsToString(['date' => $day])) ?>">
                                <div class="content">
                                    <?php echo ($day->isToday()) ? '<strong>' . $day->int() . '</strong>' : $day->int() ?>
                                
                                </div>
                            </a>

Why did you change the snippet? It did produce the correct URL?

Sorry my fault. I understood I had to change $day to $date
I changed to <a href="<?php echo url('/' . url::paramsToString(['date' => $day])) ?>"> but it has the same effect.

The $day variable, as previously, produce the correct URL, but it doens’t return the correct project with my actual controller. Every projects are still contained into every dates.

If you send me your project, I can offer to have a look.

In case anyone is interested, here is the final filter. It uses the interval between two dates to filter projects by a given date parameter

<?php
return function($site, $pages, $page) {

$projects = page('projects')->children()->visible();


if($date = param('date')) {
  $projects = $projects->filter(function($child) use($date) {

    $begin = new DateTime($child->date_from('Y-m-d') );
    $end = new DateTime($child->date_to('Y-m-d'));
    $interval = DateInterval::createFromDateString('1 day');
    $period = new DatePeriod($begin, $interval, $end);

    //create date array for each chilc
    foreach ($period as $dt):
       $dates[] = $dt->format('Y-m-d');
    endforeach;

    if(in_array($date, $dates)) {
      return $child;
    }
  });
}
 return compact('projects');
};
1 Like

Hi,
I would like to ask you a last question about this excellent script. To achieve my project, I have to redirect my page by default to the date of today.
Does a default parameter already exist for this case ?

I’m using the script from texnixe bellow, and the bastian calendar plugin. Inside, an active class already activate the date of today, How can I use it ?

<a  <?php e($day == $p, 'class="active"') ?> href="<?php echo url('/' . url::paramsToString(['date' => $day])) ?>">
     <div class="content" data-color="<?php echo $color ?>">
        <?php echo ($day->isToday()) ? '<strong>' . $newDate . '</strong>' : $newDate ?>
    </div>
</a>

Hi @Oziris,

I was away on vacation, guess your question has been answered in another thread?

Yes it was, thanks to @flokosiol