devilcius/extra-validator-bundle
Symfony bundle adding extra validators for common Spanish form fields. Includes CCC (Código Cuenta Cliente) bank account validation and NIF/DNI fiscal ID validation. Install via Composer and configure constraints in validation.xml for your entity properties.
Skip Bundle Installation Since this is a Symfony bundle, install only the core validation logic via Composer:
composer require devilcius/extra-validator-bundle --dev
Note: Extract the validator classes (CccValidator, DniValidator) manually from the bundle’s src/Validator directory.
First Use Case: Laravel Form Request
Create a custom validation rule for DNI/CCC in a FormRequest:
use Illuminate\Validation\Rule;
class StoreUserRequest extends FormRequest {
public function rules() {
return [
'dni' => ['required', 'string', new DniRule], // Custom rule
'ccc' => ['required', 'string', new CccRule], // Custom rule
];
}
}
Quick Test
Register custom rules in AppServiceProvider@boot():
Validator::extend('dni', function ($attribute, $value, $parameters, $validator) {
return preg_match('/^[0-9]{8}[A-Za-z]$/', $value) && // Basic DNI format
(strtoupper(substr($value, -1)) === self::calculateDniLetter($value));
});
Validator::extend('ccc', function ($attribute, $value, $parameters, $validator) {
return preg_match('/^\d{20}$/', $value) && // Basic CCC format
(self::validateCccChecksum($value));
});
Test with:
$validator = Validator::make(['dni' => '12345678A'], ['dni' => 'required|dni']);
if ($validator->fails()) { dd($validator->errors()); }
Custom Rule Objects (Recommended)
Create reusable rule classes in app/Rules:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class DniRule implements Rule {
public function passes($attribute, $value) {
return preg_match('/^[0-9]{8}[A-Za-z]$/', $value) &&
(strtoupper(substr($value, -1)) === $this->calculateLetter($value));
}
public function message() {
return 'El formato de DNI no es válido.';
}
private function calculateLetter($dni) { /* ... */ }
}
Use in requests:
'dni' => ['required', new DniRule],
API Validation with JSON:API
Validate nested payloads (e.g., data.attributes.dni):
$validator = Validator::make($request->json()->all(), [
'data.attributes.dni' => ['required', 'dni'],
]);
Dynamic Validation in Controllers Validate CCC during bank account creation:
$validator = Validator::make($request->all(), [
'account.ccc' => ['required', 'ccc'],
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 422);
}
Localization
Override error messages in resources/lang/es/validation.php:
return [
'dni' => [
'required' => 'El DNI es obligatorio.',
'dni' => 'El DNI introducido no es válido.',
],
'ccc' => [
'required' => 'El CCC es obligatorio.',
'ccc' => 'El número de cuenta no es válido.',
],
];
Validator::extend() for dynamic rules or Rule objects for OOP.calculateLetter()/validateChecksum() methods in PHPUnit:
$rule = new DniRule();
$this->assertFalse($rule->passes('dni', '12345678X')); // Invalid letter
Symfony vs. Laravel API Mismatch
Constraint system, which doesn’t map 1:1 to Laravel.Rule objects or Validator::extend() callbacks.Dni constraint may include Symfony-specific options (e.g., message in XML). Laravel uses message() in Rule classes or language files.Undocumented Edge Cases
X12345678Z for non-Spanish residents).Error Message Localization
Bundle Abandonment Risk
laravel-spanish-validators).Regex Overload
DniValidator::validate()) and adjust:
// Example: Allow NIE formats (e.g., 'X1234567A')
public function passes($attribute, $value) {
return preg_match('/^[0-9]{8}[A-Za-z]$|^[XYZ]\d{7}[A-Za-z]$/', $value) &&
$this->checkLetter($value);
}
Validate Manually Test the regex logic in Tinker:
php artisan tinker
>>> preg_match('/^[0-9]{8}[A-Za-z]$/', '12345678A') // Should return 1
Log Validation Failures Add debug logs in custom rules:
public function passes($attribute, $value) {
$isValidFormat = preg_match('/.../', $value);
$isValidLetter = $this->calculateLetter($value);
\Log::debug("DNI $value - Format: $isValidFormat, Letter: $isValidLetter");
return $isValidFormat && $isValidLetter;
}
Checksum Calculation For CCC validation, verify the checksum algorithm matches Spanish bank standards:
private function validateCccChecksum($ccc) {
$digits = str_split($ccc);
$weight = 1;
$sum = 0;
foreach (array_reverse($digits) as $digit) {
$sum += $digit * $weight++;
if ($weight > 10) $weight = 1;
}
return ($sum % 11) === 0;
}
Add New Validators Extend the bundle’s logic for other Spanish identifiers (e.g., NIE for foreigners, CIF for companies):
Validator::extend('nie', function ($attribute, $value) {
return preg_match('/^[XYZ]\d{7}[A-Za-z]$/', $value) &&
(strtoupper(substr($value, -1)) === $this->calculateNieLetter($value));
});
Custom Constraints
Create a CifRule for corporate tax IDs:
namespace App\Rules;
class CifRule implements Rule {
public function passes($attribute, $value) {
// Validate CIF format (e.g., 'A12345678', 'B98765432')
return preg_match('/^[A-J]\d{7}[A-Z0-9]$|^[1-9]\d{7}[A-Z0-9]$/', $value);
}
}
Integration with Laravel Nova Add validation to Nova resources:
use Laravel\Nova\Rules\Rule;
class DniRule extends Rule {
public function passes($attribute, $value) {
// Reuse existing logic
How can I help you explore Laravel packages today?