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