check(); } /** * Get custom attributes for validator errors. * * @return array */ public function attributes() { return [ 'content' => \trans('Contenu') ]; } /** * Overload createDefaultValidator * to generate rules and merge data * like booleans before validator is created * as it copies data from the request. * * The reason : using $this->merge in rules method * will not be taken into account * * @param ValidationFactory $factory * @return void */ protected function createDefaultValidator(ValidationFactory $factory) { // If is update request if ($this->modelVarName) { $this->generatedRules = $this->genRules($this->{$this->modelVarName}->content); } else { // This is store request $model = $this->model; // Nasty hack to get all block data as array beurk ! $this->generatedRules = $this->genRules(\json_decode(\json_encode((new $model())->getBlocks()), true)); } return parent::createDefaultValidator($factory); } // PRIVATE FUNCTIONS /** * Get the validation rules that apply to the request. * * @return array */ protected function genRules(array $content) { $rules = []; foreach ($content as $i => $block) { foreach ($block['content'] as $iptName => $input) { $rules = array_merge($rules, $this->getRule( compact('i', 'iptName'), $input['inputType']['value'], $content[$i]['content'][$iptName] )); } } return $rules; } // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh private function getRule(array $coords, $inputType, $content): array { \extract($coords); $inputKey = "content.$i.content.$iptName"; switch ($inputType) { case InputType::string()->value: return $this->handleString($inputKey); case InputType::text()->value: return $this->handleText($inputKey); case InputType::image()->value: return $this->handleImage($inputKey, $content); case InputType::url()->value: return $this->handleUrl($inputKey); case InputType::videoVimeo()->value: return $this->handleVideoVimeo($inputKey); case InputType::boolean()->value: return $this->handleBoolean($inputKey); case InputType::imageArray()->value: return $this->handleImageArray($coords, $inputKey, $content); case InputType::dropdownArray()->value: return $this->handleDropdownArray($coords, $inputKey); case InputType::miniblocArray()->value: return $this->handleMiniBlocArray($coords, $inputKey); case InputType::labelArray()->value: return $this->handleLabelArray($coords, $inputKey); }//end switch throw new Exception(sprintf( 'Unknown input type %s', InputType::make($inputType)->label )); } private function handleVideoVimeo(string $inputKey) { return ["$inputKey.value" => 'required|url|regex:/^https:\/\/vimeo\.com\/[0-9]{8,10}$/']; } private function handleImageArray(array $coords, string $inputKey, array $ipt): array { \extract($coords); $rules = []; $ipt = $all['content'][$i]['content'][$iptName]; $max = isset($ipt['dimensionsMax']); $dim = collect(explode( ',', $ipt['dimensions'] ?? $ipt['dimensionsMax'] ))->mapWithKeys(function ($v) { $v = explode(' ', $v); return [$v[0] => $v[1]]; }); $rules = array_merge($rules, [ "$inputKey.value.*" => 'sometimes|array' ]); if (is_array($this->input("$inputKey.value.*"))) { $all = $this->all(); $images = $this->input("$inputKey.value"); if (is_array($images)) { ksort($images); $all['content'][$i]['content'][$iptName]['value'] = $images; $this->merge($all); } foreach ($this->input("$inputKey.value.*") as $imageK => $image) { if (!is_string($image)) { $rules = array_merge($rules, [ "$inputKey.$imageK" => [ 'image', 'mimes:png,jpg', sprintf( 'dimensions:%s=%d,%s=%d', $max ? 'max_height' : 'height', $dim['hauteur'], $max ? 'max_width' : 'width', $dim['largeur'] ) ] ]); } else { $rules = array_merge($rules, [ "$inputKey.value.$imageK" => 'string' ]); } }//end foreach }//end if return $rules; } private function handleLabelArray(array $coords, string $inputKey): array { $rules = []; if (is_array($this->input("$inputKey.value"))) { \extract($coords); $all = $this->all(); foreach ($this->input("$inputKey.value") as $labelIndex => $label) { if ($labelIndex === 'X') { unset($all['content'][$i]['content'][$iptName]['value'][$labelIndex]); continue; } $rules = array_merge($rules, [ "$inputKey.value.$labelIndex.*" => 'string' ]); } $this->merge($all); } return $rules; } private function handleDropdownArray(array $coords, string $inputKey): array { $rules = []; if (is_array($this->input("$inputKey.value"))) { \extract($coords); $all = $this->all(); foreach ($this->input("$inputKey.value") as $dropdownIndex => $dropdown) { if ($dropdownIndex === 'X') { unset($all['content'][$i]['content'][$iptName]['value'][$dropdownIndex]); continue; } $rules = array_merge($rules, [ "$inputKey.value.$dropdownIndex.*" => 'string' ]); } $this->merge($all); } return $rules; } private function handleMiniBlocArray(array $coords, string $inputKey): array { return $this->handleDropdownArray($coords, $inputKey); } private function handleBoolean(string $inputKey): array { $all = $this->all(); $nested = Utils::dotStringToNestedArray( "$inputKey.value", $this->input("$inputKey.value") ? 1 : 0 ); $all = array_merge_recursive_distinct($all, $nested); $this->merge($all); return ["$inputKey.value" => 'required|boolean']; } private function handleUrl(string $inputKey): array { $all = $this->all(); $status = Utils::dotStringToNestedArray( "$inputKey.status", $this->input("$inputKey.status") ? true : false ); $newtab = Utils::dotStringToNestedArray( "$inputKey.newtab", $this->input("$inputKey.newtab") ? true : false ); $all = array_merge_recursive_distinct($all, $status); $all = array_merge_recursive_distinct($all, $newtab); $this->merge($all); return [ "$inputKey.value" => [ 'required', 'url', // @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed function ($attribute, $value, $fail) { try { Utils::assertNoInternalUrls($attribute, $value); } catch (ValidationException $e) { $fail(collect($e->errors())->first()[0]); } } ], "$inputKey.text" => 'required|string|min:2|max:80', "$inputKey.status" => 'required|boolean', "$inputKey.newtab" => 'required|boolean', ]; } private function handleImage(string $inputKey, array $ipt): array { $max = isset($ipt['dimensionsMax']); $dim = collect(explode( ',', $ipt['dimensions'] ?? $ipt['dimensionsMax'] ?? '' ))->mapWithKeys(function ($v) { $v = explode(' ', $v); return [$v[0] => $v[1]]; }); $rules = [ "$inputKey.value" => [ 'sometimes', 'image', 'mimes:png,jpg', sprintf( 'dimensions:%s=%d,%s=%d', $max ? 'max_height' : 'height', $dim['hauteur'], $max ? 'max_width' : 'width', $dim['largeur'] ) ] ]; if ($this->isStore) { $rules["$inputKey.value"][0] = 'required'; } return $rules; } private function handleText(string $inputKey): array { return ["$inputKey.html" => 'required|string|min:15']; } private function handleString(string $inputKey): array { return ["$inputKey.value" => 'required|string|min:4']; } }