ICT:D Day problem dd/mm/yyyy
Appearance
Drupal 11.3 Heritage Date Validation Module
This module implements a modern, **Object-Oriented (OOP)** approach to validate and hint text fields for historical dates (1700s–Present) using the `dd/mm/yyyy` format.
Project File Structure
To ensure PSR-4 autoloading works in Drupal 11.3, use this exact structure:
/web/modules/custom/heritage_date/
├── heritage_date.info.yml
└── src/
└── Hook/
└── DateValidationHooks.php
File: heritage_date.info.yml
name: 'Heritage Date Validator'
type: module
description: 'Enforces dd/mm/yyyy format for fields ending in _day.'
package: Custom
core_version_requirement: ^11
File: src/Hook/DateValidationHooks.php
<?php
namespace Drupal\heritage_date\Hook;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Hook\Attribute\Hook;
/**
* Modern Drupal 11 Hook class for Heritage Date handling.
*/
class DateValidationHooks {
/**
* Implements hook_form_alter().
* Automatically adds placeholders and validation to *_day fields.
*/
#[Hook('form_alter')]
public function validateHeritageDate(array &$form, FormStateInterface $form_state, $form_id): void {
// 1. Add Global Validation Handler
$form['#validate'][] = [static::class, 'performRegexCheck'];
// 2. Add Placeholders (UI Hinting)
// We scan the form structure for our naming convention.
foreach ($form as $key => &$element) {
if (str_ends_with($key, '_day') && isset($element['widget'][0]['value'])) {
$element['widget'][0]['value']['#attributes']['placeholder'] = 'dd/mm/yyyy';
}
}
}
/**
* Scans form for fields ending in '_day' and validates format.
*/
public static function performRegexCheck(array &$form, FormStateInterface $form_state): void {
$values = $form_state->getValues();
foreach ($values as $field_name => $value) {
if (str_ends_with($field_name, '_day')) {
$date_string = is_array($value) ? ($value['value'] ?? '') : '';
if (!empty($date_string)) {
// Regex for dd/mm/yyyy (Day/Month/Year)
$regex = '/^(0[1-9]|[1-2][0-9]|3)\/(0[1-9]|1[0-2])\/([0-9]{4})$/';
$label = $form[$field_name]['widget']['#title'] ?? $form[$field_name]['#title'] ?? $field_name;
if (!preg_match($regex, $date_string)) {
$form_state->setErrorByName($field_name, t('The @label must be in dd/mm/yyyy format.', ['@label' => $label]));
} else {
// Calendar sanity check (Month, Day, Year) for PHP checkdate
$parts = explode('/', $date_string);
if (!checkdate((int)$parts[1], (int)$parts[0], (int)$parts[2])) {
$form_state->setErrorByName($field_name, t('The @label contains an invalid calendar date.', ['@label' => $label]));
}
}
}
}
}
}
}
Implementation Commands
- Create the directory and files as shown in the diagram.
- Enable via Drush:
drush en heritage_date - Rebuild Cache:
drush cr(Crucial for Hook discovery).