PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/elementor/data/v2/base/base-route.php

https://gitlab.com/ebrjose/comcebu
PHP | 380 lines | 172 code | 54 blank | 154 comment | 12 complexity | 06239a4dc0a7e517d999c108fcc3cad5 MD5 | raw file
  1. <?php
  2. namespace Elementor\Data\V2\Base;
  3. use Elementor\Data\V2\Base\Exceptions\Data_Exception;
  4. use Elementor\Data\V2\Base\Exceptions\Error_500;
  5. use WP_REST_Server;
  6. if ( ! defined( 'ABSPATH' ) ) {
  7. exit; // Exit if accessed directly
  8. }
  9. /**
  10. * Class purpose is to separate routing logic into one file.
  11. */
  12. abstract class Base_Route {
  13. const AVAILABLE_METHODS = [
  14. WP_REST_Server::READABLE,
  15. WP_REST_Server::CREATABLE,
  16. WP_REST_Server::EDITABLE,
  17. WP_REST_Server::DELETABLE,
  18. WP_REST_Server::ALLMETHODS,
  19. ];
  20. /**
  21. * Controller of current endpoint.
  22. *
  23. * @var \Elementor\Data\V2\Base\Controller
  24. */
  25. protected $controller;
  26. /**
  27. * Current route, effect only in case the endpoint behave like sub-endpoint.
  28. *
  29. * @var string
  30. */
  31. protected $route;
  32. /**
  33. * All register routes.
  34. *
  35. * @var array
  36. */
  37. protected $routes = [];
  38. /**
  39. * Registered item route.
  40. *
  41. * @var array|null
  42. */
  43. protected $item_route = null;
  44. protected $id_arg_name = 'id';
  45. protected $id_arg_type_regex = '[\d]+';
  46. /**
  47. * Ensure start-with and end-with slashes.
  48. *
  49. * '/' => '/'
  50. * 'abc' => '/abc/'
  51. * '/abc' => '/abc/'
  52. * 'abc/' => '/abc/'
  53. * '/abc/' => '/abc/'
  54. *
  55. * @param string $route
  56. *
  57. * @return string
  58. */
  59. private function ensure_slashes( $route ) {
  60. if ( '/' !== $route[0] ) {
  61. $route = '/' . $route;
  62. }
  63. return trailingslashit( $route );
  64. }
  65. /**
  66. * Get base route.
  67. * This method should always return the base route starts with '/' and ends without '/'.
  68. *
  69. * @return string
  70. */
  71. public function get_base_route() {
  72. $name = $this->get_public_name();
  73. $parent = $this->get_parent();
  74. $parent_base = $parent->get_base_route();
  75. $route = '/';
  76. if ( ! ( $parent instanceof Controller ) ) {
  77. $route = $parent->item_route ? $parent->item_route['route'] . '/' : $this->route;
  78. }
  79. return untrailingslashit( '/' . trim( $parent_base . $route . $name, '/' ) );
  80. }
  81. /**
  82. * Get permission callback.
  83. *
  84. * By default get permission callback from the controller.
  85. *
  86. * @param \WP_REST_Request $request Full data about the request.
  87. *
  88. * @return boolean
  89. */
  90. public function get_permission_callback( $request ) {
  91. return $this->controller->get_permission_callback( $request );
  92. }
  93. /**
  94. * Retrieves a collection of items.
  95. *
  96. * @param \WP_REST_Request $request Full data about the request.
  97. *
  98. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  99. */
  100. protected function get_items( $request ) {
  101. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  102. }
  103. /**
  104. * Retrieves one item from the collection.
  105. *
  106. * @param string $id
  107. * @param \WP_REST_Request $request Full data about the request.
  108. *
  109. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  110. */
  111. protected function get_item( $id, $request ) {
  112. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  113. }
  114. /**
  115. * Creates multiple items.
  116. *
  117. * @param \WP_REST_Request $request Full data about the request.
  118. *
  119. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  120. */
  121. protected function create_items( $request ) {
  122. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  123. }
  124. /**
  125. * Creates one item.
  126. *
  127. * @param string $id id of request item.
  128. * @param \WP_REST_Request $request Full data about the request.
  129. *
  130. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  131. */
  132. protected function create_item( $id, $request ) {
  133. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  134. }
  135. /**
  136. * Updates multiple items.
  137. *
  138. * @param \WP_REST_Request $request Full data about the request.
  139. *
  140. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  141. */
  142. protected function update_items( $request ) {
  143. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  144. }
  145. /**
  146. * Updates one item.
  147. *
  148. * @param string $id id of request item.
  149. * @param \WP_REST_Request $request Full data about the request.
  150. *
  151. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  152. */
  153. protected function update_item( $id, $request ) {
  154. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  155. }
  156. /**
  157. * Delete multiple items.
  158. *
  159. * @param \WP_REST_Request $request Full data about the request.
  160. *
  161. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  162. */
  163. protected function delete_items( $request ) {
  164. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  165. }
  166. /**
  167. * Delete one item.
  168. *
  169. * @param string $id id of request item.
  170. * @param \WP_REST_Request $request Full data about the request.
  171. *
  172. * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure.
  173. */
  174. protected function delete_item( $id, $request ) {
  175. return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] );
  176. }
  177. /**
  178. * Register the endpoint.
  179. *
  180. * By default: register get items route.
  181. */
  182. protected function register() {
  183. $this->register_items_route();
  184. }
  185. protected function register_route( $route = '', $methods = WP_REST_Server::READABLE, $args = [] ) {
  186. if ( ! in_array( $methods, self::AVAILABLE_METHODS, true ) ) {
  187. trigger_error( "Invalid method: '$methods'.", E_USER_ERROR ); // phpcs:ignore
  188. }
  189. $route = $this->get_base_route() . $route;
  190. $this->routes [] = [
  191. 'args' => $args,
  192. 'route' => $route,
  193. ];
  194. /**
  195. * Determine behaviour of `base_callback()` and `get_permission_callback()`:
  196. * For `base_callback()` which applying the action.
  197. * Whether it's a one item request and should call `get_item_permission_callback()` or it's mutil items request and should call `get_items_permission_callback()`.
  198. */
  199. $is_multi = ! empty( $args['is_multi'] );
  200. if ( $is_multi ) {
  201. unset( $args['is_multi'] );
  202. }
  203. $callback = function ( $request ) use ( $methods, $args, $is_multi ) {
  204. return $this->base_callback( $methods, $request, $is_multi );
  205. };
  206. return register_rest_route( $this->controller->get_namespace(), $route, [
  207. [
  208. 'args' => $args,
  209. 'methods' => $methods,
  210. 'callback' => $callback,
  211. 'permission_callback' => function ( $request ) {
  212. return $this->get_permission_callback( $request );
  213. },
  214. ],
  215. ] );
  216. }
  217. /**
  218. * Register items route.
  219. *
  220. * @param string $methods
  221. * @param array $args
  222. */
  223. public function register_items_route( $methods = WP_REST_Server::READABLE, $args = [] ) {
  224. $args['is_multi'] = true;
  225. $this->register_route( '', $methods, $args );
  226. }
  227. /**
  228. * Register item route.
  229. *
  230. * @param string $route
  231. * @param array $args
  232. * @param string $methods
  233. */
  234. public function register_item_route( $methods = WP_REST_Server::READABLE, $args = [], $route = '/' ) {
  235. if ( ! empty( $args['id_arg_name'] ) ) {
  236. $this->id_arg_name = $args['id_arg_name'];
  237. unset( $args['id_arg_name'] );
  238. }
  239. if ( ! empty( $args['id_arg_type_regex'] ) ) {
  240. $this->id_arg_type_regex = $args['id_arg_type_regex'];
  241. unset( $args['id_arg_type_regex'] );
  242. }
  243. $args = array_merge( [
  244. $this->id_arg_name => [
  245. 'description' => 'Unique identifier for the object.',
  246. 'type' => 'string',
  247. 'required' => true,
  248. ],
  249. ], $args );
  250. $route .= '(?P<' . $this->id_arg_name . '>' . $this->id_arg_type_regex . ')';
  251. $this->item_route = [
  252. 'args' => $args,
  253. 'route' => $route,
  254. ];
  255. $this->register_route( $route, $methods, $args );
  256. }
  257. /**
  258. * Base callback.
  259. * All reset requests from the client should pass this function.
  260. *
  261. * @param string $methods
  262. * @param \WP_REST_Request $request
  263. * @param bool $is_multi
  264. * @param array $args
  265. *
  266. * @return mixed|\WP_Error|\WP_HTTP_Response|\WP_REST_Response
  267. */
  268. public function base_callback( $methods, $request, $is_multi = false, $args = [] ) {
  269. if ( $request ) {
  270. $json_params = $request->get_json_params();
  271. if ( $json_params ) {
  272. $request->set_body_params( $json_params );
  273. }
  274. }
  275. $args = wp_parse_args( $args, [
  276. 'is_debug' => defined( 'WP_DEBUG' ),
  277. ] );
  278. $result = new \WP_Error( 'invalid_methods', 'route not supported.' );
  279. $request->set_param( 'is_multi', $is_multi );
  280. try {
  281. switch ( $methods ) {
  282. case WP_REST_Server::READABLE:
  283. $result = $is_multi ? $this->get_items( $request ) : $this->get_item( $request->get_param( 'id' ), $request );
  284. break;
  285. case WP_REST_Server::CREATABLE:
  286. $result = $is_multi ? $this->create_items( $request ) : $this->create_item( $request->get_param( 'id' ), $request );
  287. break;
  288. case WP_REST_Server::EDITABLE:
  289. $result = $is_multi ? $this->update_items( $request ) : $this->update_item( $request->get_param( 'id' ), $request );
  290. break;
  291. case WP_REST_Server::DELETABLE:
  292. $result = $is_multi ? $this->delete_items( $request ) : $this->delete_item( $request->get_param( 'id' ), $request );
  293. break;
  294. }
  295. } catch ( Data_Exception $e ) {
  296. $result = $e->to_wp_error();
  297. } catch ( \Exception $e ) {
  298. if ( empty( $args['is_debug'] ) ) {
  299. $result = ( new Error_500() )->to_wp_error();
  300. } else {
  301. // For frontend.
  302. $exception_mapping = [
  303. 'trace' => $e->getTrace(),
  304. 'file' => $e->getFile(),
  305. 'line' => $e->getLine(),
  306. ];
  307. $e->debug = $exception_mapping;
  308. $result = ( new Data_Exception( $e->getMessage(), $e->getCode(), $e ) )->to_wp_error();
  309. }
  310. }
  311. return rest_ensure_response( $result );
  312. }
  313. /**
  314. * Constructor.
  315. *
  316. * run `$this->register()`.
  317. *
  318. * @param \Elementor\Data\V2\Base\Controller $controller
  319. * @param string $route
  320. */
  321. protected function __construct( Controller $controller, $route ) {
  322. $this->controller = $controller;
  323. $this->route = $this->ensure_slashes( $route );
  324. $this->register();
  325. }
  326. }