Skip to content

Commit 9b46976

Browse files
authored
Merge pull request #80 from utopia-php/feat-null-valid-for-optional-array-attributes
Feat: allow null and empty arrays for optional array attributes
2 parents 5ff5eea + 9d5d60b commit 9b46976

2 files changed

Lines changed: 88 additions & 38 deletions

File tree

src/Database/Validator/Structure.php

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -229,31 +229,46 @@ public function isValid($document)
229229
$format = $attribute['format'] ?? '';
230230
$required = $attribute['required'] ?? false;
231231

232+
if ($required === false && is_null($value)) { // Allow null value to optional params
233+
continue;
234+
}
235+
232236
switch ($type) {
233237
case Database::VAR_STRING:
234238
$validator = new Text(0);
235239
break;
236-
240+
237241
case Database::VAR_INTEGER:
238242
$validator = new Integer();
239243
break;
240-
244+
241245
case Database::VAR_FLOAT:
242246
$validator = new FloatValidator();
243247
break;
244-
245-
248+
246249
case Database::VAR_BOOLEAN:
247250
$validator = new Boolean();
248251
break;
249-
252+
250253
default:
251254
$this->message = 'Unknown attribute type "'.$type.'"';
252255
return false;
253256
break;
254257
}
255258

256-
if($array && !$format) { // Validate attribute type for arrays - format for arrays handled separately
259+
/** @var string $label Error messasage label, either 'format' or 'type' */
260+
$label = ($format) ? 'format' : 'type';
261+
262+
if ($format) {
263+
// Format encoded as json string containing format name and relevant format options
264+
$format = self::getFormat($format, $type);
265+
$validator = $format['callback']($attribute);
266+
}
267+
268+
if($array) { // Validate attribute type for arrays - format for arrays handled separately
269+
if($required == false && empty($value)) { // Allow both null and [] for optional arrays
270+
continue;
271+
}
257272
if(!is_array($value)) {
258273
$this->message = 'Attribute "'.$key.'" must be an array';
259274
return false;
@@ -265,47 +280,17 @@ public function isValid($document)
265280
}
266281

267282
if(!$validator->isValid($child)) {
268-
$this->message = 'Attribute "'.$key.'[\''.$x.'\']" has invalid type. '.$validator->getDescription();
283+
$this->message = 'Attribute "'.$key.'[\''.$x.'\']" has invalid '.$label.'. '.$validator->getDescription();
269284
return false;
270285
}
271286
}
272287
}
273288
else {
274-
if($required == false && is_null($value)) { // Allow null value to optional params
275-
continue;
276-
}
277-
278289
if(!$validator->isValid($value)) {
279-
$this->message = 'Attribute "'.$key.'" has invalid type. '.$validator->getDescription();
290+
$this->message = 'Attribute "'.$key.'" has invalid '.$label.'. '.$validator->getDescription();
280291
return false;
281292
}
282293
}
283-
284-
if($format) {
285-
// Format encoded as json string containing format name and relevant format options
286-
$format = self::getFormat($format, $type);
287-
$validator = $format['callback']($attribute);
288-
289-
if($array) { // Validate attribute type
290-
if(!is_array($value)) {
291-
$this->message = 'Attribute "'.$key.'" must be an array';
292-
return false;
293-
}
294-
295-
foreach ($value as $x => $child) {
296-
if(!$validator->isValid($child)) {
297-
$this->message = 'Attribute "'.$key.'[\''.$x.'\']" has invalid format. '.$validator->getDescription();
298-
return false;
299-
}
300-
}
301-
}
302-
else {
303-
if(!$validator->isValid($value)) {
304-
$this->message = 'Attribute "'.$key.'" has invalid format. '.$validator->getDescription();
305-
return false;
306-
}
307-
}
308-
}
309294
}
310295

311296
return true;

tests/Database/Validator/StructureTest.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ class StructureTest extends TestCase
4848
'array' => false,
4949
'filters' => [],
5050
],
51+
[
52+
'$id' => 'reviews',
53+
'type' => Database::VAR_INTEGER,
54+
'format' => '',
55+
'size' => 5,
56+
'required' => false,
57+
'signed' => true,
58+
'array' => true,
59+
'filters' => [],
60+
],
5161
[
5262
'$id' => 'price',
5363
'type' => Database::VAR_FLOAT,
@@ -316,6 +326,61 @@ public function testIntegerValidation()
316326
$this->assertEquals('Invalid document structure: Attribute "rating" has invalid type. Value must be a valid integer', $validator->getDescription());
317327
}
318328

329+
public function testArrayOfIntegersValidation()
330+
{
331+
$validator = new Structure(new Document($this->collection));
332+
333+
$this->assertEquals(true, $validator->isValid(new Document([
334+
'$collection' => 'posts',
335+
'title' => 'string',
336+
'description' => 'Demo description',
337+
'rating' => 5,
338+
'reviews' => [3, 4, 4, 5],
339+
'price' => 1.99,
340+
'published' => true,
341+
'tags' => ['dog', 'cat', 'mouse'],
342+
'feedback' => 'team@appwrite.io',
343+
])));
344+
345+
$this->assertEquals(true, $validator->isValid(new Document([
346+
'$collection' => 'posts',
347+
'title' => 'string',
348+
'description' => 'Demo description',
349+
'rating' => 5,
350+
'reviews' => [],
351+
'price' => 1.99,
352+
'published' => true,
353+
'tags' => ['dog', 'cat', 'mouse'],
354+
'feedback' => 'team@appwrite.io',
355+
])));
356+
357+
$this->assertEquals(true, $validator->isValid(new Document([
358+
'$collection' => 'posts',
359+
'title' => 'string',
360+
'description' => 'Demo description',
361+
'rating' => 5,
362+
'reviews' => null,
363+
'price' => 1.99,
364+
'published' => true,
365+
'tags' => ['dog', 'cat', 'mouse'],
366+
'feedback' => 'team@appwrite.io',
367+
])));
368+
369+
$this->assertEquals(false, $validator->isValid(new Document([
370+
'$collection' => 'posts',
371+
'title' => 'string',
372+
'description' => 'Demo description',
373+
'rating' => 5,
374+
'reviews' => ['', 4, 4, 5],
375+
'price' => 1.99,
376+
'published' => true,
377+
'tags' => ['dog', 'cat', 'mouse'],
378+
'feedback' => 'team@appwrite.io',
379+
])));
380+
381+
$this->assertEquals('Invalid document structure: Attribute "reviews[\'0\']" has invalid type. Value must be a valid integer', $validator->getDescription());
382+
}
383+
319384
public function testFloatValidation()
320385
{
321386
$validator = new Structure(new Document($this->collection));

0 commit comments

Comments
 (0)