Range accepts a date as well as a number. When the validated value is a
\DateTimeInterface, Symfony reads a string bound through the PHP date parser,
so both an absolute date and a relative expression are allowed:
class User
{
#[Assert\Range(
min: 'first day of this month - 14 years UTC',
max: 'today',
)]
public ?\DateTimeInterface $birthday = null;
}$builder->add('birthday', DateType::class);The browser has no equivalent of that parser, so the bounds are resolved on the
server while the form is rendered and exported as concrete dates. A DateType
exports them as Y-m-d, a DateTimeType as Y-m-d H:i:s, and the JavaScript
Range constraint compares the submitted value against them as a date instead
of as a number. Absolute bounds are exported the same way, normalized to the
format of the field.
Nothing has to be configured, but a few limits are worth knowing:
- A relative bound is frozen when the page is rendered.
max: 'today'becomes the day the form was built. A page left open across midnight validates against yesterday in the browser, and the server, which re-reads the bound on submit, has the last word. Reload the form, or use an absolute bound, where that matters. TimeTypeis not covered. Its value carries a time only, while Symfony resolves a bound such as'10:00'to that time on the current day, so the two are not comparable. Bounds of aTimeTypefield are exported unchanged and the field keeps the previous behaviour.- The field must hold a date object. With
'input' => 'string','timestamp'or'array'the model value is not a\DateTimeInterface, so Symfony compares it as a number and the bounds are exported unchanged. - The submitted value has to reach JavaScript as an ISO date. That is what
the widgets of
DateTypeandDateTimeTypeproduce, including the HTML5dateanddatetime-localinputs. A field rendered throughDateTimeToLocalizedStringTransformer— a single text widget with'html5' => false— submits a value formatted for the locale, which is reported with theinvalidDateTimeMessageof the constraint. - Messages show the bound as the exported date string. Symfony formats it for the locale of the server instead.
- A bound read from another field through
minPropertyPathormaxPropertyPath(see Comparing a field with another field) is compared as a date as well, as soon as the referenced field holds one.