276 lines
6.7 KiB
PHP
276 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace Illuminate\Validation;
|
|
|
|
use Closure;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rules\Exists;
|
|
use Illuminate\Validation\Rules\Unique;
|
|
use Illuminate\Contracts\Validation\Rule as RuleContract;
|
|
|
|
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
|
|
* @return void
|
|
*/
|
|
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);
|
|
}
|
|
}
|
|
|
|
return $rules;
|
|
}
|
|
|
|
/**
|
|
* Explode the explicit rule into an array if necessary.
|
|
*
|
|
* @param mixed $rule
|
|
* @return array
|
|
*/
|
|
protected function explodeExplicitRule($rule)
|
|
{
|
|
if (is_string($rule)) {
|
|
return explode('|', $rule);
|
|
} elseif (is_object($rule)) {
|
|
return [$this->prepareRule($rule)];
|
|
}
|
|
|
|
return array_map([$this, 'prepareRule'], $rule);
|
|
}
|
|
|
|
/**
|
|
* Prepare the given rule for the Validator.
|
|
*
|
|
* @param mixed $rule
|
|
* @return mixed
|
|
*/
|
|
protected function prepareRule($rule)
|
|
{
|
|
if ($rule instanceof Closure) {
|
|
$rule = new ClosureValidationRule($rule);
|
|
}
|
|
|
|
if (! is_object($rule) ||
|
|
$rule instanceof RuleContract ||
|
|
($rule instanceof Exists && $rule->queryCallbacks()) ||
|
|
($rule instanceof Unique && $rule->queryCallbacks())) {
|
|
return $rule;
|
|
}
|
|
|
|
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) {
|
|
$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]) : [], $merge
|
|
);
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Extract the rule name and parameters from a rule.
|
|
*
|
|
* @param array|string $rules
|
|
* @return array
|
|
*/
|
|
public static function parse($rules)
|
|
{
|
|
if ($rules instanceof RuleContract) {
|
|
return [$rules, []];
|
|
}
|
|
|
|
if (is_array($rules)) {
|
|
$rules = static::parseArrayRule($rules);
|
|
} else {
|
|
$rules = static::parseStringRule($rules);
|
|
}
|
|
|
|
$rules[0] = static::normalizeRule($rules[0]);
|
|
|
|
return $rules;
|
|
}
|
|
|
|
/**
|
|
* Parse an array based rule.
|
|
*
|
|
* @param array $rules
|
|
* @return array
|
|
*/
|
|
protected static function parseArrayRule(array $rules)
|
|
{
|
|
return [Str::studly(trim(Arr::get($rules, 0))), array_slice($rules, 1)];
|
|
}
|
|
|
|
/**
|
|
* Parse a string based rule.
|
|
*
|
|
* @param string $rules
|
|
* @return array
|
|
*/
|
|
protected static function parseStringRule($rules)
|
|
{
|
|
$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 (strpos($rules, ':') !== false) {
|
|
list($rules, $parameter) = explode(':', $rules, 2);
|
|
|
|
$parameters = static::parseParameters($rules, $parameter);
|
|
}
|
|
|
|
return [Str::studly(trim($rules)), $parameters];
|
|
}
|
|
|
|
/**
|
|
* Parse a parameter list.
|
|
*
|
|
* @param string $rule
|
|
* @param string $parameter
|
|
* @return array
|
|
*/
|
|
protected static function parseParameters($rule, $parameter)
|
|
{
|
|
if (strtolower($rule) == 'regex') {
|
|
return [$parameter];
|
|
}
|
|
|
|
return str_getcsv($parameter);
|
|
}
|
|
|
|
/**
|
|
* Normalizes a rule so that we can accept short types.
|
|
*
|
|
* @param string $rule
|
|
* @return string
|
|
*/
|
|
protected static function normalizeRule($rule)
|
|
{
|
|
switch ($rule) {
|
|
case 'Int':
|
|
return 'Integer';
|
|
case 'Bool':
|
|
return 'Boolean';
|
|
default:
|
|
return $rule;
|
|
}
|
|
}
|
|
}
|