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) { |
|
|
|
|
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) { |
|
|
|
|
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
|
|
|
|
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.