Neos Snippets #1: DateTime attributes and HTML5 input elements

The Neos Snippets series is about collecting small, helpful bits and pieces of Neos and Flow know-how. Today, I write about the HTML5 datetime-local input element and how to make it work with a Flow entity.

The goal: Enter points in time and save them in a Flow entity

Today, I was modelling an Appointment entity  that, naturally, had a property to save its start date. In an appointment creation form, the users would select the point in time when the appointment should start. After a bit of research, I decided to use one of the more recent additions to HTML5, the <input type="datetime-local"> element. I expected it to work out of the box, since the property mapper in Flow expects the W3C date format by default. Here's what my form and entity looked like:


* @Flow\Entity
class Appointment {
  * @var \DateTime
  * @Flow\Validate(type="NotEmpty")
protected $startDate;


<f:form object="{appointment}" objectName="appointment" action="create" method="POST" controller="Appointment">  
<f:form.textfield type="datetime-local" property="startDate" id="startDate" additionalAttributes="{step:'900'}"/>  
    <f:form.submit value="Send" />

Not quite so easy

When submitting my form, I was greeted by an error message by the Flow property mapper:

The date "2016-06-10T11:30" was not recognized (for format "Y-m-d\TH:i:sP").

The mistake was easy enough to spot. For a \DateTime type attribute, Flow expects a W3C-formatted date string by default. Chrome, however, omitted the seconds interval and the "P" at the end, which lead to the DateTimeConverter not being able to map the date.

Property Mapping config to the rescue

Unfortunately, there is no format attribute to tell the datetime-local input element how to format the date being sent. So I had to fix it on the server side. The property mapping in Flow can be configured to expect a different date format. This can be achieved in an initializer method in the action controller, which Flow calls by convention before the action method:

* Tell the DateTimeConverter to work with the format provided by input type="datetime-local".
* @return void
public function initializeCreateAction() {
if ($this->arguments->hasArgument('appointment')) {
// Get the property mapping configuration
$propertyMappingConfiguration = $this->arguments->getArgument('appointment')->getPropertyMappingConfiguration();

// Use the date format provided by datetime-local

Using this initializer, the property mapping config was set to the correct date format and thus was able to work with the date string sent by Chrome when using <input type="datetime-local">.

Have fun using it!