SilverStripe InPast solution for bugSilverStripe InPast solution for bug

Posted August 3rd, 2010 in SilverStripe

SilverStripe date fields have a number of functions that can be used on them in templates; one of these is the InPast function which unfortunately appears to have a bug in it (at least in SS 2.4.0 and 2.4.1). This post looks at the issue and the workaround I created.

The situation

I have a Running Calendar website which has competitions; there's a competition "holder" page which shows the list of competitions with a summary for each one. The summary shows the date the competition closes or "This competition has closed" if it has finished. This is determined in the template from a field named EndDatetime in a CompetitionPage controller.

The bug

Doing this:

$EndDatetime.InPast

outputs nothing if the date is not in past, or 1 if it is. So far so good. But doing this:

<% if EndDatetime.InPast %>

does not work because it always returns true. And doing this:

<% if EndDatetime.InPast = 1 %>

results in a template parse error. Unfortunately the logic available in the SilverStripe templating system is fairly restrictive and is something I think needs a lot of work.

The solution

To workaround this bug, a special function needs to be created. In my case I have a CompetitionHolder which contains multiple CompetitionPage pages. The CompetitionPage has the EndDatetime field and needs a function added like this (note this is added to the class that extends Page, not the one that extends Page_Controller):

public function HasClosed() {
     return $this->EndDatetime < date('Y-m-d H:i:s');
}

It can then be used in the template like this:

<% if HasClosed %>
     <p><strong>This competition has closed</strong></p>
<% else %>
     <p><strong>Date closes:</strong> $EndDatetime.nice</p>
<% end_if %>

A better solution

The solution above works but it specific to the field and cannot be used for other fields. While writing this post, I re-implemented the above function to a more generic function which is added to the Page class. Then all classes that descend from the Page class can use it.

public function InPast($fieldname) {
    return $this->$fieldname < date('Y-m-d H:i:s');
}

Then use it in the template like so, where EndDatetime is the fieldname:

<% if InPast(EndDatetime) %>
    <p><strong>This competition has closed</strong></p>
<% else %>
     <p><strong>Date closes:</strong> $EndDatetime.nice</p>
<% end_if %>

The way this works, is the InPast function of the Page class is called, passing it the string value EndDatetime (it does not pass the actual value, and this cannot currently be done in SilverStripe). The InPast function then compares the date with current date by using a feature of PHP where a property of a class can be referenced with a variable name (the $this->$fieldname) part.

Related posts:

Comments

blog comments powered by Disqus