invoiceninja/app/Rules/CommaSeparatedEmails.php

115 lines
3.3 KiB
PHP

<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
/**
* Custom validation rule for comma-separated email addresses
*
* This rule validates that a string contains valid email addresses
* separated by commas, with optional whitespace around commas.
*
* Usage examples:
* - new CommaSeparatedEmails() - basic validation (max 10 emails)
* - new CommaSeparatedEmails(5) - max 5 emails
* - new CommaSeparatedEmails(10, [';', ',']) - max 10 emails, separated by ; or ,
*
* Example input formats:
* - "user@example.com"
* - "user1@example.com, user2@example.com"
* - "user1@example.com,user2@example.com,user3@example.com"
* - " user1@example.com , user2@example.com " (whitespace is trimmed)
*/
class CommaSeparatedEmails implements ValidationRule
{
/**
* Maximum number of email addresses allowed
*/
protected int $maxEmails;
/**
* Array of valid separators
*/
protected array $separators;
/**
* Create a new rule instance.
*/
public function __construct(int $maxEmails = 10, array $separators = [','])
{
$this->maxEmails = $maxEmails;
$this->separators = $separators;
}
/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
// If the value is null or empty, it's valid (nullable rule handles this)
if (empty($value)) {
return;
}
// Split the value by the first separator and trim whitespace
$emails = array_map('trim', explode($this->separators[0], $value));
// Filter out empty strings
$emails = array_filter($emails);
// If no valid emails after splitting, fail validation
if (empty($emails)) {
$fail('The :attribute must contain at least one valid email address.');
return;
}
// Check if we exceed the maximum number of emails
if (count($emails) > $this->maxEmails) {
$fail("The :attribute cannot contain more than {$this->maxEmails} email addresses.");
return;
}
// Validate each email address
foreach ($emails as $email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$fail("The email address '{$email}' in :attribute is not valid.");
return;
}
}
}
/**
* Get the validation error message.
*/
public function message(): string
{
return 'The :attribute must contain valid email addresses separated by commas.';
}
/**
* Static method to parse comma-separated emails into an array
* Useful for processing the validated data
*/
public static function parseEmails(string $emailString): array
{
if (empty($emailString)) {
return [];
}
$emails = array_map('trim', explode(',', $emailString));
return array_filter($emails);
}
/**
* Static method to validate a single email address
*/
public static function isValidEmail(string $email): bool
{
return filter_var(trim($email), FILTER_VALIDATE_EMAIL) !== false;
}
}