1<?php 2 3/* 4 * This file is part of the TYPO3 CMS project. 5 * 6 * It is free software; you can redistribute it and/or modify it under 7 * the terms of the GNU General Public License, either version 2 8 * of the License, or any later version. 9 * 10 * For the full copyright and license information, please read the 11 * LICENSE.txt file that was distributed with this source code. 12 * 13 * The TYPO3 project - inspiring people to share! 14 */ 15 16namespace TYPO3\CMS\Extbase\Validation\Validator; 17 18use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException; 19use TYPO3\CMS\Extbase\Validation\Exception\NoSuchValidatorException; 20 21/** 22 * An abstract composite validator consisting of other validators 23 */ 24abstract class AbstractCompositeValidator implements ObjectValidatorInterface, \Countable 25{ 26 /** 27 * This contains the supported options, their default values and descriptions. 28 * 29 * @var array 30 */ 31 protected $supportedOptions = []; 32 33 /** 34 * @var array 35 */ 36 protected $options = []; 37 38 /** 39 * @var \SplObjectStorage 40 */ 41 protected $validators; 42 43 /** 44 * @var \SplObjectStorage 45 */ 46 protected $validatedInstancesContainer; 47 48 /** 49 * Constructs the composite validator and sets validation options 50 * 51 * @param array $options Options for the validator 52 * @throws \TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException 53 * @todo: __construct() will vanish in v12, this abstract will implement setOptions() to set and initialize default options. 54 */ 55 public function __construct(array $options = []) 56 { 57 $this->initializeDefaultOptions($options); 58 } 59 60 /** 61 * Adds a new validator to the conjunction. 62 * 63 * @param \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface $validator The validator that should be added 64 */ 65 public function addValidator(ValidatorInterface $validator) 66 { 67 if ($validator instanceof ObjectValidatorInterface) { 68 // @todo: provide bugfix as soon as it is fixed in TYPO3.Flow (https://forge.typo3.org/issues/48093) 69 $validator->setValidatedInstancesContainer = $this->validatedInstancesContainer; 70 } 71 $this->validators->attach($validator); 72 } 73 74 /** 75 * Removes the specified validator. 76 * 77 * @param \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface $validator The validator to remove 78 * @throws \TYPO3\CMS\Extbase\Validation\Exception\NoSuchValidatorException 79 */ 80 public function removeValidator(ValidatorInterface $validator) 81 { 82 if (!$this->validators->contains($validator)) { 83 throw new NoSuchValidatorException('Cannot remove validator because its not in the conjunction.', 1207020177); 84 } 85 $this->validators->detach($validator); 86 } 87 88 /** 89 * Returns the number of validators contained in this conjunction. 90 * 91 * @return int The number of validators 92 * @todo Set to return type int as breaking change in v12. 93 */ 94 #[\ReturnTypeWillChange] 95 public function count() 96 { 97 return count($this->validators); 98 } 99 100 /** 101 * Returns the child validators of this Composite Validator 102 * 103 * @return \SplObjectStorage 104 */ 105 public function getValidators() 106 { 107 return $this->validators; 108 } 109 110 /** 111 * Returns the options for this validator 112 * 113 * @return array 114 */ 115 public function getOptions() 116 { 117 return $this->options; 118 } 119 120 /** 121 * Allows to set a container to keep track of validated instances. 122 * 123 * @param \SplObjectStorage $validatedInstancesContainer A container to keep track of validated instances 124 */ 125 public function setValidatedInstancesContainer(\SplObjectStorage $validatedInstancesContainer) 126 { 127 $this->validatedInstancesContainer = $validatedInstancesContainer; 128 } 129 130 /** 131 * Initialize default options. 132 * @throws InvalidValidationOptionsException 133 */ 134 protected function initializeDefaultOptions(array $options): void 135 { 136 // check for options given but not supported 137 if (($unsupportedOptions = array_diff_key($options, $this->supportedOptions)) !== []) { 138 throw new InvalidValidationOptionsException('Unsupported validation option(s) found: ' . implode(', ', array_keys($unsupportedOptions)), 1339079804); 139 } 140 // check for required options being set 141 array_walk( 142 $this->supportedOptions, 143 static function ($supportedOptionData, $supportedOptionName, $options) { 144 if (isset($supportedOptionData[3]) && !array_key_exists($supportedOptionName, $options)) { 145 throw new InvalidValidationOptionsException('Required validation option not set: ' . $supportedOptionName, 1339163922); 146 } 147 }, 148 $options 149 ); 150 // merge with default values 151 $this->options = array_merge( 152 array_map( 153 static function ($value) { 154 return $value[0]; 155 }, 156 $this->supportedOptions 157 ), 158 $options 159 ); 160 $this->validators = new \SplObjectStorage(); 161 } 162} 163