Skip to content

Commit

Permalink
Added stopAtFirstError
Browse files Browse the repository at this point in the history
  • Loading branch information
sorinsarca committed Dec 29, 2024
1 parent c8d2b40 commit 6f92cb4
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 13 deletions.
8 changes: 6 additions & 2 deletions src/CompliantValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ class CompliantValidator extends Validator
'keepAdditionalItemsKeyword' => false,
];

public function __construct(?SchemaLoader $loader = null, int $max_errors = 1)
public function __construct(
?SchemaLoader $loader = null,
int $max_errors = 1,
bool $stop_at_first_error = true
)
{
parent::__construct($loader, $max_errors);
parent::__construct($loader, $max_errors, $stop_at_first_error);

// Set parser options
$parser = $this->parser();
Expand Down
34 changes: 31 additions & 3 deletions src/Schemas/ObjectSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
namespace Opis\JsonSchema\Schemas;

use Opis\JsonSchema\{Helper, Keyword, ValidationContext, KeywordValidator};
use Opis\JsonSchema\Info\SchemaInfo;
use Opis\JsonSchema\Info\{DataInfo, SchemaInfo};
use Opis\JsonSchema\Errors\ValidationError;
use Opis\JsonSchema\KeywordValidators\CallbackKeywordValidator;

Expand Down Expand Up @@ -109,12 +109,40 @@ public function doValidate(ValidationContext $context): ?ValidationError
*/
protected function applyKeywords(array $keywords, ValidationContext $context): ?ValidationError
{
if ($context->stopAtFirstError()) {
foreach ($keywords as $keyword) {
if ($error = $keyword->validate($context, $this)) {
return $error;
}
}
return null;
}

/** @var null|ValidationError[] $error_list */
$error_list = null;

foreach ($keywords as $keyword) {
if ($error = $keyword->validate($context, $this)) {
return $error;
$error_list ??= [];
$error_list[] = $error;
}
}

return null;
if (!$error_list) {
return null;
}

if (count($error_list) === 1) {
return $error_list[0];
}

return new ValidationError(
'',
$this,
DataInfo::fromContext($context),
'Data must match schema',
[],
$error_list
);
}
}
39 changes: 33 additions & 6 deletions src/ValidationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class ValidationContext

protected int $maxErrors = 1;

protected bool $stopAtFirstError = true;

/**
* @param $data
* @param SchemaLoader $loader
Expand All @@ -70,7 +72,8 @@ public function __construct(
?Schema $sender = null,
array $globals = [],
?array $slots = null,
int $max_errors = 1
int $max_errors = 1,
bool $stop_at_first_error = true
) {
$this->sender = $sender;
$this->rootData = $data;
Expand All @@ -79,6 +82,7 @@ public function __construct(
$this->globals = $globals;
$this->slots = null;
$this->maxErrors = $max_errors;
$this->stopAtFirstError = $stop_at_first_error;
$this->currentData = [
[$data, false],
];
Expand All @@ -101,18 +105,28 @@ public function newInstance(
?Schema $sender,
?array $globals = null,
?array $slots = null,
?int $max_errors = null
?int $max_errors = null,
?bool $stop_at_first_error = null
): self {
return new self($data, $this->loader, $this, $sender, $globals ?? $this->globals, $slots ?? $this->slots,
$max_errors ?? $this->maxErrors);
return new self(
$data,
$this->loader,
$this,
$sender,
$globals ?? $this->globals,
$slots ?? $this->slots,
$max_errors ?? $this->maxErrors,
$stop_at_first_error ?? $this->stopAtFirstError
);
}

public function create(
Schema $sender,
?Variables $mapper = null,
?Variables $globals = null,
?array $slots = null,
?int $maxErrors = null
?int $maxErrors = null,
?bool $stop_at_first_error = null
): self {
if ($globals) {
$globals = $globals->resolve($this->rootData(), $this->currentDataPath());
Expand All @@ -131,7 +145,7 @@ public function create(
}

return new self($data, $this->loader, $this, $sender, $globals, $slots ?? $this->slots,
$maxErrors ?? $this->maxErrors);
$maxErrors ?? $this->maxErrors, $stop_at_first_error ?? $this->stopAtFirstError);
}

public function sender(): ?Schema
Expand Down Expand Up @@ -359,6 +373,19 @@ public function setMaxErrors(int $max): self
return $this;
}


public function stopAtFirstError(): bool
{
return $this->stopAtFirstError;
}

public function setStopAtFirstError(bool $stop): self
{
$this->stopAtFirstError = $stop;

return $this;
}

/* --------------------- */

/**
Expand Down
38 changes: 36 additions & 2 deletions src/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,22 @@ class Validator
{
protected SchemaLoader $loader;
protected int $maxErrors = 1;
protected bool $stopAtFirstError = true;

/**
* @param SchemaLoader|null $loader
* @param int $max_errors
* @param bool $stop_at_first_error
*/
public function __construct(?SchemaLoader $loader = null, int $max_errors = 1)
public function __construct(
?SchemaLoader $loader = null,
int $max_errors = 1,
bool $stop_at_first_error = true
)
{
$this->loader = $loader ?? new SchemaLoader(new SchemaParser(), new SchemaResolver(), true);
$this->maxErrors = $max_errors;
$this->stopAtFirstError = $stop_at_first_error;
}

/**
Expand Down Expand Up @@ -170,7 +177,16 @@ public function createContext($data, ?array $globals = null, ?array $slots = nul
$slots = $this->parseSlots($slots);
}

return new ValidationContext($data, $this->loader, null, null, $globals ?? [], $slots, $this->maxErrors);
return new ValidationContext(
$data,
$this->loader,
null,
null,
$globals ?? [],
$slots,
$this->maxErrors,
$this->stopAtFirstError,
);
}

/**
Expand Down Expand Up @@ -249,6 +265,24 @@ public function setMaxErrors(int $max_errors): self
return $this;
}

/**
* @return bool
*/
public function getStopAtFirstError(): bool
{
return $this->stopAtFirstError;
}

/**
* @param bool $stop
* @return $this
*/
public function setStopAtFirstError(bool $stop): self
{
$this->stopAtFirstError = $stop;
return $this;
}

/**
* @param array $slots
* @return array
Expand Down

0 comments on commit 6f92cb4

Please sign in to comment.