ICT:D Day problem dd/mm/yyyy: Difference between revisions
Appearance
Created page with "== Drupal 11.3 Heritage Date Validation Module == This module implements a modern, **Object-Oriented (OOP)** approach to validate text fields for historical dates (1700s–Present) using the `dd/mm/yyyy` format. === Module Configuration === * '''Machine Name:''' <code>heritage_date</code> * '''Location:''' <code>/modules/custom/heritage_date/</code> * '''Requirement:''' Drupal 11.1+ (Uses PHP Attributes for Hooks) === File: heritage_date.info.yml === <source lang="yam..." |
No edit summary |
||
| Line 1: | Line 1: | ||
== Drupal 11.3 Heritage Date Validation Module == | == Drupal 11.3 Heritage Date Validation Module == | ||
This module implements a modern, **Object-Oriented (OOP)** approach to validate text fields for historical dates (1700s–Present) using the `dd/mm/yyyy` format. | 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: | |||
<pre> | |||
/web/modules/custom/heritage_date/ | |||
├── heritage_date.info.yml | |||
└── src/ | |||
└── Hook/ | |||
└── DateValidationHooks.php | |||
</pre> | |||
=== File: heritage_date.info.yml === | === File: heritage_date.info.yml === | ||
| Line 18: | Line 24: | ||
=== File: src/Hook/DateValidationHooks.php === | === File: src/Hook/DateValidationHooks.php === | ||
<source lang="php"> | <source lang="php"> | ||
<?php | <?php | ||
| Line 29: | Line 33: | ||
/** | /** | ||
* | * Modern Drupal 11 Hook class for Heritage Date handling. | ||
*/ | */ | ||
class DateValidationHooks { | class DateValidationHooks { | ||
| Line 35: | Line 39: | ||
/** | /** | ||
* Implements hook_form_alter(). | * Implements hook_form_alter(). | ||
* Automatically adds placeholders and validation to *_day fields. | |||
*/ | */ | ||
#[Hook('form_alter')] | #[Hook('form_alter')] | ||
public function validateHeritageDate(array &$form, FormStateInterface $form_state, $form_id): void { | public function validateHeritageDate(array &$form, FormStateInterface $form_state, $form_id): void { | ||
// | // 1. Add Global Validation Handler | ||
$form['#validate'][] = [static::class, 'performRegexCheck']; | $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'; | |||
} | |||
} | |||
} | } | ||
| Line 50: | Line 63: | ||
foreach ($values as $field_name => $value) { | foreach ($values as $field_name => $value) { | ||
if (str_ends_with($field_name, '_day')) { | if (str_ends_with($field_name, '_day')) { | ||
$date_string = is_array($value) ? ( | $date_string = is_array($value) ? ($value['value'] ?? '') : ''; | ||
if (!empty($date_string)) { | if (!empty($date_string)) { | ||
// Regex for dd/mm/yyyy | // 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})$/'; | $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; | $label = $form[$field_name]['widget']['#title'] ?? $form[$field_name]['#title'] ?? $field_name; | ||
| Line 63: | Line 75: | ||
$form_state->setErrorByName($field_name, t('The @label must be in dd/mm/yyyy format.', ['@label' => $label])); | $form_state->setErrorByName($field_name, t('The @label must be in dd/mm/yyyy format.', ['@label' => $label])); | ||
} else { | } else { | ||
// Calendar sanity check (Month, Day, Year) | // Calendar sanity check (Month, Day, Year) for PHP checkdate | ||
$parts = explode('/', $date_string); | $parts = explode('/', $date_string); | ||
if (!checkdate((int)$parts[1], (int)$parts[0], (int)$parts[2])) { | if (!checkdate((int)$parts[1], (int)$parts[0], (int)$parts[2])) { | ||
| Line 77: | Line 89: | ||
=== Implementation Commands === | === Implementation Commands === | ||
# Create the directory and files as shown in the diagram. | |||
# Create the directory | # Enable via Drush: <code>drush en heritage_date</code> | ||
# | # Rebuild Cache: <code>drush cr</code> (Crucial for Hook discovery). | ||
# | |||
[[Category:Drupal 11]] [[Category:Heritage Project]] | [[Category:Drupal 11]] [[Category:Heritage Project]] | ||
Latest revision as of 20:01, 21 March 2026
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).