Compare commits

...

49 commits

Author SHA1 Message Date
a0488daa41 update structure of composer.json and update dependencies
All checks were successful
ci/woodpecker/tag/code-style Pipeline was successful
ci/woodpecker/tag/functional-tests/1 Pipeline was successful
ci/woodpecker/tag/functional-tests/2 Pipeline was successful
ci/woodpecker/tag/functional-tests/3 Pipeline was successful
ci/woodpecker/tag/functional-tests/4 Pipeline was successful
2024-10-11 14:30:45 +02:00
230677d289 Merge branch 'release/3.2.0'
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/push/functional-tests/2 Pipeline was successful
ci/woodpecker/tag/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/3 Pipeline was successful
ci/woodpecker/push/functional-tests/4 Pipeline was successful
ci/woodpecker/tag/functional-tests/1 Pipeline was successful
ci/woodpecker/tag/functional-tests/2 Pipeline was successful
ci/woodpecker/tag/functional-tests/3 Pipeline was successful
ci/woodpecker/tag/functional-tests/4 Pipeline was successful
2024-09-04 16:05:13 +02:00
ad973f63ed Merge branch 'feature/conditional-validator' into develop
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/2 Pipeline was successful
ci/woodpecker/push/functional-tests/3 Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/push/functional-tests/4 Pipeline was successful
* feature/conditional-validator:
  add feature comment
  improve tests
  fix handling of validation groups
  add conditional validator to allow more flexible configuration
  rewrite settings validator to support validators on first level ; deprecate "properties" and "self" level
2024-09-04 16:04:29 +02:00
1f5b491d5a add feature comment
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline was successful
ci/woodpecker/push/functional-tests/2 Pipeline was successful
ci/woodpecker/push/functional-tests/3 Pipeline was successful
ci/woodpecker/push/functional-tests/4 Pipeline was successful
2024-09-04 15:59:15 +02:00
3b64e5b87b improve tests 2024-09-04 15:58:08 +02:00
cf710783d9 fix handling of validation groups 2024-09-04 15:57:55 +02:00
da4f409a8d add conditional validator to allow more flexible configuration
Some checks failed
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests/1 Pipeline failed
ci/woodpecker/push/functional-tests/2 Pipeline failed
ci/woodpecker/push/functional-tests/3 Pipeline failed
ci/woodpecker/push/functional-tests/4 Pipeline failed
2024-08-30 14:47:28 +02:00
b86110a3b0 rewrite settings validator to support validators on first level ; deprecate "properties" and "self" level 2024-08-30 14:46:49 +02:00
04d1810bb2 Merge tag '3.1.1' into develop
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests Pipeline was successful
Tagging 3.1.1
2023-02-19 00:01:04 +01:00
a3209c6976 Merge branch 'release/3.1.1'
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests Pipeline was successful
2023-02-19 00:01:00 +01:00
f452efae74 Allow recent flow versions
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/functional-tests Pipeline was successful
2023-02-18 23:55:38 +01:00
a213057567 Merge branch 'version/2.x-dev' into develop
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-10-27 12:39:50 +02:00
1e7a319604 Fixing code-style pipeline
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-10-27 12:39:26 +02:00
Robin Krahnen
a94e3a3291 Merge branch 'release/3.1.0'
Some checks failed
ci/woodpecker/push/code-style Pipeline failed
ci/woodpecker/push/test Pipeline was successful
2022-05-04 23:41:58 +02:00
Robin Krahnen
09f6aa089b Merge tag '3.1.0' into develop
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
3.1.0
2022-05-04 23:41:58 +02:00
Robin Krahnen
0e5a09e45a optimized versions in composer.json
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-05-04 19:01:14 +02:00
Robin Krahnen
0ad084f734 add "declare(strict_types=1);"
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2022-05-02 09:56:09 +02:00
7c0c667dd3 Adjusting tests to support only Flow 6.3
Some checks failed
ci/woodpecker/push/code-style Pipeline failed
ci/woodpecker/push/test Pipeline failed
2022-04-30 18:40:25 +02:00
01bb260444 Merge remote-tracking branch 'origin/feature/drone-ci-tests' into feature/drone-ci-tests-develop 2022-04-30 18:38:50 +02:00
eff9a13d22 Merge pull request 'feature/drone-ci-tests' (#1) from fkuhl/DigiComp.SettingValidator:feature/drone-ci-tests into feature/drone-ci-tests
All checks were successful
ci/woodpecker/push/code-style Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Reviewed-on: #1
2022-04-30 18:36:20 +02:00
1d09aeeced Adding Flow 4.3 build
All checks were successful
ci/woodpecker/pr/code-style Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
2022-04-30 18:22:11 +02:00
25d5a3c21f Basing functional test build on base distribution
All checks were successful
ci/woodpecker/pr/code-style Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
2022-04-30 15:16:28 +02:00
6beb9f1997 Merge branch 'feature/drone-ci-tests' into feature/drone-ci-tests-develop 2022-04-29 03:07:45 +02:00
2162238cc6 Only code-style
Some checks failed
ci/woodpecker/pr/code-style Pipeline was successful
ci/woodpecker/pr/test Pipeline failed
2022-04-29 03:02:36 +02:00
bd503834d7 adding functional test 2022-04-29 01:47:02 +02:00
86cf0c546b adding code-style pipeline
Some checks failed
ci/woodpecker/push/code-style Pipeline failed
2022-04-28 22:49:56 +02:00
Robin Krahnen
1fd6480cd2 revised code 2022-04-20 17:36:29 +02:00
Robin Krahnen
c09b13c124 optimized code from tests 2022-04-04 22:36:48 +02:00
Robin Krahnen
fb9f31ccee optimized code from code migrations 2022-04-04 22:29:30 +02:00
Robin Krahnen
3087390299 reorder entries in Validation.yaml 2022-03-03 14:25:17 +01:00
Robin Krahnen
d4e095dd54 optimized php requirement 2022-03-03 13:30:50 +01:00
Robin Krahnen
9707c47a1c optimized Package.php 2021-10-06 15:58:48 +02:00
Robin Krahnen
9c4138b4d1 added return type hints for callables 2021-09-23 09:52:07 +02:00
Robin Krahnen
51115825ac add empty line at end of License.txt 2021-09-22 15:00:26 +02:00
Robin Krahnen
26a71d266d update composer.json 2021-09-02 17:50:15 +02:00
Robin Krahnen
c4c3d94fd9 Merge branch 'develop' 2021-04-14 10:57:43 +02:00
Robin Krahnen
ba7e6ce33f code style changes 2021-04-13 08:51:04 +02:00
Robin Krahnen
a1882a2b11 optimized CHANGELOG.md 2021-03-15 19:57:44 +01:00
Robin Krahnen
d03d940f6a optimized CHANGELOG.md 2021-03-15 19:47:22 +01:00
Robin Krahnen
3fab89e54b Merge branch 'develop' 2021-02-17 14:40:53 +01:00
Robin Krahnen
bd7fca349c reorder composer.json 2021-02-17 14:40:35 +01:00
Robin Krahnen
75101c2147 fixed branch alias 2021-02-17 13:56:00 +01:00
Robin Krahnen
f857055059 update required versions 2021-02-17 09:01:00 +01:00
Robin Krahnen
591886bfdf optimized README.md 2021-02-16 12:47:06 +01:00
Robin Krahnen
20cf7bff05 use double quotes in yaml files 2021-02-16 11:19:51 +01:00
Robin Krahnen
9610c2a27e Merge branch 'develop' 2021-01-11 17:07:25 +01:00
Robin Krahnen
b01aa11242 optimized composer.json 2021-01-11 17:00:12 +01:00
Robin Krahnen
e5aed7a587 Merge branch 'develop' 2020-09-09 10:49:33 +02:00
Robin Krahnen
c5e511fecc raise required version of neos/flow to 6.3 2020-09-09 10:47:24 +02:00
17 changed files with 655 additions and 139 deletions

View file

@ -0,0 +1,8 @@
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

@ -0,0 +1,32 @@
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

@ -4,6 +4,11 @@ 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).
## 3.0.0 - 2020-08-31
## [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

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator;
/*
@ -22,17 +24,18 @@ use Neos\Flow\Package\Package as NeosFlowPackagePackage;
class Package extends NeosFlowPackagePackage
{
/**
* @param Bootstrap $bootstrap
* @inheritDoc
*/
public function boot(Bootstrap $bootstrap): void
{
parent::boot($bootstrap);
$dispatcher = $bootstrap->getSignalSlotDispatcher();
$dispatcher->connect(
ConfigurationManager::class,
'configurationManagerReady',
function (ConfigurationManager $configurationManager) {
function (ConfigurationManager $configurationManager): void {
$configurationManager->registerConfigurationType('Validation');
}
);

View file

@ -0,0 +1,152 @@
<?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

@ -0,0 +1,119 @@
<?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,5 +1,7 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Validation\Validator;
/*
@ -18,7 +20,6 @@ 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\ObjectAccess;
use Neos\Utility\TypeHandling;
/**
@ -56,6 +57,7 @@ class SettingsValidator extends AbstractValidator
{
$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(
@ -64,7 +66,44 @@ class SettingsValidator extends AbstractValidator
);
}
foreach ($this->getConfigForValidation($validations[$name]) as $validatorConfig) {
// @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;
}
@ -86,54 +125,10 @@ class SettingsValidator extends AbstractValidator
);
}
if (isset($validatorConfig['property'])) {
$this->getResult()->forProperty($validatorConfig['property'])->merge(
$validator->validate(ObjectAccess::getPropertyPath($value, $validatorConfig['property']))
);
} else {
$this->getResult()->merge($validator->validate($value));
}
$this->getResult()->merge($validator->validate($value));
}
}
/**
* @param array $validation
* @return array
*/
protected function getConfigForValidation(array $validation): array
{
$config = [];
if (isset($validation['self'])) {
foreach ($validation['self'] as $validator => $options) {
if ($options === null) {
continue;
}
$config[] = [
'validator' => $validator,
'options' => $options,
];
}
}
if (isset($validation['properties'])) {
foreach ($validation['properties'] as $property => $propertyValidation) {
foreach ($propertyValidation as $validator => $options) {
if ($options === null) {
continue;
}
$config[] = [
'property' => $property,
'validator' => $validator,
'options' => $options,
];
}
}
}
return $config;
}
/**
* Check whether at least one configured group does match, if any is configured.
*
@ -156,7 +151,7 @@ class SettingsValidator extends AbstractValidator
*/
protected function handleValidationGroups(array &$validatorConfig): void
{
if ($validatorConfig['validator'] === 'DigiComp.SettingValidator:Settings') {
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

@ -8,20 +8,15 @@ DigiComp\SettingValidator\Tests\Functional\Fixtures\TestObject:
expectedValue: false
Grumble: ~
TrueValidator:
self:
BooleanValue:
expectedValue: true
DigiComp\SettingValidator\Tests\Functional\Fixtures\TestValidationGroupsCustomObject:
self:
DigiComp.SettingValidator:Settings:
name: 'GroupValidatorCustom'
name: "GroupValidatorCustom"
DigiComp\SettingValidator\Tests\Functional\Fixtures\TestValidationGroupsDefaultObject:
self:
DigiComp.SettingValidator:Settings:
name: 'GroupValidatorDefault'
name: "GroupValidatorDefault"
GroupValidatorDefault:
properties:
@ -35,4 +30,9 @@ GroupValidatorCustom:
BooleanValue:
expectedValue: false
validationGroups:
- 'Custom'
- "Custom"
TrueValidator:
self:
BooleanValue:
expectedValue: true

View file

@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
THE SOFTWARE.

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace Neos\Flow\Core\Migrations;
/**
@ -15,11 +17,14 @@ class Version20170603120900 extends AbstractMigration
return 'DigiComp.SettingValidator-20170603120900';
}
/**
* @inheritDoc
*/
public function up(): void
{
$this->processConfiguration(
'Validation',
function (array &$configuration) {
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'])) {
@ -30,14 +35,14 @@ class Version20170603120900 extends AbstractMigration
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.'
'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'];
$newConfiguration['properties'][$validator['property']][$validator['validator']] =
$validator['options'];
} else {
$newConfiguration['self'][$validator['validator']] = $validator['options'];
}

233
README.md
View file

@ -1,40 +1,211 @@
# DigiComp.SettingValidator
This Package allows configuring Validators for your Action-Arguments or domain model properties to be set by a new
Yaml-File in your Configuration directory.
This package allows configuring validators with a new configuration type.
Let's imagine you had this action-method:
## Introduction
/**
* @Flow\Validate(argumentName="order", type="DigiComp.SettingValidator:Settings")
* @param Order $order
*/
public function createOrder($order) {...}
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.
Then your Validation.yaml could look like this:
## Resolving the validation configuration
Vendor\Package\Domain\Model\Order:
# validates the complete object
self:
'Vendor.Package:SomeOtherValidator': []
# validates properties of the object
properties:
price:
NumberRange:
maximum: 20
minimum: 10
customer:
'DigiComp.SettingValidator:Settings':
name: 'OrderCustomer'
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.
OrderCustomer:
properties:
firstName:
StringLength:
minimum: 3
maximum: 20
### Resolving by option `name`
As you see: Nesting is possible ;) That way you can easily construct flexible structures.
To resolve the validation configuration by name just use the option `name`.
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.
```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
/**
* @Flow\Validate(type="DigiComp.SettingValidator:Settings")
* @var MyObject
*/
protected MyObject $myObject;
```
The `SettingsValidator` will search for an entry inside the `Validation.yaml` with the FQCN of `MyObject`.
```yaml
My\Package\Domain\Model\MyObject:
...
```
## The validation configuration
### 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.
```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: {}
```

View file

@ -1,11 +1,11 @@
type: 'dictionary'
type: "dictionary"
additionalProperties:
type: 'dictionary'
type: "dictionary"
additionalProperties: false
properties:
type: 'dictionary'
type: "dictionary"
additionalProperties: false
properties:
type: 'dictionary'
type: "dictionary"
self:
type: 'dictionary'
type: "dictionary"

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional\Fixtures;
use Neos\Flow\Annotations as Flow;

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional\Fixtures;
class TestValidationGroupsCustomObject

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional\Fixtures;
class TestValidationGroupsDefaultObject

View file

@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace DigiComp\SettingValidator\Tests\Functional;
use DigiComp\SettingValidator\Tests\Functional\Fixtures\TestObject;
@ -20,11 +22,11 @@ class SettingsValidatorTest extends FunctionalTestCase
*/
public function ifNoNameIsGivenClassNameIsUsed(): void
{
$validator = $this->objectManager->get(SettingsValidator::class);
$result = $validator->validate(new TestObject());
$this->assertTrue($result->hasErrors());
$this->assertCount(1, $result->getFlattenedErrors());
$this->assertCount(1, $result->forProperty('shouldBeFalse')->getErrors());
$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());
}
/**
@ -35,11 +37,14 @@ class SettingsValidatorTest extends FunctionalTestCase
*/
public function conjunctionValidationWorksAsExpected(): void
{
$validatorResolver = $this->objectManager->get(ValidatorResolver::class);
$validator = $validatorResolver->getBaseValidatorConjunction(TestObject::class);
$result = $validator->validate(new TestObject());
$this->assertTrue($result->hasErrors());
$this->assertCount(1, $result->getFlattenedErrors());
$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());
}
/**
@ -48,11 +53,13 @@ class SettingsValidatorTest extends FunctionalTestCase
*/
public function defaultValidationGroupWorks(): void
{
$validator = $this->objectManager->get(SettingsValidator::class, ['validationGroups' => ['Default']]);
$result = $validator->validate(new TestValidationGroupsDefaultObject());
$this->assertTrue($result->hasErrors(), 'No Errors for validation group "Default"');
$this->assertCount(1, $result->getFlattenedErrors(), 'Got a non expected number of errors for group "Default"');
$this->assertCount(1, $result->forProperty('shouldBeTrue')->getErrors(), 'Got no error for property');
$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');
}
/**
@ -61,10 +68,12 @@ class SettingsValidatorTest extends FunctionalTestCase
*/
public function customValidationGroupWorks(): void
{
$validator = $this->objectManager->get(SettingsValidator::class, ['validationGroups' => ['Custom']]);
$result = $validator->validate(new TestValidationGroupsCustomObject());
$this->assertTrue($result->hasErrors(), 'No Errors for validation group "Custom"');
$this->assertCount(1, $result->getFlattenedErrors(), 'Got a non expected number of errors for group "Custom"');
$this->assertCount(1, $result->forProperty('shouldBeFalse')->getErrors(), 'Got no error for property');
$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

@ -2,43 +2,54 @@
"name": "digicomp/settingvalidator",
"description": "Just a Neos\\Flow Validator resolving other Validators with Configuration/Validation.yaml",
"type": "neos-package",
"authors": [
{
"name": "Ferdinand Kuhl",
"email": "f.kuhl@digital-competence.de",
"homepage": "http://www.digital-competence.de",
"role": "Developer"
}
],
"license": "MIT",
"homepage": "https://github.com/fcool/DigiComp.SettingValidator",
"keywords": [
"Neos",
"Flow",
"validation"
],
"homepage": "https://github.com/digital-competence/DigiComp.SettingValidator",
"license": "MIT",
"authors": [
{
"name": "Ferdinand Kuhl",
"email": "f.kuhl@digital-competence.de",
"homepage": "https://www.digital-competence.de",
"role": "Developer"
}
],
"require": {
"neos/flow": "^6.2.3",
"php": "~7.4.0"
"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"
},
"autoload": {
"psr-4": {
"DigiComp\\SettingValidator\\": "Classes"
"DigiComp\\SettingValidator\\": "Classes/"
}
},
"autoload-dev": {
"psr-4": {
"DigiComp\\SettingValidator\\Tests\\": "Tests"
"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"
},
"branch-alias": {
"dev-develop": "3.0.x-dev",
"dev-version/1.x-dev": "1.1.x-dev"
},
"applied-flow-migrations": [
"Inwebs.Basket-201409170938",
"TYPO3.FLOW3-201201261636",