PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.3
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.3
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Services / Spout / Reader / Common / XMLProcessor.php

XMLProcessor.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.3, at app/Services/Spout/Reader/Common/XMLProcessor.php

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