Skip to content

Commit

Permalink
🦺 Support validation for nested blocks (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
bonroyage authored Feb 7, 2025
2 parents 90da826 + 49a6e4f commit 05c996c
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 9 deletions.
55 changes: 46 additions & 9 deletions src/Repositories/Behaviors/HandleBlocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace A17\Twill\Repositories\Behaviors;

use Illuminate\Support\Str;
use Illuminate\Support\Arr;
use A17\Twill\Facades\TwillBlocks;
use A17\Twill\Facades\TwillUtil;
use A17\Twill\Models\Behaviors\HasMedias;
Expand Down Expand Up @@ -174,27 +176,38 @@ private function updateBlock(
return $blockCreated;
}

private function validate(array $formData, int $id, array $basicRules, array $translatedFieldRules): void
private function validate(array $formData, int $id, array $basicRules, array $translatedFieldRules, array $messages): void
{
$finalValidator = $this->blockValidator;
foreach ($translatedFieldRules as $field => $rules) {
foreach (config('translatable.locales') as $locale) {
$data = $formData[$field][$locale] ?? null;
$validator = Validator::make([$field => $data], [$field => $rules]);
$validator = Validator::make($formData, ["$field.$locale" => $rules], $messages);
foreach ($validator->messages()->getMessages() as $key => $errors) {
foreach ($errors as $error) {
if ($this->errorMessageIsOnNestedBlock($key)) {
$blockInfo = $this->makeValidationInfoForNestedBlocks($id, $key, $formData, true);

$id = $blockInfo['nestedBlockId'];
$key = $blockInfo['nestedField'];
}

$finalValidator->getMessageBag()->add("blocks.$id" . "[$key][$locale]", $error);
$finalValidator->getMessageBag()->add("blocks.$locale", 'Failed');
}
}
}
}
foreach ($basicRules as $field => $rules) {
$validator = Validator::make([$field => $formData[$field] ?? null], [$field => $rules]);
foreach ($validator->messages()->getMessages() as $key => $errors) {
foreach ($errors as $error) {
$finalValidator->getMessageBag()->add("blocks[$id][$key]", $error);
$validator = Validator::make($formData, $basicRules, $messages);
foreach ($validator->messages()->getMessages() as $key => $errors) {
foreach ($errors as $error) {
if ($this->errorMessageIsOnNestedBlock($key)) {
$blockInfo = $this->makeValidationInfoForNestedBlocks($id, $key, $formData, true);

$id = $blockInfo['nestedBlockId'];
$key = $blockInfo['nestedField'];
}

$finalValidator->getMessageBag()->add("blocks[$id][$key]", $error);
}
}
}
Expand Down Expand Up @@ -300,7 +313,8 @@ private function validateBlockArray(
(array)$block['content'] + ($block['medias'] ?? []) + ($block['browsers'] ?? []) + ($block['blocks'] ?? []),
$block['id'],
$blockInstance->getRules(),
$handleTranslations ? $blockInstance->getRulesForTranslatedFields() : []
$handleTranslations ? $blockInstance->getRulesForTranslatedFields() : [],
$blockInstance->getMessages()
);
}

Expand Down Expand Up @@ -533,4 +547,27 @@ protected function hasRelatedTable(): bool
}
return static::$hasRelatedTableCache;
}

public function errorMessageIsOnNestedBlock($failedKey)
{
return strpos($failedKey, '.content.') !== false;
}

public function makeValidationInfoForNestedBlocks($rootBlockId, $failedKey, $formData, $translated = false)
{
$blockFilter = Str::beforeLast($failedKey, '.content.');

$blockField = Str::afterLast($failedKey, '.content.');

if ($translated) {
$blockField = Str::beforeLast($blockField, '.');
}

$block = Arr::get($formData, $blockFilter);

return [
'nestedBlockId' => $block['id'],
'nestedField' => $blockField,
];
}
}
18 changes: 18 additions & 0 deletions src/Services/Blocks/Block.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ class Block
*/
public $rulesForTranslatedFields = [];

/**
* @var array
*/
public $messages = [];

/**
* Renderedata.
*/
Expand Down Expand Up @@ -161,6 +166,7 @@ public static function forComponent(string $componentClass): self
$class->hideTitlePrefix = $componentClass::shouldHidePrefix();
$class->rulesForTranslatedFields = (new $componentClass())->getTranslatableValidationRules();
$class->rules = (new $componentClass())->getValidationRules();
$class->messages = (new $componentClass())->getValidationMessages();

return $class;
}
Expand Down Expand Up @@ -391,6 +397,10 @@ public function parse(): self
$this->rulesForTranslatedFields = $value ?? $this->rulesForTranslatedFields;
});

$this->parseArrayProperty('ValidationMessages', $contents, $this->name, function ($value) {
$this->messages = $value ?? $this->messages;
});

$this->parseMixedProperty('titleField', $contents, $this->name, function ($value, $options) {
$this->titleField = $value;
$this->hideTitlePrefix = (bool)($options['hidePrefix'] ?? false);
Expand All @@ -415,6 +425,14 @@ public function getRulesForTranslatedFields(): array
return $this->rulesForTranslatedFields;
}

/**
* Checks both the blade file or helper class for validation rules. Returns in order the first one with data.
*/
public function getMessages(): array
{
return $this->messages;
}

/**
* Parse a string property directive in the form of `@twillTypeProperty('value')`.
*
Expand Down
5 changes: 5 additions & 0 deletions src/View/Components/Blocks/TwillBlockComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ public function getTranslatableValidationRules(): array
return [];
}

public function getValidationMessages(): array
{
return [];
}

abstract public function getForm(): Form;

final public function renderForm(): View
Expand Down

0 comments on commit 05c996c

Please sign in to comment.