Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
configurator.php
1<?php
2
3namespace Bitrix\Main\Engine;
4
10
11final class Configurator
12{
13 const EVENT_ON_BUILD_ACTIONS = 'onBuildActions';
14
15 const MODE_ANNOTATIONS = 0x0001;
16
17 protected $mode = 0;
18
22 public function __construct()
23 {
24 }
25
26 public function getConfigurationByAnnotations(array $annotations)
27 {
28 $configuration = null;
29 if (empty($annotations))
30 {
31 return $configuration;
32 }
33
34 if (isset($annotations['Action']) || array_key_exists('Action', $annotations))
35 {
36 $configuration = array(
37 'prefilters' => array(),
38 'postfilters' => array(),
39 );
40
41 if (isset($annotations['Action']['method']))
42 {
43 if (!is_array($annotations['Action']['method']))
44 {
45 $annotations['Action']['method'] = array($annotations['Action']['method']);
46 }
47
48 $configuration['prefilters'][] = new ActionFilter\HttpMethod($annotations['Action']['method']);
49 }
50
51 if (isset($annotations['Action']['csrf']) && is_bool($annotations['Action']['csrf']))
52 {
53 $configuration['prefilters'][] = new ActionFilter\Csrf($annotations['Action']['csrf']);
54 }
55
56 if (!$configuration && !isset($configuration['postfilters']))
57 {
58 $configuration['postfilters'] = array();
59 }
60 }
61
62 return $configuration;
63 }
64
65 public function getConfigurationByController(Controller $controller)
66 {
67 $newConfiguration = $this->onBuildConfigurationOfActions($controller);
68 $configuration = $controller->configureActions() ? : array();
69
70 if ($this->mode & self::MODE_ANNOTATIONS)
71 {
72 $annotationReader = new AnnotationReader();
73
74 $lengthSuffix = mb_strlen(Controllerable::METHOD_ACTION_SUFFIX);
75 $reflectionClass = new \ReflectionClass($controller);
76 foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method)
77 {
78 if (!$method->isPublic())
79 {
80 continue;
81 }
82
83 $probablySuffix = mb_substr($method->getName(), -$lengthSuffix);
84 if ($probablySuffix !== Controllerable::METHOD_ACTION_SUFFIX)
85 {
86 continue;
87 }
88
89 $actionName = mb_substr($method, 0, -$lengthSuffix);
90 if ($this->isExists($configuration, $actionName))
91 {
92 //we have already config and don't have to grab annotations
93 continue;
94 }
95
96 $annotations = $annotationReader->getMethodAnnotations($method);
97 if (!$this->checkReflectionMethodAsAction($method, $annotations))
98 {
99 continue;
100 }
101
102 $configuration[$actionName] = $this->getConfigurationByAnnotations($annotations);
103 }
104 }
105
106 $configuration = array_merge($newConfiguration, $configuration);
107 $configuration = $this->wrapClosure($configuration);
108
109 $this->checkConfigurations($configuration);
110
111 return $configuration;
112 }
113
114 private function isExists(array $configuration, $actionName)
115 {
116 $listOfActions = array_change_key_case($configuration, CASE_LOWER);
117 $actionName = mb_strtolower($actionName);
118
119 return isset($listOfActions[$actionName]);
120 }
121
122 private function checkReflectionMethodAsAction(\ReflectionMethod $reflectionMethod, array $annotations = null)
123 {
124 if (!$reflectionMethod->isPublic())
125 {
126 return false;
127 }
128
129 if ($annotations === null)
130 {
131 $annotationReader = new AnnotationReader();
132 $annotations = $annotationReader->getMethodAnnotations($reflectionMethod);
133 }
134
135 if (!is_array($annotations) || !array_key_exists('Action', $annotations))
136 {
137 return false;
138 }
139
140 return true;
141 }
142
143 private function onBuildConfigurationOfActions(Controller $controller)
144 {
145 //todo set name of the controller in event name? or use filter?
146 $event = new Event(
147 'main',
148 static::EVENT_ON_BUILD_ACTIONS,
149 array(
150 'controller' => $controller,
151 )
152 );
153 $event->send($this);
154
155 $newConfiguration = array();
156 foreach ($event->getResults() as $eventResult)
157 {
158 if ($eventResult->getType() != EventResult::SUCCESS)
159 {
160 continue;
161 }
162
163 $parameters = $eventResult->getParameters();
164 if (isset($parameters['extraActions']) && is_array($parameters['extraActions']))
165 {
166 //configuration in $this->configureActions() has more priority then configuration which was provided by event
167 $newConfiguration = array_merge($newConfiguration, $parameters['extraActions']);
168 }
169 }
170
171 return $newConfiguration;
172 }
173
174 public function wrapFiltersClosure(array $filters)
175 {
176 foreach ($filters as $i => $filter)
177 {
178 if (!($filter instanceof \Closure))
179 {
180 continue;
181 }
182
183 $filters[$i] = new ActionFilter\ClosureWrapper($filter);
184 }
185
186 return $filters;
187 }
188
189 private function wrapClosure(array $configurations)
190 {
191 foreach ($configurations as $actionName => $configuration)
192 {
193 if (!empty($configuration['prefilters']))
194 {
195 $configurations[$actionName]['prefilters'] = $this->wrapFiltersClosure($configuration['prefilters']);
196 }
197
198 if (!empty($configuration['+prefilters']))
199 {
200 $configurations[$actionName]['+prefilters'] = $this->wrapFiltersClosure($configuration['+prefilters']);
201 }
202
203 if (!empty($configuration['postfilters']))
204 {
205 $configurations[$actionName]['postfilters'] = $this->wrapFiltersClosure($configuration['postfilters']);
206 }
207
208 if (!empty($configuration['+postfilters']))
209 {
210 $configurations[$actionName]['+postfilters'] = $this->wrapFiltersClosure($configuration['+postfilters']);
211 }
212 }
213
214 return $configurations;
215 }
216
217 private function checkConfigurations(array $configurations)
218 {
219 foreach ($configurations as $actionName => $configuration)
220 {
221 if (!is_string($actionName))
222 {
223 throw new SystemException('Invalid configuration of actions. Action has to be string');
224 }
225
226 if (!is_array($configuration))
227 {
228 throw new SystemException('Invalid configuration of actions. Configuration has to be array');
229 }
230
231 if (!empty($configuration['prefilters']))
232 {
233 $this->checkFilters($configuration['prefilters']);
234 }
235
236 if (!empty($configuration['postfilters']))
237 {
238 $this->checkFilters($configuration['postfilters']);
239 }
240 }
241 }
242
243 private function checkFilters(array $filters)
244 {
245 foreach ($filters as $filter)
246 {
247 if (!($filter instanceof ActionFilter\Base))
248 {
249 throw new SystemException('Filter has to be subclass of ' . ActionFilter\Base::className());
250 }
251 }
252 }
253
254}
getConfigurationByController(Controller $controller)
getConfigurationByAnnotations(array $annotations)