PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.19
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.19
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / vendor / openspout / openspout / src / Reader / Common / XMLProcessor.php

XMLProcessor.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.3.19, at vendor/openspout/openspout/src/Reader/Common/XMLProcessor.php

129 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\OpenSpout\Reader\Common;
4
5 use FluentCart\OpenSpout\Reader\Wrapper\XMLReader;
6 /**
7 * Helps process XML files.
8 */
9 class XMLProcessor
10 {
11 // Node types
12 public const NODE_TYPE_START = XMLReader::ELEMENT;
13 public const NODE_TYPE_END = XMLReader::END_ELEMENT;
14 // Keys associated to reflection attributes to invoke a callback
15 public const CALLBACK_REFLECTION_METHOD = 'reflectionMethod';
16 public const CALLBACK_REFLECTION_OBJECT = 'reflectionObject';
17 // Values returned by the callbacks to indicate what the processor should do next
18 public const PROCESSING_CONTINUE = 1;
19 public const PROCESSING_STOP = 2;
20 /** @var \OpenSpout\Reader\Wrapper\XMLReader The XMLReader object that will help read sheet's XML data */
21 protected $xmlReader;
22 /** @var array Registered callbacks */
23 private $callbacks = [];
24 /**
25 * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object
26 */
27 public function __construct($xmlReader)
28 {
29 $this->xmlReader = $xmlReader;
30 }
31 /**
32 * @param string $nodeName A callback may be triggered when a node with this name is read
33 * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END]
34 * @param callable $callback Callback to execute when the read node has the given name and type
35 *
36 * @return XMLProcessor
37 */
38 public function registerCallback($nodeName, $nodeType, $callback)
39 {
40 $callbackKey = $this->getCallbackKey($nodeName, $nodeType);
41 $this->callbacks[$callbackKey] = $this->getInvokableCallbackData($callback);
42 return $this;
43 }
44 /**
45 * Resumes the reading of the XML file where it was left off.
46 * Stops whenever a callback indicates that reading should stop or at the end of the file.
47 *
48 * @throws \OpenSpout\Reader\Exception\XMLProcessingException
49 */
50 public function readUntilStopped()
51 {
52 while ($this->xmlReader->read()) {
53 $nodeType = $this->xmlReader->nodeType;
54 $nodeNamePossiblyWithPrefix = $this->xmlReader->name;
55 $nodeNameWithoutPrefix = $this->xmlReader->localName;
56 $callbackData = $this->getRegisteredCallbackData($nodeNamePossiblyWithPrefix, $nodeNameWithoutPrefix, $nodeType);
57 if (null !== $callbackData) {
58 $callbackResponse = $this->invokeCallback($callbackData, [$this->xmlReader]);
59 if (self::PROCESSING_STOP === $callbackResponse) {
60 // stop reading
61 break;
62 }
63 }
64 }
65 }
66 /**
67 * @param string $nodeName Name of the node
68 * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END]
69 *
70 * @return string Key used to store the associated callback
71 */
72 private function getCallbackKey($nodeName, $nodeType)
73 {
74 return "{$nodeName}{$nodeType}";
75 }
76 /**
77 * Because the callback can be a "protected" function, we don't want to use call_user_func() directly
78 * but instead invoke the callback using Reflection. This allows the invocation of "protected" functions.
79 * Since some functions can be called a lot, we pre-process the callback to only return the elements that
80 * will be needed to invoke the callback later.
81 *
82 * @param callable $callback Array reference to a callback: [OBJECT, METHOD_NAME]
83 *
84 * @return array Associative array containing the elements needed to invoke the callback using Reflection
85 */
86 private function getInvokableCallbackData($callback)
87 {
88 $callbackObject = $callback[0];
89 $callbackMethodName = $callback[1];
90 $reflectionMethod = new \ReflectionMethod(\get_class($callbackObject), $callbackMethodName);
91 $reflectionMethod->setAccessible(\true);
92 return [self::CALLBACK_REFLECTION_METHOD => $reflectionMethod, self::CALLBACK_REFLECTION_OBJECT => $callbackObject];
93 }
94 /**
95 * @param string $nodeNamePossiblyWithPrefix Name of the node, possibly prefixed
96 * @param string $nodeNameWithoutPrefix Name of the same node, un-prefixed
97 * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END]
98 *
99 * @return null|array Callback data to be used for execution when a node of the given name/type is read or NULL if none found
100 */
101 private function getRegisteredCallbackData($nodeNamePossiblyWithPrefix, $nodeNameWithoutPrefix, $nodeType)
102 {
103 // With prefixed nodes, we should match if (by order of preference):
104 // 1. the callback was registered with the prefixed node name (e.g. "x:worksheet")
105 // 2. the callback was registered with the un-prefixed node name (e.g. "worksheet")
106 $callbackKeyForPossiblyPrefixedName = $this->getCallbackKey($nodeNamePossiblyWithPrefix, $nodeType);
107 $callbackKeyForUnPrefixedName = $this->getCallbackKey($nodeNameWithoutPrefix, $nodeType);
108 $hasPrefix = $nodeNamePossiblyWithPrefix !== $nodeNameWithoutPrefix;
109 $callbackKeyToUse = $callbackKeyForUnPrefixedName;
110 if ($hasPrefix && isset($this->callbacks[$callbackKeyForPossiblyPrefixedName])) {
111 $callbackKeyToUse = $callbackKeyForPossiblyPrefixedName;
112 }
113 // Using isset here because it is way faster than array_key_exists...
114 return $this->callbacks[$callbackKeyToUse] ?? null;
115 }
116 /**
117 * @param array $callbackData Associative array containing data to invoke the callback using Reflection
118 * @param array $args Arguments to pass to the callback
119 *
120 * @return int Callback response
121 */
122 private function invokeCallback($callbackData, $args)
123 {
124 $reflectionMethod = $callbackData[self::CALLBACK_REFLECTION_METHOD];
125 $callbackObject = $callbackData[self::CALLBACK_REFLECTION_OBJECT];
126 return $reflectionMethod->invokeArgs($callbackObject, $args);
127 }
128 }
129