PageRenderTime 132ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 1ms

/laradock/vendor/illuminate/validation/ValidationRuleParser.php

https://gitlab.com/hoangduys4k5/laravelproject
PHP | 338 lines | 177 code | 48 blank | 113 comment | 22 complexity | f3d38dad75236d8ddf6492f85fa75b32 MD5 | raw file
  1. <?php
  2. namespace Illuminate\Validation;
  3. use Closure;
  4. use Illuminate\Contracts\Validation\Rule as RuleContract;
  5. use Illuminate\Support\Arr;
  6. use Illuminate\Support\Str;
  7. use Illuminate\Validation\Rules\Exists;
  8. use Illuminate\Validation\Rules\Unique;
  9. class ValidationRuleParser
  10. {
  11. /**
  12. * The data being validated.
  13. *
  14. * @var array
  15. */
  16. public $data;
  17. /**
  18. * The implicit attributes.
  19. *
  20. * @var array
  21. */
  22. public $implicitAttributes = [];
  23. /**
  24. * Create a new validation rule parser.
  25. *
  26. * @param array $data
  27. * @return void
  28. */
  29. public function __construct(array $data)
  30. {
  31. $this->data = $data;
  32. }
  33. /**
  34. * Parse the human-friendly rules into a full rules array for the validator.
  35. *
  36. * @param array $rules
  37. * @return \stdClass
  38. */
  39. public function explode($rules)
  40. {
  41. $this->implicitAttributes = [];
  42. $rules = $this->explodeRules($rules);
  43. return (object) [
  44. 'rules' => $rules,
  45. 'implicitAttributes' => $this->implicitAttributes,
  46. ];
  47. }
  48. /**
  49. * Explode the rules into an array of explicit rules.
  50. *
  51. * @param array $rules
  52. * @return array
  53. */
  54. protected function explodeRules($rules)
  55. {
  56. foreach ($rules as $key => $rule) {
  57. if (str_contains($key, '*')) {
  58. $rules = $this->explodeWildcardRules($rules, $key, [$rule]);
  59. unset($rules[$key]);
  60. } else {
  61. $rules[$key] = $this->explodeExplicitRule($rule, $key);
  62. }
  63. }
  64. return $rules;
  65. }
  66. /**
  67. * Explode the explicit rule into an array if necessary.
  68. *
  69. * @param mixed $rule
  70. * @param string $attribute
  71. * @return array
  72. */
  73. protected function explodeExplicitRule($rule, $attribute)
  74. {
  75. if (is_string($rule)) {
  76. [$name] = static::parseStringRule($rule);
  77. return static::ruleIsRegex($name) ? [$rule] : explode('|', $rule);
  78. }
  79. if (is_object($rule)) {
  80. return Arr::wrap($this->prepareRule($rule, $attribute));
  81. }
  82. return array_map(
  83. [$this, 'prepareRule'],
  84. $rule,
  85. array_fill(array_key_first($rule), count($rule), $attribute)
  86. );
  87. }
  88. /**
  89. * Prepare the given rule for the Validator.
  90. *
  91. * @param mixed $rule
  92. * @param string $attribute
  93. * @return mixed
  94. */
  95. protected function prepareRule($rule, $attribute)
  96. {
  97. if ($rule instanceof Closure) {
  98. $rule = new ClosureValidationRule($rule);
  99. }
  100. if (! is_object($rule) ||
  101. $rule instanceof RuleContract ||
  102. ($rule instanceof Exists && $rule->queryCallbacks()) ||
  103. ($rule instanceof Unique && $rule->queryCallbacks())) {
  104. return $rule;
  105. }
  106. if ($rule instanceof NestedRules) {
  107. return $rule->compile(
  108. $attribute, $this->data[$attribute] ?? null, Arr::dot($this->data)
  109. )->rules[$attribute];
  110. }
  111. return (string) $rule;
  112. }
  113. /**
  114. * Define a set of rules that apply to each element in an array attribute.
  115. *
  116. * @param array $results
  117. * @param string $attribute
  118. * @param string|array $rules
  119. * @return array
  120. */
  121. protected function explodeWildcardRules($results, $attribute, $rules)
  122. {
  123. $pattern = str_replace('\*', '[^\.]*', preg_quote($attribute));
  124. $data = ValidationData::initializeAndGatherData($attribute, $this->data);
  125. foreach ($data as $key => $value) {
  126. if (Str::startsWith($key, $attribute) || (bool) preg_match('/^'.$pattern.'\z/', $key)) {
  127. foreach (Arr::flatten((array) $rules) as $rule) {
  128. if ($rule instanceof NestedRules) {
  129. $compiled = $rule->compile($key, $value, $data);
  130. $this->implicitAttributes = array_merge_recursive(
  131. $compiled->implicitAttributes,
  132. $this->implicitAttributes,
  133. [$attribute => [$key]]
  134. );
  135. $results = $this->mergeRules($results, $compiled->rules);
  136. } else {
  137. $this->implicitAttributes[$attribute][] = $key;
  138. $results = $this->mergeRules($results, $key, $rule);
  139. }
  140. }
  141. }
  142. }
  143. return $results;
  144. }
  145. /**
  146. * Merge additional rules into a given attribute(s).
  147. *
  148. * @param array $results
  149. * @param string|array $attribute
  150. * @param string|array $rules
  151. * @return array
  152. */
  153. public function mergeRules($results, $attribute, $rules = [])
  154. {
  155. if (is_array($attribute)) {
  156. foreach ((array) $attribute as $innerAttribute => $innerRules) {
  157. $results = $this->mergeRulesForAttribute($results, $innerAttribute, $innerRules);
  158. }
  159. return $results;
  160. }
  161. return $this->mergeRulesForAttribute(
  162. $results, $attribute, $rules
  163. );
  164. }
  165. /**
  166. * Merge additional rules into a given attribute.
  167. *
  168. * @param array $results
  169. * @param string $attribute
  170. * @param string|array $rules
  171. * @return array
  172. */
  173. protected function mergeRulesForAttribute($results, $attribute, $rules)
  174. {
  175. $merge = head($this->explodeRules([$rules]));
  176. $results[$attribute] = array_merge(
  177. isset($results[$attribute]) ? $this->explodeExplicitRule($results[$attribute], $attribute) : [], $merge
  178. );
  179. return $results;
  180. }
  181. /**
  182. * Extract the rule name and parameters from a rule.
  183. *
  184. * @param array|string $rule
  185. * @return array
  186. */
  187. public static function parse($rule)
  188. {
  189. if ($rule instanceof RuleContract || $rule instanceof NestedRules) {
  190. return [$rule, []];
  191. }
  192. if (is_array($rule)) {
  193. $rule = static::parseArrayRule($rule);
  194. } else {
  195. $rule = static::parseStringRule($rule);
  196. }
  197. $rule[0] = static::normalizeRule($rule[0]);
  198. return $rule;
  199. }
  200. /**
  201. * Parse an array based rule.
  202. *
  203. * @param array $rule
  204. * @return array
  205. */
  206. protected static function parseArrayRule(array $rule)
  207. {
  208. return [Str::studly(trim(Arr::get($rule, 0, ''))), array_slice($rule, 1)];
  209. }
  210. /**
  211. * Parse a string based rule.
  212. *
  213. * @param string $rule
  214. * @return array
  215. */
  216. protected static function parseStringRule($rule)
  217. {
  218. $parameters = [];
  219. // The format for specifying validation rules and parameters follows an
  220. // easy {rule}:{parameters} formatting convention. For instance the
  221. // rule "Max:3" states that the value may only be three letters.
  222. if (str_contains($rule, ':')) {
  223. [$rule, $parameter] = explode(':', $rule, 2);
  224. $parameters = static::parseParameters($rule, $parameter);
  225. }
  226. return [Str::studly(trim($rule)), $parameters];
  227. }
  228. /**
  229. * Parse a parameter list.
  230. *
  231. * @param string $rule
  232. * @param string $parameter
  233. * @return array
  234. */
  235. protected static function parseParameters($rule, $parameter)
  236. {
  237. return static::ruleIsRegex($rule) ? [$parameter] : str_getcsv($parameter);
  238. }
  239. /**
  240. * Determine if the rule is a regular expression.
  241. *
  242. * @param string $rule
  243. * @return bool
  244. */
  245. protected static function ruleIsRegex($rule)
  246. {
  247. return in_array(strtolower($rule), ['regex', 'not_regex', 'notregex'], true);
  248. }
  249. /**
  250. * Normalizes a rule so that we can accept short types.
  251. *
  252. * @param string $rule
  253. * @return string
  254. */
  255. protected static function normalizeRule($rule)
  256. {
  257. return match ($rule) {
  258. 'Int' => 'Integer',
  259. 'Bool' => 'Boolean',
  260. default => $rule,
  261. };
  262. }
  263. /**
  264. * Expand and conditional rules in the given array of rules.
  265. *
  266. * @param array $rules
  267. * @param array $data
  268. * @return array
  269. */
  270. public static function filterConditionalRules($rules, array $data = [])
  271. {
  272. return collect($rules)->mapWithKeys(function ($attributeRules, $attribute) use ($data) {
  273. if (! is_array($attributeRules) &&
  274. ! $attributeRules instanceof ConditionalRules) {
  275. return [$attribute => $attributeRules];
  276. }
  277. if ($attributeRules instanceof ConditionalRules) {
  278. return [$attribute => $attributeRules->passes($data)
  279. ? array_filter($attributeRules->rules($data))
  280. : array_filter($attributeRules->defaultRules($data)), ];
  281. }
  282. return [$attribute => collect($attributeRules)->map(function ($rule) use ($data) {
  283. if (! $rule instanceof ConditionalRules) {
  284. return [$rule];
  285. }
  286. return $rule->passes($data) ? $rule->rules($data) : $rule->defaultRules($data);
  287. })->filter()->flatten(1)->values()->all()];
  288. })->all();
  289. }
  290. }