VOOZH about

URL: https://deepwiki.com/hypervel/validation/4.3-custom-validation-rules

⇱ Custom Validation Rules | hypervel/validation | DeepWiki


Loading...
Menu

Custom Validation Rules

Purpose and Scope

This page documents how to create custom validation rules in the Hypervel validation package. Custom rules extend the built-in validation capabilities by allowing developers to define application-specific validation logic.

This page covers:

  • Inline closure-based validation
  • Rule class implementations using the Rule and ValidationRule interfaces
  • Registering global custom extensions via the Factory
  • Custom message replacers for parameterized error messages

For documentation of the rule interface contracts themselves, see Rule Interfaces and Contracts. For factory configuration and extension registration patterns, see Extensions and Customization. For runtime-determined validation logic, see Conditional and Dynamic Rules.


Custom Rule Approaches

The validation package supports four primary approaches for creating custom validation rules, each with different use cases and levels of complexity:

ApproachUse CaseReusabilityComplexity
Inline ClosureSimple, one-off validation in a single validatorSingle useLow
ClosureValidationRuleClosure-based logic with validator contextSingle/MultipleLow-Medium
Rule InterfaceReusable rule classes with full controlMultipleMedium
Factory ExtensionsGlobal rules available throughout applicationGlobalMedium-High

Sources: src/Factory.php1-260 src/ClosureValidationRule.php1-76 src/Contracts/Rule.php1-19


Inline Closure Validation

The simplest approach is to pass a closure directly in the rules array. The closure receives the attribute name, value, and a fail callback:


The fail callback adds an error message when invoked. The :attribute placeholder is automatically replaced with the attribute's display name.

Closure Signature


Parameters:

  • $attribute - The attribute name being validated (e.g., 'email', 'users.*.name')
  • $value - The value to validate
  • $fail - Callback to invoke with error message: $fail($message) or $fail($attribute, $message)

Sources: src/ClosureValidationRule.php49-53


ClosureValidationRule Wrapper

When a closure needs access to the validator instance or other validation context, the ClosureValidationRule class wraps the closure and provides additional capabilities:


Diagram: ClosureValidationRule wraps user closures and implements rule contracts

The ClosureValidationRule automatically wraps closures and implements:

  • Rule interface - Provides passes() and message() methods
  • ValidatorAwareRule interface - Receives the validator instance via setValidator()

Enhanced Closure Signature

When wrapped in ClosureValidationRule, the closure receives a fourth parameter:


The $validator parameter allows access to:

  • Other validation data: $validator->getData()
  • Other attributes: $validator->getValue($otherAttribute)
  • Validation context for cross-field validation

Internal Mechanism

src/ClosureValidationRule.php45-56:

  1. The passes() method invokes the user closure with all four parameters
  2. If the closure calls $fail(), the $failed flag is set to true
  3. Error messages are stored in the $messages array
  4. Returns !$this->failed to indicate pass/fail status

Sources: src/ClosureValidationRule.php1-76


Rule Interface Implementation

For reusable validation logic, create a class implementing the Rule interface:


Diagram: Rule interface contract

Rule Interface Contract

src/Contracts/Rule.php7-19 defines two required methods:

MethodReturn TypePurpose
passes($attribute, $value)boolReturns true if validation passes, false otherwise
message()array|stringReturns error message(s) when validation fails

Example Implementation


Usage:


Multi-Message Support

The message() method can return an array for multiple error messages:


Sources: src/Contracts/Rule.php1-19


ValidationRule Interface Implementation

The ValidationRule interface provides an alternative contract with a modern callback-based API:


Diagram: ValidationRule interface uses fail callback pattern

ValidationRule Interface Contract

src/Contracts/ValidationRule.php9-17 defines a single method:


The $fail closure has the signature:


Example Implementation


Advantages Over Rule Interface

FeatureRuleValidationRule
Return typeboolvoid
Error reportingReturn false, then call message()Call $fail() directly
Multiple failuresReturn array from message()Call $fail() multiple times
TranslationManualAutomatic via $fail()
Conditional messagesComplex logic in message()Simple - call $fail() with condition

Sources: src/Contracts/ValidationRule.php1-18 src/ClosureValidationRule.php49-53


Factory Extension System

The Factory class provides methods to register custom validation rules globally, making them available throughout the application without instantiating rule objects:


Diagram: Factory extension registration and injection flow

Extension Method: extend()

src/Factory.php154-161 registers a standard custom validation extension:


Parameters:

  • $rule - The rule name (e.g., 'uppercase')
  • $extension - Closure or class name string
  • $message - Optional fallback error message

Closure Signature:


Example:


Usage in rules:


Implicit Extension Method: extendImplicit()

src/Factory.php166-173 registers an implicit extension that runs even when the attribute is missing or empty:


Use Case: Rules like required, required_if, accepted that validate presence rather than format.

Example:


Dependent Extension Method: extendDependent()

src/Factory.php178-185 registers a dependent extension that receives the entire data array for cross-field validation:


Closure Signature:


Example:


Usage:


Extension Type Comparison

Extension TypeRuns When Attribute MissingReceives Full DataUse Case
Standard (extend)NoNoFormat and type validation
Implicit (extendImplicit)YesNoPresence validation
Dependent (extendDependent)NoYesCross-field validation

Sources: src/Factory.php154-185


Custom Message Replacers

Custom validation extensions can define message replacers to handle placeholder substitution for rule parameters:


Diagram: Message replacer registration and execution flow

Replacer Registration

src/Factory.php190-193 registers a custom message replacer:


Closure Signature:


Example: Parameterized Custom Rule


Usage:


Error message: "The quantity must be a multiple of 5."

Replacer Execution Flow

  1. Validation fails for a custom rule
  2. Factory's fallback message is retrieved: "The :attribute must be a multiple of :divisor."
  3. Standard placeholder replacement occurs (:attribute → attribute display name)
  4. Custom replacer is invoked with message, attribute, rule name, and parameters
  5. Custom replacer substitutes rule-specific placeholders (:divisor5)
  6. Final message returned to validator

Sources: src/Factory.php190-193 src/Factory.php146-149


Extension Resolution in Validator

When a validator instance is created, the Factory injects registered extensions via the addExtensions() method:


Diagram: Extension injection during validator creation

Extension Storage in Factory

src/Factory.php21-53 defines storage arrays for custom extensions:

PropertyTypePurpose
$extensionsarray<string, Closure|string>Standard validation extensions
$implicitExtensionsarray<string, Closure|string>Implicit validation extensions
$dependentExtensionsarray<string, Closure|string>Dependent validation extensions
$replacersarray<string, Closure|string>Custom message replacers
$fallbackMessagesarray<string, string>Fallback error messages for custom rules

Injection Process

src/Factory.php135-149 transfers extensions from Factory to Validator:

  1. Standard extensions added via $validator->addExtensions($this->extensions)
  2. Implicit extensions added via $validator->addImplicitExtensions($this->implicitExtensions)
  3. Dependent extensions added via $validator->addDependentExtensions($this->dependentExtensions)
  4. Message replacers added via $validator->addReplacers($this->replacers)
  5. Fallback messages set via $validator->setFallbackMessages($this->fallbackMessages)

Sources: src/Factory.php80-108 src/Factory.php135-149


Custom Rule Execution Flow

The following diagram illustrates how different custom rule types are executed during validation:


Diagram: Custom rule execution in validation lifecycle

Rule Type Detection Order

  1. Built-in rules: Checked first via ValidatesAttributes trait methods
  2. Rule objects: Detected by instanceof Rule or instanceof ValidationRule
  3. Custom extensions: Resolved from Factory-registered extensions
  4. Closure rules: Wrapped in ClosureValidationRule automatically

Sources: src/ClosureValidationRule.php1-76 src/Factory.php135-149


Summary Table: Custom Rule Approaches

ApproachDefinition LocationRegistrationScopeValidator AccessSignature
Inline ClosureRules arrayImmediateSingle validatorVia 4th paramfn($attr, $val, $fail)
ClosureValidationRuleRules arrayAutomatic wrapSingle validatorVia 4th paramfn($attr, $val, $fail, $validator)
Rule InterfaceClass fileInstantiate in rulesReusableVia ValidatorAwareRulepasses($attr, $val): bool
ValidationRule InterfaceClass fileInstantiate in rulesReusableVia ValidatorAwareRulevalidate($attr, $val, $fail): void
Factory ExtensionFactory registrationextend()GlobalVia closure paramfn($attr, $val, $params, $validator): bool
Factory ImplicitFactory registrationextendImplicit()GlobalVia closure paramfn($attr, $val, $params, $validator): bool
Factory DependentFactory registrationextendDependent()GlobalVia closure paramfn($attr, $val, $params, $validator, $data): bool

Sources: src/Factory.php154-185 src/ClosureValidationRule.php1-76 src/Contracts/Rule.php1-19 src/Contracts/ValidationRule.php1-18

Refresh this wiki

On this page