Jump to content

ICT:D Day problem dd/mm/yyyy: Difference between revisions

From Costa Sano MediaWiki
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.


=== Module Configuration ===
=== Project File Structure ===
* '''Machine Name:''' <code>heritage_date</code>
To ensure PSR-4 autoloading works in Drupal 11.3, use this exact structure:
* '''Location:''' <code>/modules/custom/heritage_date/</code>
 
* '''Requirement:''' Drupal 11.1+ (Uses PHP Attributes for Hooks)
<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 ===
Location: <code>/modules/custom/heritage_date/src/Hook/DateValidationHooks.php</code>
<source lang="php">
<source lang="php">
<?php
<?php
Line 29: Line 33:


/**
/**
  * Validates text fields for dd/mm/yyyy format.
  * 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 {
     // Add the validation handler to all forms.
      
     // The handler will filter by field name suffix.
     // 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) {
      // Dynamic check for our naming convention
       if (str_ends_with($field_name, '_day')) {
       if (str_ends_with($field_name, '_day')) {
          
          
         $date_string = is_array($value) ? ($value[0]['value'] ?? $value['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 ===
To enable and register the new hook system:
# Create the directory and files as shown in the diagram.
# Create the directory structure above.
# Enable via Drush: <code>drush en heritage_date</code>
# Run: <code>drush en heritage_date</code>
# Rebuild Cache: <code>drush cr</code> (Crucial for Hook discovery).
# Run: <code>drush cr</code> (Cache rebuild is mandatory for Hooks to be discovered).


[[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

  1. Create the directory and files as shown in the diagram.
  2. Enable via Drush: drush en heritage_date
  3. Rebuild Cache: drush cr (Crucial for Hook discovery).