Skip to content

Commit

Permalink
Merge pull request #6 from PackageFactory/feature/strictMode
Browse files Browse the repository at this point in the history
FEATURE: Add strict mode that does not allow unvalidated props
  • Loading branch information
mficzel authored Feb 21, 2019
2 parents 8c99026 + c6b43d1 commit cf872a5
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 12 deletions.
47 changes: 37 additions & 10 deletions Classes/Aspects/PropTypeValidationAspect.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
class PropTypeValidationAspect
{
/**
* @Flow\Around("setting(PackageFactory.AtomicFusion.PropTypes.enable) && method(Neos\Fusion\FusionObjects\ComponentImplementation->evaluate())")
* @Flow\Around("setting(PackageFactory.AtomicFusion.PropTypes.enable) && method(Neos\Fusion\FusionObjects\ComponentImplementation->getProps())")
* @param JoinPointInterface $joinPoint The current join point
* @return mixed
*/
Expand All @@ -26,7 +26,7 @@ public function validatePropTypesForFusionComponents(JoinPointInterface $joinPoi
}

/**
* @Flow\Around("setting(PackageFactory.AtomicFusion.PropTypes.enable) && method(PackageFactory\AtomicFusion\FusionObjects\ComponentImplementation->evaluate())")
* @Flow\Around("setting(PackageFactory.AtomicFusion.PropTypes.enable) && method(PackageFactory\AtomicFusion\FusionObjects\ComponentImplementation->getProps())")
* @param JoinPointInterface $joinPoint The current join point
* @return mixed
*/
Expand All @@ -42,29 +42,56 @@ public function validatePropTypesForPackageFactoryAtomicFusionComponents(JoinPoi
protected function validateFusionPropTypes(JoinPointInterface $joinPoint)
{
$fusionComponentImplementation = $joinPoint->getProxy();
$strictMode = $fusionComponentImplementation['__meta/propTypes/__meta/strict'];
$validators = $fusionComponentImplementation['__meta/propTypes<Neos.Fusion:RawArray>'];
$result = new Result();
$props = $joinPoint->getAdviceChain()->proceed($joinPoint);

$validationResult = new Result();
$validatedPropNames = [];

// lazy prop validation
foreach ($validators as $propName => $validator) {
$propValue = $props[$propName] ?? null;
if ($validator instanceof ValidatorInterface) {
$result->forProperty($propName)->merge($validator->validate($fusionComponentImplementation[$propName]));
$validationResult->forProperty($propName)->merge($validator->validate($propValue));
} else {
$result->forProperty($propName)->addError(
$validationResult->forProperty($propName)->addError(
new Error(
sprintf(
'@propTypes are expected implement the ValidatorInterface %s found instead',
(is_object($validator) ? get_class($validator) : gettype($validator))
'propType for prop %s must implement the ValidatorInterface %s found instead',
$propName, (is_object($validator) ? get_class($validator) : gettype($validator))
)
)
);
}
$validatedPropNames[] = $propName;
}

// strict prop validation
if ($strictMode === true) {
foreach ($props as $propName => $propValue) {
if (!in_array($propName, $validatedPropNames)) {
$validationResult->forProperty($propName)->addError(
new Error(
sprintf(
'propType for prop %s is not declared but %s is passed',
$propName,
gettype($propValue)
)
)
);
}
}
}

if ($result->hasErrors()) {
if ($validationResult->hasErrors()) {
$prototypeName = ObjectAccess::getProperty($fusionComponentImplementation, 'fusionObjectName', true);
$exception = new PropTypeException(sprintf('The PropType validation for prototype %s failed', $prototypeName));
$exception->setResult($result);
$exception->setResult($validationResult);
throw $exception;
}
return $joinPoint->getAdviceChain()->proceed($joinPoint);

return $props;
}

}
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
```
prototype(Vendor.Site:Example) < prototype(Neos.Fusion:Component) {
@propTypes {
# optional, enforce that only validated props exist
@strict = true
# validation rules for props
title = ${PropTypes.string.isRequired}
subtitle = ${PropTypes.string}
}
Expand Down Expand Up @@ -66,7 +69,23 @@ The `PropTypes`-EelHelper is a wrapper around the `PackageFactory\AtomicFusion\P
which is an EelHelper and Validator at the same time. This Object is creates an compound-validator that is
controlled in a react-propTypes like syntax via eel.

By creating FusionObjects or EelHelpers that return custom validators you can extend this mechanism if needed.
By creating FusionObjects or EelHelpers that return custom validators you can extend this mechanism if needed.

### Strict mode

In strict mode an error is thrown if an unvalidated prop is passed to
a component in development context. This ensures that all props are validated.

To enable strict mode for a component add `@strict = true` to the `@propTypes`.

```
prototype(Vendor.Site:Example) < prototype(Neos.Fusion:Component) {
@propTypes {
@strict = true
...
}
}
```

## Settings

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "packagefactory/atomicfusion-proptypes",
"license": "GPL-3.0-or-later",
"require": {
"neos/fusion": "^3.0.0 || ^4.0.0 || dev-master"
"neos/fusion": "^4.2.0 || dev-master"
},
"autoload": {
"psr-4": {
Expand Down

0 comments on commit cf872a5

Please sign in to comment.