check(); } /** * Prepare the data for validation. * * @return void */ protected function prepareForValidation(): void { $this->configModel = PageConfig::query()->whereKey($this->input('config_id'))->firstOrFail(); } /** * Get the validation rules that apply to the request. * * @return array * @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh * @phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ public function rules(): array { // phpcs:enable $rules = []; foreach ($this->configModel->config as $input) { $rules = array_merge($rules, $this->recursiveRules($input, $this->fieldName)); } //end foreach return $rules; } private function recursiveRules(&$input, $prefix): array { $rules = []; $ruleKey = "$prefix.$input[key]"; switch ($input['type']) { case DynamicFieldTypes::string->value: $rules = array_merge($rules, [ $ruleKey => $this->compileValidate('required|string|min:3', $input) ]); break; case DynamicFieldTypes::text->value: $mergeRules = $this->compileValidate('required|string|min:15', $input); $mergeRules = collect($mergeRules) ->map(function ($rule) { // TODO: check pour utiliser la rule wysiwyg length. if (\strpos($rule, 'max:') !== false) { $max = \intval(str_replace('max:', '', $rule)); return function ($attribute, $value, $fail) use ($max) { if (\strlen(\strip_tags($value)) > $max) { $fail("$attribute ne doit pas excéder $max caractères"); } }; } return $rule; })->all(); $rules = array_merge($rules, [ $ruleKey => $mergeRules ]); break; case DynamicFieldTypes::number->value: $rules = array_merge($rules, [ $ruleKey => $this->compileValidate('required|numeric', $input) ]); break; case DynamicFieldTypes::boolean->value: $all = $this->all(); $nested = ToolboxHelper::dotStringToNestedArray( $ruleKey, $this->input($ruleKey) ? true : false ); $all = ToolboxHelper::arrayMergeRecursiveDistinct($all, $nested); $this->merge($all); $rules = array_merge($rules, [ $ruleKey => $this->compileValidate('boolean', $input) ]); break; case DynamicFieldTypes::url->value: $rules = array_merge($rules, [ $ruleKey => [ 'required', 'url', // @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed function ($attribute, $value, $fail) { try { ToolboxHelper::assertNoInternalUrls($attribute, $value); ToolboxHelper::assertNoInternalBoUrls($attribute, $value); } catch (ValidationException $e) { $fail(collect($e->errors())->first()[0]); } } ] ]); break; case DynamicFieldTypes::email->value: $rules = array_merge($rules, [ $ruleKey => $this->compileValidate('required|email|min:3', $input) ]); break; case DynamicFieldTypes::image->value: $defaultRules = 'required|file|mimes:jpg,jpeg,png,pdf|max:5120|dimensions:width=100,height=100'; $imgRules = $this->compileValidate($defaultRules, $input); $rules = array_merge($rules, [ $ruleKey => $this->pictureRules($ruleKey, implode("|", $imgRules)), ]); break; case DynamicFieldTypes::list->value: $rules = array_merge($rules, [ "$ruleKey.*.order" => "required|numeric|min:1", $ruleKey => $this->compileValidate('min:1|max:10', $input), ]); foreach ($input['children'] as $key => $children) { $rules = array_merge($rules, $this->recursiveRules($children, $ruleKey . ".*")); } break; } //end switch return $rules; } /** * Get custom attributes for validator errors. * * @return array */ public function attributes(): array { $attributes = []; foreach ($this->configModel->config as $input) { $attributes = array_merge($attributes, $this->recursiveAttributes($input, $this->fieldName)); } return $attributes; } public function recursiveAttributes(&$input, $prefix): array { $attributes = []; $attributeKey = sprintf("%s.%s", $prefix, $input['key']); $attributes = array_merge($attributes, [$attributeKey => Str::lower($input['label'])]); if (isset($input['children'])) { foreach ($input['children'] as $key => $children) { $attributes = array_merge($attributes, $this->recursiveAttributes($children, $attributeKey . ".*")); } } return $attributes; } /** * Merge native validations and custom validations. * * @param string|array $defaultValidations * @param array $input * @return array */ private function compileValidate(string|array $defaultValidations, array $input): array { $newValidations = $this->mergeValidations($defaultValidations, $input); // Get unique rule and priorise important rules first. $rules = \collect($newValidations)->unique()->sort(function ($valueA, $valueB) { $valueA = $this->ruleHasToComeFirst($valueA); $valueB = $this->ruleHasToComeFirst($valueB); return $valueA - $valueB; }); // Conditions the rules. $hasRequire = $rules->first(fn($rule) => $rule === 'required') ? true : false; $hasRequireCond = $rules->first(fn($rule) => \strpos($rule, 'required_') !== false) ? true : false; $hasNullable = $rules->first(fn($rule) => \strpos($rule, 'nullable') !== false) ? true : false; $hasSometime = $rules->first(fn($rule) => \strpos($rule, 'sometimes') !== false) ? true : false; $hasPresent = $rules->first(fn($rule) => \strpos($rule, 'present') !== false) ? true : false; if ($hasRequire and ($hasRequireCond or $hasNullable or $hasSometime or $hasPresent)) { $rules = $rules->reject(fn($rule) => $rule === 'required'); } return $rules->all(); } /** * Merge new validations into default validations. * * @param string|array $defaultValidations * @param array $input * @return array */ private function mergeValidations($defaultValidations, $input): array { if (\is_string($defaultValidations)) { $defaultValidations = explode('|', $defaultValidations); } /** @var array|string $inputValidations */ $inputValidations = \collect($input)->get('validation', $input); $inputValidations = \is_string($inputValidations) ? explode('|', $inputValidations) : $inputValidations; foreach ($inputValidations as $validate) { // Split a string by a special character. $parts = explode(':', $validate, 2); // Check if there is a special character. if (count($parts) > 1) { [$ruleName, $ruleValue] = $parts; // Deletes any old rule that starts with “ruleName:”. $defaultValidations = collect($defaultValidations) ->reject(function ($existingRule) use ($ruleName) { return is_string($existingRule) && str_starts_with($existingRule, sprintf('%s:', $ruleName)); }) ->values() ->all(); // Add the new rule. $defaultValidations[] = $validate; } else { // Check if rule without special character already exist. if (!in_array($validate, $defaultValidations)) { // Add the input rule. $defaultValidations[] = $validate; } } } return $defaultValidations; } /** * Does the rule need to come first ? * * @param string $rule * @return integer */ private function ruleHasToComeFirst(string $rule): int { $rule = \collect(\explode(':', $rule, 2))->filter()->first(null, ''); $rules = \collect([ 'required_if', 'required_unless', 'required_with', 'required_with_all', 'required_without', 'required_without_all', 'required_with_all', 'missing', 'missing_if', 'missing_unless', 'missing_with', 'missing_with_all', 'nullable', 'sometimes', 'present', 'required' ]); $itemKey = $rules->search(fn(string $firstRule) => \strpos($rule, $firstRule) === 0); if (\is_bool($itemKey)) { return $rules->count() + 1; } return $itemKey; } }