You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We encountered a strange behavior when using normalization with Expect::structure(). It seemed that when specifying a before() method on a property inside the structure and passing an object to the Nette\Schema\Processor::process() method, it would not get normalized.
I managed to track it down to the Nette\Schema\Elements\Structure::normalize() method, specifically the is_array method in the condition, which was indeed the case:
useNette\Schema\Expect;
useNette\Schema\Processor;
useNette\Utils\ArrayHash;
// The example from https://doc.nette.org/en/3.0/schema#toc-custom-normalization, just wrapped it in a structure$schema = Expect::structure([
'data' => Expect::arrayOf('string')->before(function ($v) { returnexplode('', $v); })
]);
$values = ['data' => 'a b c'];
$processor = newProcessor();
// Simple array// stdClass { data => [ 'a', 'b', 'c' ] }$arrayResult = $processor->process($schema, $values);
// Non-iterable class// Nette\Schema\ValidationException: The option 'data' expects to be array, string 'a b c' given$objectResult = $processor->process($schema, (object) $values);
// An ArrayHash, or any class that implements \Traversable// Nette\Schema\ValidationException: The option 'data' expects to be array, string 'a b c' given$traversableResult = $processor->process($schema, ArrayHash::from($values));
Expected Behavior
If the structure is an object, it's properties get properly normalized.
Possible Solution
I tried my best with rewriting the Nette\Schema\Elements\Structure::normalize() method to support objects, and I came up with this:
publicfunctionnormalize($value, Context$context)
{
$value = $this->doNormalize($value, $context);
if (is_array($value) || is_object($value)) {
// When non-iterable object is received, iterate through its public properties$properties = is_iterable($value) ? $value : get_object_vars($value);
foreach ($propertiesas$key => $val) {
$itemSchema = $this->items[$key] ?? $this->otherItems;
if ($itemSchema) {
$context->path[] = $key;
if (is_object($value)) {
$value->{$key} = $itemSchema->normalize($val, $context);
} else {
$value[$key] = $itemSchema->normalize($val, $context);
}
array_pop($context->path);
}
}
}
return$value;
}
With this modification, all of the examples I showed in Steps to Reproduce section work as expected:
useNette\Schema\Expect;
useNette\Schema\Processor;
useNette\Utils\ArrayHash;
$schema = Expect::structure([
'data' => Expect::arrayOf('string')->before(function ($v) { returnexplode('', $v); })
]);
$values = ['data' => 'a b c'];
$processor = newProcessor();
// Simple array$arrayResult = $processor->process($schema, $values);
// Non-iterable class$objectResult = $processor->process($schema, (object) $values);
// An ArrayHash, or any class that implements \Traversable$traversableResult = $processor->process($schema, ArrayHash::from($values));
dump($arrayResult); // stdClass { data => [ 'a', 'b', 'c' ] }dump($objectResult); // stdClass { data => [ 'a', 'b', 'c' ] }dump($traversableResult); // stdClass { data => [ 'a', 'b', 'c' ] }
Edit: I created a PR in case the solution would be acceptable.
The text was updated successfully, but these errors were encountered:
Version: 1.0.0
Bug Description
We encountered a strange behavior when using normalization with
Expect::structure()
. It seemed that when specifying abefore()
method on a property inside the structure and passing an object to theNette\Schema\Processor::process()
method, it would not get normalized.I managed to track it down to the
Nette\Schema\Elements\Structure::normalize()
method, specifically theis_array
method in the condition, which was indeed the case:Steps To Reproduce
This code snippet reproduces the problem:
Expected Behavior
If the structure is an object, it's properties get properly normalized.
Possible Solution
I tried my best with rewriting the
Nette\Schema\Elements\Structure::normalize()
method to support objects, and I came up with this:With this modification, all of the examples I showed in Steps to Reproduce section work as expected:
Edit: I created a PR in case the solution would be acceptable.
The text was updated successfully, but these errors were encountered: