Compare commits

..

No commits in common. "master" and "version/1.x-dev" have entirely different histories.

20 changed files with 192 additions and 1086 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.svn

View file

@ -1,8 +0,0 @@
pipeline:
code-style:
image: composer
commands:
- composer global config repositories.repo-name vcs https://git.digital-competence.de/Packages/php-codesniffer
- composer global config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
- composer global require digicomp/php-codesniffer:@dev
- composer global exec -- phpcs --runtime-set ignore_warnings_on_exit 1 --standard=DigiComp Classes/ Migrations/ Tests/ Resources/Private/

View file

@ -1,32 +0,0 @@
workspace:
base: /woodpecker
path: package
matrix:
include:
- FLOW_VERSION: 6.3
PHP_VERSION: 7.4
- FLOW_VERSION: 7.3
PHP_VERSION: 7.4
- FLOW_VERSION: 7.3
PHP_VERSION: 8.2
- FLOW_VERSION: 8.2
PHP_VERSION: 8.2
pipeline:
functional-tests:
image: thecodingmachine/php:${PHP_VERSION}-v4-cli
environment:
# Enable the PDO_SQLITE extension
- "PHP_EXTENSION_PDO_SQLITE=1"
- "FLOW_VERSION=${FLOW_VERSION}"
- "NEOS_BUILD_DIR=/woodpecker/Build-${FLOW_VERSION}"
commands:
- "sudo mkdir $NEOS_BUILD_DIR"
- "sudo chown -R docker:docker $NEOS_BUILD_DIR"
- "cd $NEOS_BUILD_DIR"
- "composer create-project --no-install neos/flow-base-distribution:^$FLOW_VERSION ."
- "composer config repositories.repo-name path /woodpecker/package"
- "composer remove --dev --no-update neos/behat || composer remove --no-update neos/behat"
- "composer require digicomp/settingvalidator:@dev"
- "bin/phpunit --configuration Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Application/DigiComp.SettingValidator/Tests/Functional"

View file

@ -1,14 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [3.0.1] - 2020-09-09
### Changed
- dependency to Flow ^6.3
## [3.0.0] - 2020-08-31
Start of the changelog.

View file

@ -0,0 +1,33 @@
<?php
namespace DigiComp\SettingValidator;
use Doctrine\ORM\Mapping as ORM;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Configuration\ConfigurationManager;
use TYPO3\Flow\Core\Bootstrap;
use \TYPO3\Flow\Package\Package as BasePackage;
/**
* @Flow\Scope("prototype")
*/
class Package extends BasePackage
{
public function boot(Bootstrap $bootstrap)
{
parent::boot($bootstrap);
$dispatcher = $bootstrap->getSignalSlotDispatcher();
$dispatcher->connect(
'TYPO3\Flow\Configuration\ConfigurationManager',
'configurationManagerReady',
function (ConfigurationManager $configurationManager) {
$configurationManager->registerConfigurationType(
'Validation',
ConfigurationManager::CONFIGURATION_PROCESSING_TYPE_DEFAULT,
true
);
}
);
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace DigiComp\SettingValidator\Validation\Validator;
use Doctrine\ORM\Mapping as ORM;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Configuration\ConfigurationManager;
use TYPO3\Flow\Reflection\ObjectAccess;
use TYPO3\Flow\Reflection\ReflectionService;
use TYPO3\Flow\Validation\Exception\InvalidValidationConfigurationException;
use TYPO3\Flow\Validation\Exception\InvalidValidationOptionsException;
use TYPO3\Flow\Validation\Validator\AbstractValidator;
use TYPO3\Flow\Validation\ValidatorResolver;
/**
* Validator resolving other Validators defined in Validation.yaml
*
* @Flow\Scope("prototype")
*/
class SettingsValidator extends AbstractValidator
{
/**
* @var ValidatorResolver
* @Flow\Inject
*/
protected $validatorResolver;
/**
* @var array
*/
protected $validations;
/**
* @var \TYPO3\Flow\Configuration\ConfigurationManager
*/
protected $configurationManager;
public function injectConfigurationManager(ConfigurationManager $configurationManager)
{
$this->configurationManager = $configurationManager;
$this->validations = $this->configurationManager->getConfiguration('Validation');
}
/**
* @var ReflectionService
* @Flow\Inject
*/
protected $reflectionService;
protected $supportedOptions = array(
'name' => array('', 'Set the name of the setting-array to use', 'string', false)
);
/**
* Check if $value is valid. If it is not valid, needs to add an error
* to Result.
*
* @param mixed $value
*
* @throws InvalidValidationOptionsException
* @throws InvalidValidationConfigurationException
*/
protected function isValid($value)
{
$name = $this->options['name'] ? $this->options['name'] : $this->reflectionService->getClassNameByObject(
$value
);
if (!isset($this->validations[$name])) {
throw new InvalidValidationOptionsException(
'The name ' . $name . ' has not been defined in Validation.yaml!',
1397821438
);
}
$config = &$this->validations[$name];
foreach ($config as $validatorConfig) {
$validator = $this->validatorResolver->createValidator(
$validatorConfig['validator'],
$validatorConfig['options']
);
if (!$validator) {
throw new InvalidValidationConfigurationException(
'Validator could not be resolved: ' .
$validatorConfig['validator'] . '. Check your Validation.yaml',
1402326139
);
}
if (isset($validatorConfig['property'])) {
$this->result->forProperty($validatorConfig['property'])->merge(
$validator->validate(ObjectAccess::getPropertyPath($value, $validatorConfig['property']))
);
} else {
$this->result->merge($validator->validate($value));
}
}
}
}

View file

@ -1,43 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator;
/*
* This file is part of the DigiComp.SettingValidator package.
*
* (c) digital competence
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/
use Neos\Flow\Configuration\ConfigurationManager;
use Neos\Flow\Core\Bootstrap;
use Neos\Flow\Package\Package as NeosFlowPackagePackage;
/**
* Package base class of the DigiComp.SettingValidator package.
*/
class Package extends NeosFlowPackagePackage
{
/**
* @inheritDoc
*/
public function boot(Bootstrap $bootstrap): void
{
parent::boot($bootstrap);
$dispatcher = $bootstrap->getSignalSlotDispatcher();
$dispatcher->connect(
ConfigurationManager::class,
'configurationManagerReady',
function (ConfigurationManager $configurationManager): void {
$configurationManager->registerConfigurationType('Validation');
}
);
}
}

View file

@ -1,152 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Validation\Validator;
/*
* This file is part of the DigiComp.SettingValidator package.
*
* (c) digital competence
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/
use Neos\Eel\EelEvaluatorInterface;
use Neos\Eel\Exception as NeosEelException;
use Neos\Eel\Utility;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\ObjectManagement\DependencyInjection\DependencyProxy;
use Neos\Flow\Validation\Exception\InvalidValidationConfigurationException;
use Neos\Flow\Validation\Exception\NoSuchValidatorException;
use Neos\Flow\Validation\Validator\AbstractValidator;
use Neos\Flow\Validation\ValidatorResolver;
class ConditionalValidator extends AbstractValidator
{
/**
* @Flow\Inject
* @var EelEvaluatorInterface
*/
protected $eelEvaluator;
/**
* @Flow\Inject
* @var ValidatorResolver
*/
protected $validatorResolver;
/**
* @inheritDoc
*/
protected $supportedOptions = [
'conditions' => [[], 'List of entries with "condition" (eel expression) and "validators" (list of validators).', 'array', true],
'fallbackValidators' => [[], 'List of validators that is used if no condition matched.', 'array'],
'validationGroups' => [['Default'], 'Same as "Validation Groups" of Flow Framework', 'array'],
];
/**
* @inheritDoc
* @throws InvalidValidationConfigurationException
* @throws NeosEelException
* @throws NoSuchValidatorException
*/
protected function isValid($value): void
{
$validatorConfigs = [];
$hasMatch = false;
foreach ($this->options['conditions'] as $condition) {
if ($this->eelEvaluator instanceof DependencyProxy) {
$this->eelEvaluator->_activateDependency();
}
if (!Utility::evaluateEelExpression($condition['condition'], $this->eelEvaluator, ['this' => $value])) {
continue;
}
$hasMatch = true;
foreach ($condition['validators'] as $validator => $options) {
if ($options === null) {
continue;
}
$validatorConfigs[] = [
'validator' => $validator,
'options' => $options,
];
}
}
if (!$hasMatch) {
foreach ($this->options['fallbackValidators'] as $validator => $options) {
if ($options === null) {
continue;
}
$validatorConfigs[] = [
'validator' => $validator,
'options' => $options,
];
}
}
foreach ($validatorConfigs as $validatorConfig) {
if (!$this->doesValidationGroupsMatch($validatorConfig)) {
continue;
}
$this->handleValidationGroups($validatorConfig);
$validator = $this->validatorResolver->createValidator(
$validatorConfig['validator'],
$validatorConfig['options']
);
if ($validator === null) {
throw new InvalidValidationConfigurationException(
\sprintf(
'Validator "%s" could not be resolved. Check your Validation.yaml',
$validatorConfig['validator']
),
1402326139
);
}
$this->getResult()->merge($validator->validate($value));
}
}
/**
* Check whether at least one configured group does match, if any is configured.
*
* @param array $validatorConfig
* @return bool
*/
protected function doesValidationGroupsMatch(array $validatorConfig): bool
{
return !isset($validatorConfig['options']['validationGroups'])
|| \array_intersect(
$validatorConfig['options']['validationGroups'],
$this->options['validationGroups']
) !== [];
}
/**
* Add validation groups for recursion if necessary.
*
* @param array $validatorConfig
*/
protected function handleValidationGroups(array &$validatorConfig): void
{
if (\in_array($validatorConfig['validator'], ['DigiComp.SettingValidator:Settings', 'DigiComp.SettingValidator:Conditional', 'DigiComp.SettingValidator:Properties', 'Neos.Flow:Collection'])) {
$validatorConfig['options']['validationGroups'] = $this->options['validationGroups'];
} elseif (isset($validatorConfig['options']['validationGroups'])) {
unset($validatorConfig['options']['validationGroups']);
}
}
}

View file

@ -1,119 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Validation\Validator;
/*
* This file is part of the DigiComp.SettingValidator package.
*
* (c) digital competence
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Validation\Exception\InvalidValidationConfigurationException;
use Neos\Flow\Validation\Exception\NoSuchValidatorException;
use Neos\Flow\Validation\Validator\AbstractValidator;
use Neos\Flow\Validation\ValidatorResolver;
use Neos\Utility\ObjectAccess;
class PropertiesValidator extends AbstractValidator
{
/**
* @Flow\Inject
* @var ValidatorResolver
*/
protected $validatorResolver;
/**
* @inheritDoc
*/
protected $supportedOptions = [
'validatorsForProperties' => [[], 'List of validators for properties. ', 'array', true],
'validationGroups' => [['Default'], 'Same as "Validation Groups" of Flow Framework', 'array'],
];
/**
* @inheritDoc
* @throws InvalidValidationConfigurationException
* @throws NoSuchValidatorException
*/
protected function isValid($value): void
{
$validatorConfigs = [];
foreach ($this->options['validatorsForProperties'] as $property => $validators) {
foreach ($validators as $validator => $options) {
if ($options === null) {
continue;
}
$validatorConfigs[] = [
'validator' => $validator,
'options' => $options,
'property' => $property,
];
}
}
foreach ($validatorConfigs as $validatorConfig) {
if (!$this->doesValidationGroupsMatch($validatorConfig)) {
continue;
}
$this->handleValidationGroups($validatorConfig);
$validator = $this->validatorResolver->createValidator(
$validatorConfig['validator'],
$validatorConfig['options']
);
if ($validator === null) {
throw new InvalidValidationConfigurationException(
\sprintf(
'Validator "%s" could not be resolved. Check your Validation.yaml',
$validatorConfig['validator']
),
1402326139
);
}
$this->getResult()->forProperty($validatorConfig['property'])->merge(
$validator->validate(ObjectAccess::getPropertyPath($value, $validatorConfig['property']))
);
}
}
/**
* Check whether at least one configured group does match, if any is configured.
*
* @param array $validatorConfig
* @return bool
*/
protected function doesValidationGroupsMatch(array $validatorConfig): bool
{
return !isset($validatorConfig['options']['validationGroups'])
|| \array_intersect(
$validatorConfig['options']['validationGroups'],
$this->options['validationGroups']
) !== [];
}
/**
* Add validation groups for recursion if necessary.
*
* @param array $validatorConfig
*/
protected function handleValidationGroups(array &$validatorConfig): void
{
if (\in_array($validatorConfig['validator'], ['DigiComp.SettingValidator:Settings', 'DigiComp.SettingValidator:Conditional', 'DigiComp.SettingValidator:Properties', 'Neos.Flow:Collection'])) {
$validatorConfig['options']['validationGroups'] = $this->options['validationGroups'];
} elseif (isset($validatorConfig['options']['validationGroups'])) {
unset($validatorConfig['options']['validationGroups']);
}
}
}

View file

@ -1,160 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Validation\Validator;
/*
* This file is part of the DigiComp.SettingValidator package.
*
* (c) digital competence
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Validation\Exception\InvalidValidationConfigurationException;
use Neos\Flow\Validation\Exception\InvalidValidationOptionsException;
use Neos\Flow\Validation\Exception\NoSuchValidatorException;
use Neos\Flow\Validation\Validator\AbstractValidator;
use Neos\Flow\Validation\ValidatorResolver;
use Neos\Utility\TypeHandling;
/**
* Validator resolving other Validators defined in Validation.yaml
*/
class SettingsValidator extends AbstractValidator
{
/**
* @Flow\Inject
* @var ValidatorResolver
*/
protected $validatorResolver;
/**
* @Flow\InjectConfiguration(type="Validation")
* @var array
*/
protected array $validations;
/**
* @inheritDoc
*/
protected $supportedOptions = [
'name' => ['', 'Name of the setting array to use', 'string'],
'validationGroups' => [['Default'], 'Same as "Validation Groups" of Flow Framework', 'array'],
];
/**
* @inheritDoc
* @throws InvalidValidationOptionsException
* @throws InvalidValidationConfigurationException
* @throws NoSuchValidatorException
*/
protected function isValid($value): void
{
$validations = $this->validations;
// TODO: feature idea - we could extend the library to automatically be part of the base conjunction validator
$name = $this->options['name'] !== '' ? $this->options['name'] : TypeHandling::getTypeForValue($value);
if (!isset($validations[$name])) {
throw new InvalidValidationOptionsException(
'The name "' . $name . '" has not been defined in Validation.yaml!',
1397821438
);
}
// @deprecated - converts old "self" to new structure
if (isset($validations[$name]['self'])) {
foreach ($validations[$name]['self'] as $validator => $options) {
if (isset($validations[$name][$validator])) {
throw new \RuntimeException('The validator "' . $validator . '" is already defined on parent level.', 1725000364);
}
$validations[$name][$validator] = $options;
}
unset($validations[$name]['self']);
}
// @deprecated - converts old "properties" to new structure
if (isset($validations[$name]['properties'])) {
if (isset($validations[$name]['DigiComp.SettingValidator:Properties'])) {
throw new \RuntimeException('The validator "DigiComp.SettingValidator:Properties" is already defined on parent level.', 1725000396);
}
$validations[$name]['DigiComp.SettingValidator:Properties'] = [
'validatorsForProperties' => $validations[$name]['properties'],
];
unset($validations[$name]['properties']);
}
$validatorConfigs = [];
foreach ($validations[$name] as $validator => $options) {
if ($options === null) {
continue;
}
$validatorConfigs[] = [
'validator' => $validator,
'options' => $options,
];
}
foreach ($validatorConfigs as $validatorConfig) {
if (!$this->doesValidationGroupsMatch($validatorConfig)) {
continue;
}
$this->handleValidationGroups($validatorConfig);
$validator = $this->validatorResolver->createValidator(
$validatorConfig['validator'],
$validatorConfig['options']
);
if ($validator === null) {
throw new InvalidValidationConfigurationException(
\sprintf(
'Validator "%s" could not be resolved. Check your Validation.yaml',
$validatorConfig['validator']
),
1402326139
);
}
$this->getResult()->merge($validator->validate($value));
}
}
/**
* Check whether at least one configured group does match, if any is configured.
*
* @param array $validatorConfig
* @return bool
*/
protected function doesValidationGroupsMatch(array $validatorConfig): bool
{
return !isset($validatorConfig['options']['validationGroups'])
|| \array_intersect(
$validatorConfig['options']['validationGroups'],
$this->options['validationGroups']
) !== [];
}
/**
* Add validation groups for recursion if necessary.
*
* @param array $validatorConfig
*/
protected function handleValidationGroups(array &$validatorConfig): void
{
if (\in_array($validatorConfig['validator'], ['DigiComp.SettingValidator:Settings', 'DigiComp.SettingValidator:Conditional', 'DigiComp.SettingValidator:Properties', 'Neos.Flow:Collection'])) {
$validatorConfig['options']['validationGroups'] = $this->options['validationGroups'];
} elseif (isset($validatorConfig['options']['validationGroups'])) {
unset($validatorConfig['options']['validationGroups']);
}
}
}

View file

@ -1,38 +0,0 @@
DigiComp\SettingValidator\Tests\Functional\Fixtures\TestObject:
properties:
shouldBeTrue:
BooleanValue:
expectedValue: true
shouldBeFalse:
BooleanValue:
expectedValue: false
Grumble: ~
DigiComp\SettingValidator\Tests\Functional\Fixtures\TestValidationGroupsCustomObject:
self:
DigiComp.SettingValidator:Settings:
name: "GroupValidatorCustom"
DigiComp\SettingValidator\Tests\Functional\Fixtures\TestValidationGroupsDefaultObject:
self:
DigiComp.SettingValidator:Settings:
name: "GroupValidatorDefault"
GroupValidatorDefault:
properties:
shouldBeTrue:
BooleanValue:
expectedValue: true
GroupValidatorCustom:
properties:
shouldBeFalse:
BooleanValue:
expectedValue: false
validationGroups:
- "Custom"
TrueValidator:
self:
BooleanValue:
expectedValue: true

View file

@ -1,56 +0,0 @@
<?php
declare(strict_types=1);
namespace Neos\Flow\Core\Migrations;
/**
* Restructures all Validation.yaml to new format
*/
class Version20170603120900 extends AbstractMigration
{
/**
* @return string
*/
public function getIdentifier(): string
{
return 'DigiComp.SettingValidator-20170603120900';
}
/**
* @inheritDoc
*/
public function up(): void
{
$this->processConfiguration(
'Validation',
function (array &$configuration): void {
foreach ($configuration as $validatorName => &$validators) {
// guard that protects configuration, which has already the new format:
if (isset($validators['properties']) || isset($validators['self'])) {
continue;
}
$newConfiguration = ['properties' => [], 'self' => []];
foreach ($validators as $key => $validator) {
if (!isset($validator['validator']) || !isset($validator['options'])) {
$this->showWarning(
'The Validation.yaml files contained no validator or options for validation: '
. '"' . $validatorName . '.' . $key . '". It was not migrated.'
);
continue;
}
if (isset($validator['property'])) {
$newConfiguration['properties'][$validator['property']][$validator['validator']] =
$validator['options'];
} else {
$newConfiguration['self'][$validator['validator']] = $validator['options'];
}
}
$validators = $newConfiguration;
}
},
true
);
}
}

233
README.md
View file

@ -1,211 +1,46 @@
# DigiComp.SettingValidator
DigiComp.SettingValidator
-------------------------
This package allows configuring validators with a new configuration type.
## Introduction
This Package allows to configure Validators for your Action-Arguments or domain model properties to be set by a new
Yaml-File in your Configuration directory.
This package provides the `SettingsValidator` which uses the configuration type `Validation` to resolve the validators
that should be applied to the value. It distinguishes between validators that are applied to the value itself and its
properties.
Lets imagine you had this action-method:
## Resolving the validation configuration
The `SettingsValidator` has an option `name`. If it is set, the name is used to resolve the validation configuration,
otherwise the type of the value is used, which is mainly useful for objects where the FQCN is used.
### Resolving by option `name`
To resolve the validation configuration by name just use the option `name`.
```php
/**
* @Flow\Validate(type="DigiComp.SettingValidator:Settings", options={"name"="MyNamedValidator"})
* @var MyObject
*/
protected MyObject $myObject;
```
The `SettingsValidator` will search for an entry inside the `Validation.yaml` with that name.
```yaml
MyNamedValidator:
...
```
### Resolving by type
To resolve the validation configuration by type just do not set the option `name`.
```php
/**
/**
* @param Order $order
* @Flow\Validate(type="DigiComp.SettingValidator:Settings")
* @var MyObject
*/
protected MyObject $myObject;
```
public function createOrder($order) {...}
The `SettingsValidator` will search for an entry inside the `Validation.yaml` with the FQCN of `MyObject`.
Then your Validation.yaml could look like this:
```yaml
My\Package\Domain\Model\MyObject:
...
```
SuperVendor\SuperPackage\Domain\Model\Order:
-
property: price
validator: NumberRange
options:
maximum: 20
minimum: 10
-
validator: SuperVendor.SuperPackage:SomeOtherValidator #validates the complete object
options: []
-
property: customer
validator: DigiComp.SettingValidator:Settings
options:
name: OrderCustomer
## The validation configuration
OrderCustomer:
-
property: firstName
validator: StringLength
options:
minimum: 3
maximum: 20
### Difference between `self` and `properties`
`self` contains a map of validators that are applied to the value itself. `properties` contains a map with property
names of the value you would like to validate and each entry contains a map of validators that are applied to that
property.
As you see: Nesting is possible ;) That way you can easily construct flexible structures.
```yaml
MyNamedValidator:
self:
...
properties:
myProperty1:
...
myProperty2:
...
```
### Configuring a validator
To configure a validator you use the type of the validator as key and the options as entries of that key. If the
validator has no options or all the default values are used, set an empty map as options.
```yaml
MyNamedValidator:
self:
'My.Package:SomeValidator':
myOption: "myOptionValue"
properties:
myProperty1:
'My.Package:SomeOtherValidator': {}
myProperty2:
'My.Package:SomeOtherValidator': {}
```
### Disable a validator
To disable a validator you need to set the options to `null`.
```yaml
MyNamedValidator:
self:
'My.Package:SomeValidator': ~
```
## Using the `SettingsValidator`
The `SettingsValidator` can be used to reduce the number of `@Flow\Validate` annotations and gives you the possibility
of overwriting existing validation configurations in other packages.
### Using on properties
Old PHP code:
```php
/**
* @Flow\Validate(type="My.Package:SomeValidator", options={"myOption"="myOptionValue"})
* @Flow\Validate(type="My.Package:SomeOtherValidator")
* @var MyObject
*/
protected MyObject $myObject;
```
New PHP code:
```php
/**
* @Flow\Validate(type="DigiComp.SettingValidator:Settings", options={"name"="MyNamedValidator"})
* @var MyObject
*/
protected MyObject $myObject;
```
New validation configuration:
```yaml
MyNamedValidator:
self:
'My.Package:SomeValidator':
myOption: "myOptionValue"
'My.Package:SomeOtherValidator': {}
```
### Using on actions
Old PHP code:
```php
/**
* @Flow\Validate(argumentName="myObject", type="My.Package:SomeValidator", options={"myOption"="myOptionValue"})
* @Flow\Validate(argumentName="myObject", type="My.Package:SomeOtherValidator")
* @param MyObject $myObject
*/
public function myAction(MyObject $myObject)
{
...
}
```
New PHP code:
```php
/**
* @Flow\Validate(argumentName="myObject", type="DigiComp.SettingValidator:Settings", options={"name"="MyNamedValidator"})
* @param MyObject $myObject
*/
public function myAction(MyObject $myObject)
{
...
}
```
New validation configuration:
```yaml
MyNamedValidator:
self:
'My.Package:SomeValidator':
myOption: "myOptionValue"
'My.Package:SomeOtherValidator': {}
```
### Using inside validator configurations
You can use the `SettingsValidator` inside the validator configuration to easily construct flexible structures.
```yaml
MyNamedValidator:
properties:
myProperty1:
'DigiComp.SettingValidator:Settings':
name: "MyOtherNamedValidator"
MyOtherNamedValidator:
self:
'My.Package:SomeOtherValidator': {}
```
## Providing an empty validator
It can be useful to provide an empty validator in code that is used by many projects. By doing so you can make sure that
a different validation is possible in any project.
```php
/**
* @Flow\Validate(argumentName="myObject", type="DigiComp.SettingValidator:Settings", options={"name"="MyNamedValidator"})
* @param MyObject $myObject
*/
public function myAction(MyObject $myObject)
{
...
}
```
```yaml
MyNamedValidator: {}
```
The SettingsValidator has an optional option: "name" - If you don't give one, it assumes your validation value is an
object and searches in Validation.yaml for the FQCN.

View file

@ -1,11 +1,11 @@
type: "dictionary"
type: dictionary
additionalProperties:
type: "dictionary"
type: array
items:
type: dictionary
additionalProperties: false
# This validation sadly only hits the first level of validation, and options are not coverable with current validator
properties:
type: "dictionary"
additionalProperties: false
properties:
type: "dictionary"
self:
type: "dictionary"
validator: {type: string, required: TRUE}
options: {type: dictionary, required: TRUE}
property: {type: string, required: FALSE}

View file

@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional\Fixtures;
use Neos\Flow\Annotations as Flow;
class TestObject
{
/**
* @var bool
*/
protected bool $shouldBeTrue = true;
/**
* @var bool
*/
protected bool $shouldBeFalse = true;
/**
* @Flow\Validate(type="DigiComp.SettingValidator:Settings", options={"name"="TrueValidator"})
* @var bool
*/
protected bool $shouldBeTrueAndValidatedByAnnotation = false;
/**
* @return bool
*/
public function isShouldBeTrue(): bool
{
return $this->shouldBeTrue;
}
/**
* @return bool
*/
public function isShouldBeFalse(): bool
{
return $this->shouldBeFalse;
}
/**
* @return bool
*/
public function isShouldBeTrueAndValidatedByAnnotation(): bool
{
return $this->shouldBeTrueAndValidatedByAnnotation;
}
}

View file

@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional\Fixtures;
class TestValidationGroupsCustomObject
{
/**
* @var bool
*/
protected bool $shouldBeTrue = false;
/**
* @var bool
*/
protected bool $shouldBeFalse = true;
/**
* @return bool
*/
public function isShouldBeTrue(): bool
{
return $this->shouldBeTrue;
}
/**
* @return bool
*/
public function isShouldBeFalse(): bool
{
return $this->shouldBeFalse;
}
}

View file

@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional\Fixtures;
class TestValidationGroupsDefaultObject
{
/**
* @var bool
*/
protected bool $shouldBeTrue = false;
/**
* @var bool
*/
protected bool $shouldBeFalse = true;
/**
* @return bool
*/
public function isShouldBeTrue(): bool
{
return $this->shouldBeTrue;
}
/**
* @return bool
*/
public function isShouldBeFalse(): bool
{
return $this->shouldBeFalse;
}
}

View file

@ -1,79 +0,0 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional;
use DigiComp\SettingValidator\Tests\Functional\Fixtures\TestObject;
use DigiComp\SettingValidator\Tests\Functional\Fixtures\TestValidationGroupsCustomObject;
use DigiComp\SettingValidator\Tests\Functional\Fixtures\TestValidationGroupsDefaultObject;
use DigiComp\SettingValidator\Validation\Validator\SettingsValidator;
use Neos\Flow\Tests\FunctionalTestCase;
use Neos\Flow\Validation\Exception\InvalidValidationConfigurationException;
use Neos\Flow\Validation\Exception\InvalidValidationOptionsException;
use Neos\Flow\Validation\Exception\NoSuchValidatorException;
use Neos\Flow\Validation\ValidatorResolver;
class SettingsValidatorTest extends FunctionalTestCase
{
/**
* @test
* @throws InvalidValidationOptionsException
*/
public function ifNoNameIsGivenClassNameIsUsed(): void
{
$result = $this->objectManager->get(SettingsValidator::class)->validate(new TestObject());
self::assertTrue($result->hasErrors());
self::assertCount(1, $result->getFlattenedErrors());
self::assertCount(1, $result->forProperty('shouldBeFalse')->getErrors());
}
/**
* @test
* @throws InvalidValidationConfigurationException
* @throws InvalidValidationOptionsException
* @throws NoSuchValidatorException
*/
public function conjunctionValidationWorksAsExpected(): void
{
$result = $this->objectManager
->get(ValidatorResolver::class)
->getBaseValidatorConjunction(TestObject::class)
->validate(new TestObject());
self::assertTrue($result->hasErrors());
self::assertCount(1, $result->getFlattenedErrors());
self::assertCount(1, $result->forProperty('shouldBeTrueAndValidatedByAnnotation')->getErrors());
}
/**
* @test
* @throws InvalidValidationOptionsException
*/
public function defaultValidationGroupWorks(): void
{
$result = $this->objectManager
->get(SettingsValidator::class, ['validationGroups' => ['Default']])
->validate(new TestValidationGroupsDefaultObject());
self::assertTrue($result->hasErrors(), 'No errors for validation group "Default"');
self::assertCount(1, $result->getFlattenedErrors(), 'Got a non expected number of errors for group "Default"');
self::assertCount(1, $result->forProperty('shouldBeTrue')->getErrors(), 'Got no error for property');
}
/**
* @test
* @throws InvalidValidationOptionsException
*/
public function customValidationGroupWorks(): void
{
$result = $this->objectManager
->get(SettingsValidator::class, ['validationGroups' => ['Custom']])
->validate(new TestValidationGroupsCustomObject());
self::assertTrue($result->hasErrors(), 'No errors for validation group "Custom"');
self::assertCount(1, $result->getFlattenedErrors(), 'Got a non expected number of errors for group "Custom"');
self::assertCount(1, $result->forProperty('shouldBeFalse')->getErrors(), 'Got no error for property');
}
}

View file

@ -1,55 +1,34 @@
{
"name": "digicomp/settingvalidator",
"description": "Just a Neos\\Flow Validator resolving other Validators with Configuration/Validation.yaml",
"type": "neos-package",
"keywords": [
"Neos",
"Flow",
"validation"
],
"homepage": "https://github.com/digital-competence/DigiComp.SettingValidator",
"license": "MIT",
"type": "typo3-flow-package",
"description": "Just a TYPO3\\Flow Validator resolving other Validators with Configuration/Validation.yaml",
"authors": [
{
"name": "Ferdinand Kuhl",
"email": "f.kuhl@digital-competence.de",
"homepage": "https://www.digital-competence.de",
"homepage": "http://www.digital-competence.de",
"role": "Developer"
}
],
"license": "MIT",
"homepage": "https://github.com/fcool/DigiComp.SettingValidator",
"keywords": [
"Flow",
"validation"
],
"require": {
"php": ">=7.4.0",
"neos/flow": "^6.3.5 || ^7.0 || ^8.0"
},
"require-dev": {
"mikey179/vfsstream": "^1.6.1",
"neos/buildessentials": "^7.0.0",
"phpunit/phpunit": "~8.5",
"vimeo/psalm": "~4.22.0"
"typo3/flow": "~2.0|~3.0",
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"DigiComp\\SettingValidator\\": "Classes/"
"psr-0": {
"DigiComp\\SettingValidator": "Classes"
}
},
"autoload-dev": {
"psr-4": {
"DigiComp\\SettingValidator\\Tests\\": "Tests/"
}
},
"config": {
"sort-packages": true,
"platform-check": true
},
"extra": {
"branch-alias": {
"dev-develop": "3.2.x-dev",
"dev-version/2.x-dev": "2.1.x-dev",
"dev-version/1.x-dev": "1.0.x-dev"
},
"neos": {
"package-key": "DigiComp.SettingValidator"
},
"applied-flow-migrations": [
"Inwebs.Basket-201409170938",
"TYPO3.FLOW3-201201261636",
@ -65,26 +44,7 @@
"TYPO3.Fluid-20141113120800",
"TYPO3.Flow-20141113121400",
"TYPO3.Fluid-20141121091700",
"TYPO3.Fluid-20150214130800",
"TYPO3.Flow-20151113161300",
"TYPO3.Flow-20161115140400",
"TYPO3.Flow-20161115140430",
"Neos.Flow-20161124204700",
"Neos.Flow-20161124204701",
"Neos.Flow-20161124224015",
"Neos.Eel-20161124230101",
"Neos.Imagine-20161124231742",
"Neos.Media-20161124233100",
"Neos.Flow-20161125124112",
"Neos.SwiftMailer-20161130105617",
"TYPO3.FluidAdaptor-20161130112935",
"Neos.Media-20161219094126",
"Neos.Flow-20170125103800",
"Neos.Flow-20170127183102",
"DigiComp.SettingValidator-20170603120900",
"Neos.Flow-20180415105700",
"Neos.Flow-20190425144900",
"Neos.Flow-20190515215000"
"TYPO3.Fluid-20150214130800"
]
}
}