Skip to content

Commit 6f92cb4

Browse files
committed
Added stopAtFirstError
1 parent c8d2b40 commit 6f92cb4

File tree

4 files changed

+106
-13
lines changed

4 files changed

+106
-13
lines changed

src/CompliantValidator.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ class CompliantValidator extends Validator
3838
'keepAdditionalItemsKeyword' => false,
3939
];
4040

41-
public function __construct(?SchemaLoader $loader = null, int $max_errors = 1)
41+
public function __construct(
42+
?SchemaLoader $loader = null,
43+
int $max_errors = 1,
44+
bool $stop_at_first_error = true
45+
)
4246
{
43-
parent::__construct($loader, $max_errors);
47+
parent::__construct($loader, $max_errors, $stop_at_first_error);
4448

4549
// Set parser options
4650
$parser = $this->parser();

src/Schemas/ObjectSchema.php

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
namespace Opis\JsonSchema\Schemas;
1919

2020
use Opis\JsonSchema\{Helper, Keyword, ValidationContext, KeywordValidator};
21-
use Opis\JsonSchema\Info\SchemaInfo;
21+
use Opis\JsonSchema\Info\{DataInfo, SchemaInfo};
2222
use Opis\JsonSchema\Errors\ValidationError;
2323
use Opis\JsonSchema\KeywordValidators\CallbackKeywordValidator;
2424

@@ -109,12 +109,40 @@ public function doValidate(ValidationContext $context): ?ValidationError
109109
*/
110110
protected function applyKeywords(array $keywords, ValidationContext $context): ?ValidationError
111111
{
112+
if ($context->stopAtFirstError()) {
113+
foreach ($keywords as $keyword) {
114+
if ($error = $keyword->validate($context, $this)) {
115+
return $error;
116+
}
117+
}
118+
return null;
119+
}
120+
121+
/** @var null|ValidationError[] $error_list */
122+
$error_list = null;
123+
112124
foreach ($keywords as $keyword) {
113125
if ($error = $keyword->validate($context, $this)) {
114-
return $error;
126+
$error_list ??= [];
127+
$error_list[] = $error;
115128
}
116129
}
117130

118-
return null;
131+
if (!$error_list) {
132+
return null;
133+
}
134+
135+
if (count($error_list) === 1) {
136+
return $error_list[0];
137+
}
138+
139+
return new ValidationError(
140+
'',
141+
$this,
142+
DataInfo::fromContext($context),
143+
'Data must match schema',
144+
[],
145+
$error_list
146+
);
119147
}
120148
}

src/ValidationContext.php

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class ValidationContext
5454

5555
protected int $maxErrors = 1;
5656

57+
protected bool $stopAtFirstError = true;
58+
5759
/**
5860
* @param $data
5961
* @param SchemaLoader $loader
@@ -70,7 +72,8 @@ public function __construct(
7072
?Schema $sender = null,
7173
array $globals = [],
7274
?array $slots = null,
73-
int $max_errors = 1
75+
int $max_errors = 1,
76+
bool $stop_at_first_error = true
7477
) {
7578
$this->sender = $sender;
7679
$this->rootData = $data;
@@ -79,6 +82,7 @@ public function __construct(
7982
$this->globals = $globals;
8083
$this->slots = null;
8184
$this->maxErrors = $max_errors;
85+
$this->stopAtFirstError = $stop_at_first_error;
8286
$this->currentData = [
8387
[$data, false],
8488
];
@@ -101,18 +105,28 @@ public function newInstance(
101105
?Schema $sender,
102106
?array $globals = null,
103107
?array $slots = null,
104-
?int $max_errors = null
108+
?int $max_errors = null,
109+
?bool $stop_at_first_error = null
105110
): self {
106-
return new self($data, $this->loader, $this, $sender, $globals ?? $this->globals, $slots ?? $this->slots,
107-
$max_errors ?? $this->maxErrors);
111+
return new self(
112+
$data,
113+
$this->loader,
114+
$this,
115+
$sender,
116+
$globals ?? $this->globals,
117+
$slots ?? $this->slots,
118+
$max_errors ?? $this->maxErrors,
119+
$stop_at_first_error ?? $this->stopAtFirstError
120+
);
108121
}
109122

110123
public function create(
111124
Schema $sender,
112125
?Variables $mapper = null,
113126
?Variables $globals = null,
114127
?array $slots = null,
115-
?int $maxErrors = null
128+
?int $maxErrors = null,
129+
?bool $stop_at_first_error = null
116130
): self {
117131
if ($globals) {
118132
$globals = $globals->resolve($this->rootData(), $this->currentDataPath());
@@ -131,7 +145,7 @@ public function create(
131145
}
132146

133147
return new self($data, $this->loader, $this, $sender, $globals, $slots ?? $this->slots,
134-
$maxErrors ?? $this->maxErrors);
148+
$maxErrors ?? $this->maxErrors, $stop_at_first_error ?? $this->stopAtFirstError);
135149
}
136150

137151
public function sender(): ?Schema
@@ -359,6 +373,19 @@ public function setMaxErrors(int $max): self
359373
return $this;
360374
}
361375

376+
377+
public function stopAtFirstError(): bool
378+
{
379+
return $this->stopAtFirstError;
380+
}
381+
382+
public function setStopAtFirstError(bool $stop): self
383+
{
384+
$this->stopAtFirstError = $stop;
385+
386+
return $this;
387+
}
388+
362389
/* --------------------- */
363390

364391
/**

src/Validator.php

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,22 @@ class Validator
2626
{
2727
protected SchemaLoader $loader;
2828
protected int $maxErrors = 1;
29+
protected bool $stopAtFirstError = true;
2930

3031
/**
3132
* @param SchemaLoader|null $loader
3233
* @param int $max_errors
34+
* @param bool $stop_at_first_error
3335
*/
34-
public function __construct(?SchemaLoader $loader = null, int $max_errors = 1)
36+
public function __construct(
37+
?SchemaLoader $loader = null,
38+
int $max_errors = 1,
39+
bool $stop_at_first_error = true
40+
)
3541
{
3642
$this->loader = $loader ?? new SchemaLoader(new SchemaParser(), new SchemaResolver(), true);
3743
$this->maxErrors = $max_errors;
44+
$this->stopAtFirstError = $stop_at_first_error;
3845
}
3946

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

173-
return new ValidationContext($data, $this->loader, null, null, $globals ?? [], $slots, $this->maxErrors);
180+
return new ValidationContext(
181+
$data,
182+
$this->loader,
183+
null,
184+
null,
185+
$globals ?? [],
186+
$slots,
187+
$this->maxErrors,
188+
$this->stopAtFirstError,
189+
);
174190
}
175191

176192
/**
@@ -249,6 +265,24 @@ public function setMaxErrors(int $max_errors): self
249265
return $this;
250266
}
251267

268+
/**
269+
* @return bool
270+
*/
271+
public function getStopAtFirstError(): bool
272+
{
273+
return $this->stopAtFirstError;
274+
}
275+
276+
/**
277+
* @param bool $stop
278+
* @return $this
279+
*/
280+
public function setStopAtFirstError(bool $stop): self
281+
{
282+
$this->stopAtFirstError = $stop;
283+
return $this;
284+
}
285+
252286
/**
253287
* @param array $slots
254288
* @return array

0 commit comments

Comments
 (0)