This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @link https://github.com/nnx-framework/jms-serializer-module |
||
4 | * @author Malofeykin Andrey <[email protected]> |
||
5 | */ |
||
6 | namespace Nnx\JmsSerializerModule\DataContainerBuilder; |
||
7 | |||
8 | use Nnx\JmsSerializerModule\DataContainer; |
||
9 | use Ramsey\Uuid\Uuid; |
||
10 | use SimpleXMLElement; |
||
11 | |||
12 | |||
13 | |||
14 | /** |
||
15 | * Class ManagerRegistryFactory |
||
16 | * |
||
17 | * @package Nnx\JmsSerializerModule\Util |
||
18 | */ |
||
19 | class XmlBuilder implements XmlBuilderInterface |
||
20 | { |
||
21 | /** |
||
22 | * Имя корневого тега по умолчанию |
||
23 | * |
||
24 | * @var string |
||
25 | */ |
||
26 | protected $defaultRootName = 'result'; |
||
27 | |||
28 | /** |
||
29 | * Имя тега являющегося контейнером для сущности |
||
30 | * |
||
31 | * @var string |
||
32 | */ |
||
33 | protected $xmlEntryName = 'entry'; |
||
34 | |||
35 | /** |
||
36 | * Xpath запрос для получения вложенных сущностей |
||
37 | * |
||
38 | * @var string |
||
39 | */ |
||
40 | protected $childEntryQuery; |
||
41 | |||
42 | /** |
||
43 | * Ключем является хеш SimpleXMLElement, а значением закешированные данные |
||
44 | * |
||
45 | * @var array |
||
46 | */ |
||
47 | protected $itemNodeUuidToCacheData = []; |
||
48 | |||
49 | /** |
||
50 | * Имя атрибута для того что бы связать SimpleXMLElement и контейнер с данными |
||
51 | * |
||
52 | * @var string |
||
53 | */ |
||
54 | protected $defaultUuidAttribute = '____UUID____'; |
||
55 | |||
56 | /** |
||
57 | * Определяет есть ли готовые данные для данного элемента |
||
58 | * |
||
59 | * @param SimpleXMLElement $resource |
||
60 | * |
||
61 | * @return boolean |
||
62 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\Exception\RuntimeException |
||
63 | */ |
||
64 | public function hasDataInCache(SimpleXMLElement $resource) |
||
65 | { |
||
66 | if ($this->hasUuidAttribute($resource)) { |
||
67 | $uuid = $this->getUuidAttribute($resource); |
||
68 | return array_key_exists($uuid, $this->itemNodeUuidToCacheData); |
||
69 | } |
||
70 | return false; |
||
71 | } |
||
72 | |||
73 | /** |
||
74 | * Возвращает контейнер с данными из кеша |
||
75 | * |
||
76 | * @param SimpleXMLElement $resource |
||
77 | * |
||
78 | * @return DataContainer\DataContainerInterface |
||
79 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\Exception\RuntimeException |
||
80 | */ |
||
81 | View Code Duplication | public function getDataContainerFromCache(SimpleXMLElement $resource) |
|
0 ignored issues
–
show
|
|||
82 | { |
||
83 | if (!$this->hasDataInCache($resource)) { |
||
84 | $errMsg = 'Data container not found'; |
||
85 | throw new Exception\RuntimeException($errMsg); |
||
86 | } |
||
87 | |||
88 | $uuid = $this->getUuidAttribute($resource); |
||
89 | return $this->itemNodeUuidToCacheData[$uuid]['dataContainer']; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Возвращает контейнер с данными для сущности |
||
94 | * |
||
95 | * @param SimpleXMLElement $resource |
||
96 | * |
||
97 | * @return DataContainer\EntityInterface |
||
98 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\Exception\RuntimeException |
||
99 | */ |
||
100 | View Code Duplication | public function getEntityFromCache(SimpleXMLElement $resource) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
101 | { |
||
102 | if (!$this->hasDataInCache($resource)) { |
||
103 | $errMsg = 'Entity not found'; |
||
104 | throw new Exception\RuntimeException($errMsg); |
||
105 | } |
||
106 | |||
107 | $uuid = $this->getUuidAttribute($resource); |
||
108 | return $this->itemNodeUuidToCacheData[$uuid]['entity']; |
||
109 | } |
||
110 | |||
111 | /** |
||
112 | * Подготавливает нормализованный контейнер с данными на основе узла SimpleXMLElement |
||
113 | * |
||
114 | * @param SimpleXMLElement $resource |
||
115 | * |
||
116 | * @return DataContainer\DataContainerInterface |
||
117 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\Exception\RuntimeException |
||
118 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\XmlBuilder\Exception\InvalidParserContextException |
||
119 | * @throws \Nnx\JmsSerializerModule\DataContainer\Exception\InvalidArgumentException |
||
120 | * @throws Exception\InvalidResourceException |
||
121 | */ |
||
122 | public function loadDataFromResource(SimpleXMLElement $resource) |
||
123 | { |
||
124 | if ($this->hasUuidAttribute($resource)) { |
||
125 | $uuid = $this->getUuidAttribute($resource); |
||
126 | if (array_key_exists($uuid, $this->itemNodeUuidToCacheData)) { |
||
127 | return $this->itemNodeUuidToCacheData[$uuid]['dataContainer']; |
||
128 | } |
||
129 | } |
||
130 | |||
131 | $query = sprintf('/descendant-or-self::%s/%s', $this->getDefaultRootName(), $this->getXmlEntryName()); |
||
132 | $itemNodes = $resource->xpath($query); |
||
133 | |||
134 | if (0 === count($itemNodes)) { |
||
135 | $itemNodes = $resource->xpath('.'); |
||
136 | } |
||
137 | |||
138 | |||
139 | $index = new DataContainer\Index(); |
||
140 | $dataContainer = new DataContainer\DataContainer($index); |
||
141 | |||
142 | $context = new XmlBuilder\ParserContext(); |
||
143 | $context |
||
144 | ->setIndex($index) |
||
145 | ->setItemNodes($itemNodes) |
||
146 | ->setDataContainer($dataContainer); |
||
147 | |||
148 | $this->parseItem($context); |
||
149 | |||
150 | return $dataContainer; |
||
151 | } |
||
152 | |||
153 | |||
154 | /** |
||
155 | * Обработка набора узлов xml документа, в которых описываются данные для сущности |
||
156 | * |
||
157 | * @param XmlBuilder\ParserContext $context |
||
158 | * |
||
159 | * @return DataContainer\DataContainerInterface |
||
160 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\Exception\RuntimeException |
||
161 | * @throws \Nnx\JmsSerializerModule\DataContainer\Exception\InvalidArgumentException |
||
162 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\XmlBuilder\Exception\InvalidParserContextException |
||
163 | * |
||
164 | */ |
||
165 | protected function parseItem(XmlBuilder\ParserContext $context) |
||
166 | { |
||
167 | $context->validate(); |
||
168 | |||
169 | $itemNodes = $context->getItemNodes(); |
||
170 | $level = $context->getLevel(); |
||
171 | $parentEntity = $context->getParentEntity(); |
||
172 | $parentAssociationName = $context->getParentAssociation(); |
||
173 | $dataContainer = $context->getDataContainer(); |
||
174 | $index = $context->getIndex(); |
||
175 | |||
176 | |||
177 | foreach ($itemNodes as $itemNode) { |
||
178 | $properties = $itemNode->xpath('./*'); |
||
179 | |||
180 | if (0 === count($properties)) { |
||
181 | continue; |
||
182 | } |
||
183 | |||
184 | $entity = new DataContainer\Entity(); |
||
185 | $entity->setLevel($level); |
||
186 | |||
187 | |||
188 | if (!$this->hasUuidAttribute($itemNode)) { |
||
189 | $this->generateUuid($itemNode); |
||
190 | } |
||
191 | $currentUuid = $this->getUuidAttribute($itemNode); |
||
192 | |||
193 | if (!array_key_exists($currentUuid, $this->itemNodeUuidToCacheData)) { |
||
194 | $this->itemNodeUuidToCacheData[$currentUuid] = [ |
||
195 | 'entity' => $entity, |
||
196 | 'dataContainer' => $dataContainer |
||
197 | ]; |
||
198 | } |
||
199 | |||
200 | |||
201 | if (null !== $parentEntity) { |
||
202 | $entity->setParentEntity($parentEntity); |
||
203 | |||
204 | if (!$parentEntity->hasAssociation($parentAssociationName)) { |
||
205 | $association = new DataContainer\Association($index); |
||
206 | $association->setName($parentAssociationName); |
||
207 | $parentEntity->addAssociation($association); |
||
208 | } else { |
||
209 | $association = $parentEntity->getAssociation($parentAssociationName); |
||
210 | } |
||
211 | |||
212 | $association->addEntity($entity); |
||
213 | } else { |
||
214 | $dataContainer->addEntity($entity); |
||
215 | } |
||
216 | |||
217 | $existingProperties = []; |
||
218 | foreach ($properties as $property) { |
||
219 | $propertyName = $property->getName(); |
||
220 | |||
221 | if (array_key_exists($propertyName, $existingProperties)) { |
||
222 | $errMsg = sprintf('Property %s already exists', $propertyName); |
||
223 | throw new Exception\RuntimeException($errMsg); |
||
224 | } |
||
225 | $existingProperties[$propertyName] = $propertyName; |
||
226 | |||
227 | $childElements = $property->xpath('./*'); |
||
228 | |||
229 | if (count($childElements) > 0) { |
||
230 | $childEntryCollection = $property->xpath($this->getChildEntryQuery()); |
||
231 | if (count($childEntryCollection) > 0) { |
||
232 | $childItems = $childEntryCollection; |
||
233 | } else { |
||
234 | $childItems = $property->xpath('.'); |
||
235 | } |
||
236 | |||
237 | $childLevel = $level + 1; |
||
238 | $newContext = new XmlBuilder\ParserContext(); |
||
239 | $newContext |
||
240 | ->setItemNodes($childItems) |
||
241 | ->setParentEntity($entity) |
||
242 | ->setLevel($childLevel) |
||
243 | ->setParentAssociation($propertyName) |
||
244 | ->setDataContainer($context->getDataContainer()) |
||
245 | ->setIndex($context->getIndex()); |
||
246 | |||
247 | $this->parseItem($newContext); |
||
248 | } else { |
||
249 | $propertyValue = (string)$property; |
||
250 | $property = new DataContainer\Property(); |
||
251 | $property |
||
252 | ->setName($propertyName) |
||
253 | ->setValue($propertyValue) |
||
254 | ; |
||
255 | $entity->addProperty($property); |
||
256 | } |
||
257 | } |
||
258 | } |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Определяет есть ли uuid атрибут у элемента |
||
263 | * |
||
264 | * @param SimpleXMLElement $itemNode |
||
265 | * |
||
266 | * @return bool |
||
267 | */ |
||
268 | public function hasUuidAttribute(SimpleXMLElement $itemNode) |
||
269 | { |
||
270 | $uuidAttribute = $this->getDefaultUuidAttribute(); |
||
271 | $attributesItemNode = $itemNode->attributes(); |
||
272 | return isset($attributesItemNode[$uuidAttribute]); |
||
273 | } |
||
274 | |||
275 | |||
276 | /** |
||
277 | * Определяет есть ли uuid атрибут у элемента |
||
278 | * |
||
279 | * @param SimpleXMLElement $itemNode |
||
280 | * |
||
281 | * @return string |
||
282 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\Exception\RuntimeException |
||
283 | */ |
||
284 | public function getUuidAttribute(SimpleXMLElement $itemNode) |
||
285 | { |
||
286 | if (!$this->hasUuidAttribute($itemNode)) { |
||
287 | $errMsg = sprintf('Uuid attribute not found in %s', $itemNode->getName()); |
||
288 | throw new Exception\RuntimeException($errMsg); |
||
289 | } |
||
290 | |||
291 | $uuidAttribute = $this->getDefaultUuidAttribute(); |
||
292 | return (string)$itemNode[$uuidAttribute]; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Генерирует uuid атррибут |
||
297 | * |
||
298 | * @param SimpleXMLElement $itemNode |
||
299 | * |
||
300 | * @return SimpleXMLElement |
||
301 | * @throws \Nnx\JmsSerializerModule\DataContainerBuilder\Exception\RuntimeException |
||
302 | */ |
||
303 | public function generateUuid(SimpleXMLElement $itemNode) |
||
304 | { |
||
305 | if ($this->hasUuidAttribute($itemNode)) { |
||
306 | $errMsg = sprintf('Uuid attribute already exists %s', $itemNode->getName()); |
||
307 | throw new Exception\RuntimeException($errMsg); |
||
308 | } |
||
309 | |||
310 | $uuidAttribute = $this->getDefaultUuidAttribute(); |
||
311 | $uuid = Uuid::uuid4()->toString(); |
||
312 | $itemNode->addAttribute($uuidAttribute, $uuid); |
||
313 | |||
314 | return $itemNode; |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * Возвращает имя корневого тега по умолчанию |
||
319 | * |
||
320 | * @return string |
||
321 | */ |
||
322 | public function getDefaultRootName() |
||
323 | { |
||
324 | return $this->defaultRootName; |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * Устанавливает имя корневого тега по умолчанию |
||
329 | * |
||
330 | * @param string $defaultRootName |
||
331 | * |
||
332 | * @return $this |
||
333 | */ |
||
334 | public function setDefaultRootName($defaultRootName) |
||
335 | { |
||
336 | $this->defaultRootName = $defaultRootName; |
||
337 | |||
338 | return $this; |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Возвращает имя тега являющегося контейнером для сущности |
||
343 | * |
||
344 | * @return string |
||
345 | */ |
||
346 | public function getXmlEntryName() |
||
347 | { |
||
348 | return $this->xmlEntryName; |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Устанавливает имя тега являющегося контейнером для сущности |
||
353 | * |
||
354 | * @param string $xmlEntryName |
||
355 | * |
||
356 | * @return $this |
||
357 | */ |
||
358 | public function setXmlEntryName($xmlEntryName) |
||
359 | { |
||
360 | $this->xmlEntryName = $xmlEntryName; |
||
361 | |||
362 | return $this; |
||
363 | } |
||
364 | |||
365 | /** |
||
366 | * Возвращает Xpath запрос для получения вложенных сущностей |
||
367 | * |
||
368 | * @return string |
||
369 | */ |
||
370 | public function getChildEntryQuery() |
||
371 | { |
||
372 | if (null === $this->childEntryQuery) { |
||
373 | $this->childEntryQuery = sprintf('./%s', $this->getXmlEntryName()); |
||
374 | } |
||
375 | |||
376 | return $this->childEntryQuery; |
||
377 | } |
||
378 | |||
379 | /** |
||
380 | * Возвращает имя атрибута для того что бы связать SimpleXMLElement и контейнер с данными |
||
381 | * |
||
382 | * @return string |
||
383 | */ |
||
384 | public function getDefaultUuidAttribute() |
||
385 | { |
||
386 | return $this->defaultUuidAttribute; |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * Устанавливает имя атрибута для того что бы связать SimpleXMLElement и контейнер с данными |
||
391 | * |
||
392 | * @param string $defaultUuidAttribute |
||
393 | * |
||
394 | * @return $this |
||
395 | */ |
||
396 | public function setDefaultUuidAttribute($defaultUuidAttribute) |
||
397 | { |
||
398 | $this->defaultUuidAttribute = $defaultUuidAttribute; |
||
399 | |||
400 | return $this; |
||
401 | } |
||
402 | } |
||
403 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.