123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- <?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)
- {
- $rule = strtolower($rule);
-
- if ($rule === 'regex' || $rule === 'not_regex' || $rule === 'notregex') {
- 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;
- }
- }
- }
|