Skip to content

Commit

Permalink
Merge pull request #26 from itsrafsanjani/feat/validation
Browse files Browse the repository at this point in the history
feat: validation support
  • Loading branch information
alaminfirdows authored Oct 22, 2024
2 parents 97a423c + 13e811d commit 693a248
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 1 deletion.
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
"autoload": {
"psr-4": {
"AlAminFirdows\\LaravelEditorJs\\": "src/"
}
},
"files": [
"src/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
Expand Down
21 changes: 21 additions & 0 deletions src/LaravelEditorJs.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace AlAminFirdows\LaravelEditorJs;

use AlAminFirdows\LaravelEditorJs\Rules\EditorJsRule;
use EditorJS\EditorJS;
use EditorJS\EditorJSException;
use Exception;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Str;

Expand Down Expand Up @@ -45,4 +47,23 @@ public function render(string $data): string
throw new Exception($e->getMessage());
}
}

/**
* Check if the data is valid
*
* @param string $data
* @return bool
*/
public function isValid(string $data): bool
{
$validator = Validator::make(['data' => $data], [
'data' => ['required', 'string', new EditorJsRule]
]);

if ($validator->passes()) {
return true;
}

return false;
}
}
126 changes: 126 additions & 0 deletions src/Rules/EditorJsRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

namespace AlAminFirdows\LaravelEditorJs\Rules;

use Closure;
use EditorJS\EditorJS;
use EditorJS\EditorJSException;
use Illuminate\Contracts\Validation\ValidationRule;

class EditorJsRule implements ValidationRule
{
/**
* Run the validation rule.
*
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (!is_string($value)) {
$fail('The :attribute must be a string.');
return;
}

try {
$decodedData = json_decode($value, true);

if (json_last_error() !== JSON_ERROR_NONE) {
$fail('The :attribute must be a valid JSON string.');
return;
}

if (!isset($decodedData['blocks']) || !is_array($decodedData['blocks'])) {
$fail('The :attribute must contain a blocks array.');
return;
}

$configJson = json_encode(config('laravel_editorjs.config') ?: []);
new EditorJS($value, $configJson);

} catch (EditorJSException $e) {
$this->handleEditorJSException($e, $decodedData['blocks'] ?? [], $fail);
}
}

/**
* Handle EditorJS exceptions and call the fail closure with appropriate messages
*
* @param EditorJSException $e
* @param array $blocks
* @param Closure(string): void $fail
*/
private function handleEditorJSException(EditorJSException $e, array $blocks, Closure $fail): void
{
$message = $e->getMessage();

if (preg_match('/Tool `(.+)` not found/', $message, $matches)) {
$invalidTool = $matches[1];
$blockIndex = $this->findBlockIndex($blocks, $invalidTool);

$fail("Block type '{$invalidTool}' is not supported" .
($blockIndex !== null ? " (found in block {$blockIndex})" : ""));

} elseif (preg_match('/Not found required param `(.+)`/', $message, $matches)) {
$missingParam = $matches[1];
$location = $this->findParameterLocation($blocks, $missingParam);

$errorMessage = "Missing required parameter '{$missingParam}'";
if ($location) {
$errorMessage .= " in block {$location['blockIndex']} (type: {$location['blockType']})";
}

$fail($errorMessage);

} elseif (preg_match('/Found extra param `(.+)`/', $message, $matches)) {
$extraParam = $matches[1];
$location = $this->findParameterLocation($blocks, $extraParam);

$errorMessage = "Unexpected parameter '{$extraParam}'";
if ($location) {
$errorMessage .= " in block {$location['blockIndex']} (type: {$location['blockType']})";
}

$fail($errorMessage);

} else {
$fail($message);
}
}

/**
* Find block index by type
*
* @param array $blocks
* @param string $type
* @return int|null
*/
private function findBlockIndex(array $blocks, string $type): ?int
{
foreach ($blocks as $index => $block) {
if (isset($block['type']) && $block['type'] === $type) {
return $index;
}
}
return null;
}

/**
* Find parameter location in blocks
*
* @param array $blocks
* @param string $param
* @return array|null
*/
private function findParameterLocation(array $blocks, string $param): ?array
{
foreach ($blocks as $index => $block) {
if (isset($block['data']) && array_key_exists($param, $block['data'])) {
return [
'blockIndex' => $index,
'blockType' => $block['type'] ?? 'unknown',
];
}
}
return null;
}
}
13 changes: 13 additions & 0 deletions src/helpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

use AlAminFirdows\LaravelEditorJs\LaravelEditorJs;

if (! function_exists('editorjs')) {
/**
* @return LaravelEditorJs
*/
function editorjs()
{
return app(LaravelEditorJs::class);
}
}

0 comments on commit 693a248

Please sign in to comment.