PluginProbe
Elementor Website Builder – more than just a page builder / 3.1.0
Elementor Website Builder – more than just a page builder v3.1.0
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / data / manager.php

manager.php in Elementor Website Builder – more than just a page builder 3.1.0, at data/manager.php

424 lines 9.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Data;
4
5 use Elementor\Core\Base\Module as BaseModule;
6 use Elementor\Data\Base\Processor;
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit; // Exit if accessed directly
10 }
11
12 class Manager extends BaseModule {
13
14 const ROOT_NAMESPACE = 'elementor';
15
16 const REST_BASE = '';
17
18 const VERSION = '1';
19
20 /**
21 * @var \WP_REST_Server
22 */
23 private $server;
24
25 /**
26 * @var boolean
27 */
28 private $is_internal = false;
29
30 /**
31 * @var array
32 */
33 private $cache = [];
34
35 /**
36 * Loaded controllers.
37 *
38 * @var \Elementor\Data\Base\Controller[]
39 */
40 public $controllers = [];
41
42 /**
43 * Loaded command(s) format.
44 *
45 * @var string[]
46 */
47 public $command_formats = [];
48
49 /**
50 * Fix issue with 'Potentially polymorphic call. The code may be inoperable depending on the actual class instance passed as the argument.'.
51 *
52 * @return \Elementor\Core\Base\Module|\Elementor\Data\Manager
53 */
54 public static function instance() {
55 return ( parent::instance() );
56 }
57
58 public function __construct() {
59 add_action( 'rest_api_init', [ $this, 'register_rest_error_handler' ] );
60 }
61
62 public function get_name() {
63 return 'data-manager';
64 }
65
66 /**
67 * @return \Elementor\Data\Base\Controller[]
68 */
69 public function get_controllers() {
70 return $this->controllers;
71 }
72
73 private function get_cache( $key ) {
74 return self::get_items( $this->cache, $key );
75 }
76
77 private function set_cache( $key, $value ) {
78 $this->cache[ $key ] = $value;
79 }
80
81 /**
82 * Register controller.
83 *
84 * @param string $controller_class_name
85 *
86 * @return \Elementor\Data\Base\Controller
87 */
88 public function register_controller( $controller_class_name ) {
89 $controller_instance = new $controller_class_name();
90
91 return $this->register_controller_instance( $controller_instance );
92 }
93
94 /**
95 * Register controller instance.
96 *
97 * @param \Elementor\Data\Base\Controller $controller_instance
98 *
99 * @return \Elementor\Data\Base\Controller
100 */
101 public function register_controller_instance( $controller_instance ) {
102 // TODO: Validate instance.
103
104 $this->controllers[ $controller_instance->get_name() ] = $controller_instance;
105
106 return $controller_instance;
107 }
108
109 /**
110 * Register endpoint format.
111 *
112 * @param string $command
113 * @param string $format
114 *
115 */
116 public function register_endpoint_format( $command, $format ) {
117 $this->command_formats[ $command ] = rtrim( $format, '/' );
118 }
119
120 public function register_rest_error_handler() {
121 // TODO: Remove - Find better solution.
122 return;
123
124 if ( ! $this->is_internal() ) {
125 $logger_manager = \Elementor\Core\Logger\Manager::instance();
126
127 set_error_handler( [ $logger_manager, 'rest_error_handler' ], E_ALL );
128 }
129 }
130
131 /**
132 * Find controller instance.
133 *
134 * By given command name.
135 *
136 * @param string $command
137 *
138 * @return false|\Elementor\Data\Base\Controller
139 */
140 public function find_controller_instance( $command ) {
141 $command_parts = explode( '/', $command );
142 $assumed_command_parts = [];
143
144 foreach ( $command_parts as $command_part ) {
145 $assumed_command_parts [] = $command_part;
146
147 foreach ( $this->controllers as $controller_name => $controller ) {
148 $assumed_command = implode( '/', $assumed_command_parts );
149
150 if ( $assumed_command === $controller_name ) {
151 return $controller;
152 }
153 }
154 }
155
156 return false;
157 }
158
159 /**
160 * Command extract args.
161 *
162 * @param string $command
163 * @param array $args
164 *
165 * @return \stdClass
166 */
167 public function command_extract_args( $command, $args = [] ) {
168 $result = new \stdClass();
169 $result->command = $command;
170 $result->args = $args;
171
172 if ( false !== strpos( $command, '?' ) ) {
173 $command_parts = explode( '?', $command );
174 $pure_command = $command_parts[0];
175 $query_string = $command_parts[1];
176
177 parse_str( $query_string, $temp );
178
179 $result->command = rtrim( $pure_command, '/' );
180 $result->args = array_merge( $args, $temp );
181 }
182
183 return $result;
184 }
185
186 /**
187 * Command to endpoint.
188 *
189 * Format is required otherwise $command will returned.
190 *
191 * @param string $command
192 * @param string $format
193 * @param array $args
194 *
195 * @return string endpoint
196 */
197 public function command_to_endpoint( $command, $format, $args ) {
198 $endpoint = $command;
199
200 if ( $format ) {
201 $formatted = $format;
202
203 array_walk( $args, function ( $val, $key ) use ( &$formatted ) {
204 $formatted = str_replace( '{' . $key . '}', $val, $formatted );
205 } );
206
207 // Remove remaining format if not requested via `$args`.
208 if ( strstr( $formatted, '/{' ) ) {
209 /**
210 * Example:
211 * $command = 'example/documents';
212 * $format = 'example/documents/{document_id}/elements/{element_id}';
213 * $formatted = 'example/documents/1618/elements/{element_id}';
214 * Result:
215 * $formatted = 'example/documents/1618/elements';
216 */
217 $formatted = substr( $formatted, 0, strpos( $formatted, '/{' ) );
218 }
219
220 $endpoint = $formatted;
221 }
222
223 return $endpoint;
224 }
225
226 /**
227 * Run server.
228 *
229 * Init WordPress reset api.
230 *
231 * @return \WP_REST_Server
232 */
233 public function run_server() {
234 /**
235 * If run_server() called means, that rest api is simulated from the backend.
236 */
237 $this->is_internal = true;
238
239 if ( ! $this->server ) {
240 // Remove all 'rest_api_init' actions.
241 remove_all_actions( 'rest_api_init' );
242
243 // Call custom reset api loader.
244 do_action( 'elementor_rest_api_before_init' );
245
246 $this->server = rest_get_server(); // Init API.
247 }
248
249 return $this->server;
250 }
251
252 /**
253 * Kill server.
254 *
255 * Free server and controllers.
256 */
257 public function kill_server() {
258 global $wp_rest_server;
259
260 $this->controllers = [];
261 $this->command_formats = [];
262 $this->server = false;
263 $this->is_internal = false;
264 $this->cache = [];
265 $wp_rest_server = false;
266 }
267
268 /**
269 * Run processor.
270 *
271 * @param \Elementor\Data\Base\Processor $processor
272 * @param array $data
273 *
274 * @return mixed
275 */
276 public function run_processor( $processor, $data ) {
277 if ( call_user_func_array( [ $processor, 'get_conditions' ], $data ) ) {
278 return call_user_func_array( [ $processor, 'apply' ], $data );
279 }
280
281 return null;
282 }
283
284 /**
285 * Run processors.
286 *
287 * Filter them by class.
288 *
289 * @param \Elementor\Data\Base\Processor[] $processors
290 * @param string $filter_by_class
291 * @param array $data
292 *
293 * @return false|array
294 */
295 public function run_processors( $processors, $filter_by_class, $data ) {
296 foreach ( $processors as $processor ) {
297 if ( $processor instanceof $filter_by_class ) {
298 if ( Processor\Before::class === $filter_by_class ) {
299 $this->run_processor( $processor, $data );
300 } elseif ( Processor\After::class === $filter_by_class ) {
301 $result = $this->run_processor( $processor, $data );
302 if ( $result ) {
303 $data[1] = $result;
304 }
305 } else {
306 // TODO: error
307 break;
308 }
309 }
310 }
311
312 return isset( $data[1] ) ? $data[1] : false;
313 }
314
315 /**
316 * Run request.
317 *
318 * Simulate rest API from within the backend.
319 * Use args as query.
320 *
321 * @param string $endpoint
322 * @param array $args
323 * @param string $method
324 *
325 * @return \WP_REST_Response
326 */
327 private function run_request( $endpoint, $args, $method ) {
328 $this->run_server();
329
330 $endpoint = '/' . self::ROOT_NAMESPACE . '/v' . self::VERSION . '/' . $endpoint;
331
332 // Run reset api.
333 $request = new \WP_REST_Request( $method, $endpoint );
334
335 if ( 'GET' === $method ) {
336 $request->set_query_params( $args );
337 } else {
338 $request->set_body_params( $args );
339 }
340
341 return rest_do_request( $request );
342 }
343
344 /**
345 * Run endpoint.
346 *
347 * Wrapper for `$this->run_request` return `$response->getData()` instead of `$response`.
348 *
349 * @param string $endpoint
350 * @param array $args
351 * @param string $method
352 *
353 * @return array
354 */
355 public function run_endpoint( $endpoint, $args = [], $method = 'GET' ) {
356 $response = $this->run_request( $endpoint, $args, $method );
357
358 return $response->get_data();
359 }
360
361 /**
362 * Run ( simulated reset api ).
363 *
364 * Do:
365 * Init reset server.
366 * Run before processors.
367 * Run command as reset api endpoint from internal.
368 * Run after processors.
369 *
370 * @param string $command
371 * @param array $args
372 * @param string $method
373 *
374 * @return array|false processed result
375 */
376 public function run( $command, $args = [], $method = 'GET' ) {
377 $key = crc32( $command . '-' . wp_json_encode( $args ) . '-' . $method );
378 $cache = $this->get_cache( $key );
379
380 if ( $cache ) {
381 return $cache;
382 }
383
384 $this->run_server();
385
386 $controller_instance = $this->find_controller_instance( $command );
387
388 if ( ! $controller_instance ) {
389 $this->set_cache( $key, [] );
390 return [];
391 }
392
393 $extracted_command = $this->command_extract_args( $command, $args );
394 $command = $extracted_command->command;
395 $args = $extracted_command->args;
396
397 $format = isset( $this->command_formats[ $command ] ) ? $this->command_formats[ $command ] : false;
398
399 $command_processors = $controller_instance->get_processors( $command );
400
401 $endpoint = $this->command_to_endpoint( $command, $format, $args );
402
403 $this->run_processors( $command_processors, Processor\Before::class, [ $args ] );
404
405 $response = $this->run_request( $endpoint, $args, $method );
406 $result = $response->get_data();
407
408 if ( $response->is_error() ) {
409 $this->set_cache( $key, [] );
410 return [];
411 }
412
413 $result = $this->run_processors( $command_processors, Processor\After::class, [ $args, $result ] );
414
415 $this->set_cache( $key, $result );
416
417 return $result;
418 }
419
420 public function is_internal() {
421 return $this->is_internal;
422 }
423 }
424