htmlformscakephpcakephp-3.0formhelper

How to set custom names for datetime inputs generated by the form helper?


What you did

echo $this->Form->create(null, [
    'type' => 'get', 
    'url' => ['controller' => 'Holidays', 'action' => 'calendar']
]);
echo $this->Form->month('month', ['empty' => 'Select month', 'value' => @$month]);
echo $this->Form->year('year', ['minYear' => date('Y'), 'maxYear' => 2020, 'empty' => 'Select year', 'value' => @$year]);

Expected Behavior

I was expecting that when a submit the form my resulting url would look like example.com/holiday/calendar?month=03&year=2016

Actual Behavior

example.com/holidays/calendar?month%5Bmonth%5D=03&year%5Byear%5D=2016

First thought

So the first thought is to use the name option.

echo $this->Form->month('month', ['name' => 'foo', 'empty' => 'Select month', 'value' => @$month]);

Which will produce <select name="foo[month]".. which has the same issue.

Second thought

Customise the form input template. This doesn't allow customisation of the name token as it's passed as {{name}} so by the time it's got to the template it's too late.

Third thought

Use the array and name the fields the same.

echo $this->Form->month('month', ['name' =>'when', 'empty' => 'Select month', 'value' => @$month]);
echo $this->Form->year('year', ['name' => 'when', 'minYear' => date('Y'), 'maxYear' => 2020, 'empty' => 'Select year', 'value' => @$year]);

I would then expect example.com/holidays/calendar?when[month]=03&when[year]=2016, but you actually get /holidays/calendar?when%5Bmonth%5D=02&when%5Byear%5D=2016

Conclusion

So unfortunately with three different approaches I've not been able to solve this use-case. I'd be interested if anyone knows how to customise the html name attribute generated by the form helper, or prevent get forms from being escaped, so that my urls don't look so messy.


Solution

  • Whether the URL is being displayed encoded or not, depends on your browser. Firefox will for example display it unencoded, while Chromes shows it encoded.

    The date widget uses nested names, so that the date/time parser for date/time columns receives everything it needs for parsing and constructing objects from it.

    With how the date widget currently works, there is no way to change the way the name is built. What you could do is for example using a custom select template for that input, or create a select type input with the necessary options on your own.

    You've probably tried the former with global templates, which is why it failed. You need to use local ones, and consequently you'll have to use FormHelper::input() in order for the form helper to use them, like

    echo $this->Form->input('month', [
        'type' => 'month',
        'empty' => 'Select month',
        'value' => @$month,
        'templates' => [
            'select' => '<select name="month"{{attrs}}>{{content}}</select>'
        ]
    ]);
    echo $this->Form->input('year', [
        'type' => 'year',
        'minYear' => date('Y'),
        'maxYear' => 2020,
        'empty' => 'Select year',
        'value' => @$year,
        'templates' => [
            'select' => '<select name="year"{{attrs}}>{{content}}</select>'
        ]
    ]);