PluginProbe
Elementor Website Builder – more than just a page builder / 3.0.0
Elementor Website Builder – more than just a page builder v3.0.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.0.0, at data/manager.php

421 lines 9.2 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 if ( ! $this->is_internal() ) {
122 $logger_manager = \Elementor\Core\Logger\Manager::instance();
123
124 set_error_handler( [ $logger_manager, 'rest_error_handler' ], E_ALL );
125 }
126 }
127
128 /**
129 * Find controller instance.
130 *
131 * By given command name.
132 *
133 * @param string $command
134 *
135 * @return false|\Elementor\Data\Base\Controller
136 */
137 public function find_controller_instance( $command ) {
138 $command_parts = explode( '/', $command );
139 $assumed_command_parts = [];
140
141 foreach ( $command_parts as $command_part ) {
142 $assumed_command_parts [] = $command_part;
143
144 foreach ( $this->controllers as $controller_name => $controller ) {
145 $assumed_command = implode( '/', $assumed_command_parts );
146
147 if ( $assumed_command === $controller_name ) {
148 return $controller;
149 }
150 }
151 }
152
153 return false;
154 }
155
156 /**
157 * Command extract args.
158 *
159 * @param string $command
160 * @param array $args
161 *
162 * @return \stdClass
163 */
164 public function command_extract_args( $command, $args = [] ) {
165 $result = new \stdClass();
166 $result->command = $command;
167 $result->args = $args;
168
169 if ( false !== strpos( $command, '?' ) ) {
170 $command_parts = explode( '?', $command );
171 $pure_command = $command_parts[0];
172 $query_string = $command_parts[1];
173
174 parse_str( $query_string, $temp );
175
176 $result->command = rtrim( $pure_command, '/' );
177 $result->args = array_merge( $args, $temp );
178 }
179
180 return $result;
181 }
182
183 /**
184 * Command to endpoint.
185 *
186 * Format is required otherwise $command will returned.
187 *
188 * @param string $command
189 * @param string $format
190 * @param array $args
191 *
192 * @return string endpoint
193 */
194 public function command_to_endpoint( $command, $format, $args ) {
195 $endpoint = $command;
196
197 if ( $format ) {
198 $formatted = $format;
199
200 array_walk( $args, function ( $val, $key ) use ( &$formatted ) {
201 $formatted = str_replace( '{' . $key . '}', $val, $formatted );
202 } );
203
204 // Remove remaining format if not requested via `$args`.
205 if ( strstr( $formatted, '/{' ) ) {
206 /**
207 * Example:
208 * $command = 'example/documents';
209 * $format = 'example/documents/{document_id}/elements/{element_id}';
210 * $formatted = 'example/documents/1618/elements/{element_id}';
211 * Result:
212 * $formatted = 'example/documents/1618/elements';
213 */
214 $formatted = substr( $formatted, 0, strpos( $formatted, '/{' ) );
215 }
216
217 $endpoint = $formatted;
218 }
219
220 return $endpoint;
221 }
222
223 /**
224 * Run server.
225 *
226 * Init WordPress reset api.
227 *
228 * @return \WP_REST_Server
229 */
230 public function run_server() {
231 /**
232 * If run_server() called means, that rest api is simulated from the backend.
233 */
234 $this->is_internal = true;
235
236 if ( ! $this->server ) {
237 // Remove all 'rest_api_init' actions.
238 remove_all_actions( 'rest_api_init' );
239
240 // Call custom reset api loader.
241 do_action( 'elementor_rest_api_before_init' );
242
243 $this->server = rest_get_server(); // Init API.
244 }
245
246 return $this->server;
247 }
248
249 /**
250 * Kill server.
251 *
252 * Free server and controllers.
253 */
254 public function kill_server() {
255 global $wp_rest_server;
256
257 $this->controllers = [];
258 $this->command_formats = [];
259 $this->server = false;
260 $this->is_internal = false;
261 $this->cache = [];
262 $wp_rest_server = false;
263 }
264
265 /**
266 * Run processor.
267 *
268 * @param \Elementor\Data\Base\Processor $processor
269 * @param array $data
270 *
271 * @return mixed
272 */
273 public function run_processor( $processor, $data ) {
274 if ( call_user_func_array( [ $processor, 'get_conditions' ], $data ) ) {
275 return call_user_func_array( [ $processor, 'apply' ], $data );
276 }
277
278 return null;
279 }
280
281 /**
282 * Run processors.
283 *
284 * Filter them by class.
285 *
286 * @param \Elementor\Data\Base\Processor[] $processors
287 * @param string $filter_by_class
288 * @param array $data
289 *
290 * @return false|array
291 */
292 public function run_processors( $processors, $filter_by_class, $data ) {
293 foreach ( $processors as $processor ) {
294 if ( $processor instanceof $filter_by_class ) {
295 if ( Processor\Before::class === $filter_by_class ) {
296 $this->run_processor( $processor, $data );
297 } elseif ( Processor\After::class === $filter_by_class ) {
298 $result = $this->run_processor( $processor, $data );
299 if ( $result ) {
300 $data[1] = $result;
301 }
302 } else {
303 // TODO: error
304 break;
305 }
306 }
307 }
308
309 return isset( $data[1] ) ? $data[1] : false;
310 }
311
312 /**
313 * Run request.
314 *
315 * Simulate rest API from within the backend.
316 * Use args as query.
317 *
318 * @param string $endpoint
319 * @param array $args
320 * @param string $method
321 *
322 * @return \WP_REST_Response
323 */
324 private function run_request( $endpoint, $args, $method ) {
325 $this->run_server();
326
327 $endpoint = '/' . self::ROOT_NAMESPACE . '/v' . self::VERSION . '/' . $endpoint;
328
329 // Run reset api.
330 $request = new \WP_REST_Request( $method, $endpoint );
331
332 if ( 'GET' === $method ) {
333 $request->set_query_params( $args );
334 } else {
335 $request->set_body_params( $args );
336 }
337
338 return rest_do_request( $request );
339 }
340
341 /**
342 * Run endpoint.
343 *
344 * Wrapper for `$this->run_request` return `$response->getData()` instead of `$response`.
345 *
346 * @param string $endpoint
347 * @param array $args
348 * @param string $method
349 *
350 * @return array
351 */
352 public function run_endpoint( $endpoint, $args = [], $method = 'GET' ) {
353 $response = $this->run_request( $endpoint, $args, $method );
354
355 return $response->get_data();
356 }
357
358 /**
359 * Run ( simulated reset api ).
360 *
361 * Do:
362 * Init reset server.
363 * Run before processors.
364 * Run command as reset api endpoint from internal.
365 * Run after processors.
366 *
367 * @param string $command
368 * @param array $args
369 * @param string $method
370 *
371 * @return array processed result
372 */
373 public function run( $command, $args = [], $method = 'GET' ) {
374 $key = crc32( $command . '-' . wp_json_encode( $args ) . '-' . $method );
375 $cache = $this->get_cache( $key );
376
377 if ( $cache ) {
378 return $cache;
379 }
380
381 $this->run_server();
382
383 $controller_instance = $this->find_controller_instance( $command );
384
385 if ( ! $controller_instance ) {
386 $this->set_cache( $key, [] );
387 return [];
388 }
389
390 $extracted_command = $this->command_extract_args( $command, $args );
391 $command = $extracted_command->command;
392 $args = $extracted_command->args;
393
394 $format = isset( $this->command_formats[ $command ] ) ? $this->command_formats[ $command ] : false;
395
396 $command_processors = $controller_instance->get_processors( $command );
397
398 $endpoint = $this->command_to_endpoint( $command, $format, $args );
399
400 $this->run_processors( $command_processors, Processor\Before::class, [ $args ] );
401
402 $response = $this->run_request( $endpoint, $args, $method );
403 $result = $response->get_data();
404
405 if ( $response->is_error() ) {
406 $this->set_cache( $key, [] );
407 return [];
408 }
409
410 $result = $this->run_processors( $command_processors, Processor\After::class, [ $args, $result ] );
411
412 $this->set_cache( $key, $result );
413
414 return $result;
415 }
416
417 public function is_internal() {
418 return $this->is_internal;
419 }
420 }
421