PluginProbe
QuadMenu – Mega Menu / 3.3.8
QuadMenu – Mega Menu v3.3.8
3.3.8 3.3.7 3.3.6 trunk 1.8.4 1.8.5 1.8.7 1.8.8 1.8.9 1.9.0 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 88 releases
quadmenu / vendor / franmastromarino / wp-orm / src / helpers.php

helpers.php in QuadMenu – Mega Menu 3.3.8, at vendor/franmastromarino/wp-orm/src/helpers.php

253 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace QuadLayers\WP_Orm\V2\Helpers;
4
5 use QuadLayers\WP_Orm\Entity\EntityInterface;
6
7 function isAssociativeArray(array $array): bool
8 {
9 if ([] === $array) {
10 return false;
11 }
12 return array_keys($array) !== range(0, count($array) - 1);
13 }
14
15 /**
16 * PHP does not filter out private and protected properties when called from within the same class.
17 * So, we've created this function to call get_object_vars outside class scope.
18 */
19 function getObjectVars($object)
20 {
21 $vars = get_object_vars($object);
22 if ($vars === false) {
23 return [];
24 }
25 return $vars;
26 }
27
28 function getObjectSchema($properties): array
29 {
30 // Initialize the defaults array
31 $schema = [];
32 // Iterate over each public property
33 foreach ($properties as $propertyName => $default) {
34 // Get the type and default value of the property
35 $type = gettype($default);
36 // Add the property to the schema array
37 $schema[$propertyName] = [
38 'type' => $type,
39 'default' => $default
40 ];
41 if ($type === 'object') {
42 $schema[$propertyName]['properties'] = getObjectSchema((array) $default);
43 } elseif ($type === 'array' && isAssociativeArray($default)) {
44 $schema[$propertyName]['properties'] = getObjectSchema($default);
45 }
46 }
47 // Return the schema array
48 return $schema;
49 }
50
51 /**
52 * Recursively compares two arrays and returns the differences between them.
53 *
54 * @param array $array1 The first array to compare.
55 * @param array $array2 The second array to compare.
56 *
57 * @return array The differences between the two arrays.
58 */
59 function arrayRecursiveDiff($array1, $array2)
60 {
61 $result = [];
62
63 foreach ($array2 as $key => $value) {
64 // Condition 1: Check if the key doesn't exist in $array1 or if the values are not equal
65 if (!array_key_exists($key, $array1) || $value !== $array1[$key]) {
66 $result[$key] = $value;
67 }
68 // Condition 2: Check if the value is an array
69 elseif (is_array($value)) {
70 // Recursively compare arrays
71 $recursiveDiff = arrayRecursiveDiff($array1[$key], $value);
72 // Check if there are any differences
73 if (count($recursiveDiff)) {
74 $result[$key] = $recursiveDiff;
75 }
76 }
77 // Condition 3: Check if the value is an object
78 elseif (is_object($value)) {
79 // Convert objects to arrays and recursively compare
80 $recursiveDiff = arrayRecursiveDiff((array)$array1[$key], (array)$value);
81 // Check if there are any differences
82 if (count($recursiveDiff)) {
83 $result[$key] = (object)$recursiveDiff;
84 }
85 }
86 }
87
88 return $result;
89 }
90
91 function getSanitizedData($data, array $schema, bool $strict = false)
92 {
93 if (is_object($data)) {
94 $data = (array)$data;
95 }
96
97 if (!is_array($data)) {
98 throw new \InvalidArgumentException('The data provided should be an array or object');
99 }
100
101 $sanitized = [];
102 foreach ($schema as $key => $property) {
103 if (!isset($data[$key]) || ($strict && gettype($data[$key]) !== $property['type'])) {
104 if (!$strict) {
105 // Check if default is set before assigning.
106 if (array_key_exists('default', $property)) {
107 $sanitized[$key] = $property['default'];
108 }
109 }
110 continue;
111 }
112
113 $value = $data[$key] ?? null;
114
115 switch ($property['type']) {
116 case 'NULL':
117 $sanitized[$key] = null;
118 break;
119 case 'integer':
120 case 'double':
121 case 'number':
122 if (gettype($value) === 'integer' || gettype($value) === 'double') {
123 $sanitized[$key] = $value;
124 } else {
125 $sanitizedValue = filter_var($value, FILTER_VALIDATE_FLOAT);
126 if ($sanitizedValue === false) {
127 // Check if default is set before assigning.
128 if (array_key_exists('default', $property)) {
129 $sanitized[$key] = $property['default'];
130 }
131 } else {
132 // Keep the number as an integer if it has no decimal part
133 $sanitized[$key] = floor($sanitizedValue) == $sanitizedValue ? (int)$sanitizedValue : $sanitizedValue;
134 }
135 }
136 break;
137 case 'string':
138 $sanitized[$key] = (string) $value;
139 break;
140 case 'array':
141 if (is_array($value) || is_object($value)) {
142 if (isset($property['properties'])) {
143 $sanitized[$key] = (array) getSanitizedData($value, $property['properties'], $strict);
144 } else {
145 $sanitized[$key] = (array) $value;
146 }
147 } else {
148 // Check if default is set before assigning.
149 if (array_key_exists('default', $property)) {
150 $sanitized[$key] = $property['default'];
151 }
152 }
153 break;
154 case 'object':
155 if (is_object($value) || is_array($value)) {
156 if (isset($property['properties'])) {
157 $sanitized[$key] = (object) getSanitizedData($value, $property['properties'], $strict);
158 } else {
159 $sanitized[$key] = (object) $value;
160 }
161 } else {
162 // Check if default is set before assigning.
163 if (array_key_exists('default', $property)) {
164 $sanitized[$key] = $property['default'];
165 }
166 }
167 break;
168 // break;
169 case 'boolean':
170 if (is_bool($value)) {
171 $sanitized[$key] = $value;
172 } elseif (is_string($value)) {
173 // Convert 'true'/'false' strings to corresponding boolean values
174 if (strtolower($value) === 'true' || strtolower($value) === '1') {
175 $sanitized[$key] = true;
176 } elseif (strtolower($value) === 'false' || strtolower($value) === '0') {
177 $sanitized[$key] = false;
178 } else {
179 // Check if default is set before assigning.
180 if (array_key_exists('default', $property)) {
181 $sanitized[$key] = $property['default'];
182 }
183 }
184 } else {
185 // Cast non-string values to boolean
186 $sanitized[$key] = (bool)$value;
187 }
188 break;
189 default:
190 throw new \InvalidArgumentException("Unsupported type '{$property['type']}' in schema for key '{$key}'");
191 }
192 }
193
194 return $sanitized;
195 }
196
197 function getSanitizeValue(EntityInterface $entity, $propertyName, $value)
198 {
199 $sanitizeProperties = $entity::$sanitizeProperties;
200
201 if (!isset($sanitizeProperties[$propertyName])) {
202 return $value;
203 }
204
205 return invokeMethod($sanitizeProperties[$propertyName], $value, $entity);
206 }
207
208 function isValidValue(EntityInterface $entity, $propertyName, $value): bool
209 {
210 $validateProperties = $entity::$validateProperties;
211
212 if (empty($validateProperties) || !isset($validateProperties[$propertyName])) {
213 return true;
214 }
215
216 return invokeMethod($validateProperties[$propertyName], $value, $entity);
217 }
218
219 function invokeMethod($method, $value, $context = null)
220 {
221 static $methodCache = [];
222
223 $contextClass = is_object($context) ? get_class($context) : 'global';
224 $cacheKey = is_string($method) ? $method . '@' . $contextClass : json_encode($method);
225
226 if (!isset($methodCache[$cacheKey])) {
227 if (is_string($method)) {
228 if (strpos($method, 'self::') === 0 && $contextClass !== 'global') {
229 $method = [$contextClass, substr($method, 6)];
230 } elseif (strpos($method, '$this->') === 0 && $context) {
231 $method = [$context, substr($method, 7)];
232 } elseif (strpos($method, '::') !== false) {
233 $parts = explode('::', $method);
234 if (class_exists($parts[0])) {
235 $method = $parts;
236 }
237 } else if (function_exists($method)) {
238 $method = $method;
239 } else {
240 throw new \InvalidArgumentException("Unknown function or method reference: $method");
241 }
242 }
243
244 if (!is_callable($method)) {
245 throw new \InvalidArgumentException("Method $cacheKey is not callable.");
246 }
247
248 $methodCache[$cacheKey] = $method;
249 }
250
251 return call_user_func($methodCache[$cacheKey], $value);
252 }
253