OperationConfigurationValidator::handleError()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 15
rs 9.2
cc 4
eloc 8
nc 6
nop 4
1
<?php
2
3
namespace Oro\Bundle\ActionBundle\Configuration;
4
5
use Doctrine\Common\Collections\Collection;
6
7
use Psr\Log\LoggerInterface;
8
9
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
10
use Symfony\Component\Routing\RouterInterface;
11
12
use Oro\Bundle\EntityBundle\ORM\DoctrineHelper;
13
14
class OperationConfigurationValidator implements ConfigurationValidatorInterface
15
{
16
    /** @var RouterInterface */
17
    protected $router;
18
19
    /** @var \Twig_ExistsLoaderInterface */
20
    protected $twigLoader;
21
22
    /** @var DoctrineHelper */
23
    protected $doctrineHelper;
24
25
    /** @var LoggerInterface */
26
    protected $logger;
27
28
    /** @var bool */
29
    protected $debug;
30
31
    /** @var Collection */
32
    protected $errors;
33
34
    /**
35
     * @param RouterInterface $router
36
     * @param \Twig_Loader_Filesystem $twigLoader
37
     * @param DoctrineHelper $doctrineHelper
38
     * @param LoggerInterface $logger
39
     * @param bool $debug
40
     */
41
    public function __construct(
42
        RouterInterface $router,
43
        \Twig_Loader_Filesystem $twigLoader,
44
        DoctrineHelper $doctrineHelper,
45
        LoggerInterface $logger,
46
        $debug
47
    ) {
48
        $this->router = $router;
49
        $this->twigLoader = $twigLoader;
50
        $this->doctrineHelper = $doctrineHelper;
51
        $this->logger = $logger;
52
        $this->debug = $debug;
53
    }
54
55
    /**
56
     * @param array $configuration
57
     * @param Collection $errors
58
     */
59
    public function validate(array $configuration, Collection $errors = null)
60
    {
61
        $this->errors = $errors;
62
63
        foreach ($configuration as $name => $action) {
64
            $this->validateTemplate($action, $name, 'button_options');
65
            $this->validateTemplate($action, $name, 'frontend_options');
66
            $this->validateFormOptions($action, $name);
67
            $this->validateRoutes($action['routes'], $this->getPath($name, 'routes'));
68
            $this->validateEntities($action['entities'], $this->getPath($name, 'entities'));
69
        }
70
    }
71
72
    /**
73
     * @param array $config
74
     * @param string $path
75
     * @param string $sectionName
76
     */
77
    protected function validateTemplate(array $config, $path, $sectionName)
78
    {
79
        if (!array_key_exists($sectionName, $config)) {
80
            return;
81
        }
82
83
        $optionsPath = $this->getPath($path, $sectionName);
84
        $options = $config[$sectionName];
85
86
        $this->assertTemplate($options, $optionsPath, 'template');
87
    }
88
89
    /**
90
     * @param array $options
91
     * @param string $path
92
     * @param string $paramName
93
     */
94
    protected function assertTemplate(array $options, $path, $paramName)
95
    {
96
        if (isset($options[$paramName]) && !$this->twigLoader->exists($options[$paramName])) {
97
            $this->handleError(
98
                $this->getPath($path, $paramName),
99
                'Unable to find template "%s"',
100
                $options[$paramName],
101
                false
102
            );
103
        }
104
    }
105
106
    /**
107
     * @param array $config
108
     * @param string $path
109
     */
110
    protected function validateFormOptions(array $config, $path)
111
    {
112
        $sectionName = 'form_options';
113
        if (!array_key_exists($sectionName, $config)) {
114
            return;
115
        }
116
117
        $optionsPath = $this->getPath($path, $sectionName);
118
119
        $this->validateFormOptionsAttributes($config, 'attribute_fields', $optionsPath);
120
        $this->validateFormOptionsAttributes($config, 'attribute_default_values', $optionsPath);
121
    }
122
123
    /**
124
     * @param array $config
125
     * @param string $sectionName
126
     * @param string $path
127
     */
128
    protected function validateFormOptionsAttributes(array $config, $sectionName, $path)
129
    {
130
        if (!array_key_exists($sectionName, $config['form_options'])) {
131
            return;
132
        }
133
134
        foreach (array_keys($config['form_options'][$sectionName]) as $attributeName) {
135
            if (!isset($config['attributes'][$attributeName])) {
136
                $this->handleError(
137
                    $this->getPath($path, $sectionName),
138
                    'Unknown attribute "%s".',
139
                    $attributeName,
140
                    false
141
                );
142
            }
143
        }
144
    }
145
146
    /**
147
     * @param array $items
148
     * @param string $path
149
     */
150
    protected function validateRoutes(array $items, $path)
151
    {
152
        if (!$items) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $items of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
153
            return;
154
        }
155
156
        $routeCollection = $this->router->getRouteCollection();
157
158
        foreach ($items as $key => $item) {
159
            if (!$routeCollection->get($item)) {
160
                $this->handleError($this->getPath($path, $key), 'Route "%s" not found.', $item);
161
            }
162
        }
163
    }
164
165
    /**
166
     * @param array $items
167
     * @param string $path
168
     */
169
    protected function validateEntities(array $items, $path)
170
    {
171
        foreach ($items as $key => $item) {
172
            if (!$this->validateEntity($item)) {
173
                $this->handleError($this->getPath($path, $key), 'Entity "%s" not found.', $item);
174
            }
175
        }
176
    }
177
178
    /**
179
     * @param string $entityName
180
     * @return boolean
181
     */
182
    protected function validateEntity($entityName)
183
    {
184
        try {
185
            $entityClass = $this->doctrineHelper->getEntityClass($entityName);
186
187
            if (!class_exists($entityClass, true)) {
188
                return false;
189
            }
190
191
            $reflection = new \ReflectionClass($entityClass);
192
193
            return $this->doctrineHelper->isManageableEntity($reflection->getName());
194
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
195
        }
196
197
        return false;
198
    }
199
200
    /**
201
     * @param string $path
202
     * @param string $subpath
203
     * @return string
204
     */
205
    protected function getPath($path, $subpath)
206
    {
207
        return $path . '.' . $subpath;
208
    }
209
210
    /**
211
     * @param string $path
212
     * @param string $message
213
     * @param mixed $value
214
     * @param bool $silent
215
     * @throws InvalidConfigurationException
216
     */
217
    protected function handleError($path, $message, $value, $silent = true)
218
    {
219
        $errorMessage = sprintf('%s: ' . $message, $path, $value);
220
        if ($this->debug) {
221
            $this->logger->warning('InvalidConfiguration: ' . $errorMessage, ['ActionConfiguration']);
222
        }
223
224
        if (!$silent) {
225
            throw new InvalidConfigurationException($errorMessage);
226
        }
227
228
        if ($this->errors !== null) {
229
            $this->errors->add($errorMessage);
230
        }
231
    }
232
}
233