📋 Commit iniziale con: - ✅ Documentazione unificata in docs/ - ✅ Codice Laravel in netgescon-laravel/ - ✅ Script automazione in scripts/ - ✅ Configurazione sync rsync - ✅ Struttura organizzata e pulita 🔄 Versione: 2025.07.19-1644 🎯 Sistema pronto per Git distribuito
358 lines
9.9 KiB
PHP
358 lines
9.9 KiB
PHP
<?php
|
|
|
|
namespace Illuminate\Validation;
|
|
|
|
use Closure;
|
|
use Illuminate\Contracts\Validation\CompilableRules;
|
|
use Illuminate\Contracts\Validation\InvokableRule;
|
|
use Illuminate\Contracts\Validation\Rule as RuleContract;
|
|
use Illuminate\Contracts\Validation\ValidationRule;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rules\Date;
|
|
use Illuminate\Validation\Rules\Exists;
|
|
use Illuminate\Validation\Rules\Numeric;
|
|
use Illuminate\Validation\Rules\Unique;
|
|
|
|
class ValidationRuleParser
|
|
{
|
|
/**
|
|
* The data being validated.
|
|
*
|
|
* @var array
|
|
*/
|
|
public $data;
|
|
|
|
/**
|
|
* The implicit attributes.
|
|
*
|
|
* @var array
|
|
*/
|
|
public $implicitAttributes = [];
|
|
|
|
/**
|
|
* Create a new validation rule parser.
|
|
*
|
|
* @param array $data
|
|
*/
|
|
public function __construct(array $data)
|
|
{
|
|
$this->data = $data;
|
|
}
|
|
|
|
/**
|
|
* Parse the human-friendly rules into a full rules array for the validator.
|
|
*
|
|
* @param array $rules
|
|
* @return \stdClass
|
|
*/
|
|
public function explode($rules)
|
|
{
|
|
$this->implicitAttributes = [];
|
|
|
|
$rules = $this->explodeRules($rules);
|
|
|
|
return (object) [
|
|
'rules' => $rules,
|
|
'implicitAttributes' => $this->implicitAttributes,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Explode the rules into an array of explicit rules.
|
|
*
|
|
* @param array $rules
|
|
* @return array
|
|
*/
|
|
protected function explodeRules($rules)
|
|
{
|
|
foreach ($rules as $key => $rule) {
|
|
if (str_contains($key, '*')) {
|
|
$rules = $this->explodeWildcardRules($rules, $key, [$rule]);
|
|
|
|
unset($rules[$key]);
|
|
} else {
|
|
$rules[$key] = $this->explodeExplicitRule($rule, $key);
|
|
}
|
|
}
|
|
|
|
return $rules;
|
|
}
|
|
|
|
/**
|
|
* Explode the explicit rule into an array if necessary.
|
|
*
|
|
* @param mixed $rule
|
|
* @param string $attribute
|
|
* @return array
|
|
*/
|
|
protected function explodeExplicitRule($rule, $attribute)
|
|
{
|
|
if (is_string($rule)) {
|
|
return explode('|', $rule);
|
|
}
|
|
|
|
if (is_object($rule)) {
|
|
if ($rule instanceof Date || $rule instanceof Numeric) {
|
|
return explode('|', (string) $rule);
|
|
}
|
|
|
|
return Arr::wrap($this->prepareRule($rule, $attribute));
|
|
}
|
|
|
|
$rules = [];
|
|
|
|
foreach ($rule as $value) {
|
|
if ($value instanceof Date || $value instanceof Numeric) {
|
|
$rules = array_merge($rules, explode('|', (string) $value));
|
|
} else {
|
|
$rules[] = $this->prepareRule($value, $attribute);
|
|
}
|
|
}
|
|
|
|
return $rules;
|
|
}
|
|
|
|
/**
|
|
* Prepare the given rule for the Validator.
|
|
*
|
|
* @param mixed $rule
|
|
* @param string $attribute
|
|
* @return mixed
|
|
*/
|
|
protected function prepareRule($rule, $attribute)
|
|
{
|
|
if ($rule instanceof Closure) {
|
|
$rule = new ClosureValidationRule($rule);
|
|
}
|
|
|
|
if ($rule instanceof InvokableRule || $rule instanceof ValidationRule) {
|
|
$rule = InvokableValidationRule::make($rule);
|
|
}
|
|
|
|
if (! is_object($rule) ||
|
|
$rule instanceof RuleContract ||
|
|
($rule instanceof Exists && $rule->queryCallbacks()) ||
|
|
($rule instanceof Unique && $rule->queryCallbacks())) {
|
|
return $rule;
|
|
}
|
|
|
|
if ($rule instanceof CompilableRules) {
|
|
return $rule->compile(
|
|
$attribute, $this->data[$attribute] ?? null, Arr::dot($this->data), $this->data
|
|
)->rules[$attribute];
|
|
}
|
|
|
|
return (string) $rule;
|
|
}
|
|
|
|
/**
|
|
* Define a set of rules that apply to each element in an array attribute.
|
|
*
|
|
* @param array $results
|
|
* @param string $attribute
|
|
* @param string|array $rules
|
|
* @return array
|
|
*/
|
|
protected function explodeWildcardRules($results, $attribute, $rules)
|
|
{
|
|
$pattern = str_replace('\*', '[^\.]*', preg_quote($attribute, '/'));
|
|
|
|
$data = ValidationData::initializeAndGatherData($attribute, $this->data);
|
|
|
|
foreach ($data as $key => $value) {
|
|
if (Str::startsWith($key, $attribute) || (bool) preg_match('/^'.$pattern.'\z/', $key)) {
|
|
foreach ((array) $rules as $rule) {
|
|
if ($rule instanceof CompilableRules) {
|
|
$context = Arr::get($this->data, Str::beforeLast($key, '.'));
|
|
|
|
$compiled = $rule->compile($key, $value, $data, $context);
|
|
|
|
$this->implicitAttributes = array_merge_recursive(
|
|
$compiled->implicitAttributes,
|
|
$this->implicitAttributes,
|
|
[$attribute => [$key]]
|
|
);
|
|
|
|
$results = $this->mergeRules($results, $compiled->rules);
|
|
} else {
|
|
$this->implicitAttributes[$attribute][] = $key;
|
|
|
|
$results = $this->mergeRules($results, $key, $rule);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Merge additional rules into a given attribute(s).
|
|
*
|
|
* @param array $results
|
|
* @param string|array $attribute
|
|
* @param string|array $rules
|
|
* @return array
|
|
*/
|
|
public function mergeRules($results, $attribute, $rules = [])
|
|
{
|
|
if (is_array($attribute)) {
|
|
foreach ((array) $attribute as $innerAttribute => $innerRules) {
|
|
$results = $this->mergeRulesForAttribute($results, $innerAttribute, $innerRules);
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
return $this->mergeRulesForAttribute(
|
|
$results, $attribute, $rules
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Merge additional rules into a given attribute.
|
|
*
|
|
* @param array $results
|
|
* @param string $attribute
|
|
* @param string|array $rules
|
|
* @return array
|
|
*/
|
|
protected function mergeRulesForAttribute($results, $attribute, $rules)
|
|
{
|
|
$merge = head($this->explodeRules([$rules]));
|
|
|
|
$results[$attribute] = array_merge(
|
|
isset($results[$attribute]) ? $this->explodeExplicitRule($results[$attribute], $attribute) : [], $merge
|
|
);
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Extract the rule name and parameters from a rule.
|
|
*
|
|
* @param array|string $rule
|
|
* @return array
|
|
*/
|
|
public static function parse($rule)
|
|
{
|
|
if ($rule instanceof RuleContract || $rule instanceof CompilableRules) {
|
|
return [$rule, []];
|
|
}
|
|
|
|
if (is_array($rule)) {
|
|
$rule = static::parseArrayRule($rule);
|
|
} else {
|
|
$rule = static::parseStringRule($rule);
|
|
}
|
|
|
|
$rule[0] = static::normalizeRule($rule[0]);
|
|
|
|
return $rule;
|
|
}
|
|
|
|
/**
|
|
* Parse an array based rule.
|
|
*
|
|
* @param array $rule
|
|
* @return array
|
|
*/
|
|
protected static function parseArrayRule(array $rule)
|
|
{
|
|
return [Str::studly(trim(Arr::get($rule, 0, ''))), array_slice($rule, 1)];
|
|
}
|
|
|
|
/**
|
|
* Parse a string based rule.
|
|
*
|
|
* @param string $rule
|
|
* @return array
|
|
*/
|
|
protected static function parseStringRule($rule)
|
|
{
|
|
$parameters = [];
|
|
|
|
// The format for specifying validation rules and parameters follows an
|
|
// easy {rule}:{parameters} formatting convention. For instance the
|
|
// rule "Max:3" states that the value may only be three letters.
|
|
if (str_contains($rule, ':')) {
|
|
[$rule, $parameter] = explode(':', $rule, 2);
|
|
|
|
$parameters = static::parseParameters($rule, $parameter);
|
|
}
|
|
|
|
return [Str::studly(trim($rule)), $parameters];
|
|
}
|
|
|
|
/**
|
|
* Parse a parameter list.
|
|
*
|
|
* @param string $rule
|
|
* @param string $parameter
|
|
* @return array
|
|
*/
|
|
protected static function parseParameters($rule, $parameter)
|
|
{
|
|
return static::ruleIsRegex($rule) ? [$parameter] : str_getcsv($parameter, escape: '\\');
|
|
}
|
|
|
|
/**
|
|
* Determine if the rule is a regular expression.
|
|
*
|
|
* @param string $rule
|
|
* @return bool
|
|
*/
|
|
protected static function ruleIsRegex($rule)
|
|
{
|
|
return in_array(strtolower($rule), ['regex', 'not_regex', 'notregex'], true);
|
|
}
|
|
|
|
/**
|
|
* Normalizes a rule so that we can accept short types.
|
|
*
|
|
* @param string $rule
|
|
* @return string
|
|
*/
|
|
protected static function normalizeRule($rule)
|
|
{
|
|
return match ($rule) {
|
|
'Int' => 'Integer',
|
|
'Bool' => 'Boolean',
|
|
default => $rule,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Expand the conditional rules in the given array of rules.
|
|
*
|
|
* @param array $rules
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
public static function filterConditionalRules($rules, array $data = [])
|
|
{
|
|
return (new Collection($rules))->mapWithKeys(function ($attributeRules, $attribute) use ($data) {
|
|
if (! is_array($attributeRules) &&
|
|
! $attributeRules instanceof ConditionalRules) {
|
|
return [$attribute => $attributeRules];
|
|
}
|
|
|
|
if ($attributeRules instanceof ConditionalRules) {
|
|
return [$attribute => $attributeRules->passes($data)
|
|
? array_filter($attributeRules->rules($data))
|
|
: array_filter($attributeRules->defaultRules($data)), ];
|
|
}
|
|
|
|
return [$attribute => (new Collection($attributeRules))->map(function ($rule) use ($data) {
|
|
if (! $rule instanceof ConditionalRules) {
|
|
return [$rule];
|
|
}
|
|
|
|
return $rule->passes($data) ? $rule->rules($data) : $rule->defaultRules($data);
|
|
})->filter()->flatten(1)->values()->all()];
|
|
})->all();
|
|
}
|
|
}
|