CoolCMS API

StrictDateInput
in package

FinalYes

Strict parser of `<input type=datetime-local>` and `<input type=date>` values, plus a server rule that rejects an invalid value on the field before `onSuccess` (so before manager `save()`).

new DateTime($value) and DateTime::createFromFormat() silently normalize a nonexistent date (2026-02-30 becomes 2026-03-02, warnings unchecked), and new DateTime() accepts any relative text (next monday) that a browser never sends for these input types. This parser uses the exact format (createFromFormat with !, which zeroes components outside the format), checks getLastErrors() and round-trips back to the same string, which also catches valid but rearranged notations.

NOTE: it does not replace AdminFormHelpersTrait::parseDateTime() and its local copies, which are still used for texts outside the datetime-local/date contract (for example ProductSet snapshots in the DB shape Y-m-d H:i:s). Use this class only on fields where the HTML type guarantees the value.

No seconds: no admin datetime-local field declares step, so the browser always sends Y-m-d\TH:i; a round-trip to a longer format would always fail on a real request.

Messages are global keys with the // prefix (as in ColumnGate): validation is called from dozens of forms across modules, and a domain-prefixed key would have to be copied into every NEON file.

Table of Contents

Constants

DATE_MESSAGE  : string = '//admin.general.strictDate.date'
Message for an invalid date; global key.
DATETIME_LOCAL_MESSAGE  : string = '//admin.general.strictDate.datetimeLocal'
Message for an invalid date and time; global key.
DATE_FORMAT  : string = 'Y-m-d'
DATETIME_LOCAL_FORMAT  : string = 'Y-m-d\TH:i'

Methods

dateRule()  : BaseControl
Server rule for `<input type=date>`; same logic as {@see datetimeLocalRule()}.
dateRules()  : void
Batch variant of {@see dateRule()}; see {@see datetimeLocalRules()}.
datetimeLocalRule()  : BaseControl
Server rule for `<input type=datetime-local>`. An empty value passes (Nette skips rules on an optional empty field anyway, see {@see ColumnGate}); the caller's `setRequired()` enforces filling.
datetimeLocalRules()  : void
Batch variant of {@see datetimeLocalRule()}; see {@see ColumnGate::lengths()} for the name matching rules. A missing control is skipped (fields are sometimes built conditionally).
keepSeconds()  : DateTime|null
Keeps the seconds of the stored value: `datetime-local` without `step` sends no seconds, so saving unchanged would cut `23:59:59` to `23:59:00`.
parseDate()  : DateTime|null
Parses `<input type=date>` into `DateTime` (midnight), or null.
parseDatetimeLocal()  : DateTime|null
Parses `<input type=datetime-local>` (without `step`, so without seconds) into `DateTime`, or null.
isValidOrEmpty()  : bool
parse()  : DateTime|null

Constants

DATE_MESSAGE

Message for an invalid date; global key.

public string DATE_MESSAGE = '//admin.general.strictDate.date'

DATETIME_LOCAL_MESSAGE

Message for an invalid date and time; global key.

public string DATETIME_LOCAL_MESSAGE = '//admin.general.strictDate.datetimeLocal'

DATETIME_LOCAL_FORMAT

private string DATETIME_LOCAL_FORMAT = 'Y-m-d\TH:i'

Methods

dateRule()

Server rule for `<input type=date>`; same logic as {@see datetimeLocalRule()}.

public static dateRule(BaseControl $control[, string $message = self::DATE_MESSAGE ]) : BaseControl
Parameters
$control : BaseControl
$message : string = self::DATE_MESSAGE
Return values
BaseControl

dateRules()

Batch variant of {@see dateRule()}; see {@see datetimeLocalRules()}.

public static dateRules(Container $container, array<int, string> $names) : void
Parameters
$container : Container
$names : array<int, string>

datetimeLocalRule()

Server rule for `<input type=datetime-local>`. An empty value passes (Nette skips rules on an optional empty field anyway, see {@see ColumnGate}); the caller's `setRequired()` enforces filling.

public static datetimeLocalRule(BaseControl $control[, string $message = self::DATETIME_LOCAL_MESSAGE ]) : BaseControl
Parameters
$control : BaseControl
$message : string = self::DATETIME_LOCAL_MESSAGE
Return values
BaseControl

datetimeLocalRules()

Batch variant of {@see datetimeLocalRule()}; see {@see ColumnGate::lengths()} for the name matching rules. A missing control is skipped (fields are sometimes built conditionally).

public static datetimeLocalRules(Container $container, array<int, string> $names) : void
Parameters
$container : Container
$names : array<int, string>

keepSeconds()

Keeps the seconds of the stored value: `datetime-local` without `step` sends no seconds, so saving unchanged would cut `23:59:59` to `23:59:00`.

public static keepSeconds(DateTime|null $submitted, DateTimeInterface|null $original) : DateTime|null

When the submitted value falls into the same minute as the original, the original (with seconds) is returned; otherwise the submitted one. Call it with the entity value before overwriting.

Parameters
$submitted : DateTime|null
$original : DateTimeInterface|null
Return values
DateTime|null

parseDate()

Parses `<input type=date>` into `DateTime` (midnight), or null.

public static parseDate(mixed $value) : DateTime|null
Parameters
$value : mixed
Return values
DateTime|null

parseDatetimeLocal()

Parses `<input type=datetime-local>` (without `step`, so without seconds) into `DateTime`, or null.

public static parseDatetimeLocal(mixed $value) : DateTime|null
Parameters
$value : mixed
Return values
DateTime|null

isValidOrEmpty()

private static isValidOrEmpty(mixed $value, string $format) : bool
Parameters
$value : mixed
$format : string
Return values
bool

parse()

private static parse(mixed $value, string $format) : DateTime|null
Parameters
$value : mixed
$format : string
Return values
DateTime|null
On this page

Search results