@@ -22,1268 +22,1268 @@ |
||
22 | 22 | class EED_Core_Rest_Api extends \EED_Module |
23 | 23 | { |
24 | 24 | |
25 | - const ee_api_namespace = Domain::API_NAMESPACE; |
|
26 | - |
|
27 | - const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/'; |
|
28 | - |
|
29 | - const saved_routes_option_names = 'ee_core_routes'; |
|
30 | - |
|
31 | - /** |
|
32 | - * string used in _links response bodies to make them globally unique. |
|
33 | - * |
|
34 | - * @see http://v2.wp-api.org/extending/linking/ |
|
35 | - */ |
|
36 | - const ee_api_link_namespace = 'https://api.eventespresso.com/'; |
|
37 | - |
|
38 | - /** |
|
39 | - * @var CalculatedModelFields |
|
40 | - */ |
|
41 | - protected static $_field_calculator; |
|
42 | - |
|
43 | - |
|
44 | - /** |
|
45 | - * @return EED_Core_Rest_Api|EED_Module |
|
46 | - */ |
|
47 | - public static function instance() |
|
48 | - { |
|
49 | - self::$_field_calculator = new CalculatedModelFields(); |
|
50 | - return parent::get_instance(__CLASS__); |
|
51 | - } |
|
52 | - |
|
53 | - |
|
54 | - /** |
|
55 | - * set_hooks - for hooking into EE Core, other modules, etc |
|
56 | - * |
|
57 | - * @access public |
|
58 | - * @return void |
|
59 | - */ |
|
60 | - public static function set_hooks() |
|
61 | - { |
|
62 | - self::set_hooks_both(); |
|
63 | - } |
|
64 | - |
|
65 | - |
|
66 | - /** |
|
67 | - * set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
|
68 | - * |
|
69 | - * @access public |
|
70 | - * @return void |
|
71 | - */ |
|
72 | - public static function set_hooks_admin() |
|
73 | - { |
|
74 | - self::set_hooks_both(); |
|
75 | - } |
|
76 | - |
|
77 | - |
|
78 | - public static function set_hooks_both() |
|
79 | - { |
|
80 | - add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10); |
|
81 | - add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5); |
|
82 | - add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2); |
|
83 | - add_filter( |
|
84 | - 'rest_index', |
|
85 | - array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex') |
|
86 | - ); |
|
87 | - EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change(); |
|
88 | - } |
|
89 | - |
|
90 | - |
|
91 | - /** |
|
92 | - * sets up hooks which only need to be included as part of REST API requests; |
|
93 | - * other requests like to the frontend or admin etc don't need them |
|
94 | - * |
|
95 | - * @throws \EE_Error |
|
96 | - */ |
|
97 | - public static function set_hooks_rest_api() |
|
98 | - { |
|
99 | - // set hooks which account for changes made to the API |
|
100 | - EED_Core_Rest_Api::_set_hooks_for_changes(); |
|
101 | - } |
|
102 | - |
|
103 | - |
|
104 | - /** |
|
105 | - * public wrapper of _set_hooks_for_changes. |
|
106 | - * Loads all the hooks which make requests to old versions of the API |
|
107 | - * appear the same as they always did |
|
108 | - * |
|
109 | - * @throws EE_Error |
|
110 | - */ |
|
111 | - public static function set_hooks_for_changes() |
|
112 | - { |
|
113 | - self::_set_hooks_for_changes(); |
|
114 | - } |
|
115 | - |
|
116 | - |
|
117 | - /** |
|
118 | - * Loads all the hooks which make requests to old versions of the API |
|
119 | - * appear the same as they always did |
|
120 | - * |
|
121 | - * @throws EE_Error |
|
122 | - */ |
|
123 | - protected static function _set_hooks_for_changes() |
|
124 | - { |
|
125 | - $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false); |
|
126 | - foreach ($folder_contents as $classname_in_namespace => $filepath) { |
|
127 | - // ignore the base parent class |
|
128 | - // and legacy named classes |
|
129 | - if ($classname_in_namespace === 'ChangesInBase' |
|
130 | - || strpos($classname_in_namespace, 'Changes_In_') === 0 |
|
131 | - ) { |
|
132 | - continue; |
|
133 | - } |
|
134 | - $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace; |
|
135 | - if (class_exists($full_classname)) { |
|
136 | - $instance_of_class = new $full_classname; |
|
137 | - if ($instance_of_class instanceof ChangesInBase) { |
|
138 | - $instance_of_class->setHooks(); |
|
139 | - } |
|
140 | - } |
|
141 | - } |
|
142 | - } |
|
143 | - |
|
144 | - |
|
145 | - /** |
|
146 | - * Filters the WP routes to add our EE-related ones. This takes a bit of time |
|
147 | - * so we actually prefer to only do it when an EE plugin is activated or upgraded |
|
148 | - * |
|
149 | - * @throws \EE_Error |
|
150 | - */ |
|
151 | - public static function register_routes() |
|
152 | - { |
|
153 | - foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) { |
|
154 | - foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) { |
|
155 | - /** |
|
156 | - * @var array $data_for_multiple_endpoints numerically indexed array |
|
157 | - * but can also contain route options like { |
|
158 | - * @type array $schema { |
|
159 | - * @type callable $schema_callback |
|
160 | - * @type array $callback_args arguments that will be passed to the callback, after the |
|
161 | - * WP_REST_Request of course |
|
162 | - * } |
|
163 | - * } |
|
164 | - */ |
|
165 | - // when registering routes, register all the endpoints' data at the same time |
|
166 | - $multiple_endpoint_args = array(); |
|
167 | - foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) { |
|
168 | - /** |
|
169 | - * @var array $data_for_single_endpoint { |
|
170 | - * @type callable $callback |
|
171 | - * @type string methods |
|
172 | - * @type array args |
|
173 | - * @type array _links |
|
174 | - * @type array $callback_args arguments that will be passed to the callback, after the |
|
175 | - * WP_REST_Request of course |
|
176 | - * } |
|
177 | - */ |
|
178 | - // skip route options |
|
179 | - if (! is_numeric($endpoint_key)) { |
|
180 | - continue; |
|
181 | - } |
|
182 | - if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) { |
|
183 | - throw new EE_Error( |
|
184 | - esc_html__( |
|
185 | - // @codingStandardsIgnoreStart |
|
186 | - 'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).', |
|
187 | - // @codingStandardsIgnoreEnd |
|
188 | - 'event_espresso' |
|
189 | - ) |
|
190 | - ); |
|
191 | - } |
|
192 | - $callback = $data_for_single_endpoint['callback']; |
|
193 | - $single_endpoint_args = array( |
|
194 | - 'methods' => $data_for_single_endpoint['methods'], |
|
195 | - 'args' => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args'] |
|
196 | - : array(), |
|
197 | - ); |
|
198 | - if (isset($data_for_single_endpoint['_links'])) { |
|
199 | - $single_endpoint_args['_links'] = $data_for_single_endpoint['_links']; |
|
200 | - } |
|
201 | - if (isset($data_for_single_endpoint['callback_args'])) { |
|
202 | - $callback_args = $data_for_single_endpoint['callback_args']; |
|
203 | - $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use ( |
|
204 | - $callback, |
|
205 | - $callback_args |
|
206 | - ) { |
|
207 | - array_unshift($callback_args, $request); |
|
208 | - return call_user_func_array( |
|
209 | - $callback, |
|
210 | - $callback_args |
|
211 | - ); |
|
212 | - }; |
|
213 | - } else { |
|
214 | - $single_endpoint_args['callback'] = $data_for_single_endpoint['callback']; |
|
215 | - } |
|
216 | - $multiple_endpoint_args[] = $single_endpoint_args; |
|
217 | - } |
|
218 | - if (isset($data_for_multiple_endpoints['schema'])) { |
|
219 | - $schema_route_data = $data_for_multiple_endpoints['schema']; |
|
220 | - $schema_callback = $schema_route_data['schema_callback']; |
|
221 | - $callback_args = $schema_route_data['callback_args']; |
|
222 | - $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) { |
|
223 | - return call_user_func_array( |
|
224 | - $schema_callback, |
|
225 | - $callback_args |
|
226 | - ); |
|
227 | - }; |
|
228 | - } |
|
229 | - register_rest_route( |
|
230 | - $namespace, |
|
231 | - $relative_route, |
|
232 | - $multiple_endpoint_args |
|
233 | - ); |
|
234 | - } |
|
235 | - } |
|
236 | - } |
|
237 | - |
|
238 | - |
|
239 | - /** |
|
240 | - * Checks if there was a version change or something that merits invalidating the cached |
|
241 | - * route data. If so, invalidates the cached route data so that it gets refreshed |
|
242 | - * next time the WP API is used |
|
243 | - */ |
|
244 | - public static function invalidate_cached_route_data_on_version_change() |
|
245 | - { |
|
246 | - if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) { |
|
247 | - EED_Core_Rest_Api::invalidate_cached_route_data(); |
|
248 | - } |
|
249 | - foreach (EE_Registry::instance()->addons as $addon) { |
|
250 | - if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) { |
|
251 | - EED_Core_Rest_Api::invalidate_cached_route_data(); |
|
252 | - } |
|
253 | - } |
|
254 | - } |
|
255 | - |
|
256 | - |
|
257 | - /** |
|
258 | - * Removes the cached route data so it will get refreshed next time the WP API is used |
|
259 | - */ |
|
260 | - public static function invalidate_cached_route_data() |
|
261 | - { |
|
262 | - // delete the saved EE REST API routes |
|
263 | - foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) { |
|
264 | - delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version); |
|
265 | - } |
|
266 | - } |
|
267 | - |
|
268 | - |
|
269 | - /** |
|
270 | - * Gets the EE route data |
|
271 | - * |
|
272 | - * @return array top-level key is the namespace, next-level key is the route and its value is array{ |
|
273 | - * @throws \EE_Error |
|
274 | - * @type string|array $callback |
|
275 | - * @type string $methods |
|
276 | - * @type boolean $hidden_endpoint |
|
277 | - * } |
|
278 | - */ |
|
279 | - public static function get_ee_route_data() |
|
280 | - { |
|
281 | - $ee_routes = array(); |
|
282 | - foreach (self::versions_served() as $version => $hidden_endpoints) { |
|
283 | - $ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version( |
|
284 | - $version, |
|
285 | - $hidden_endpoints |
|
286 | - ); |
|
287 | - } |
|
288 | - return $ee_routes; |
|
289 | - } |
|
290 | - |
|
291 | - |
|
292 | - /** |
|
293 | - * Gets the EE route data from the wp options if it exists already, |
|
294 | - * otherwise re-generates it and saves it to the option |
|
295 | - * |
|
296 | - * @param string $version |
|
297 | - * @param boolean $hidden_endpoints |
|
298 | - * @return array |
|
299 | - * @throws \EE_Error |
|
300 | - */ |
|
301 | - protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false) |
|
302 | - { |
|
303 | - $ee_routes = get_option(self::saved_routes_option_names . $version, null); |
|
304 | - if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) { |
|
305 | - $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints); |
|
306 | - } |
|
307 | - return $ee_routes; |
|
308 | - } |
|
309 | - |
|
310 | - |
|
311 | - /** |
|
312 | - * Saves the EE REST API route data to a wp option and returns it |
|
313 | - * |
|
314 | - * @param string $version |
|
315 | - * @param boolean $hidden_endpoints |
|
316 | - * @return mixed|null |
|
317 | - * @throws \EE_Error |
|
318 | - */ |
|
319 | - protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false) |
|
320 | - { |
|
321 | - $instance = self::instance(); |
|
322 | - $routes = apply_filters( |
|
323 | - 'EED_Core_Rest_Api__save_ee_route_data_for_version__routes', |
|
324 | - array_replace_recursive( |
|
325 | - $instance->_get_config_route_data_for_version($version, $hidden_endpoints), |
|
326 | - $instance->_get_meta_route_data_for_version($version, $hidden_endpoints), |
|
327 | - $instance->_get_model_route_data_for_version($version, $hidden_endpoints), |
|
328 | - $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints) |
|
329 | - ) |
|
330 | - ); |
|
331 | - $option_name = self::saved_routes_option_names . $version; |
|
332 | - if (get_option($option_name)) { |
|
333 | - update_option($option_name, $routes, true); |
|
334 | - } else { |
|
335 | - add_option($option_name, $routes, null, 'no'); |
|
336 | - } |
|
337 | - return $routes; |
|
338 | - } |
|
339 | - |
|
340 | - |
|
341 | - /** |
|
342 | - * Calculates all the EE routes and saves it to a WordPress option so we don't |
|
343 | - * need to calculate it on every request |
|
344 | - * |
|
345 | - * @deprecated since version 4.9.1 |
|
346 | - * @return void |
|
347 | - */ |
|
348 | - public static function save_ee_routes() |
|
349 | - { |
|
350 | - if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
351 | - $instance = self::instance(); |
|
352 | - $routes = apply_filters( |
|
353 | - 'EED_Core_Rest_Api__save_ee_routes__routes', |
|
354 | - array_replace_recursive( |
|
355 | - $instance->_register_config_routes(), |
|
356 | - $instance->_register_meta_routes(), |
|
357 | - $instance->_register_model_routes(), |
|
358 | - $instance->_register_rpc_routes() |
|
359 | - ) |
|
360 | - ); |
|
361 | - update_option(self::saved_routes_option_names, $routes, true); |
|
362 | - } |
|
363 | - } |
|
364 | - |
|
365 | - |
|
366 | - /** |
|
367 | - * Gets all the route information relating to EE models |
|
368 | - * |
|
369 | - * @return array @see get_ee_route_data |
|
370 | - * @deprecated since version 4.9.1 |
|
371 | - */ |
|
372 | - protected function _register_model_routes() |
|
373 | - { |
|
374 | - $model_routes = array(); |
|
375 | - foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
376 | - $model_routes[ EED_Core_Rest_Api::ee_api_namespace |
|
377 | - . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint); |
|
378 | - } |
|
379 | - return $model_routes; |
|
380 | - } |
|
381 | - |
|
382 | - |
|
383 | - /** |
|
384 | - * Decides whether or not to add write endpoints for this model. |
|
385 | - * |
|
386 | - * Currently, this defaults to exclude all global tables and models |
|
387 | - * which would allow inserting WP core data (we don't want to duplicate |
|
388 | - * what WP API does, as it's unnecessary, extra work, and potentially extra bugs) |
|
389 | - * |
|
390 | - * @param EEM_Base $model |
|
391 | - * @return bool |
|
392 | - */ |
|
393 | - public static function should_have_write_endpoints(EEM_Base $model) |
|
394 | - { |
|
395 | - if ($model->is_wp_core_model()) { |
|
396 | - return false; |
|
397 | - } |
|
398 | - foreach ($model->get_tables() as $table) { |
|
399 | - if ($table->is_global()) { |
|
400 | - return false; |
|
401 | - } |
|
402 | - } |
|
403 | - return true; |
|
404 | - } |
|
405 | - |
|
406 | - |
|
407 | - /** |
|
408 | - * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`) |
|
409 | - * in this versioned namespace of EE4 |
|
410 | - * |
|
411 | - * @param $version |
|
412 | - * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event') |
|
413 | - */ |
|
414 | - public static function model_names_with_plural_routes($version) |
|
415 | - { |
|
416 | - $model_version_info = new ModelVersionInfo($version); |
|
417 | - $models_to_register = $model_version_info->modelsForRequestedVersion(); |
|
418 | - // let's not bother having endpoints for extra metas |
|
419 | - unset( |
|
420 | - $models_to_register['Extra_Meta'], |
|
421 | - $models_to_register['Extra_Join'], |
|
422 | - $models_to_register['Post_Meta'] |
|
423 | - ); |
|
424 | - return apply_filters( |
|
425 | - 'FHEE__EED_Core_REST_API___register_model_routes', |
|
426 | - $models_to_register |
|
427 | - ); |
|
428 | - } |
|
429 | - |
|
430 | - |
|
431 | - /** |
|
432 | - * Gets the route data for EE models in the specified version |
|
433 | - * |
|
434 | - * @param string $version |
|
435 | - * @param boolean $hidden_endpoint |
|
436 | - * @return array |
|
437 | - * @throws EE_Error |
|
438 | - */ |
|
439 | - protected function _get_model_route_data_for_version($version, $hidden_endpoint = false) |
|
440 | - { |
|
441 | - $model_routes = array(); |
|
442 | - $model_version_info = new ModelVersionInfo($version); |
|
443 | - foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) { |
|
444 | - $model = \EE_Registry::instance()->load_model($model_name); |
|
445 | - // if this isn't a valid model then let's skip iterate to the next item in the loop. |
|
446 | - if (! $model instanceof EEM_Base) { |
|
447 | - continue; |
|
448 | - } |
|
449 | - // yes we could just register one route for ALL models, but then they wouldn't show up in the index |
|
450 | - $plural_model_route = EED_Core_Rest_Api::get_collection_route($model); |
|
451 | - $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)'); |
|
452 | - $model_routes[ $plural_model_route ] = array( |
|
453 | - array( |
|
454 | - 'callback' => array( |
|
455 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
456 | - 'handleRequestGetAll', |
|
457 | - ), |
|
458 | - 'callback_args' => array($version, $model_name), |
|
459 | - 'methods' => WP_REST_Server::READABLE, |
|
460 | - 'hidden_endpoint' => $hidden_endpoint, |
|
461 | - 'args' => $this->_get_read_query_params($model, $version), |
|
462 | - '_links' => array( |
|
463 | - 'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route), |
|
464 | - ), |
|
465 | - ), |
|
466 | - 'schema' => array( |
|
467 | - 'schema_callback' => array( |
|
468 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
469 | - 'handleSchemaRequest', |
|
470 | - ), |
|
471 | - 'callback_args' => array($version, $model_name), |
|
472 | - ), |
|
473 | - ); |
|
474 | - $model_routes[ $singular_model_route ] = array( |
|
475 | - array( |
|
476 | - 'callback' => array( |
|
477 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
478 | - 'handleRequestGetOne', |
|
479 | - ), |
|
480 | - 'callback_args' => array($version, $model_name), |
|
481 | - 'methods' => WP_REST_Server::READABLE, |
|
482 | - 'hidden_endpoint' => $hidden_endpoint, |
|
483 | - 'args' => $this->_get_response_selection_query_params($model, $version), |
|
484 | - ), |
|
485 | - ); |
|
486 | - if (apply_filters( |
|
487 | - 'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints', |
|
488 | - EED_Core_Rest_Api::should_have_write_endpoints($model), |
|
489 | - $model |
|
490 | - )) { |
|
491 | - $model_routes[ $plural_model_route ][] = array( |
|
492 | - 'callback' => array( |
|
493 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Write', |
|
494 | - 'handleRequestInsert', |
|
495 | - ), |
|
496 | - 'callback_args' => array($version, $model_name), |
|
497 | - 'methods' => WP_REST_Server::CREATABLE, |
|
498 | - 'hidden_endpoint' => $hidden_endpoint, |
|
499 | - 'args' => $this->_get_write_params($model_name, $model_version_info, true), |
|
500 | - ); |
|
501 | - $model_routes[ $singular_model_route ] = array_merge( |
|
502 | - $model_routes[ $singular_model_route ], |
|
503 | - array( |
|
504 | - array( |
|
505 | - 'callback' => array( |
|
506 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Write', |
|
507 | - 'handleRequestUpdate', |
|
508 | - ), |
|
509 | - 'callback_args' => array($version, $model_name), |
|
510 | - 'methods' => WP_REST_Server::EDITABLE, |
|
511 | - 'hidden_endpoint' => $hidden_endpoint, |
|
512 | - 'args' => $this->_get_write_params($model_name, $model_version_info), |
|
513 | - ), |
|
514 | - array( |
|
515 | - 'callback' => array( |
|
516 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Write', |
|
517 | - 'handleRequestDelete', |
|
518 | - ), |
|
519 | - 'callback_args' => array($version, $model_name), |
|
520 | - 'methods' => WP_REST_Server::DELETABLE, |
|
521 | - 'hidden_endpoint' => $hidden_endpoint, |
|
522 | - 'args' => $this->_get_delete_query_params($model, $version), |
|
523 | - ), |
|
524 | - ) |
|
525 | - ); |
|
526 | - } |
|
527 | - foreach ($model->relation_settings() as $relation_name => $relation_obj) { |
|
528 | - $related_route = EED_Core_Rest_Api::get_relation_route_via( |
|
529 | - $model, |
|
530 | - '(?P<id>[^\/]+)', |
|
531 | - $relation_obj |
|
532 | - ); |
|
533 | - $endpoints = array( |
|
534 | - array( |
|
535 | - 'callback' => array( |
|
536 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
537 | - 'handleRequestGetRelated', |
|
538 | - ), |
|
539 | - 'callback_args' => array($version, $model_name, $relation_name), |
|
540 | - 'methods' => WP_REST_Server::READABLE, |
|
541 | - 'hidden_endpoint' => $hidden_endpoint, |
|
542 | - 'args' => $this->_get_read_query_params($relation_obj->get_other_model(), $version), |
|
543 | - ), |
|
544 | - ); |
|
545 | - $model_routes[ $related_route ] = $endpoints; |
|
546 | - } |
|
547 | - } |
|
548 | - return $model_routes; |
|
549 | - } |
|
550 | - |
|
551 | - |
|
552 | - /** |
|
553 | - * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace, |
|
554 | - * excluding the preceding slash. |
|
555 | - * Eg you pass get_plural_route_to('Event') = 'events' |
|
556 | - * |
|
557 | - * @param EEM_Base $model |
|
558 | - * @return string |
|
559 | - */ |
|
560 | - public static function get_collection_route(EEM_Base $model) |
|
561 | - { |
|
562 | - return EEH_Inflector::pluralize_and_lower($model->get_this_model_name()); |
|
563 | - } |
|
564 | - |
|
565 | - |
|
566 | - /** |
|
567 | - * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace, |
|
568 | - * excluding the preceding slash. |
|
569 | - * Eg you pass get_plural_route_to('Event', 12) = 'events/12' |
|
570 | - * |
|
571 | - * @param EEM_Base $model eg Event or Venue |
|
572 | - * @param string $id |
|
573 | - * @return string |
|
574 | - */ |
|
575 | - public static function get_entity_route($model, $id) |
|
576 | - { |
|
577 | - return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id; |
|
578 | - } |
|
579 | - |
|
580 | - |
|
581 | - /** |
|
582 | - * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace, |
|
583 | - * excluding the preceding slash. |
|
584 | - * Eg you pass get_plural_route_to('Event', 12) = 'events/12' |
|
585 | - * |
|
586 | - * @param EEM_Base $model eg Event or Venue |
|
587 | - * @param string $id |
|
588 | - * @param EE_Model_Relation_Base $relation_obj |
|
589 | - * @return string |
|
590 | - */ |
|
591 | - public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj) |
|
592 | - { |
|
593 | - $related_model_name_endpoint_part = ModelRead::getRelatedEntityName( |
|
594 | - $relation_obj->get_other_model()->get_this_model_name(), |
|
595 | - $relation_obj |
|
596 | - ); |
|
597 | - return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part; |
|
598 | - } |
|
599 | - |
|
600 | - |
|
601 | - /** |
|
602 | - * Adds onto the $relative_route the EE4 REST API versioned namespace. |
|
603 | - * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events' |
|
604 | - * |
|
605 | - * @param string $relative_route |
|
606 | - * @param string $version |
|
607 | - * @return string |
|
608 | - */ |
|
609 | - public static function get_versioned_route_to($relative_route, $version = '4.8.36') |
|
610 | - { |
|
611 | - return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route; |
|
612 | - } |
|
613 | - |
|
614 | - |
|
615 | - /** |
|
616 | - * Adds all the RPC-style routes (remote procedure call-like routes, ie |
|
617 | - * routes that don't conform to the traditional REST CRUD-style). |
|
618 | - * |
|
619 | - * @deprecated since 4.9.1 |
|
620 | - */ |
|
621 | - protected function _register_rpc_routes() |
|
622 | - { |
|
623 | - $routes = array(); |
|
624 | - foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
625 | - $routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version( |
|
626 | - $version, |
|
627 | - $hidden_endpoint |
|
628 | - ); |
|
629 | - } |
|
630 | - return $routes; |
|
631 | - } |
|
632 | - |
|
633 | - |
|
634 | - /** |
|
635 | - * @param string $version |
|
636 | - * @param boolean $hidden_endpoint |
|
637 | - * @return array |
|
638 | - */ |
|
639 | - protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false) |
|
640 | - { |
|
641 | - $this_versions_routes = array(); |
|
642 | - // checkin endpoint |
|
643 | - $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array( |
|
644 | - array( |
|
645 | - 'callback' => array( |
|
646 | - 'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin', |
|
647 | - 'handleRequestToggleCheckin', |
|
648 | - ), |
|
649 | - 'methods' => WP_REST_Server::CREATABLE, |
|
650 | - 'hidden_endpoint' => $hidden_endpoint, |
|
651 | - 'args' => array( |
|
652 | - 'force' => array( |
|
653 | - 'required' => false, |
|
654 | - 'default' => false, |
|
655 | - 'description' => __( |
|
656 | - // @codingStandardsIgnoreStart |
|
657 | - 'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses', |
|
658 | - // @codingStandardsIgnoreEnd |
|
659 | - 'event_espresso' |
|
660 | - ), |
|
661 | - ), |
|
662 | - ), |
|
663 | - 'callback_args' => array($version), |
|
664 | - ), |
|
665 | - ); |
|
666 | - return apply_filters( |
|
667 | - 'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes', |
|
668 | - $this_versions_routes, |
|
669 | - $version, |
|
670 | - $hidden_endpoint |
|
671 | - ); |
|
672 | - } |
|
673 | - |
|
674 | - |
|
675 | - /** |
|
676 | - * Gets the query params that can be used when request one or many |
|
677 | - * |
|
678 | - * @param EEM_Base $model |
|
679 | - * @param string $version |
|
680 | - * @return array |
|
681 | - */ |
|
682 | - protected function _get_response_selection_query_params(\EEM_Base $model, $version) |
|
683 | - { |
|
684 | - return apply_filters( |
|
685 | - 'FHEE__EED_Core_Rest_Api___get_response_selection_query_params', |
|
686 | - array( |
|
687 | - 'include' => array( |
|
688 | - 'required' => false, |
|
689 | - 'default' => '*', |
|
690 | - 'type' => 'string', |
|
691 | - ), |
|
692 | - 'calculate' => array( |
|
693 | - 'required' => false, |
|
694 | - 'default' => '', |
|
695 | - 'enum' => self::$_field_calculator->retrieveCalculatedFieldsForModel($model), |
|
696 | - 'type' => 'string', |
|
697 | - // because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization |
|
698 | - // freaks out. We'll just validate this argument while handling the request |
|
699 | - 'validate_callback' => null, |
|
700 | - 'sanitize_callback' => null, |
|
701 | - ), |
|
702 | - ), |
|
703 | - $model, |
|
704 | - $version |
|
705 | - ); |
|
706 | - } |
|
707 | - |
|
708 | - |
|
709 | - /** |
|
710 | - * Gets the parameters acceptable for delete requests |
|
711 | - * |
|
712 | - * @param \EEM_Base $model |
|
713 | - * @param string $version |
|
714 | - * @return array |
|
715 | - */ |
|
716 | - protected function _get_delete_query_params(\EEM_Base $model, $version) |
|
717 | - { |
|
718 | - $params_for_delete = array( |
|
719 | - 'allow_blocking' => array( |
|
720 | - 'required' => false, |
|
721 | - 'default' => true, |
|
722 | - 'type' => 'boolean', |
|
723 | - ), |
|
724 | - ); |
|
725 | - $params_for_delete['force'] = array( |
|
726 | - 'required' => false, |
|
727 | - 'default' => false, |
|
728 | - 'type' => 'boolean', |
|
729 | - ); |
|
730 | - return apply_filters( |
|
731 | - 'FHEE__EED_Core_Rest_Api___get_delete_query_params', |
|
732 | - $params_for_delete, |
|
733 | - $model, |
|
734 | - $version |
|
735 | - ); |
|
736 | - } |
|
737 | - |
|
738 | - |
|
739 | - /** |
|
740 | - * Gets info about reading query params that are acceptable |
|
741 | - * |
|
742 | - * @param \EEM_Base $model eg 'Event' or 'Venue' |
|
743 | - * @param string $version |
|
744 | - * @return array describing the args acceptable when querying this model |
|
745 | - * @throws EE_Error |
|
746 | - */ |
|
747 | - protected function _get_read_query_params(\EEM_Base $model, $version) |
|
748 | - { |
|
749 | - $default_orderby = array(); |
|
750 | - foreach ($model->get_combined_primary_key_fields() as $key_field) { |
|
751 | - $default_orderby[ $key_field->get_name() ] = 'ASC'; |
|
752 | - } |
|
753 | - return array_merge( |
|
754 | - $this->_get_response_selection_query_params($model, $version), |
|
755 | - array( |
|
756 | - 'where' => array( |
|
757 | - 'required' => false, |
|
758 | - 'default' => array(), |
|
759 | - 'type' => 'object', |
|
760 | - // because we accept an almost infinite list of possible where conditions, WP |
|
761 | - // core validation and sanitization freaks out. We'll just validate this argument |
|
762 | - // while handling the request |
|
763 | - 'validate_callback' => null, |
|
764 | - 'sanitize_callback' => null, |
|
765 | - ), |
|
766 | - 'limit' => array( |
|
767 | - 'required' => false, |
|
768 | - 'default' => EED_Core_Rest_Api::get_default_query_limit(), |
|
769 | - 'type' => array( |
|
770 | - 'array', |
|
771 | - 'string', |
|
772 | - 'integer', |
|
773 | - ), |
|
774 | - // because we accept a variety of types, WP core validation and sanitization |
|
775 | - // freaks out. We'll just validate this argument while handling the request |
|
776 | - 'validate_callback' => null, |
|
777 | - 'sanitize_callback' => null, |
|
778 | - ), |
|
779 | - 'order_by' => array( |
|
780 | - 'required' => false, |
|
781 | - 'default' => $default_orderby, |
|
782 | - 'type' => array( |
|
783 | - 'object', |
|
784 | - 'string', |
|
785 | - ),// because we accept a variety of types, WP core validation and sanitization |
|
786 | - // freaks out. We'll just validate this argument while handling the request |
|
787 | - 'validate_callback' => null, |
|
788 | - 'sanitize_callback' => null, |
|
789 | - ), |
|
790 | - 'group_by' => array( |
|
791 | - 'required' => false, |
|
792 | - 'default' => null, |
|
793 | - 'type' => array( |
|
794 | - 'object', |
|
795 | - 'string', |
|
796 | - ), |
|
797 | - // because we accept an almost infinite list of possible groupings, |
|
798 | - // WP core validation and sanitization |
|
799 | - // freaks out. We'll just validate this argument while handling the request |
|
800 | - 'validate_callback' => null, |
|
801 | - 'sanitize_callback' => null, |
|
802 | - ), |
|
803 | - 'having' => array( |
|
804 | - 'required' => false, |
|
805 | - 'default' => null, |
|
806 | - 'type' => 'object', |
|
807 | - // because we accept an almost infinite list of possible where conditions, WP |
|
808 | - // core validation and sanitization freaks out. We'll just validate this argument |
|
809 | - // while handling the request |
|
810 | - 'validate_callback' => null, |
|
811 | - 'sanitize_callback' => null, |
|
812 | - ), |
|
813 | - 'caps' => array( |
|
814 | - 'required' => false, |
|
815 | - 'default' => EEM_Base::caps_read, |
|
816 | - 'type' => 'string', |
|
817 | - 'enum' => array( |
|
818 | - EEM_Base::caps_read, |
|
819 | - EEM_Base::caps_read_admin, |
|
820 | - EEM_Base::caps_edit, |
|
821 | - EEM_Base::caps_delete, |
|
822 | - ), |
|
823 | - ), |
|
824 | - ) |
|
825 | - ); |
|
826 | - } |
|
827 | - |
|
828 | - |
|
829 | - /** |
|
830 | - * Gets parameter information for a model regarding writing data |
|
831 | - * |
|
832 | - * @param string $model_name |
|
833 | - * @param ModelVersionInfo $model_version_info |
|
834 | - * @param boolean $create whether this is for request to create (in |
|
835 | - * which case we need all required params) or |
|
836 | - * just to update (in which case we don't |
|
837 | - * need those on every request) |
|
838 | - * @return array |
|
839 | - */ |
|
840 | - protected function _get_write_params( |
|
841 | - $model_name, |
|
842 | - ModelVersionInfo $model_version_info, |
|
843 | - $create = false |
|
844 | - ) { |
|
845 | - $model = EE_Registry::instance()->load_model($model_name); |
|
846 | - $fields = $model_version_info->fieldsOnModelInThisVersion($model); |
|
847 | - $args_info = array(); |
|
848 | - foreach ($fields as $field_name => $field_obj) { |
|
849 | - if ($field_obj->is_auto_increment()) { |
|
850 | - // totally ignore auto increment IDs |
|
851 | - continue; |
|
852 | - } |
|
853 | - $arg_info = $field_obj->getSchema(); |
|
854 | - $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null; |
|
855 | - $arg_info['required'] = $required; |
|
856 | - // remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right? |
|
857 | - unset($arg_info['readonly']); |
|
858 | - $schema_properties = $field_obj->getSchemaProperties(); |
|
859 | - if (isset($schema_properties['raw']) |
|
860 | - && $field_obj->getSchemaType() === 'object' |
|
861 | - ) { |
|
862 | - // if there's a "raw" form of this argument, use those properties instead |
|
863 | - $arg_info = array_replace( |
|
864 | - $arg_info, |
|
865 | - $schema_properties['raw'] |
|
866 | - ); |
|
867 | - } |
|
868 | - $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson( |
|
869 | - $field_obj, |
|
870 | - $field_obj->get_default_value(), |
|
871 | - $model_version_info->requestedVersion() |
|
872 | - ); |
|
873 | - // we do our own validation and sanitization within the controller |
|
874 | - if (function_exists('rest_validate_value_from_schema')) { |
|
875 | - $sanitize_callback = array( |
|
876 | - 'EED_Core_Rest_Api', |
|
877 | - 'default_sanitize_callback', |
|
878 | - ); |
|
879 | - } else { |
|
880 | - $sanitize_callback = null; |
|
881 | - } |
|
882 | - $arg_info['sanitize_callback'] = $sanitize_callback; |
|
883 | - $args_info[ $field_name ] = $arg_info; |
|
884 | - if ($field_obj instanceof EE_Datetime_Field) { |
|
885 | - $gmt_arg_info = $arg_info; |
|
886 | - $gmt_arg_info['description'] = sprintf( |
|
887 | - esc_html__( |
|
888 | - '%1$s - the value for this field in UTC. Ignored if %2$s is provided.', |
|
889 | - 'event_espresso' |
|
890 | - ), |
|
891 | - $field_obj->get_nicename(), |
|
892 | - $field_name |
|
893 | - ); |
|
894 | - $args_info[ $field_name . '_gmt' ] = $gmt_arg_info; |
|
895 | - } |
|
896 | - } |
|
897 | - return $args_info; |
|
898 | - } |
|
899 | - |
|
900 | - |
|
901 | - /** |
|
902 | - * Replacement for WP API's 'rest_parse_request_arg'. |
|
903 | - * If the value is blank but not required, don't bother validating it. |
|
904 | - * Also, it uses our email validation instead of WP API's default. |
|
905 | - * |
|
906 | - * @param $value |
|
907 | - * @param WP_REST_Request $request |
|
908 | - * @param $param |
|
909 | - * @return bool|true|WP_Error |
|
910 | - * @throws InvalidArgumentException |
|
911 | - * @throws InvalidInterfaceException |
|
912 | - * @throws InvalidDataTypeException |
|
913 | - */ |
|
914 | - public static function default_sanitize_callback($value, WP_REST_Request $request, $param) |
|
915 | - { |
|
916 | - $attributes = $request->get_attributes(); |
|
917 | - if (! isset($attributes['args'][ $param ]) |
|
918 | - || ! is_array($attributes['args'][ $param ])) { |
|
919 | - $validation_result = true; |
|
920 | - } else { |
|
921 | - $args = $attributes['args'][ $param ]; |
|
922 | - if (( |
|
923 | - $value === '' |
|
924 | - || $value === null |
|
925 | - ) |
|
926 | - && (! isset($args['required']) |
|
927 | - || $args['required'] === false |
|
928 | - ) |
|
929 | - ) { |
|
930 | - // not required and not provided? that's cool |
|
931 | - $validation_result = true; |
|
932 | - } elseif (isset($args['format']) |
|
933 | - && $args['format'] === 'email' |
|
934 | - ) { |
|
935 | - $validation_result = true; |
|
936 | - if (! self::_validate_email($value)) { |
|
937 | - $validation_result = new WP_Error( |
|
938 | - 'rest_invalid_param', |
|
939 | - esc_html__( |
|
940 | - 'The email address is not valid or does not exist.', |
|
941 | - 'event_espresso' |
|
942 | - ) |
|
943 | - ); |
|
944 | - } |
|
945 | - } else { |
|
946 | - $validation_result = rest_validate_value_from_schema($value, $args, $param); |
|
947 | - } |
|
948 | - } |
|
949 | - if (is_wp_error($validation_result)) { |
|
950 | - return $validation_result; |
|
951 | - } |
|
952 | - return rest_sanitize_request_arg($value, $request, $param); |
|
953 | - } |
|
954 | - |
|
955 | - |
|
956 | - /** |
|
957 | - * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email() |
|
958 | - * |
|
959 | - * @param $email |
|
960 | - * @return bool |
|
961 | - * @throws InvalidArgumentException |
|
962 | - * @throws InvalidInterfaceException |
|
963 | - * @throws InvalidDataTypeException |
|
964 | - */ |
|
965 | - protected static function _validate_email($email) |
|
966 | - { |
|
967 | - try { |
|
968 | - EmailAddressFactory::create($email); |
|
969 | - return true; |
|
970 | - } catch (EmailValidationException $e) { |
|
971 | - return false; |
|
972 | - } |
|
973 | - } |
|
974 | - |
|
975 | - |
|
976 | - /** |
|
977 | - * Gets routes for the config |
|
978 | - * |
|
979 | - * @return array @see _register_model_routes |
|
980 | - * @deprecated since version 4.9.1 |
|
981 | - */ |
|
982 | - protected function _register_config_routes() |
|
983 | - { |
|
984 | - $config_routes = array(); |
|
985 | - foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
986 | - $config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version( |
|
987 | - $version, |
|
988 | - $hidden_endpoint |
|
989 | - ); |
|
990 | - } |
|
991 | - return $config_routes; |
|
992 | - } |
|
993 | - |
|
994 | - |
|
995 | - /** |
|
996 | - * Gets routes for the config for the specified version |
|
997 | - * |
|
998 | - * @param string $version |
|
999 | - * @param boolean $hidden_endpoint |
|
1000 | - * @return array |
|
1001 | - */ |
|
1002 | - protected function _get_config_route_data_for_version($version, $hidden_endpoint) |
|
1003 | - { |
|
1004 | - return array( |
|
1005 | - 'config' => array( |
|
1006 | - array( |
|
1007 | - 'callback' => array( |
|
1008 | - 'EventEspresso\core\libraries\rest_api\controllers\config\Read', |
|
1009 | - 'handleRequest', |
|
1010 | - ), |
|
1011 | - 'methods' => WP_REST_Server::READABLE, |
|
1012 | - 'hidden_endpoint' => $hidden_endpoint, |
|
1013 | - 'callback_args' => array($version), |
|
1014 | - ), |
|
1015 | - ), |
|
1016 | - 'site_info' => array( |
|
1017 | - array( |
|
1018 | - 'callback' => array( |
|
1019 | - 'EventEspresso\core\libraries\rest_api\controllers\config\Read', |
|
1020 | - 'handleRequestSiteInfo', |
|
1021 | - ), |
|
1022 | - 'methods' => WP_REST_Server::READABLE, |
|
1023 | - 'hidden_endpoint' => $hidden_endpoint, |
|
1024 | - 'callback_args' => array($version), |
|
1025 | - ), |
|
1026 | - ), |
|
1027 | - ); |
|
1028 | - } |
|
1029 | - |
|
1030 | - |
|
1031 | - /** |
|
1032 | - * Gets the meta info routes |
|
1033 | - * |
|
1034 | - * @return array @see _register_model_routes |
|
1035 | - * @deprecated since version 4.9.1 |
|
1036 | - */ |
|
1037 | - protected function _register_meta_routes() |
|
1038 | - { |
|
1039 | - $meta_routes = array(); |
|
1040 | - foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
1041 | - $meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version( |
|
1042 | - $version, |
|
1043 | - $hidden_endpoint |
|
1044 | - ); |
|
1045 | - } |
|
1046 | - return $meta_routes; |
|
1047 | - } |
|
1048 | - |
|
1049 | - |
|
1050 | - /** |
|
1051 | - * @param string $version |
|
1052 | - * @param boolean $hidden_endpoint |
|
1053 | - * @return array |
|
1054 | - */ |
|
1055 | - protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false) |
|
1056 | - { |
|
1057 | - return array( |
|
1058 | - 'resources' => array( |
|
1059 | - array( |
|
1060 | - 'callback' => array( |
|
1061 | - 'EventEspresso\core\libraries\rest_api\controllers\model\Meta', |
|
1062 | - 'handleRequestModelsMeta', |
|
1063 | - ), |
|
1064 | - 'methods' => WP_REST_Server::READABLE, |
|
1065 | - 'hidden_endpoint' => $hidden_endpoint, |
|
1066 | - 'callback_args' => array($version), |
|
1067 | - ), |
|
1068 | - ), |
|
1069 | - ); |
|
1070 | - } |
|
1071 | - |
|
1072 | - |
|
1073 | - /** |
|
1074 | - * Tries to hide old 4.6 endpoints from the |
|
1075 | - * |
|
1076 | - * @param array $route_data |
|
1077 | - * @return array |
|
1078 | - * @throws \EE_Error |
|
1079 | - */ |
|
1080 | - public static function hide_old_endpoints($route_data) |
|
1081 | - { |
|
1082 | - // allow API clients to override which endpoints get hidden, in case |
|
1083 | - // they want to discover particular endpoints |
|
1084 | - // also, we don't have access to the request so we have to just grab it from the superglobal |
|
1085 | - $force_show_ee_namespace = ltrim( |
|
1086 | - EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''), |
|
1087 | - '/' |
|
1088 | - ); |
|
1089 | - foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) { |
|
1090 | - foreach ($relative_urls as $resource_name => $endpoints) { |
|
1091 | - foreach ($endpoints as $key => $endpoint) { |
|
1092 | - // skip schema and other route options |
|
1093 | - if (! is_numeric($key)) { |
|
1094 | - continue; |
|
1095 | - } |
|
1096 | - // by default, hide "hidden_endpoint"s, unless the request indicates |
|
1097 | - // to $force_show_ee_namespace, in which case only show that one |
|
1098 | - // namespace's endpoints (and hide all others) |
|
1099 | - if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace) |
|
1100 | - || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '') |
|
1101 | - ) { |
|
1102 | - $full_route = '/' . ltrim($namespace, '/'); |
|
1103 | - $full_route .= '/' . ltrim($resource_name, '/'); |
|
1104 | - unset($route_data[ $full_route ]); |
|
1105 | - } |
|
1106 | - } |
|
1107 | - } |
|
1108 | - } |
|
1109 | - return $route_data; |
|
1110 | - } |
|
1111 | - |
|
1112 | - |
|
1113 | - /** |
|
1114 | - * Returns an array describing which versions of core support serving requests for. |
|
1115 | - * Keys are core versions' major and minor version, and values are the |
|
1116 | - * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like |
|
1117 | - * data by just removing a few models and fields from the responses. However, 4.15 might remove |
|
1118 | - * the answers table entirely, in which case it would be very difficult for |
|
1119 | - * it to serve 4.6-style responses. |
|
1120 | - * Versions of core that are missing from this array are unknowns. |
|
1121 | - * previous ver |
|
1122 | - * |
|
1123 | - * @return array |
|
1124 | - */ |
|
1125 | - public static function version_compatibilities() |
|
1126 | - { |
|
1127 | - return apply_filters( |
|
1128 | - 'FHEE__EED_Core_REST_API__version_compatibilities', |
|
1129 | - array( |
|
1130 | - '4.8.29' => '4.8.29', |
|
1131 | - '4.8.33' => '4.8.29', |
|
1132 | - '4.8.34' => '4.8.29', |
|
1133 | - '4.8.36' => '4.8.29', |
|
1134 | - ) |
|
1135 | - ); |
|
1136 | - } |
|
1137 | - |
|
1138 | - |
|
1139 | - /** |
|
1140 | - * Gets the latest API version served. Eg if there |
|
1141 | - * are two versions served of the API, 4.8.29 and 4.8.32, and |
|
1142 | - * we are on core version 4.8.34, it will return the string "4.8.32" |
|
1143 | - * |
|
1144 | - * @return string |
|
1145 | - */ |
|
1146 | - public static function latest_rest_api_version() |
|
1147 | - { |
|
1148 | - $versions_served = \EED_Core_Rest_Api::versions_served(); |
|
1149 | - $versions_served_keys = array_keys($versions_served); |
|
1150 | - return end($versions_served_keys); |
|
1151 | - } |
|
1152 | - |
|
1153 | - |
|
1154 | - /** |
|
1155 | - * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of |
|
1156 | - * EE the API can serve requests for. Eg, if we are on 4.15 of core, and |
|
1157 | - * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ). |
|
1158 | - * We also indicate whether or not this version should be put in the index or not |
|
1159 | - * |
|
1160 | - * @return array keys are API version numbers (just major and minor numbers), and values |
|
1161 | - * are whether or not they should be hidden |
|
1162 | - */ |
|
1163 | - public static function versions_served() |
|
1164 | - { |
|
1165 | - $versions_served = array(); |
|
1166 | - $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities(); |
|
1167 | - $lowest_compatible_version = end($possibly_served_versions); |
|
1168 | - reset($possibly_served_versions); |
|
1169 | - $versions_served_historically = array_keys($possibly_served_versions); |
|
1170 | - $latest_version = end($versions_served_historically); |
|
1171 | - reset($versions_served_historically); |
|
1172 | - // for each version of core we have ever served: |
|
1173 | - foreach ($versions_served_historically as $key_versioned_endpoint) { |
|
1174 | - // if it's not above the current core version, and it's compatible with the current version of core |
|
1175 | - if ($key_versioned_endpoint === $latest_version) { |
|
1176 | - // don't hide the latest version in the index |
|
1177 | - $versions_served[ $key_versioned_endpoint ] = false; |
|
1178 | - } elseif ($key_versioned_endpoint >= $lowest_compatible_version |
|
1179 | - && $key_versioned_endpoint < EED_Core_Rest_Api::core_version() |
|
1180 | - ) { |
|
1181 | - // include, but hide, previous versions which are still supported |
|
1182 | - $versions_served[ $key_versioned_endpoint ] = true; |
|
1183 | - } elseif (apply_filters( |
|
1184 | - 'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions', |
|
1185 | - false, |
|
1186 | - $possibly_served_versions |
|
1187 | - )) { |
|
1188 | - // if a version is no longer supported, don't include it in index or list of versions served |
|
1189 | - $versions_served[ $key_versioned_endpoint ] = true; |
|
1190 | - } |
|
1191 | - } |
|
1192 | - return $versions_served; |
|
1193 | - } |
|
1194 | - |
|
1195 | - |
|
1196 | - /** |
|
1197 | - * Gets the major and minor version of EE core's version string |
|
1198 | - * |
|
1199 | - * @return string |
|
1200 | - */ |
|
1201 | - public static function core_version() |
|
1202 | - { |
|
1203 | - return apply_filters( |
|
1204 | - 'FHEE__EED_Core_REST_API__core_version', |
|
1205 | - implode( |
|
1206 | - '.', |
|
1207 | - array_slice( |
|
1208 | - explode( |
|
1209 | - '.', |
|
1210 | - espresso_version() |
|
1211 | - ), |
|
1212 | - 0, |
|
1213 | - 3 |
|
1214 | - ) |
|
1215 | - ) |
|
1216 | - ); |
|
1217 | - } |
|
1218 | - |
|
1219 | - |
|
1220 | - /** |
|
1221 | - * Gets the default limit that should be used when querying for resources |
|
1222 | - * |
|
1223 | - * @return int |
|
1224 | - */ |
|
1225 | - public static function get_default_query_limit() |
|
1226 | - { |
|
1227 | - // we actually don't use a const because we want folks to always use |
|
1228 | - // this method, not the const directly |
|
1229 | - return apply_filters( |
|
1230 | - 'FHEE__EED_Core_Rest_Api__get_default_query_limit', |
|
1231 | - 50 |
|
1232 | - ); |
|
1233 | - } |
|
1234 | - |
|
1235 | - |
|
1236 | - /** |
|
1237 | - * |
|
1238 | - * @param string $version api version string (i.e. '4.8.36') |
|
1239 | - * @return array |
|
1240 | - */ |
|
1241 | - public static function getCollectionRoutesIndexedByModelName($version = '') |
|
1242 | - { |
|
1243 | - $version = empty($version) ? self::latest_rest_api_version() : $version; |
|
1244 | - $model_names = self::model_names_with_plural_routes($version); |
|
1245 | - $collection_routes = array(); |
|
1246 | - foreach ($model_names as $model_name => $model_class_name) { |
|
1247 | - $collection_routes[ strtolower($model_name) ] = '/' . self::ee_api_namespace . $version . '/' |
|
1248 | - . EEH_Inflector::pluralize_and_lower($model_name); |
|
1249 | - } |
|
1250 | - return $collection_routes; |
|
1251 | - } |
|
1252 | - |
|
1253 | - |
|
1254 | - /** |
|
1255 | - * Returns an array of primary key names indexed by model names. |
|
1256 | - * @param string $version |
|
1257 | - * @return array |
|
1258 | - */ |
|
1259 | - public static function getPrimaryKeyNamesIndexedByModelName($version = '') |
|
1260 | - { |
|
1261 | - $version = empty($version) ? self::latest_rest_api_version() : $version; |
|
1262 | - $model_names = self::model_names_with_plural_routes($version); |
|
1263 | - $primary_key_items = array(); |
|
1264 | - foreach ($model_names as $model_name => $model_class_name) { |
|
1265 | - $primary_keys = $model_class_name::instance()->get_combined_primary_key_fields(); |
|
1266 | - foreach ($primary_keys as $primary_key_name => $primary_key_field) { |
|
1267 | - if (count($primary_keys) > 1) { |
|
1268 | - $primary_key_items[ strtolower($model_name) ][] = $primary_key_name; |
|
1269 | - } else { |
|
1270 | - $primary_key_items[ strtolower($model_name) ] = $primary_key_name; |
|
1271 | - } |
|
1272 | - } |
|
1273 | - } |
|
1274 | - return $primary_key_items; |
|
1275 | - } |
|
1276 | - |
|
1277 | - |
|
1278 | - |
|
1279 | - /** |
|
1280 | - * run - initial module setup |
|
1281 | - * |
|
1282 | - * @access public |
|
1283 | - * @param WP $WP |
|
1284 | - * @return void |
|
1285 | - */ |
|
1286 | - public function run($WP) |
|
1287 | - { |
|
1288 | - } |
|
25 | + const ee_api_namespace = Domain::API_NAMESPACE; |
|
26 | + |
|
27 | + const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/'; |
|
28 | + |
|
29 | + const saved_routes_option_names = 'ee_core_routes'; |
|
30 | + |
|
31 | + /** |
|
32 | + * string used in _links response bodies to make them globally unique. |
|
33 | + * |
|
34 | + * @see http://v2.wp-api.org/extending/linking/ |
|
35 | + */ |
|
36 | + const ee_api_link_namespace = 'https://api.eventespresso.com/'; |
|
37 | + |
|
38 | + /** |
|
39 | + * @var CalculatedModelFields |
|
40 | + */ |
|
41 | + protected static $_field_calculator; |
|
42 | + |
|
43 | + |
|
44 | + /** |
|
45 | + * @return EED_Core_Rest_Api|EED_Module |
|
46 | + */ |
|
47 | + public static function instance() |
|
48 | + { |
|
49 | + self::$_field_calculator = new CalculatedModelFields(); |
|
50 | + return parent::get_instance(__CLASS__); |
|
51 | + } |
|
52 | + |
|
53 | + |
|
54 | + /** |
|
55 | + * set_hooks - for hooking into EE Core, other modules, etc |
|
56 | + * |
|
57 | + * @access public |
|
58 | + * @return void |
|
59 | + */ |
|
60 | + public static function set_hooks() |
|
61 | + { |
|
62 | + self::set_hooks_both(); |
|
63 | + } |
|
64 | + |
|
65 | + |
|
66 | + /** |
|
67 | + * set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
|
68 | + * |
|
69 | + * @access public |
|
70 | + * @return void |
|
71 | + */ |
|
72 | + public static function set_hooks_admin() |
|
73 | + { |
|
74 | + self::set_hooks_both(); |
|
75 | + } |
|
76 | + |
|
77 | + |
|
78 | + public static function set_hooks_both() |
|
79 | + { |
|
80 | + add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10); |
|
81 | + add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5); |
|
82 | + add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2); |
|
83 | + add_filter( |
|
84 | + 'rest_index', |
|
85 | + array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex') |
|
86 | + ); |
|
87 | + EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change(); |
|
88 | + } |
|
89 | + |
|
90 | + |
|
91 | + /** |
|
92 | + * sets up hooks which only need to be included as part of REST API requests; |
|
93 | + * other requests like to the frontend or admin etc don't need them |
|
94 | + * |
|
95 | + * @throws \EE_Error |
|
96 | + */ |
|
97 | + public static function set_hooks_rest_api() |
|
98 | + { |
|
99 | + // set hooks which account for changes made to the API |
|
100 | + EED_Core_Rest_Api::_set_hooks_for_changes(); |
|
101 | + } |
|
102 | + |
|
103 | + |
|
104 | + /** |
|
105 | + * public wrapper of _set_hooks_for_changes. |
|
106 | + * Loads all the hooks which make requests to old versions of the API |
|
107 | + * appear the same as they always did |
|
108 | + * |
|
109 | + * @throws EE_Error |
|
110 | + */ |
|
111 | + public static function set_hooks_for_changes() |
|
112 | + { |
|
113 | + self::_set_hooks_for_changes(); |
|
114 | + } |
|
115 | + |
|
116 | + |
|
117 | + /** |
|
118 | + * Loads all the hooks which make requests to old versions of the API |
|
119 | + * appear the same as they always did |
|
120 | + * |
|
121 | + * @throws EE_Error |
|
122 | + */ |
|
123 | + protected static function _set_hooks_for_changes() |
|
124 | + { |
|
125 | + $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false); |
|
126 | + foreach ($folder_contents as $classname_in_namespace => $filepath) { |
|
127 | + // ignore the base parent class |
|
128 | + // and legacy named classes |
|
129 | + if ($classname_in_namespace === 'ChangesInBase' |
|
130 | + || strpos($classname_in_namespace, 'Changes_In_') === 0 |
|
131 | + ) { |
|
132 | + continue; |
|
133 | + } |
|
134 | + $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace; |
|
135 | + if (class_exists($full_classname)) { |
|
136 | + $instance_of_class = new $full_classname; |
|
137 | + if ($instance_of_class instanceof ChangesInBase) { |
|
138 | + $instance_of_class->setHooks(); |
|
139 | + } |
|
140 | + } |
|
141 | + } |
|
142 | + } |
|
143 | + |
|
144 | + |
|
145 | + /** |
|
146 | + * Filters the WP routes to add our EE-related ones. This takes a bit of time |
|
147 | + * so we actually prefer to only do it when an EE plugin is activated or upgraded |
|
148 | + * |
|
149 | + * @throws \EE_Error |
|
150 | + */ |
|
151 | + public static function register_routes() |
|
152 | + { |
|
153 | + foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) { |
|
154 | + foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) { |
|
155 | + /** |
|
156 | + * @var array $data_for_multiple_endpoints numerically indexed array |
|
157 | + * but can also contain route options like { |
|
158 | + * @type array $schema { |
|
159 | + * @type callable $schema_callback |
|
160 | + * @type array $callback_args arguments that will be passed to the callback, after the |
|
161 | + * WP_REST_Request of course |
|
162 | + * } |
|
163 | + * } |
|
164 | + */ |
|
165 | + // when registering routes, register all the endpoints' data at the same time |
|
166 | + $multiple_endpoint_args = array(); |
|
167 | + foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) { |
|
168 | + /** |
|
169 | + * @var array $data_for_single_endpoint { |
|
170 | + * @type callable $callback |
|
171 | + * @type string methods |
|
172 | + * @type array args |
|
173 | + * @type array _links |
|
174 | + * @type array $callback_args arguments that will be passed to the callback, after the |
|
175 | + * WP_REST_Request of course |
|
176 | + * } |
|
177 | + */ |
|
178 | + // skip route options |
|
179 | + if (! is_numeric($endpoint_key)) { |
|
180 | + continue; |
|
181 | + } |
|
182 | + if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) { |
|
183 | + throw new EE_Error( |
|
184 | + esc_html__( |
|
185 | + // @codingStandardsIgnoreStart |
|
186 | + 'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).', |
|
187 | + // @codingStandardsIgnoreEnd |
|
188 | + 'event_espresso' |
|
189 | + ) |
|
190 | + ); |
|
191 | + } |
|
192 | + $callback = $data_for_single_endpoint['callback']; |
|
193 | + $single_endpoint_args = array( |
|
194 | + 'methods' => $data_for_single_endpoint['methods'], |
|
195 | + 'args' => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args'] |
|
196 | + : array(), |
|
197 | + ); |
|
198 | + if (isset($data_for_single_endpoint['_links'])) { |
|
199 | + $single_endpoint_args['_links'] = $data_for_single_endpoint['_links']; |
|
200 | + } |
|
201 | + if (isset($data_for_single_endpoint['callback_args'])) { |
|
202 | + $callback_args = $data_for_single_endpoint['callback_args']; |
|
203 | + $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use ( |
|
204 | + $callback, |
|
205 | + $callback_args |
|
206 | + ) { |
|
207 | + array_unshift($callback_args, $request); |
|
208 | + return call_user_func_array( |
|
209 | + $callback, |
|
210 | + $callback_args |
|
211 | + ); |
|
212 | + }; |
|
213 | + } else { |
|
214 | + $single_endpoint_args['callback'] = $data_for_single_endpoint['callback']; |
|
215 | + } |
|
216 | + $multiple_endpoint_args[] = $single_endpoint_args; |
|
217 | + } |
|
218 | + if (isset($data_for_multiple_endpoints['schema'])) { |
|
219 | + $schema_route_data = $data_for_multiple_endpoints['schema']; |
|
220 | + $schema_callback = $schema_route_data['schema_callback']; |
|
221 | + $callback_args = $schema_route_data['callback_args']; |
|
222 | + $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) { |
|
223 | + return call_user_func_array( |
|
224 | + $schema_callback, |
|
225 | + $callback_args |
|
226 | + ); |
|
227 | + }; |
|
228 | + } |
|
229 | + register_rest_route( |
|
230 | + $namespace, |
|
231 | + $relative_route, |
|
232 | + $multiple_endpoint_args |
|
233 | + ); |
|
234 | + } |
|
235 | + } |
|
236 | + } |
|
237 | + |
|
238 | + |
|
239 | + /** |
|
240 | + * Checks if there was a version change or something that merits invalidating the cached |
|
241 | + * route data. If so, invalidates the cached route data so that it gets refreshed |
|
242 | + * next time the WP API is used |
|
243 | + */ |
|
244 | + public static function invalidate_cached_route_data_on_version_change() |
|
245 | + { |
|
246 | + if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) { |
|
247 | + EED_Core_Rest_Api::invalidate_cached_route_data(); |
|
248 | + } |
|
249 | + foreach (EE_Registry::instance()->addons as $addon) { |
|
250 | + if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) { |
|
251 | + EED_Core_Rest_Api::invalidate_cached_route_data(); |
|
252 | + } |
|
253 | + } |
|
254 | + } |
|
255 | + |
|
256 | + |
|
257 | + /** |
|
258 | + * Removes the cached route data so it will get refreshed next time the WP API is used |
|
259 | + */ |
|
260 | + public static function invalidate_cached_route_data() |
|
261 | + { |
|
262 | + // delete the saved EE REST API routes |
|
263 | + foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) { |
|
264 | + delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version); |
|
265 | + } |
|
266 | + } |
|
267 | + |
|
268 | + |
|
269 | + /** |
|
270 | + * Gets the EE route data |
|
271 | + * |
|
272 | + * @return array top-level key is the namespace, next-level key is the route and its value is array{ |
|
273 | + * @throws \EE_Error |
|
274 | + * @type string|array $callback |
|
275 | + * @type string $methods |
|
276 | + * @type boolean $hidden_endpoint |
|
277 | + * } |
|
278 | + */ |
|
279 | + public static function get_ee_route_data() |
|
280 | + { |
|
281 | + $ee_routes = array(); |
|
282 | + foreach (self::versions_served() as $version => $hidden_endpoints) { |
|
283 | + $ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version( |
|
284 | + $version, |
|
285 | + $hidden_endpoints |
|
286 | + ); |
|
287 | + } |
|
288 | + return $ee_routes; |
|
289 | + } |
|
290 | + |
|
291 | + |
|
292 | + /** |
|
293 | + * Gets the EE route data from the wp options if it exists already, |
|
294 | + * otherwise re-generates it and saves it to the option |
|
295 | + * |
|
296 | + * @param string $version |
|
297 | + * @param boolean $hidden_endpoints |
|
298 | + * @return array |
|
299 | + * @throws \EE_Error |
|
300 | + */ |
|
301 | + protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false) |
|
302 | + { |
|
303 | + $ee_routes = get_option(self::saved_routes_option_names . $version, null); |
|
304 | + if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) { |
|
305 | + $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints); |
|
306 | + } |
|
307 | + return $ee_routes; |
|
308 | + } |
|
309 | + |
|
310 | + |
|
311 | + /** |
|
312 | + * Saves the EE REST API route data to a wp option and returns it |
|
313 | + * |
|
314 | + * @param string $version |
|
315 | + * @param boolean $hidden_endpoints |
|
316 | + * @return mixed|null |
|
317 | + * @throws \EE_Error |
|
318 | + */ |
|
319 | + protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false) |
|
320 | + { |
|
321 | + $instance = self::instance(); |
|
322 | + $routes = apply_filters( |
|
323 | + 'EED_Core_Rest_Api__save_ee_route_data_for_version__routes', |
|
324 | + array_replace_recursive( |
|
325 | + $instance->_get_config_route_data_for_version($version, $hidden_endpoints), |
|
326 | + $instance->_get_meta_route_data_for_version($version, $hidden_endpoints), |
|
327 | + $instance->_get_model_route_data_for_version($version, $hidden_endpoints), |
|
328 | + $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints) |
|
329 | + ) |
|
330 | + ); |
|
331 | + $option_name = self::saved_routes_option_names . $version; |
|
332 | + if (get_option($option_name)) { |
|
333 | + update_option($option_name, $routes, true); |
|
334 | + } else { |
|
335 | + add_option($option_name, $routes, null, 'no'); |
|
336 | + } |
|
337 | + return $routes; |
|
338 | + } |
|
339 | + |
|
340 | + |
|
341 | + /** |
|
342 | + * Calculates all the EE routes and saves it to a WordPress option so we don't |
|
343 | + * need to calculate it on every request |
|
344 | + * |
|
345 | + * @deprecated since version 4.9.1 |
|
346 | + * @return void |
|
347 | + */ |
|
348 | + public static function save_ee_routes() |
|
349 | + { |
|
350 | + if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
351 | + $instance = self::instance(); |
|
352 | + $routes = apply_filters( |
|
353 | + 'EED_Core_Rest_Api__save_ee_routes__routes', |
|
354 | + array_replace_recursive( |
|
355 | + $instance->_register_config_routes(), |
|
356 | + $instance->_register_meta_routes(), |
|
357 | + $instance->_register_model_routes(), |
|
358 | + $instance->_register_rpc_routes() |
|
359 | + ) |
|
360 | + ); |
|
361 | + update_option(self::saved_routes_option_names, $routes, true); |
|
362 | + } |
|
363 | + } |
|
364 | + |
|
365 | + |
|
366 | + /** |
|
367 | + * Gets all the route information relating to EE models |
|
368 | + * |
|
369 | + * @return array @see get_ee_route_data |
|
370 | + * @deprecated since version 4.9.1 |
|
371 | + */ |
|
372 | + protected function _register_model_routes() |
|
373 | + { |
|
374 | + $model_routes = array(); |
|
375 | + foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
376 | + $model_routes[ EED_Core_Rest_Api::ee_api_namespace |
|
377 | + . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint); |
|
378 | + } |
|
379 | + return $model_routes; |
|
380 | + } |
|
381 | + |
|
382 | + |
|
383 | + /** |
|
384 | + * Decides whether or not to add write endpoints for this model. |
|
385 | + * |
|
386 | + * Currently, this defaults to exclude all global tables and models |
|
387 | + * which would allow inserting WP core data (we don't want to duplicate |
|
388 | + * what WP API does, as it's unnecessary, extra work, and potentially extra bugs) |
|
389 | + * |
|
390 | + * @param EEM_Base $model |
|
391 | + * @return bool |
|
392 | + */ |
|
393 | + public static function should_have_write_endpoints(EEM_Base $model) |
|
394 | + { |
|
395 | + if ($model->is_wp_core_model()) { |
|
396 | + return false; |
|
397 | + } |
|
398 | + foreach ($model->get_tables() as $table) { |
|
399 | + if ($table->is_global()) { |
|
400 | + return false; |
|
401 | + } |
|
402 | + } |
|
403 | + return true; |
|
404 | + } |
|
405 | + |
|
406 | + |
|
407 | + /** |
|
408 | + * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`) |
|
409 | + * in this versioned namespace of EE4 |
|
410 | + * |
|
411 | + * @param $version |
|
412 | + * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event') |
|
413 | + */ |
|
414 | + public static function model_names_with_plural_routes($version) |
|
415 | + { |
|
416 | + $model_version_info = new ModelVersionInfo($version); |
|
417 | + $models_to_register = $model_version_info->modelsForRequestedVersion(); |
|
418 | + // let's not bother having endpoints for extra metas |
|
419 | + unset( |
|
420 | + $models_to_register['Extra_Meta'], |
|
421 | + $models_to_register['Extra_Join'], |
|
422 | + $models_to_register['Post_Meta'] |
|
423 | + ); |
|
424 | + return apply_filters( |
|
425 | + 'FHEE__EED_Core_REST_API___register_model_routes', |
|
426 | + $models_to_register |
|
427 | + ); |
|
428 | + } |
|
429 | + |
|
430 | + |
|
431 | + /** |
|
432 | + * Gets the route data for EE models in the specified version |
|
433 | + * |
|
434 | + * @param string $version |
|
435 | + * @param boolean $hidden_endpoint |
|
436 | + * @return array |
|
437 | + * @throws EE_Error |
|
438 | + */ |
|
439 | + protected function _get_model_route_data_for_version($version, $hidden_endpoint = false) |
|
440 | + { |
|
441 | + $model_routes = array(); |
|
442 | + $model_version_info = new ModelVersionInfo($version); |
|
443 | + foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) { |
|
444 | + $model = \EE_Registry::instance()->load_model($model_name); |
|
445 | + // if this isn't a valid model then let's skip iterate to the next item in the loop. |
|
446 | + if (! $model instanceof EEM_Base) { |
|
447 | + continue; |
|
448 | + } |
|
449 | + // yes we could just register one route for ALL models, but then they wouldn't show up in the index |
|
450 | + $plural_model_route = EED_Core_Rest_Api::get_collection_route($model); |
|
451 | + $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)'); |
|
452 | + $model_routes[ $plural_model_route ] = array( |
|
453 | + array( |
|
454 | + 'callback' => array( |
|
455 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
456 | + 'handleRequestGetAll', |
|
457 | + ), |
|
458 | + 'callback_args' => array($version, $model_name), |
|
459 | + 'methods' => WP_REST_Server::READABLE, |
|
460 | + 'hidden_endpoint' => $hidden_endpoint, |
|
461 | + 'args' => $this->_get_read_query_params($model, $version), |
|
462 | + '_links' => array( |
|
463 | + 'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route), |
|
464 | + ), |
|
465 | + ), |
|
466 | + 'schema' => array( |
|
467 | + 'schema_callback' => array( |
|
468 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
469 | + 'handleSchemaRequest', |
|
470 | + ), |
|
471 | + 'callback_args' => array($version, $model_name), |
|
472 | + ), |
|
473 | + ); |
|
474 | + $model_routes[ $singular_model_route ] = array( |
|
475 | + array( |
|
476 | + 'callback' => array( |
|
477 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
478 | + 'handleRequestGetOne', |
|
479 | + ), |
|
480 | + 'callback_args' => array($version, $model_name), |
|
481 | + 'methods' => WP_REST_Server::READABLE, |
|
482 | + 'hidden_endpoint' => $hidden_endpoint, |
|
483 | + 'args' => $this->_get_response_selection_query_params($model, $version), |
|
484 | + ), |
|
485 | + ); |
|
486 | + if (apply_filters( |
|
487 | + 'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints', |
|
488 | + EED_Core_Rest_Api::should_have_write_endpoints($model), |
|
489 | + $model |
|
490 | + )) { |
|
491 | + $model_routes[ $plural_model_route ][] = array( |
|
492 | + 'callback' => array( |
|
493 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Write', |
|
494 | + 'handleRequestInsert', |
|
495 | + ), |
|
496 | + 'callback_args' => array($version, $model_name), |
|
497 | + 'methods' => WP_REST_Server::CREATABLE, |
|
498 | + 'hidden_endpoint' => $hidden_endpoint, |
|
499 | + 'args' => $this->_get_write_params($model_name, $model_version_info, true), |
|
500 | + ); |
|
501 | + $model_routes[ $singular_model_route ] = array_merge( |
|
502 | + $model_routes[ $singular_model_route ], |
|
503 | + array( |
|
504 | + array( |
|
505 | + 'callback' => array( |
|
506 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Write', |
|
507 | + 'handleRequestUpdate', |
|
508 | + ), |
|
509 | + 'callback_args' => array($version, $model_name), |
|
510 | + 'methods' => WP_REST_Server::EDITABLE, |
|
511 | + 'hidden_endpoint' => $hidden_endpoint, |
|
512 | + 'args' => $this->_get_write_params($model_name, $model_version_info), |
|
513 | + ), |
|
514 | + array( |
|
515 | + 'callback' => array( |
|
516 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Write', |
|
517 | + 'handleRequestDelete', |
|
518 | + ), |
|
519 | + 'callback_args' => array($version, $model_name), |
|
520 | + 'methods' => WP_REST_Server::DELETABLE, |
|
521 | + 'hidden_endpoint' => $hidden_endpoint, |
|
522 | + 'args' => $this->_get_delete_query_params($model, $version), |
|
523 | + ), |
|
524 | + ) |
|
525 | + ); |
|
526 | + } |
|
527 | + foreach ($model->relation_settings() as $relation_name => $relation_obj) { |
|
528 | + $related_route = EED_Core_Rest_Api::get_relation_route_via( |
|
529 | + $model, |
|
530 | + '(?P<id>[^\/]+)', |
|
531 | + $relation_obj |
|
532 | + ); |
|
533 | + $endpoints = array( |
|
534 | + array( |
|
535 | + 'callback' => array( |
|
536 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
|
537 | + 'handleRequestGetRelated', |
|
538 | + ), |
|
539 | + 'callback_args' => array($version, $model_name, $relation_name), |
|
540 | + 'methods' => WP_REST_Server::READABLE, |
|
541 | + 'hidden_endpoint' => $hidden_endpoint, |
|
542 | + 'args' => $this->_get_read_query_params($relation_obj->get_other_model(), $version), |
|
543 | + ), |
|
544 | + ); |
|
545 | + $model_routes[ $related_route ] = $endpoints; |
|
546 | + } |
|
547 | + } |
|
548 | + return $model_routes; |
|
549 | + } |
|
550 | + |
|
551 | + |
|
552 | + /** |
|
553 | + * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace, |
|
554 | + * excluding the preceding slash. |
|
555 | + * Eg you pass get_plural_route_to('Event') = 'events' |
|
556 | + * |
|
557 | + * @param EEM_Base $model |
|
558 | + * @return string |
|
559 | + */ |
|
560 | + public static function get_collection_route(EEM_Base $model) |
|
561 | + { |
|
562 | + return EEH_Inflector::pluralize_and_lower($model->get_this_model_name()); |
|
563 | + } |
|
564 | + |
|
565 | + |
|
566 | + /** |
|
567 | + * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace, |
|
568 | + * excluding the preceding slash. |
|
569 | + * Eg you pass get_plural_route_to('Event', 12) = 'events/12' |
|
570 | + * |
|
571 | + * @param EEM_Base $model eg Event or Venue |
|
572 | + * @param string $id |
|
573 | + * @return string |
|
574 | + */ |
|
575 | + public static function get_entity_route($model, $id) |
|
576 | + { |
|
577 | + return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id; |
|
578 | + } |
|
579 | + |
|
580 | + |
|
581 | + /** |
|
582 | + * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace, |
|
583 | + * excluding the preceding slash. |
|
584 | + * Eg you pass get_plural_route_to('Event', 12) = 'events/12' |
|
585 | + * |
|
586 | + * @param EEM_Base $model eg Event or Venue |
|
587 | + * @param string $id |
|
588 | + * @param EE_Model_Relation_Base $relation_obj |
|
589 | + * @return string |
|
590 | + */ |
|
591 | + public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj) |
|
592 | + { |
|
593 | + $related_model_name_endpoint_part = ModelRead::getRelatedEntityName( |
|
594 | + $relation_obj->get_other_model()->get_this_model_name(), |
|
595 | + $relation_obj |
|
596 | + ); |
|
597 | + return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part; |
|
598 | + } |
|
599 | + |
|
600 | + |
|
601 | + /** |
|
602 | + * Adds onto the $relative_route the EE4 REST API versioned namespace. |
|
603 | + * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events' |
|
604 | + * |
|
605 | + * @param string $relative_route |
|
606 | + * @param string $version |
|
607 | + * @return string |
|
608 | + */ |
|
609 | + public static function get_versioned_route_to($relative_route, $version = '4.8.36') |
|
610 | + { |
|
611 | + return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route; |
|
612 | + } |
|
613 | + |
|
614 | + |
|
615 | + /** |
|
616 | + * Adds all the RPC-style routes (remote procedure call-like routes, ie |
|
617 | + * routes that don't conform to the traditional REST CRUD-style). |
|
618 | + * |
|
619 | + * @deprecated since 4.9.1 |
|
620 | + */ |
|
621 | + protected function _register_rpc_routes() |
|
622 | + { |
|
623 | + $routes = array(); |
|
624 | + foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
625 | + $routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version( |
|
626 | + $version, |
|
627 | + $hidden_endpoint |
|
628 | + ); |
|
629 | + } |
|
630 | + return $routes; |
|
631 | + } |
|
632 | + |
|
633 | + |
|
634 | + /** |
|
635 | + * @param string $version |
|
636 | + * @param boolean $hidden_endpoint |
|
637 | + * @return array |
|
638 | + */ |
|
639 | + protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false) |
|
640 | + { |
|
641 | + $this_versions_routes = array(); |
|
642 | + // checkin endpoint |
|
643 | + $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array( |
|
644 | + array( |
|
645 | + 'callback' => array( |
|
646 | + 'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin', |
|
647 | + 'handleRequestToggleCheckin', |
|
648 | + ), |
|
649 | + 'methods' => WP_REST_Server::CREATABLE, |
|
650 | + 'hidden_endpoint' => $hidden_endpoint, |
|
651 | + 'args' => array( |
|
652 | + 'force' => array( |
|
653 | + 'required' => false, |
|
654 | + 'default' => false, |
|
655 | + 'description' => __( |
|
656 | + // @codingStandardsIgnoreStart |
|
657 | + 'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses', |
|
658 | + // @codingStandardsIgnoreEnd |
|
659 | + 'event_espresso' |
|
660 | + ), |
|
661 | + ), |
|
662 | + ), |
|
663 | + 'callback_args' => array($version), |
|
664 | + ), |
|
665 | + ); |
|
666 | + return apply_filters( |
|
667 | + 'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes', |
|
668 | + $this_versions_routes, |
|
669 | + $version, |
|
670 | + $hidden_endpoint |
|
671 | + ); |
|
672 | + } |
|
673 | + |
|
674 | + |
|
675 | + /** |
|
676 | + * Gets the query params that can be used when request one or many |
|
677 | + * |
|
678 | + * @param EEM_Base $model |
|
679 | + * @param string $version |
|
680 | + * @return array |
|
681 | + */ |
|
682 | + protected function _get_response_selection_query_params(\EEM_Base $model, $version) |
|
683 | + { |
|
684 | + return apply_filters( |
|
685 | + 'FHEE__EED_Core_Rest_Api___get_response_selection_query_params', |
|
686 | + array( |
|
687 | + 'include' => array( |
|
688 | + 'required' => false, |
|
689 | + 'default' => '*', |
|
690 | + 'type' => 'string', |
|
691 | + ), |
|
692 | + 'calculate' => array( |
|
693 | + 'required' => false, |
|
694 | + 'default' => '', |
|
695 | + 'enum' => self::$_field_calculator->retrieveCalculatedFieldsForModel($model), |
|
696 | + 'type' => 'string', |
|
697 | + // because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization |
|
698 | + // freaks out. We'll just validate this argument while handling the request |
|
699 | + 'validate_callback' => null, |
|
700 | + 'sanitize_callback' => null, |
|
701 | + ), |
|
702 | + ), |
|
703 | + $model, |
|
704 | + $version |
|
705 | + ); |
|
706 | + } |
|
707 | + |
|
708 | + |
|
709 | + /** |
|
710 | + * Gets the parameters acceptable for delete requests |
|
711 | + * |
|
712 | + * @param \EEM_Base $model |
|
713 | + * @param string $version |
|
714 | + * @return array |
|
715 | + */ |
|
716 | + protected function _get_delete_query_params(\EEM_Base $model, $version) |
|
717 | + { |
|
718 | + $params_for_delete = array( |
|
719 | + 'allow_blocking' => array( |
|
720 | + 'required' => false, |
|
721 | + 'default' => true, |
|
722 | + 'type' => 'boolean', |
|
723 | + ), |
|
724 | + ); |
|
725 | + $params_for_delete['force'] = array( |
|
726 | + 'required' => false, |
|
727 | + 'default' => false, |
|
728 | + 'type' => 'boolean', |
|
729 | + ); |
|
730 | + return apply_filters( |
|
731 | + 'FHEE__EED_Core_Rest_Api___get_delete_query_params', |
|
732 | + $params_for_delete, |
|
733 | + $model, |
|
734 | + $version |
|
735 | + ); |
|
736 | + } |
|
737 | + |
|
738 | + |
|
739 | + /** |
|
740 | + * Gets info about reading query params that are acceptable |
|
741 | + * |
|
742 | + * @param \EEM_Base $model eg 'Event' or 'Venue' |
|
743 | + * @param string $version |
|
744 | + * @return array describing the args acceptable when querying this model |
|
745 | + * @throws EE_Error |
|
746 | + */ |
|
747 | + protected function _get_read_query_params(\EEM_Base $model, $version) |
|
748 | + { |
|
749 | + $default_orderby = array(); |
|
750 | + foreach ($model->get_combined_primary_key_fields() as $key_field) { |
|
751 | + $default_orderby[ $key_field->get_name() ] = 'ASC'; |
|
752 | + } |
|
753 | + return array_merge( |
|
754 | + $this->_get_response_selection_query_params($model, $version), |
|
755 | + array( |
|
756 | + 'where' => array( |
|
757 | + 'required' => false, |
|
758 | + 'default' => array(), |
|
759 | + 'type' => 'object', |
|
760 | + // because we accept an almost infinite list of possible where conditions, WP |
|
761 | + // core validation and sanitization freaks out. We'll just validate this argument |
|
762 | + // while handling the request |
|
763 | + 'validate_callback' => null, |
|
764 | + 'sanitize_callback' => null, |
|
765 | + ), |
|
766 | + 'limit' => array( |
|
767 | + 'required' => false, |
|
768 | + 'default' => EED_Core_Rest_Api::get_default_query_limit(), |
|
769 | + 'type' => array( |
|
770 | + 'array', |
|
771 | + 'string', |
|
772 | + 'integer', |
|
773 | + ), |
|
774 | + // because we accept a variety of types, WP core validation and sanitization |
|
775 | + // freaks out. We'll just validate this argument while handling the request |
|
776 | + 'validate_callback' => null, |
|
777 | + 'sanitize_callback' => null, |
|
778 | + ), |
|
779 | + 'order_by' => array( |
|
780 | + 'required' => false, |
|
781 | + 'default' => $default_orderby, |
|
782 | + 'type' => array( |
|
783 | + 'object', |
|
784 | + 'string', |
|
785 | + ),// because we accept a variety of types, WP core validation and sanitization |
|
786 | + // freaks out. We'll just validate this argument while handling the request |
|
787 | + 'validate_callback' => null, |
|
788 | + 'sanitize_callback' => null, |
|
789 | + ), |
|
790 | + 'group_by' => array( |
|
791 | + 'required' => false, |
|
792 | + 'default' => null, |
|
793 | + 'type' => array( |
|
794 | + 'object', |
|
795 | + 'string', |
|
796 | + ), |
|
797 | + // because we accept an almost infinite list of possible groupings, |
|
798 | + // WP core validation and sanitization |
|
799 | + // freaks out. We'll just validate this argument while handling the request |
|
800 | + 'validate_callback' => null, |
|
801 | + 'sanitize_callback' => null, |
|
802 | + ), |
|
803 | + 'having' => array( |
|
804 | + 'required' => false, |
|
805 | + 'default' => null, |
|
806 | + 'type' => 'object', |
|
807 | + // because we accept an almost infinite list of possible where conditions, WP |
|
808 | + // core validation and sanitization freaks out. We'll just validate this argument |
|
809 | + // while handling the request |
|
810 | + 'validate_callback' => null, |
|
811 | + 'sanitize_callback' => null, |
|
812 | + ), |
|
813 | + 'caps' => array( |
|
814 | + 'required' => false, |
|
815 | + 'default' => EEM_Base::caps_read, |
|
816 | + 'type' => 'string', |
|
817 | + 'enum' => array( |
|
818 | + EEM_Base::caps_read, |
|
819 | + EEM_Base::caps_read_admin, |
|
820 | + EEM_Base::caps_edit, |
|
821 | + EEM_Base::caps_delete, |
|
822 | + ), |
|
823 | + ), |
|
824 | + ) |
|
825 | + ); |
|
826 | + } |
|
827 | + |
|
828 | + |
|
829 | + /** |
|
830 | + * Gets parameter information for a model regarding writing data |
|
831 | + * |
|
832 | + * @param string $model_name |
|
833 | + * @param ModelVersionInfo $model_version_info |
|
834 | + * @param boolean $create whether this is for request to create (in |
|
835 | + * which case we need all required params) or |
|
836 | + * just to update (in which case we don't |
|
837 | + * need those on every request) |
|
838 | + * @return array |
|
839 | + */ |
|
840 | + protected function _get_write_params( |
|
841 | + $model_name, |
|
842 | + ModelVersionInfo $model_version_info, |
|
843 | + $create = false |
|
844 | + ) { |
|
845 | + $model = EE_Registry::instance()->load_model($model_name); |
|
846 | + $fields = $model_version_info->fieldsOnModelInThisVersion($model); |
|
847 | + $args_info = array(); |
|
848 | + foreach ($fields as $field_name => $field_obj) { |
|
849 | + if ($field_obj->is_auto_increment()) { |
|
850 | + // totally ignore auto increment IDs |
|
851 | + continue; |
|
852 | + } |
|
853 | + $arg_info = $field_obj->getSchema(); |
|
854 | + $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null; |
|
855 | + $arg_info['required'] = $required; |
|
856 | + // remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right? |
|
857 | + unset($arg_info['readonly']); |
|
858 | + $schema_properties = $field_obj->getSchemaProperties(); |
|
859 | + if (isset($schema_properties['raw']) |
|
860 | + && $field_obj->getSchemaType() === 'object' |
|
861 | + ) { |
|
862 | + // if there's a "raw" form of this argument, use those properties instead |
|
863 | + $arg_info = array_replace( |
|
864 | + $arg_info, |
|
865 | + $schema_properties['raw'] |
|
866 | + ); |
|
867 | + } |
|
868 | + $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson( |
|
869 | + $field_obj, |
|
870 | + $field_obj->get_default_value(), |
|
871 | + $model_version_info->requestedVersion() |
|
872 | + ); |
|
873 | + // we do our own validation and sanitization within the controller |
|
874 | + if (function_exists('rest_validate_value_from_schema')) { |
|
875 | + $sanitize_callback = array( |
|
876 | + 'EED_Core_Rest_Api', |
|
877 | + 'default_sanitize_callback', |
|
878 | + ); |
|
879 | + } else { |
|
880 | + $sanitize_callback = null; |
|
881 | + } |
|
882 | + $arg_info['sanitize_callback'] = $sanitize_callback; |
|
883 | + $args_info[ $field_name ] = $arg_info; |
|
884 | + if ($field_obj instanceof EE_Datetime_Field) { |
|
885 | + $gmt_arg_info = $arg_info; |
|
886 | + $gmt_arg_info['description'] = sprintf( |
|
887 | + esc_html__( |
|
888 | + '%1$s - the value for this field in UTC. Ignored if %2$s is provided.', |
|
889 | + 'event_espresso' |
|
890 | + ), |
|
891 | + $field_obj->get_nicename(), |
|
892 | + $field_name |
|
893 | + ); |
|
894 | + $args_info[ $field_name . '_gmt' ] = $gmt_arg_info; |
|
895 | + } |
|
896 | + } |
|
897 | + return $args_info; |
|
898 | + } |
|
899 | + |
|
900 | + |
|
901 | + /** |
|
902 | + * Replacement for WP API's 'rest_parse_request_arg'. |
|
903 | + * If the value is blank but not required, don't bother validating it. |
|
904 | + * Also, it uses our email validation instead of WP API's default. |
|
905 | + * |
|
906 | + * @param $value |
|
907 | + * @param WP_REST_Request $request |
|
908 | + * @param $param |
|
909 | + * @return bool|true|WP_Error |
|
910 | + * @throws InvalidArgumentException |
|
911 | + * @throws InvalidInterfaceException |
|
912 | + * @throws InvalidDataTypeException |
|
913 | + */ |
|
914 | + public static function default_sanitize_callback($value, WP_REST_Request $request, $param) |
|
915 | + { |
|
916 | + $attributes = $request->get_attributes(); |
|
917 | + if (! isset($attributes['args'][ $param ]) |
|
918 | + || ! is_array($attributes['args'][ $param ])) { |
|
919 | + $validation_result = true; |
|
920 | + } else { |
|
921 | + $args = $attributes['args'][ $param ]; |
|
922 | + if (( |
|
923 | + $value === '' |
|
924 | + || $value === null |
|
925 | + ) |
|
926 | + && (! isset($args['required']) |
|
927 | + || $args['required'] === false |
|
928 | + ) |
|
929 | + ) { |
|
930 | + // not required and not provided? that's cool |
|
931 | + $validation_result = true; |
|
932 | + } elseif (isset($args['format']) |
|
933 | + && $args['format'] === 'email' |
|
934 | + ) { |
|
935 | + $validation_result = true; |
|
936 | + if (! self::_validate_email($value)) { |
|
937 | + $validation_result = new WP_Error( |
|
938 | + 'rest_invalid_param', |
|
939 | + esc_html__( |
|
940 | + 'The email address is not valid or does not exist.', |
|
941 | + 'event_espresso' |
|
942 | + ) |
|
943 | + ); |
|
944 | + } |
|
945 | + } else { |
|
946 | + $validation_result = rest_validate_value_from_schema($value, $args, $param); |
|
947 | + } |
|
948 | + } |
|
949 | + if (is_wp_error($validation_result)) { |
|
950 | + return $validation_result; |
|
951 | + } |
|
952 | + return rest_sanitize_request_arg($value, $request, $param); |
|
953 | + } |
|
954 | + |
|
955 | + |
|
956 | + /** |
|
957 | + * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email() |
|
958 | + * |
|
959 | + * @param $email |
|
960 | + * @return bool |
|
961 | + * @throws InvalidArgumentException |
|
962 | + * @throws InvalidInterfaceException |
|
963 | + * @throws InvalidDataTypeException |
|
964 | + */ |
|
965 | + protected static function _validate_email($email) |
|
966 | + { |
|
967 | + try { |
|
968 | + EmailAddressFactory::create($email); |
|
969 | + return true; |
|
970 | + } catch (EmailValidationException $e) { |
|
971 | + return false; |
|
972 | + } |
|
973 | + } |
|
974 | + |
|
975 | + |
|
976 | + /** |
|
977 | + * Gets routes for the config |
|
978 | + * |
|
979 | + * @return array @see _register_model_routes |
|
980 | + * @deprecated since version 4.9.1 |
|
981 | + */ |
|
982 | + protected function _register_config_routes() |
|
983 | + { |
|
984 | + $config_routes = array(); |
|
985 | + foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
986 | + $config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version( |
|
987 | + $version, |
|
988 | + $hidden_endpoint |
|
989 | + ); |
|
990 | + } |
|
991 | + return $config_routes; |
|
992 | + } |
|
993 | + |
|
994 | + |
|
995 | + /** |
|
996 | + * Gets routes for the config for the specified version |
|
997 | + * |
|
998 | + * @param string $version |
|
999 | + * @param boolean $hidden_endpoint |
|
1000 | + * @return array |
|
1001 | + */ |
|
1002 | + protected function _get_config_route_data_for_version($version, $hidden_endpoint) |
|
1003 | + { |
|
1004 | + return array( |
|
1005 | + 'config' => array( |
|
1006 | + array( |
|
1007 | + 'callback' => array( |
|
1008 | + 'EventEspresso\core\libraries\rest_api\controllers\config\Read', |
|
1009 | + 'handleRequest', |
|
1010 | + ), |
|
1011 | + 'methods' => WP_REST_Server::READABLE, |
|
1012 | + 'hidden_endpoint' => $hidden_endpoint, |
|
1013 | + 'callback_args' => array($version), |
|
1014 | + ), |
|
1015 | + ), |
|
1016 | + 'site_info' => array( |
|
1017 | + array( |
|
1018 | + 'callback' => array( |
|
1019 | + 'EventEspresso\core\libraries\rest_api\controllers\config\Read', |
|
1020 | + 'handleRequestSiteInfo', |
|
1021 | + ), |
|
1022 | + 'methods' => WP_REST_Server::READABLE, |
|
1023 | + 'hidden_endpoint' => $hidden_endpoint, |
|
1024 | + 'callback_args' => array($version), |
|
1025 | + ), |
|
1026 | + ), |
|
1027 | + ); |
|
1028 | + } |
|
1029 | + |
|
1030 | + |
|
1031 | + /** |
|
1032 | + * Gets the meta info routes |
|
1033 | + * |
|
1034 | + * @return array @see _register_model_routes |
|
1035 | + * @deprecated since version 4.9.1 |
|
1036 | + */ |
|
1037 | + protected function _register_meta_routes() |
|
1038 | + { |
|
1039 | + $meta_routes = array(); |
|
1040 | + foreach (self::versions_served() as $version => $hidden_endpoint) { |
|
1041 | + $meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version( |
|
1042 | + $version, |
|
1043 | + $hidden_endpoint |
|
1044 | + ); |
|
1045 | + } |
|
1046 | + return $meta_routes; |
|
1047 | + } |
|
1048 | + |
|
1049 | + |
|
1050 | + /** |
|
1051 | + * @param string $version |
|
1052 | + * @param boolean $hidden_endpoint |
|
1053 | + * @return array |
|
1054 | + */ |
|
1055 | + protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false) |
|
1056 | + { |
|
1057 | + return array( |
|
1058 | + 'resources' => array( |
|
1059 | + array( |
|
1060 | + 'callback' => array( |
|
1061 | + 'EventEspresso\core\libraries\rest_api\controllers\model\Meta', |
|
1062 | + 'handleRequestModelsMeta', |
|
1063 | + ), |
|
1064 | + 'methods' => WP_REST_Server::READABLE, |
|
1065 | + 'hidden_endpoint' => $hidden_endpoint, |
|
1066 | + 'callback_args' => array($version), |
|
1067 | + ), |
|
1068 | + ), |
|
1069 | + ); |
|
1070 | + } |
|
1071 | + |
|
1072 | + |
|
1073 | + /** |
|
1074 | + * Tries to hide old 4.6 endpoints from the |
|
1075 | + * |
|
1076 | + * @param array $route_data |
|
1077 | + * @return array |
|
1078 | + * @throws \EE_Error |
|
1079 | + */ |
|
1080 | + public static function hide_old_endpoints($route_data) |
|
1081 | + { |
|
1082 | + // allow API clients to override which endpoints get hidden, in case |
|
1083 | + // they want to discover particular endpoints |
|
1084 | + // also, we don't have access to the request so we have to just grab it from the superglobal |
|
1085 | + $force_show_ee_namespace = ltrim( |
|
1086 | + EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''), |
|
1087 | + '/' |
|
1088 | + ); |
|
1089 | + foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) { |
|
1090 | + foreach ($relative_urls as $resource_name => $endpoints) { |
|
1091 | + foreach ($endpoints as $key => $endpoint) { |
|
1092 | + // skip schema and other route options |
|
1093 | + if (! is_numeric($key)) { |
|
1094 | + continue; |
|
1095 | + } |
|
1096 | + // by default, hide "hidden_endpoint"s, unless the request indicates |
|
1097 | + // to $force_show_ee_namespace, in which case only show that one |
|
1098 | + // namespace's endpoints (and hide all others) |
|
1099 | + if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace) |
|
1100 | + || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '') |
|
1101 | + ) { |
|
1102 | + $full_route = '/' . ltrim($namespace, '/'); |
|
1103 | + $full_route .= '/' . ltrim($resource_name, '/'); |
|
1104 | + unset($route_data[ $full_route ]); |
|
1105 | + } |
|
1106 | + } |
|
1107 | + } |
|
1108 | + } |
|
1109 | + return $route_data; |
|
1110 | + } |
|
1111 | + |
|
1112 | + |
|
1113 | + /** |
|
1114 | + * Returns an array describing which versions of core support serving requests for. |
|
1115 | + * Keys are core versions' major and minor version, and values are the |
|
1116 | + * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like |
|
1117 | + * data by just removing a few models and fields from the responses. However, 4.15 might remove |
|
1118 | + * the answers table entirely, in which case it would be very difficult for |
|
1119 | + * it to serve 4.6-style responses. |
|
1120 | + * Versions of core that are missing from this array are unknowns. |
|
1121 | + * previous ver |
|
1122 | + * |
|
1123 | + * @return array |
|
1124 | + */ |
|
1125 | + public static function version_compatibilities() |
|
1126 | + { |
|
1127 | + return apply_filters( |
|
1128 | + 'FHEE__EED_Core_REST_API__version_compatibilities', |
|
1129 | + array( |
|
1130 | + '4.8.29' => '4.8.29', |
|
1131 | + '4.8.33' => '4.8.29', |
|
1132 | + '4.8.34' => '4.8.29', |
|
1133 | + '4.8.36' => '4.8.29', |
|
1134 | + ) |
|
1135 | + ); |
|
1136 | + } |
|
1137 | + |
|
1138 | + |
|
1139 | + /** |
|
1140 | + * Gets the latest API version served. Eg if there |
|
1141 | + * are two versions served of the API, 4.8.29 and 4.8.32, and |
|
1142 | + * we are on core version 4.8.34, it will return the string "4.8.32" |
|
1143 | + * |
|
1144 | + * @return string |
|
1145 | + */ |
|
1146 | + public static function latest_rest_api_version() |
|
1147 | + { |
|
1148 | + $versions_served = \EED_Core_Rest_Api::versions_served(); |
|
1149 | + $versions_served_keys = array_keys($versions_served); |
|
1150 | + return end($versions_served_keys); |
|
1151 | + } |
|
1152 | + |
|
1153 | + |
|
1154 | + /** |
|
1155 | + * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of |
|
1156 | + * EE the API can serve requests for. Eg, if we are on 4.15 of core, and |
|
1157 | + * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ). |
|
1158 | + * We also indicate whether or not this version should be put in the index or not |
|
1159 | + * |
|
1160 | + * @return array keys are API version numbers (just major and minor numbers), and values |
|
1161 | + * are whether or not they should be hidden |
|
1162 | + */ |
|
1163 | + public static function versions_served() |
|
1164 | + { |
|
1165 | + $versions_served = array(); |
|
1166 | + $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities(); |
|
1167 | + $lowest_compatible_version = end($possibly_served_versions); |
|
1168 | + reset($possibly_served_versions); |
|
1169 | + $versions_served_historically = array_keys($possibly_served_versions); |
|
1170 | + $latest_version = end($versions_served_historically); |
|
1171 | + reset($versions_served_historically); |
|
1172 | + // for each version of core we have ever served: |
|
1173 | + foreach ($versions_served_historically as $key_versioned_endpoint) { |
|
1174 | + // if it's not above the current core version, and it's compatible with the current version of core |
|
1175 | + if ($key_versioned_endpoint === $latest_version) { |
|
1176 | + // don't hide the latest version in the index |
|
1177 | + $versions_served[ $key_versioned_endpoint ] = false; |
|
1178 | + } elseif ($key_versioned_endpoint >= $lowest_compatible_version |
|
1179 | + && $key_versioned_endpoint < EED_Core_Rest_Api::core_version() |
|
1180 | + ) { |
|
1181 | + // include, but hide, previous versions which are still supported |
|
1182 | + $versions_served[ $key_versioned_endpoint ] = true; |
|
1183 | + } elseif (apply_filters( |
|
1184 | + 'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions', |
|
1185 | + false, |
|
1186 | + $possibly_served_versions |
|
1187 | + )) { |
|
1188 | + // if a version is no longer supported, don't include it in index or list of versions served |
|
1189 | + $versions_served[ $key_versioned_endpoint ] = true; |
|
1190 | + } |
|
1191 | + } |
|
1192 | + return $versions_served; |
|
1193 | + } |
|
1194 | + |
|
1195 | + |
|
1196 | + /** |
|
1197 | + * Gets the major and minor version of EE core's version string |
|
1198 | + * |
|
1199 | + * @return string |
|
1200 | + */ |
|
1201 | + public static function core_version() |
|
1202 | + { |
|
1203 | + return apply_filters( |
|
1204 | + 'FHEE__EED_Core_REST_API__core_version', |
|
1205 | + implode( |
|
1206 | + '.', |
|
1207 | + array_slice( |
|
1208 | + explode( |
|
1209 | + '.', |
|
1210 | + espresso_version() |
|
1211 | + ), |
|
1212 | + 0, |
|
1213 | + 3 |
|
1214 | + ) |
|
1215 | + ) |
|
1216 | + ); |
|
1217 | + } |
|
1218 | + |
|
1219 | + |
|
1220 | + /** |
|
1221 | + * Gets the default limit that should be used when querying for resources |
|
1222 | + * |
|
1223 | + * @return int |
|
1224 | + */ |
|
1225 | + public static function get_default_query_limit() |
|
1226 | + { |
|
1227 | + // we actually don't use a const because we want folks to always use |
|
1228 | + // this method, not the const directly |
|
1229 | + return apply_filters( |
|
1230 | + 'FHEE__EED_Core_Rest_Api__get_default_query_limit', |
|
1231 | + 50 |
|
1232 | + ); |
|
1233 | + } |
|
1234 | + |
|
1235 | + |
|
1236 | + /** |
|
1237 | + * |
|
1238 | + * @param string $version api version string (i.e. '4.8.36') |
|
1239 | + * @return array |
|
1240 | + */ |
|
1241 | + public static function getCollectionRoutesIndexedByModelName($version = '') |
|
1242 | + { |
|
1243 | + $version = empty($version) ? self::latest_rest_api_version() : $version; |
|
1244 | + $model_names = self::model_names_with_plural_routes($version); |
|
1245 | + $collection_routes = array(); |
|
1246 | + foreach ($model_names as $model_name => $model_class_name) { |
|
1247 | + $collection_routes[ strtolower($model_name) ] = '/' . self::ee_api_namespace . $version . '/' |
|
1248 | + . EEH_Inflector::pluralize_and_lower($model_name); |
|
1249 | + } |
|
1250 | + return $collection_routes; |
|
1251 | + } |
|
1252 | + |
|
1253 | + |
|
1254 | + /** |
|
1255 | + * Returns an array of primary key names indexed by model names. |
|
1256 | + * @param string $version |
|
1257 | + * @return array |
|
1258 | + */ |
|
1259 | + public static function getPrimaryKeyNamesIndexedByModelName($version = '') |
|
1260 | + { |
|
1261 | + $version = empty($version) ? self::latest_rest_api_version() : $version; |
|
1262 | + $model_names = self::model_names_with_plural_routes($version); |
|
1263 | + $primary_key_items = array(); |
|
1264 | + foreach ($model_names as $model_name => $model_class_name) { |
|
1265 | + $primary_keys = $model_class_name::instance()->get_combined_primary_key_fields(); |
|
1266 | + foreach ($primary_keys as $primary_key_name => $primary_key_field) { |
|
1267 | + if (count($primary_keys) > 1) { |
|
1268 | + $primary_key_items[ strtolower($model_name) ][] = $primary_key_name; |
|
1269 | + } else { |
|
1270 | + $primary_key_items[ strtolower($model_name) ] = $primary_key_name; |
|
1271 | + } |
|
1272 | + } |
|
1273 | + } |
|
1274 | + return $primary_key_items; |
|
1275 | + } |
|
1276 | + |
|
1277 | + |
|
1278 | + |
|
1279 | + /** |
|
1280 | + * run - initial module setup |
|
1281 | + * |
|
1282 | + * @access public |
|
1283 | + * @param WP $WP |
|
1284 | + * @return void |
|
1285 | + */ |
|
1286 | + public function run($WP) |
|
1287 | + { |
|
1288 | + } |
|
1289 | 1289 | } |
@@ -122,7 +122,7 @@ discard block |
||
122 | 122 | */ |
123 | 123 | protected static function _set_hooks_for_changes() |
124 | 124 | { |
125 | - $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false); |
|
125 | + $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES.'rest_api'.DS.'changes'), false); |
|
126 | 126 | foreach ($folder_contents as $classname_in_namespace => $filepath) { |
127 | 127 | // ignore the base parent class |
128 | 128 | // and legacy named classes |
@@ -131,7 +131,7 @@ discard block |
||
131 | 131 | ) { |
132 | 132 | continue; |
133 | 133 | } |
134 | - $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace; |
|
134 | + $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\'.$classname_in_namespace; |
|
135 | 135 | if (class_exists($full_classname)) { |
136 | 136 | $instance_of_class = new $full_classname; |
137 | 137 | if ($instance_of_class instanceof ChangesInBase) { |
@@ -176,10 +176,10 @@ discard block |
||
176 | 176 | * } |
177 | 177 | */ |
178 | 178 | // skip route options |
179 | - if (! is_numeric($endpoint_key)) { |
|
179 | + if ( ! is_numeric($endpoint_key)) { |
|
180 | 180 | continue; |
181 | 181 | } |
182 | - if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) { |
|
182 | + if ( ! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) { |
|
183 | 183 | throw new EE_Error( |
184 | 184 | esc_html__( |
185 | 185 | // @codingStandardsIgnoreStart |
@@ -200,7 +200,7 @@ discard block |
||
200 | 200 | } |
201 | 201 | if (isset($data_for_single_endpoint['callback_args'])) { |
202 | 202 | $callback_args = $data_for_single_endpoint['callback_args']; |
203 | - $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use ( |
|
203 | + $single_endpoint_args['callback'] = function(\WP_REST_Request $request) use ( |
|
204 | 204 | $callback, |
205 | 205 | $callback_args |
206 | 206 | ) { |
@@ -219,7 +219,7 @@ discard block |
||
219 | 219 | $schema_route_data = $data_for_multiple_endpoints['schema']; |
220 | 220 | $schema_callback = $schema_route_data['schema_callback']; |
221 | 221 | $callback_args = $schema_route_data['callback_args']; |
222 | - $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) { |
|
222 | + $multiple_endpoint_args['schema'] = function() use ($schema_callback, $callback_args) { |
|
223 | 223 | return call_user_func_array( |
224 | 224 | $schema_callback, |
225 | 225 | $callback_args |
@@ -261,7 +261,7 @@ discard block |
||
261 | 261 | { |
262 | 262 | // delete the saved EE REST API routes |
263 | 263 | foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) { |
264 | - delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version); |
|
264 | + delete_option(EED_Core_Rest_Api::saved_routes_option_names.$version); |
|
265 | 265 | } |
266 | 266 | } |
267 | 267 | |
@@ -280,7 +280,7 @@ discard block |
||
280 | 280 | { |
281 | 281 | $ee_routes = array(); |
282 | 282 | foreach (self::versions_served() as $version => $hidden_endpoints) { |
283 | - $ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version( |
|
283 | + $ee_routes[self::ee_api_namespace.$version] = self::_get_ee_route_data_for_version( |
|
284 | 284 | $version, |
285 | 285 | $hidden_endpoints |
286 | 286 | ); |
@@ -300,8 +300,8 @@ discard block |
||
300 | 300 | */ |
301 | 301 | protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false) |
302 | 302 | { |
303 | - $ee_routes = get_option(self::saved_routes_option_names . $version, null); |
|
304 | - if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) { |
|
303 | + $ee_routes = get_option(self::saved_routes_option_names.$version, null); |
|
304 | + if ( ! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) { |
|
305 | 305 | $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints); |
306 | 306 | } |
307 | 307 | return $ee_routes; |
@@ -328,7 +328,7 @@ discard block |
||
328 | 328 | $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints) |
329 | 329 | ) |
330 | 330 | ); |
331 | - $option_name = self::saved_routes_option_names . $version; |
|
331 | + $option_name = self::saved_routes_option_names.$version; |
|
332 | 332 | if (get_option($option_name)) { |
333 | 333 | update_option($option_name, $routes, true); |
334 | 334 | } else { |
@@ -373,8 +373,8 @@ discard block |
||
373 | 373 | { |
374 | 374 | $model_routes = array(); |
375 | 375 | foreach (self::versions_served() as $version => $hidden_endpoint) { |
376 | - $model_routes[ EED_Core_Rest_Api::ee_api_namespace |
|
377 | - . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint); |
|
376 | + $model_routes[EED_Core_Rest_Api::ee_api_namespace |
|
377 | + . $version] = $this->_get_config_route_data_for_version($version, $hidden_endpoint); |
|
378 | 378 | } |
379 | 379 | return $model_routes; |
380 | 380 | } |
@@ -443,13 +443,13 @@ discard block |
||
443 | 443 | foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) { |
444 | 444 | $model = \EE_Registry::instance()->load_model($model_name); |
445 | 445 | // if this isn't a valid model then let's skip iterate to the next item in the loop. |
446 | - if (! $model instanceof EEM_Base) { |
|
446 | + if ( ! $model instanceof EEM_Base) { |
|
447 | 447 | continue; |
448 | 448 | } |
449 | 449 | // yes we could just register one route for ALL models, but then they wouldn't show up in the index |
450 | 450 | $plural_model_route = EED_Core_Rest_Api::get_collection_route($model); |
451 | 451 | $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)'); |
452 | - $model_routes[ $plural_model_route ] = array( |
|
452 | + $model_routes[$plural_model_route] = array( |
|
453 | 453 | array( |
454 | 454 | 'callback' => array( |
455 | 455 | 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
@@ -460,7 +460,7 @@ discard block |
||
460 | 460 | 'hidden_endpoint' => $hidden_endpoint, |
461 | 461 | 'args' => $this->_get_read_query_params($model, $version), |
462 | 462 | '_links' => array( |
463 | - 'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route), |
|
463 | + 'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace.$version.$singular_model_route), |
|
464 | 464 | ), |
465 | 465 | ), |
466 | 466 | 'schema' => array( |
@@ -471,7 +471,7 @@ discard block |
||
471 | 471 | 'callback_args' => array($version, $model_name), |
472 | 472 | ), |
473 | 473 | ); |
474 | - $model_routes[ $singular_model_route ] = array( |
|
474 | + $model_routes[$singular_model_route] = array( |
|
475 | 475 | array( |
476 | 476 | 'callback' => array( |
477 | 477 | 'EventEspresso\core\libraries\rest_api\controllers\model\Read', |
@@ -488,7 +488,7 @@ discard block |
||
488 | 488 | EED_Core_Rest_Api::should_have_write_endpoints($model), |
489 | 489 | $model |
490 | 490 | )) { |
491 | - $model_routes[ $plural_model_route ][] = array( |
|
491 | + $model_routes[$plural_model_route][] = array( |
|
492 | 492 | 'callback' => array( |
493 | 493 | 'EventEspresso\core\libraries\rest_api\controllers\model\Write', |
494 | 494 | 'handleRequestInsert', |
@@ -498,8 +498,8 @@ discard block |
||
498 | 498 | 'hidden_endpoint' => $hidden_endpoint, |
499 | 499 | 'args' => $this->_get_write_params($model_name, $model_version_info, true), |
500 | 500 | ); |
501 | - $model_routes[ $singular_model_route ] = array_merge( |
|
502 | - $model_routes[ $singular_model_route ], |
|
501 | + $model_routes[$singular_model_route] = array_merge( |
|
502 | + $model_routes[$singular_model_route], |
|
503 | 503 | array( |
504 | 504 | array( |
505 | 505 | 'callback' => array( |
@@ -542,7 +542,7 @@ discard block |
||
542 | 542 | 'args' => $this->_get_read_query_params($relation_obj->get_other_model(), $version), |
543 | 543 | ), |
544 | 544 | ); |
545 | - $model_routes[ $related_route ] = $endpoints; |
|
545 | + $model_routes[$related_route] = $endpoints; |
|
546 | 546 | } |
547 | 547 | } |
548 | 548 | return $model_routes; |
@@ -574,7 +574,7 @@ discard block |
||
574 | 574 | */ |
575 | 575 | public static function get_entity_route($model, $id) |
576 | 576 | { |
577 | - return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id; |
|
577 | + return EED_Core_Rest_Api::get_collection_route($model).'/'.$id; |
|
578 | 578 | } |
579 | 579 | |
580 | 580 | |
@@ -594,7 +594,7 @@ discard block |
||
594 | 594 | $relation_obj->get_other_model()->get_this_model_name(), |
595 | 595 | $relation_obj |
596 | 596 | ); |
597 | - return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part; |
|
597 | + return EED_Core_Rest_Api::get_entity_route($model, $id).'/'.$related_model_name_endpoint_part; |
|
598 | 598 | } |
599 | 599 | |
600 | 600 | |
@@ -608,7 +608,7 @@ discard block |
||
608 | 608 | */ |
609 | 609 | public static function get_versioned_route_to($relative_route, $version = '4.8.36') |
610 | 610 | { |
611 | - return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route; |
|
611 | + return '/'.EED_Core_Rest_Api::ee_api_namespace.$version.'/'.$relative_route; |
|
612 | 612 | } |
613 | 613 | |
614 | 614 | |
@@ -622,7 +622,7 @@ discard block |
||
622 | 622 | { |
623 | 623 | $routes = array(); |
624 | 624 | foreach (self::versions_served() as $version => $hidden_endpoint) { |
625 | - $routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version( |
|
625 | + $routes[self::ee_api_namespace.$version] = $this->_get_rpc_route_data_for_version( |
|
626 | 626 | $version, |
627 | 627 | $hidden_endpoint |
628 | 628 | ); |
@@ -748,7 +748,7 @@ discard block |
||
748 | 748 | { |
749 | 749 | $default_orderby = array(); |
750 | 750 | foreach ($model->get_combined_primary_key_fields() as $key_field) { |
751 | - $default_orderby[ $key_field->get_name() ] = 'ASC'; |
|
751 | + $default_orderby[$key_field->get_name()] = 'ASC'; |
|
752 | 752 | } |
753 | 753 | return array_merge( |
754 | 754 | $this->_get_response_selection_query_params($model, $version), |
@@ -782,7 +782,7 @@ discard block |
||
782 | 782 | 'type' => array( |
783 | 783 | 'object', |
784 | 784 | 'string', |
785 | - ),// because we accept a variety of types, WP core validation and sanitization |
|
785 | + ), // because we accept a variety of types, WP core validation and sanitization |
|
786 | 786 | // freaks out. We'll just validate this argument while handling the request |
787 | 787 | 'validate_callback' => null, |
788 | 788 | 'sanitize_callback' => null, |
@@ -880,7 +880,7 @@ discard block |
||
880 | 880 | $sanitize_callback = null; |
881 | 881 | } |
882 | 882 | $arg_info['sanitize_callback'] = $sanitize_callback; |
883 | - $args_info[ $field_name ] = $arg_info; |
|
883 | + $args_info[$field_name] = $arg_info; |
|
884 | 884 | if ($field_obj instanceof EE_Datetime_Field) { |
885 | 885 | $gmt_arg_info = $arg_info; |
886 | 886 | $gmt_arg_info['description'] = sprintf( |
@@ -891,7 +891,7 @@ discard block |
||
891 | 891 | $field_obj->get_nicename(), |
892 | 892 | $field_name |
893 | 893 | ); |
894 | - $args_info[ $field_name . '_gmt' ] = $gmt_arg_info; |
|
894 | + $args_info[$field_name.'_gmt'] = $gmt_arg_info; |
|
895 | 895 | } |
896 | 896 | } |
897 | 897 | return $args_info; |
@@ -914,16 +914,16 @@ discard block |
||
914 | 914 | public static function default_sanitize_callback($value, WP_REST_Request $request, $param) |
915 | 915 | { |
916 | 916 | $attributes = $request->get_attributes(); |
917 | - if (! isset($attributes['args'][ $param ]) |
|
918 | - || ! is_array($attributes['args'][ $param ])) { |
|
917 | + if ( ! isset($attributes['args'][$param]) |
|
918 | + || ! is_array($attributes['args'][$param])) { |
|
919 | 919 | $validation_result = true; |
920 | 920 | } else { |
921 | - $args = $attributes['args'][ $param ]; |
|
921 | + $args = $attributes['args'][$param]; |
|
922 | 922 | if (( |
923 | 923 | $value === '' |
924 | 924 | || $value === null |
925 | 925 | ) |
926 | - && (! isset($args['required']) |
|
926 | + && ( ! isset($args['required']) |
|
927 | 927 | || $args['required'] === false |
928 | 928 | ) |
929 | 929 | ) { |
@@ -933,7 +933,7 @@ discard block |
||
933 | 933 | && $args['format'] === 'email' |
934 | 934 | ) { |
935 | 935 | $validation_result = true; |
936 | - if (! self::_validate_email($value)) { |
|
936 | + if ( ! self::_validate_email($value)) { |
|
937 | 937 | $validation_result = new WP_Error( |
938 | 938 | 'rest_invalid_param', |
939 | 939 | esc_html__( |
@@ -983,7 +983,7 @@ discard block |
||
983 | 983 | { |
984 | 984 | $config_routes = array(); |
985 | 985 | foreach (self::versions_served() as $version => $hidden_endpoint) { |
986 | - $config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version( |
|
986 | + $config_routes[self::ee_api_namespace.$version] = $this->_get_config_route_data_for_version( |
|
987 | 987 | $version, |
988 | 988 | $hidden_endpoint |
989 | 989 | ); |
@@ -1038,7 +1038,7 @@ discard block |
||
1038 | 1038 | { |
1039 | 1039 | $meta_routes = array(); |
1040 | 1040 | foreach (self::versions_served() as $version => $hidden_endpoint) { |
1041 | - $meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version( |
|
1041 | + $meta_routes[self::ee_api_namespace.$version] = $this->_get_meta_route_data_for_version( |
|
1042 | 1042 | $version, |
1043 | 1043 | $hidden_endpoint |
1044 | 1044 | ); |
@@ -1090,7 +1090,7 @@ discard block |
||
1090 | 1090 | foreach ($relative_urls as $resource_name => $endpoints) { |
1091 | 1091 | foreach ($endpoints as $key => $endpoint) { |
1092 | 1092 | // skip schema and other route options |
1093 | - if (! is_numeric($key)) { |
|
1093 | + if ( ! is_numeric($key)) { |
|
1094 | 1094 | continue; |
1095 | 1095 | } |
1096 | 1096 | // by default, hide "hidden_endpoint"s, unless the request indicates |
@@ -1099,9 +1099,9 @@ discard block |
||
1099 | 1099 | if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace) |
1100 | 1100 | || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '') |
1101 | 1101 | ) { |
1102 | - $full_route = '/' . ltrim($namespace, '/'); |
|
1103 | - $full_route .= '/' . ltrim($resource_name, '/'); |
|
1104 | - unset($route_data[ $full_route ]); |
|
1102 | + $full_route = '/'.ltrim($namespace, '/'); |
|
1103 | + $full_route .= '/'.ltrim($resource_name, '/'); |
|
1104 | + unset($route_data[$full_route]); |
|
1105 | 1105 | } |
1106 | 1106 | } |
1107 | 1107 | } |
@@ -1174,19 +1174,19 @@ discard block |
||
1174 | 1174 | // if it's not above the current core version, and it's compatible with the current version of core |
1175 | 1175 | if ($key_versioned_endpoint === $latest_version) { |
1176 | 1176 | // don't hide the latest version in the index |
1177 | - $versions_served[ $key_versioned_endpoint ] = false; |
|
1177 | + $versions_served[$key_versioned_endpoint] = false; |
|
1178 | 1178 | } elseif ($key_versioned_endpoint >= $lowest_compatible_version |
1179 | 1179 | && $key_versioned_endpoint < EED_Core_Rest_Api::core_version() |
1180 | 1180 | ) { |
1181 | 1181 | // include, but hide, previous versions which are still supported |
1182 | - $versions_served[ $key_versioned_endpoint ] = true; |
|
1182 | + $versions_served[$key_versioned_endpoint] = true; |
|
1183 | 1183 | } elseif (apply_filters( |
1184 | 1184 | 'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions', |
1185 | 1185 | false, |
1186 | 1186 | $possibly_served_versions |
1187 | 1187 | )) { |
1188 | 1188 | // if a version is no longer supported, don't include it in index or list of versions served |
1189 | - $versions_served[ $key_versioned_endpoint ] = true; |
|
1189 | + $versions_served[$key_versioned_endpoint] = true; |
|
1190 | 1190 | } |
1191 | 1191 | } |
1192 | 1192 | return $versions_served; |
@@ -1244,7 +1244,7 @@ discard block |
||
1244 | 1244 | $model_names = self::model_names_with_plural_routes($version); |
1245 | 1245 | $collection_routes = array(); |
1246 | 1246 | foreach ($model_names as $model_name => $model_class_name) { |
1247 | - $collection_routes[ strtolower($model_name) ] = '/' . self::ee_api_namespace . $version . '/' |
|
1247 | + $collection_routes[strtolower($model_name)] = '/'.self::ee_api_namespace.$version.'/' |
|
1248 | 1248 | . EEH_Inflector::pluralize_and_lower($model_name); |
1249 | 1249 | } |
1250 | 1250 | return $collection_routes; |
@@ -1265,9 +1265,9 @@ discard block |
||
1265 | 1265 | $primary_keys = $model_class_name::instance()->get_combined_primary_key_fields(); |
1266 | 1266 | foreach ($primary_keys as $primary_key_name => $primary_key_field) { |
1267 | 1267 | if (count($primary_keys) > 1) { |
1268 | - $primary_key_items[ strtolower($model_name) ][] = $primary_key_name; |
|
1268 | + $primary_key_items[strtolower($model_name)][] = $primary_key_name; |
|
1269 | 1269 | } else { |
1270 | - $primary_key_items[ strtolower($model_name) ] = $primary_key_name; |
|
1270 | + $primary_key_items[strtolower($model_name)] = $primary_key_name; |
|
1271 | 1271 | } |
1272 | 1272 | } |
1273 | 1273 | } |
@@ -16,561 +16,561 @@ |
||
16 | 16 | abstract class EEM_CPT_Base extends EEM_Soft_Delete_Base |
17 | 17 | { |
18 | 18 | |
19 | - const EVENT_CATEGORY_TAXONOMY = 'espresso_event_category'; |
|
20 | - |
|
21 | - /** |
|
22 | - * @var string post_status_publish - the wp post status for published cpts |
|
23 | - */ |
|
24 | - const post_status_publish = 'publish'; |
|
25 | - |
|
26 | - /** |
|
27 | - * @var string post_status_future - the wp post status for scheduled cpts |
|
28 | - */ |
|
29 | - const post_status_future = 'future'; |
|
30 | - |
|
31 | - /** |
|
32 | - * @var string post_status_draft - the wp post status for draft cpts |
|
33 | - */ |
|
34 | - const post_status_draft = 'draft'; |
|
35 | - |
|
36 | - /** |
|
37 | - * @var string post_status_pending - the wp post status for pending cpts |
|
38 | - */ |
|
39 | - const post_status_pending = 'pending'; |
|
40 | - |
|
41 | - /** |
|
42 | - * @var string post_status_private - the wp post status for private cpts |
|
43 | - */ |
|
44 | - const post_status_private = 'private'; |
|
45 | - |
|
46 | - /** |
|
47 | - * @var string post_status_trashed - the wp post status for trashed cpts |
|
48 | - */ |
|
49 | - const post_status_trashed = 'trash'; |
|
50 | - |
|
51 | - /** |
|
52 | - * This is an array of custom statuses for the given CPT model (modified by children) |
|
53 | - * format: |
|
54 | - * array( |
|
55 | - * 'status_name' => array( |
|
56 | - * 'label' => __('Status Name', 'event_espresso'), |
|
57 | - * 'public' => TRUE //whether a public status or not. |
|
58 | - * ) |
|
59 | - * ) |
|
60 | - * |
|
61 | - * @var array |
|
62 | - */ |
|
63 | - protected $_custom_stati = array(); |
|
64 | - |
|
65 | - |
|
66 | - /** |
|
67 | - * Adds a relationship to Term_Taxonomy for each CPT_Base |
|
68 | - * |
|
69 | - * @param string $timezone |
|
70 | - * @throws \EE_Error |
|
71 | - */ |
|
72 | - protected function __construct($timezone = null) |
|
73 | - { |
|
74 | - // adds a relationship to Term_Taxonomy for all these models. For this to work |
|
75 | - // Term_Relationship must have a relation to each model subclassing EE_CPT_Base explicitly |
|
76 | - // eg, in EEM_Term_Relationship, inside the _model_relations array, there must be an entry |
|
77 | - // with key equalling the subclassing model's model name (eg 'Event' or 'Venue'), and the value |
|
78 | - // must also be new EE_HABTM_Relation('Term_Relationship'); |
|
79 | - $this->_model_relations['Term_Taxonomy'] = new EE_HABTM_Relation('Term_Relationship'); |
|
80 | - $primary_table_name = null; |
|
81 | - // add the common _status field to all CPT primary tables. |
|
82 | - foreach ($this->_tables as $alias => $table_obj) { |
|
83 | - if ($table_obj instanceof EE_Primary_Table) { |
|
84 | - $primary_table_name = $alias; |
|
85 | - } |
|
86 | - } |
|
87 | - // set default wp post statuses if child has not already set. |
|
88 | - if (! isset($this->_fields[ $primary_table_name ]['status'])) { |
|
89 | - $this->_fields[ $primary_table_name ]['status'] = new EE_WP_Post_Status_Field( |
|
90 | - 'post_status', |
|
91 | - __("Event Status", "event_espresso"), |
|
92 | - false, |
|
93 | - 'draft' |
|
94 | - ); |
|
95 | - } |
|
96 | - if (! isset($this->_fields[ $primary_table_name ]['to_ping'])) { |
|
97 | - $this->_fields[ $primary_table_name ]['to_ping'] = new EE_DB_Only_Text_Field( |
|
98 | - 'to_ping', |
|
99 | - __('To Ping', 'event_espresso'), |
|
100 | - false, |
|
101 | - '' |
|
102 | - ); |
|
103 | - } |
|
104 | - if (! isset($this->_fields[ $primary_table_name ]['pinged'])) { |
|
105 | - $this->_fields[ $primary_table_name ]['pinged'] = new EE_DB_Only_Text_Field( |
|
106 | - 'pinged', |
|
107 | - __('Pinged', 'event_espresso'), |
|
108 | - false, |
|
109 | - '' |
|
110 | - ); |
|
111 | - } |
|
112 | - if (! isset($this->_fields[ $primary_table_name ]['comment_status'])) { |
|
113 | - $this->_fields[ $primary_table_name ]['comment_status'] = new EE_Plain_Text_Field( |
|
114 | - 'comment_status', |
|
115 | - __('Comment Status', 'event_espresso'), |
|
116 | - false, |
|
117 | - 'open' |
|
118 | - ); |
|
119 | - } |
|
120 | - if (! isset($this->_fields[ $primary_table_name ]['ping_status'])) { |
|
121 | - $this->_fields[ $primary_table_name ]['ping_status'] = new EE_Plain_Text_Field( |
|
122 | - 'ping_status', |
|
123 | - __('Ping Status', 'event_espresso'), |
|
124 | - false, |
|
125 | - 'open' |
|
126 | - ); |
|
127 | - } |
|
128 | - if (! isset($this->_fields[ $primary_table_name ]['post_content_filtered'])) { |
|
129 | - $this->_fields[ $primary_table_name ]['post_content_filtered'] = new EE_DB_Only_Text_Field( |
|
130 | - 'post_content_filtered', |
|
131 | - __('Post Content Filtered', 'event_espresso'), |
|
132 | - false, |
|
133 | - '' |
|
134 | - ); |
|
135 | - } |
|
136 | - if (! isset($this->_model_relations['Post_Meta'])) { |
|
137 | - // don't block deletes though because we want to maintain the current behaviour |
|
138 | - $this->_model_relations['Post_Meta'] = new EE_Has_Many_Relation(false); |
|
139 | - } |
|
140 | - if (! $this->_minimum_where_conditions_strategy instanceof EE_Default_Where_Conditions) { |
|
141 | - // nothing was set during child constructor, so set default |
|
142 | - $this->_minimum_where_conditions_strategy = new EE_CPT_Minimum_Where_Conditions($this->post_type()); |
|
143 | - } |
|
144 | - if (! $this->_default_where_conditions_strategy instanceof EE_Default_Where_Conditions) { |
|
145 | - // nothing was set during child constructor, so set default |
|
146 | - // it's ok for child classes to specify this, but generally this is more DRY |
|
147 | - $this->_default_where_conditions_strategy = new EE_CPT_Where_Conditions($this->post_type()); |
|
148 | - } |
|
149 | - parent::__construct($timezone); |
|
150 | - } |
|
151 | - |
|
152 | - |
|
153 | - /** |
|
154 | - * @return array |
|
155 | - */ |
|
156 | - public function public_event_stati() |
|
157 | - { |
|
158 | - // @see wp-includes/post.php |
|
159 | - return get_post_stati(array('public' => true)); |
|
160 | - } |
|
161 | - |
|
162 | - |
|
163 | - /** |
|
164 | - * Searches for field on this model of type 'deleted_flag'. if it is found, |
|
165 | - * returns it's name. BUT That doesn't apply to CPTs. We should instead use post_status_field_name |
|
166 | - * |
|
167 | - * @return string |
|
168 | - * @throws EE_Error |
|
169 | - */ |
|
170 | - public function deleted_field_name() |
|
171 | - { |
|
172 | - throw new EE_Error( |
|
173 | - sprintf( |
|
174 | - __( |
|
175 | - "EEM_CPT_Base should nto call deleted_field_name! It should instead use post_status_field_name", |
|
176 | - "event_espresso" |
|
177 | - ) |
|
178 | - ) |
|
179 | - ); |
|
180 | - } |
|
181 | - |
|
182 | - |
|
183 | - /** |
|
184 | - * Gets the field's name that sets the post status |
|
185 | - * |
|
186 | - * @return string |
|
187 | - * @throws EE_Error |
|
188 | - */ |
|
189 | - public function post_status_field_name() |
|
190 | - { |
|
191 | - $field = $this->get_a_field_of_type('EE_WP_Post_Status_Field'); |
|
192 | - if ($field) { |
|
193 | - return $field->get_name(); |
|
194 | - } else { |
|
195 | - throw new EE_Error( |
|
196 | - sprintf( |
|
197 | - __( |
|
198 | - 'We are trying to find the post status flag field on %s, but none was found. Are you sure there is a field of type EE_Trashed_Flag_Field in %s constructor?', |
|
199 | - 'event_espresso' |
|
200 | - ), |
|
201 | - get_class($this), |
|
202 | - get_class($this) |
|
203 | - ) |
|
204 | - ); |
|
205 | - } |
|
206 | - } |
|
207 | - |
|
208 | - |
|
209 | - /** |
|
210 | - * Alters the query params so that only trashed/soft-deleted items are considered |
|
211 | - * |
|
212 | - * @param array $query_params like EEM_Base::get_all's $query_params |
|
213 | - * @return array like EEM_Base::get_all's $query_params |
|
214 | - */ |
|
215 | - protected function _alter_query_params_so_only_trashed_items_included($query_params) |
|
216 | - { |
|
217 | - $post_status_field_name = $this->post_status_field_name(); |
|
218 | - $query_params[0][ $post_status_field_name ] = self::post_status_trashed; |
|
219 | - return $query_params; |
|
220 | - } |
|
221 | - |
|
222 | - |
|
223 | - /** |
|
224 | - * Alters the query params so each item's deleted status is ignored. |
|
225 | - * |
|
226 | - * @param array $query_params |
|
227 | - * @return array |
|
228 | - */ |
|
229 | - protected function _alter_query_params_so_deleted_and_undeleted_items_included($query_params) |
|
230 | - { |
|
231 | - $query_params['default_where_conditions'] = 'minimum'; |
|
232 | - return $query_params; |
|
233 | - } |
|
234 | - |
|
235 | - |
|
236 | - /** |
|
237 | - * Performs deletes or restores on items. Both soft-deleted and non-soft-deleted items considered. |
|
238 | - * |
|
239 | - * @param boolean $delete true to indicate deletion, false to indicate restoration |
|
240 | - * @param array $query_params like EEM_Base::get_all |
|
241 | - * @return boolean success |
|
242 | - */ |
|
243 | - public function delete_or_restore($delete = true, $query_params = array()) |
|
244 | - { |
|
245 | - $post_status_field_name = $this->post_status_field_name(); |
|
246 | - $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params); |
|
247 | - $new_status = $delete ? self::post_status_trashed : 'draft'; |
|
248 | - if ($this->update(array($post_status_field_name => $new_status), $query_params)) { |
|
249 | - return true; |
|
250 | - } else { |
|
251 | - return false; |
|
252 | - } |
|
253 | - } |
|
254 | - |
|
255 | - |
|
256 | - /** |
|
257 | - * meta_table |
|
258 | - * returns first EE_Secondary_Table table name |
|
259 | - * |
|
260 | - * @access public |
|
261 | - * @return string |
|
262 | - */ |
|
263 | - public function meta_table() |
|
264 | - { |
|
265 | - $meta_table = $this->_get_other_tables(); |
|
266 | - $meta_table = reset($meta_table); |
|
267 | - return $meta_table instanceof EE_Secondary_Table ? $meta_table->get_table_name() : null; |
|
268 | - } |
|
269 | - |
|
270 | - |
|
271 | - /** |
|
272 | - * This simply returns an array of the meta table fields (useful for when we just need to update those fields) |
|
273 | - * |
|
274 | - * @param bool $all triggers whether we include DB_Only fields or JUST non DB_Only fields. Defaults to false (no |
|
275 | - * db only fields) |
|
276 | - * @return array |
|
277 | - */ |
|
278 | - public function get_meta_table_fields($all = false) |
|
279 | - { |
|
280 | - $all_fields = $fields_to_return = array(); |
|
281 | - foreach ($this->_tables as $alias => $table_obj) { |
|
282 | - if ($table_obj instanceof EE_Secondary_Table) { |
|
283 | - $all_fields = array_merge($this->_get_fields_for_table($alias), $all_fields); |
|
284 | - } |
|
285 | - } |
|
286 | - if (! $all) { |
|
287 | - foreach ($all_fields as $name => $obj) { |
|
288 | - if ($obj instanceof EE_DB_Only_Field_Base) { |
|
289 | - continue; |
|
290 | - } |
|
291 | - $fields_to_return[] = $name; |
|
292 | - } |
|
293 | - } else { |
|
294 | - $fields_to_return = array_keys($all_fields); |
|
295 | - } |
|
296 | - return $fields_to_return; |
|
297 | - } |
|
298 | - |
|
299 | - |
|
300 | - /** |
|
301 | - * Adds an event category with the specified name and description to the specified |
|
302 | - * $cpt_model_object. Intelligently adds a term if necessary, and adds a term_taxonomy if necessary, |
|
303 | - * and adds an entry in the term_relationship if necessary. |
|
304 | - * |
|
305 | - * @param EE_CPT_Base $cpt_model_object |
|
306 | - * @param string $category_name (used to derive the term slug too) |
|
307 | - * @param string $category_description |
|
308 | - * @param int $parent_term_taxonomy_id |
|
309 | - * @return EE_Term_Taxonomy |
|
310 | - */ |
|
311 | - public function add_event_category( |
|
312 | - EE_CPT_Base $cpt_model_object, |
|
313 | - $category_name, |
|
314 | - $category_description = '', |
|
315 | - $parent_term_taxonomy_id = null |
|
316 | - ) { |
|
317 | - // create term |
|
318 | - require_once(EE_MODELS . 'EEM_Term.model.php'); |
|
319 | - // first, check for a term by the same name or slug |
|
320 | - $category_slug = sanitize_title($category_name); |
|
321 | - $term = EEM_Term::instance()->get_one( |
|
322 | - array( |
|
323 | - array( |
|
324 | - 'OR' => array( |
|
325 | - 'name' => $category_name, |
|
326 | - 'slug' => $category_slug, |
|
327 | - ), |
|
328 | - ), |
|
329 | - ) |
|
330 | - ); |
|
331 | - if (! $term) { |
|
332 | - $term = EE_Term::new_instance( |
|
333 | - array( |
|
334 | - 'name' => $category_name, |
|
335 | - 'slug' => $category_slug, |
|
336 | - ) |
|
337 | - ); |
|
338 | - $term->save(); |
|
339 | - } |
|
340 | - // make sure there's a term-taxonomy entry too |
|
341 | - require_once(EE_MODELS . 'EEM_Term_Taxonomy.model.php'); |
|
342 | - $term_taxonomy = EEM_Term_Taxonomy::instance()->get_one( |
|
343 | - array( |
|
344 | - array( |
|
345 | - 'term_id' => $term->ID(), |
|
346 | - 'taxonomy' => self::EVENT_CATEGORY_TAXONOMY, |
|
347 | - ), |
|
348 | - ) |
|
349 | - ); |
|
350 | - /** @var $term_taxonomy EE_Term_Taxonomy */ |
|
351 | - if (! $term_taxonomy) { |
|
352 | - $term_taxonomy = EE_Term_Taxonomy::new_instance( |
|
353 | - array( |
|
354 | - 'term_id' => $term->ID(), |
|
355 | - 'taxonomy' => self::EVENT_CATEGORY_TAXONOMY, |
|
356 | - 'description' => $category_description, |
|
357 | - 'term_count' => 1, |
|
358 | - 'parent' => $parent_term_taxonomy_id, |
|
359 | - ) |
|
360 | - ); |
|
361 | - $term_taxonomy->save(); |
|
362 | - } else { |
|
363 | - $term_taxonomy->set_count($term_taxonomy->count() + 1); |
|
364 | - $term_taxonomy->save(); |
|
365 | - } |
|
366 | - return $this->add_relationship_to($cpt_model_object, $term_taxonomy, 'Term_Taxonomy'); |
|
367 | - } |
|
368 | - |
|
369 | - |
|
370 | - /** |
|
371 | - * Removed the category specified by name as having a relation to this event. |
|
372 | - * Does not remove the term or term_taxonomy. |
|
373 | - * |
|
374 | - * @param EE_CPT_Base $cpt_model_object_event |
|
375 | - * @param string $category_name name of the event category (term) |
|
376 | - * @return bool |
|
377 | - */ |
|
378 | - public function remove_event_category(EE_CPT_Base $cpt_model_object_event, $category_name) |
|
379 | - { |
|
380 | - // find the term_taxonomy by that name |
|
381 | - $term_taxonomy = $this->get_first_related( |
|
382 | - $cpt_model_object_event, |
|
383 | - 'Term_Taxonomy', |
|
384 | - array(array('Term.name' => $category_name, 'taxonomy' => self::EVENT_CATEGORY_TAXONOMY)) |
|
385 | - ); |
|
386 | - /** @var $term_taxonomy EE_Term_Taxonomy */ |
|
387 | - if ($term_taxonomy) { |
|
388 | - $term_taxonomy->set_count($term_taxonomy->count() - 1); |
|
389 | - $term_taxonomy->save(); |
|
390 | - } |
|
391 | - return $this->remove_relationship_to($cpt_model_object_event, $term_taxonomy, 'Term_Taxonomy'); |
|
392 | - } |
|
393 | - |
|
394 | - |
|
395 | - /** |
|
396 | - * This is a wrapper for the WordPress get_the_post_thumbnail() function that returns the feature image for the |
|
397 | - * given CPT ID. It accepts the same params as what get_the_post_thumbnail() accepts. |
|
398 | - * |
|
399 | - * @link http://codex.wordpress.org/Function_Reference/get_the_post_thumbnail |
|
400 | - * @access public |
|
401 | - * @param int $id the ID for the cpt we want the feature image for |
|
402 | - * @param string|array $size (optional) Image size. Defaults to 'post-thumbnail' but can also be a 2-item array |
|
403 | - * representing width and height in pixels (i.e. array(32,32) ). |
|
404 | - * @param string|array $attr Optional. Query string or array of attributes. |
|
405 | - * @return string HTML image element |
|
406 | - */ |
|
407 | - public function get_feature_image($id, $size = 'thumbnail', $attr = '') |
|
408 | - { |
|
409 | - return get_the_post_thumbnail($id, $size, $attr); |
|
410 | - } |
|
411 | - |
|
412 | - |
|
413 | - /** |
|
414 | - * Just a handy way to get the list of post statuses currently registered with WP. |
|
415 | - * |
|
416 | - * @global array $wp_post_statuses set in wp core for storing all the post stati |
|
417 | - * @return array |
|
418 | - */ |
|
419 | - public function get_post_statuses() |
|
420 | - { |
|
421 | - global $wp_post_statuses; |
|
422 | - $statuses = array(); |
|
423 | - foreach ($wp_post_statuses as $post_status => $args_object) { |
|
424 | - $statuses[ $post_status ] = $args_object->label; |
|
425 | - } |
|
426 | - return $statuses; |
|
427 | - } |
|
428 | - |
|
429 | - |
|
430 | - /** |
|
431 | - * public method that can be used to retrieve the protected status array on the instantiated cpt model |
|
432 | - * |
|
433 | - * @return array array of statuses. |
|
434 | - */ |
|
435 | - public function get_status_array() |
|
436 | - { |
|
437 | - $statuses = $this->get_post_statuses(); |
|
438 | - // first the global filter |
|
439 | - $statuses = apply_filters('FHEE_EEM_CPT_Base__get_status_array', $statuses); |
|
440 | - // now the class specific filter |
|
441 | - $statuses = apply_filters('FHEE_EEM_' . get_class($this) . '__get_status_array', $statuses); |
|
442 | - return $statuses; |
|
443 | - } |
|
444 | - |
|
445 | - |
|
446 | - /** |
|
447 | - * this returns the post statuses that are NOT the default wordpress status |
|
448 | - * |
|
449 | - * @return array |
|
450 | - */ |
|
451 | - public function get_custom_post_statuses() |
|
452 | - { |
|
453 | - $new_stati = array(); |
|
454 | - foreach ($this->_custom_stati as $status => $props) { |
|
455 | - $new_stati[ $status ] = $props['label']; |
|
456 | - } |
|
457 | - return $new_stati; |
|
458 | - } |
|
459 | - |
|
460 | - |
|
461 | - /** |
|
462 | - * Creates a child of EE_CPT_Base given a WP_Post or array of wpdb results which |
|
463 | - * are a row from the posts table. If we're missing any fields required for the model, |
|
464 | - * we just fetch the entire entry from the DB (ie, if you want to use this to save DB queries, |
|
465 | - * make sure you are attaching all the model's fields onto the post) |
|
466 | - * |
|
467 | - * @param WP_Post|array $post |
|
468 | - * @return EE_Base_Class|EE_Soft_Delete_Base_Class |
|
469 | - */ |
|
470 | - public function instantiate_class_from_post_object_orig($post) |
|
471 | - { |
|
472 | - $post = (array) $post; |
|
473 | - $has_all_necessary_fields_for_table = true; |
|
474 | - // check if the post has fields on the meta table already |
|
475 | - foreach ($this->_get_other_tables() as $table_obj) { |
|
476 | - $fields_for_that_table = $this->_get_fields_for_table($table_obj->get_table_alias()); |
|
477 | - foreach ($fields_for_that_table as $field_obj) { |
|
478 | - if (! isset($post[ $field_obj->get_table_column() ]) |
|
479 | - && ! isset($post[ $field_obj->get_qualified_column() ]) |
|
480 | - ) { |
|
481 | - $has_all_necessary_fields_for_table = false; |
|
482 | - } |
|
483 | - } |
|
484 | - } |
|
485 | - // if we don't have all the fields we need, then just fetch the proper model from the DB |
|
486 | - if (! $has_all_necessary_fields_for_table) { |
|
487 | - return $this->get_one_by_ID($post['ID']); |
|
488 | - } else { |
|
489 | - return $this->instantiate_class_from_array_or_object($post); |
|
490 | - } |
|
491 | - } |
|
492 | - |
|
493 | - |
|
494 | - /** |
|
495 | - * @param null $post |
|
496 | - * @return EE_Base_Class|EE_Soft_Delete_Base_Class |
|
497 | - */ |
|
498 | - public function instantiate_class_from_post_object($post = null) |
|
499 | - { |
|
500 | - if (empty($post)) { |
|
501 | - global $post; |
|
502 | - } |
|
503 | - $post = (array) $post; |
|
504 | - $tables_needing_to_be_queried = array(); |
|
505 | - // check if the post has fields on the meta table already |
|
506 | - foreach ($this->get_tables() as $table_obj) { |
|
507 | - $fields_for_that_table = $this->_get_fields_for_table($table_obj->get_table_alias()); |
|
508 | - foreach ($fields_for_that_table as $field_obj) { |
|
509 | - if (! isset($post[ $field_obj->get_table_column() ]) |
|
510 | - && ! isset($post[ $field_obj->get_qualified_column() ]) |
|
511 | - ) { |
|
512 | - $tables_needing_to_be_queried[ $table_obj->get_table_alias() ] = $table_obj; |
|
513 | - } |
|
514 | - } |
|
515 | - } |
|
516 | - // if we don't have all the fields we need, then just fetch the proper model from the DB |
|
517 | - if ($tables_needing_to_be_queried) { |
|
518 | - if (count($tables_needing_to_be_queried) == 1 |
|
519 | - && reset($tables_needing_to_be_queried) |
|
520 | - instanceof |
|
521 | - EE_Secondary_Table |
|
522 | - ) { |
|
523 | - // so we're only missing data from a secondary table. Well that's not too hard to query for |
|
524 | - $table_to_query = reset($tables_needing_to_be_queried); |
|
525 | - $missing_data = $this->_do_wpdb_query( |
|
526 | - 'get_row', |
|
527 | - array( |
|
528 | - 'SELECT * FROM ' |
|
529 | - . $table_to_query->get_table_name() |
|
530 | - . ' WHERE ' |
|
531 | - . $table_to_query->get_fk_on_table() |
|
532 | - . ' = ' |
|
533 | - . $post['ID'], |
|
534 | - ARRAY_A, |
|
535 | - ) |
|
536 | - ); |
|
537 | - if (! empty($missing_data)) { |
|
538 | - $post = array_merge($post, $missing_data); |
|
539 | - } |
|
540 | - } else { |
|
541 | - return $this->get_one_by_ID($post['ID']); |
|
542 | - } |
|
543 | - } |
|
544 | - return $this->instantiate_class_from_array_or_object($post); |
|
545 | - } |
|
546 | - |
|
547 | - |
|
548 | - /** |
|
549 | - * Gets the post type associated with this |
|
550 | - * |
|
551 | - * @throws EE_Error |
|
552 | - * @return string |
|
553 | - */ |
|
554 | - public function post_type() |
|
555 | - { |
|
556 | - $post_type_field = null; |
|
557 | - foreach ($this->field_settings(true) as $field_obj) { |
|
558 | - if ($field_obj instanceof EE_WP_Post_Type_Field) { |
|
559 | - $post_type_field = $field_obj; |
|
560 | - break; |
|
561 | - } |
|
562 | - } |
|
563 | - if ($post_type_field == null) { |
|
564 | - throw new EE_Error( |
|
565 | - sprintf( |
|
566 | - __( |
|
567 | - "CPT Model %s should have a field of type EE_WP_Post_Type, but doesnt", |
|
568 | - "event_espresso" |
|
569 | - ), |
|
570 | - get_class($this) |
|
571 | - ) |
|
572 | - ); |
|
573 | - } |
|
574 | - return $post_type_field->get_default_value(); |
|
575 | - } |
|
19 | + const EVENT_CATEGORY_TAXONOMY = 'espresso_event_category'; |
|
20 | + |
|
21 | + /** |
|
22 | + * @var string post_status_publish - the wp post status for published cpts |
|
23 | + */ |
|
24 | + const post_status_publish = 'publish'; |
|
25 | + |
|
26 | + /** |
|
27 | + * @var string post_status_future - the wp post status for scheduled cpts |
|
28 | + */ |
|
29 | + const post_status_future = 'future'; |
|
30 | + |
|
31 | + /** |
|
32 | + * @var string post_status_draft - the wp post status for draft cpts |
|
33 | + */ |
|
34 | + const post_status_draft = 'draft'; |
|
35 | + |
|
36 | + /** |
|
37 | + * @var string post_status_pending - the wp post status for pending cpts |
|
38 | + */ |
|
39 | + const post_status_pending = 'pending'; |
|
40 | + |
|
41 | + /** |
|
42 | + * @var string post_status_private - the wp post status for private cpts |
|
43 | + */ |
|
44 | + const post_status_private = 'private'; |
|
45 | + |
|
46 | + /** |
|
47 | + * @var string post_status_trashed - the wp post status for trashed cpts |
|
48 | + */ |
|
49 | + const post_status_trashed = 'trash'; |
|
50 | + |
|
51 | + /** |
|
52 | + * This is an array of custom statuses for the given CPT model (modified by children) |
|
53 | + * format: |
|
54 | + * array( |
|
55 | + * 'status_name' => array( |
|
56 | + * 'label' => __('Status Name', 'event_espresso'), |
|
57 | + * 'public' => TRUE //whether a public status or not. |
|
58 | + * ) |
|
59 | + * ) |
|
60 | + * |
|
61 | + * @var array |
|
62 | + */ |
|
63 | + protected $_custom_stati = array(); |
|
64 | + |
|
65 | + |
|
66 | + /** |
|
67 | + * Adds a relationship to Term_Taxonomy for each CPT_Base |
|
68 | + * |
|
69 | + * @param string $timezone |
|
70 | + * @throws \EE_Error |
|
71 | + */ |
|
72 | + protected function __construct($timezone = null) |
|
73 | + { |
|
74 | + // adds a relationship to Term_Taxonomy for all these models. For this to work |
|
75 | + // Term_Relationship must have a relation to each model subclassing EE_CPT_Base explicitly |
|
76 | + // eg, in EEM_Term_Relationship, inside the _model_relations array, there must be an entry |
|
77 | + // with key equalling the subclassing model's model name (eg 'Event' or 'Venue'), and the value |
|
78 | + // must also be new EE_HABTM_Relation('Term_Relationship'); |
|
79 | + $this->_model_relations['Term_Taxonomy'] = new EE_HABTM_Relation('Term_Relationship'); |
|
80 | + $primary_table_name = null; |
|
81 | + // add the common _status field to all CPT primary tables. |
|
82 | + foreach ($this->_tables as $alias => $table_obj) { |
|
83 | + if ($table_obj instanceof EE_Primary_Table) { |
|
84 | + $primary_table_name = $alias; |
|
85 | + } |
|
86 | + } |
|
87 | + // set default wp post statuses if child has not already set. |
|
88 | + if (! isset($this->_fields[ $primary_table_name ]['status'])) { |
|
89 | + $this->_fields[ $primary_table_name ]['status'] = new EE_WP_Post_Status_Field( |
|
90 | + 'post_status', |
|
91 | + __("Event Status", "event_espresso"), |
|
92 | + false, |
|
93 | + 'draft' |
|
94 | + ); |
|
95 | + } |
|
96 | + if (! isset($this->_fields[ $primary_table_name ]['to_ping'])) { |
|
97 | + $this->_fields[ $primary_table_name ]['to_ping'] = new EE_DB_Only_Text_Field( |
|
98 | + 'to_ping', |
|
99 | + __('To Ping', 'event_espresso'), |
|
100 | + false, |
|
101 | + '' |
|
102 | + ); |
|
103 | + } |
|
104 | + if (! isset($this->_fields[ $primary_table_name ]['pinged'])) { |
|
105 | + $this->_fields[ $primary_table_name ]['pinged'] = new EE_DB_Only_Text_Field( |
|
106 | + 'pinged', |
|
107 | + __('Pinged', 'event_espresso'), |
|
108 | + false, |
|
109 | + '' |
|
110 | + ); |
|
111 | + } |
|
112 | + if (! isset($this->_fields[ $primary_table_name ]['comment_status'])) { |
|
113 | + $this->_fields[ $primary_table_name ]['comment_status'] = new EE_Plain_Text_Field( |
|
114 | + 'comment_status', |
|
115 | + __('Comment Status', 'event_espresso'), |
|
116 | + false, |
|
117 | + 'open' |
|
118 | + ); |
|
119 | + } |
|
120 | + if (! isset($this->_fields[ $primary_table_name ]['ping_status'])) { |
|
121 | + $this->_fields[ $primary_table_name ]['ping_status'] = new EE_Plain_Text_Field( |
|
122 | + 'ping_status', |
|
123 | + __('Ping Status', 'event_espresso'), |
|
124 | + false, |
|
125 | + 'open' |
|
126 | + ); |
|
127 | + } |
|
128 | + if (! isset($this->_fields[ $primary_table_name ]['post_content_filtered'])) { |
|
129 | + $this->_fields[ $primary_table_name ]['post_content_filtered'] = new EE_DB_Only_Text_Field( |
|
130 | + 'post_content_filtered', |
|
131 | + __('Post Content Filtered', 'event_espresso'), |
|
132 | + false, |
|
133 | + '' |
|
134 | + ); |
|
135 | + } |
|
136 | + if (! isset($this->_model_relations['Post_Meta'])) { |
|
137 | + // don't block deletes though because we want to maintain the current behaviour |
|
138 | + $this->_model_relations['Post_Meta'] = new EE_Has_Many_Relation(false); |
|
139 | + } |
|
140 | + if (! $this->_minimum_where_conditions_strategy instanceof EE_Default_Where_Conditions) { |
|
141 | + // nothing was set during child constructor, so set default |
|
142 | + $this->_minimum_where_conditions_strategy = new EE_CPT_Minimum_Where_Conditions($this->post_type()); |
|
143 | + } |
|
144 | + if (! $this->_default_where_conditions_strategy instanceof EE_Default_Where_Conditions) { |
|
145 | + // nothing was set during child constructor, so set default |
|
146 | + // it's ok for child classes to specify this, but generally this is more DRY |
|
147 | + $this->_default_where_conditions_strategy = new EE_CPT_Where_Conditions($this->post_type()); |
|
148 | + } |
|
149 | + parent::__construct($timezone); |
|
150 | + } |
|
151 | + |
|
152 | + |
|
153 | + /** |
|
154 | + * @return array |
|
155 | + */ |
|
156 | + public function public_event_stati() |
|
157 | + { |
|
158 | + // @see wp-includes/post.php |
|
159 | + return get_post_stati(array('public' => true)); |
|
160 | + } |
|
161 | + |
|
162 | + |
|
163 | + /** |
|
164 | + * Searches for field on this model of type 'deleted_flag'. if it is found, |
|
165 | + * returns it's name. BUT That doesn't apply to CPTs. We should instead use post_status_field_name |
|
166 | + * |
|
167 | + * @return string |
|
168 | + * @throws EE_Error |
|
169 | + */ |
|
170 | + public function deleted_field_name() |
|
171 | + { |
|
172 | + throw new EE_Error( |
|
173 | + sprintf( |
|
174 | + __( |
|
175 | + "EEM_CPT_Base should nto call deleted_field_name! It should instead use post_status_field_name", |
|
176 | + "event_espresso" |
|
177 | + ) |
|
178 | + ) |
|
179 | + ); |
|
180 | + } |
|
181 | + |
|
182 | + |
|
183 | + /** |
|
184 | + * Gets the field's name that sets the post status |
|
185 | + * |
|
186 | + * @return string |
|
187 | + * @throws EE_Error |
|
188 | + */ |
|
189 | + public function post_status_field_name() |
|
190 | + { |
|
191 | + $field = $this->get_a_field_of_type('EE_WP_Post_Status_Field'); |
|
192 | + if ($field) { |
|
193 | + return $field->get_name(); |
|
194 | + } else { |
|
195 | + throw new EE_Error( |
|
196 | + sprintf( |
|
197 | + __( |
|
198 | + 'We are trying to find the post status flag field on %s, but none was found. Are you sure there is a field of type EE_Trashed_Flag_Field in %s constructor?', |
|
199 | + 'event_espresso' |
|
200 | + ), |
|
201 | + get_class($this), |
|
202 | + get_class($this) |
|
203 | + ) |
|
204 | + ); |
|
205 | + } |
|
206 | + } |
|
207 | + |
|
208 | + |
|
209 | + /** |
|
210 | + * Alters the query params so that only trashed/soft-deleted items are considered |
|
211 | + * |
|
212 | + * @param array $query_params like EEM_Base::get_all's $query_params |
|
213 | + * @return array like EEM_Base::get_all's $query_params |
|
214 | + */ |
|
215 | + protected function _alter_query_params_so_only_trashed_items_included($query_params) |
|
216 | + { |
|
217 | + $post_status_field_name = $this->post_status_field_name(); |
|
218 | + $query_params[0][ $post_status_field_name ] = self::post_status_trashed; |
|
219 | + return $query_params; |
|
220 | + } |
|
221 | + |
|
222 | + |
|
223 | + /** |
|
224 | + * Alters the query params so each item's deleted status is ignored. |
|
225 | + * |
|
226 | + * @param array $query_params |
|
227 | + * @return array |
|
228 | + */ |
|
229 | + protected function _alter_query_params_so_deleted_and_undeleted_items_included($query_params) |
|
230 | + { |
|
231 | + $query_params['default_where_conditions'] = 'minimum'; |
|
232 | + return $query_params; |
|
233 | + } |
|
234 | + |
|
235 | + |
|
236 | + /** |
|
237 | + * Performs deletes or restores on items. Both soft-deleted and non-soft-deleted items considered. |
|
238 | + * |
|
239 | + * @param boolean $delete true to indicate deletion, false to indicate restoration |
|
240 | + * @param array $query_params like EEM_Base::get_all |
|
241 | + * @return boolean success |
|
242 | + */ |
|
243 | + public function delete_or_restore($delete = true, $query_params = array()) |
|
244 | + { |
|
245 | + $post_status_field_name = $this->post_status_field_name(); |
|
246 | + $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params); |
|
247 | + $new_status = $delete ? self::post_status_trashed : 'draft'; |
|
248 | + if ($this->update(array($post_status_field_name => $new_status), $query_params)) { |
|
249 | + return true; |
|
250 | + } else { |
|
251 | + return false; |
|
252 | + } |
|
253 | + } |
|
254 | + |
|
255 | + |
|
256 | + /** |
|
257 | + * meta_table |
|
258 | + * returns first EE_Secondary_Table table name |
|
259 | + * |
|
260 | + * @access public |
|
261 | + * @return string |
|
262 | + */ |
|
263 | + public function meta_table() |
|
264 | + { |
|
265 | + $meta_table = $this->_get_other_tables(); |
|
266 | + $meta_table = reset($meta_table); |
|
267 | + return $meta_table instanceof EE_Secondary_Table ? $meta_table->get_table_name() : null; |
|
268 | + } |
|
269 | + |
|
270 | + |
|
271 | + /** |
|
272 | + * This simply returns an array of the meta table fields (useful for when we just need to update those fields) |
|
273 | + * |
|
274 | + * @param bool $all triggers whether we include DB_Only fields or JUST non DB_Only fields. Defaults to false (no |
|
275 | + * db only fields) |
|
276 | + * @return array |
|
277 | + */ |
|
278 | + public function get_meta_table_fields($all = false) |
|
279 | + { |
|
280 | + $all_fields = $fields_to_return = array(); |
|
281 | + foreach ($this->_tables as $alias => $table_obj) { |
|
282 | + if ($table_obj instanceof EE_Secondary_Table) { |
|
283 | + $all_fields = array_merge($this->_get_fields_for_table($alias), $all_fields); |
|
284 | + } |
|
285 | + } |
|
286 | + if (! $all) { |
|
287 | + foreach ($all_fields as $name => $obj) { |
|
288 | + if ($obj instanceof EE_DB_Only_Field_Base) { |
|
289 | + continue; |
|
290 | + } |
|
291 | + $fields_to_return[] = $name; |
|
292 | + } |
|
293 | + } else { |
|
294 | + $fields_to_return = array_keys($all_fields); |
|
295 | + } |
|
296 | + return $fields_to_return; |
|
297 | + } |
|
298 | + |
|
299 | + |
|
300 | + /** |
|
301 | + * Adds an event category with the specified name and description to the specified |
|
302 | + * $cpt_model_object. Intelligently adds a term if necessary, and adds a term_taxonomy if necessary, |
|
303 | + * and adds an entry in the term_relationship if necessary. |
|
304 | + * |
|
305 | + * @param EE_CPT_Base $cpt_model_object |
|
306 | + * @param string $category_name (used to derive the term slug too) |
|
307 | + * @param string $category_description |
|
308 | + * @param int $parent_term_taxonomy_id |
|
309 | + * @return EE_Term_Taxonomy |
|
310 | + */ |
|
311 | + public function add_event_category( |
|
312 | + EE_CPT_Base $cpt_model_object, |
|
313 | + $category_name, |
|
314 | + $category_description = '', |
|
315 | + $parent_term_taxonomy_id = null |
|
316 | + ) { |
|
317 | + // create term |
|
318 | + require_once(EE_MODELS . 'EEM_Term.model.php'); |
|
319 | + // first, check for a term by the same name or slug |
|
320 | + $category_slug = sanitize_title($category_name); |
|
321 | + $term = EEM_Term::instance()->get_one( |
|
322 | + array( |
|
323 | + array( |
|
324 | + 'OR' => array( |
|
325 | + 'name' => $category_name, |
|
326 | + 'slug' => $category_slug, |
|
327 | + ), |
|
328 | + ), |
|
329 | + ) |
|
330 | + ); |
|
331 | + if (! $term) { |
|
332 | + $term = EE_Term::new_instance( |
|
333 | + array( |
|
334 | + 'name' => $category_name, |
|
335 | + 'slug' => $category_slug, |
|
336 | + ) |
|
337 | + ); |
|
338 | + $term->save(); |
|
339 | + } |
|
340 | + // make sure there's a term-taxonomy entry too |
|
341 | + require_once(EE_MODELS . 'EEM_Term_Taxonomy.model.php'); |
|
342 | + $term_taxonomy = EEM_Term_Taxonomy::instance()->get_one( |
|
343 | + array( |
|
344 | + array( |
|
345 | + 'term_id' => $term->ID(), |
|
346 | + 'taxonomy' => self::EVENT_CATEGORY_TAXONOMY, |
|
347 | + ), |
|
348 | + ) |
|
349 | + ); |
|
350 | + /** @var $term_taxonomy EE_Term_Taxonomy */ |
|
351 | + if (! $term_taxonomy) { |
|
352 | + $term_taxonomy = EE_Term_Taxonomy::new_instance( |
|
353 | + array( |
|
354 | + 'term_id' => $term->ID(), |
|
355 | + 'taxonomy' => self::EVENT_CATEGORY_TAXONOMY, |
|
356 | + 'description' => $category_description, |
|
357 | + 'term_count' => 1, |
|
358 | + 'parent' => $parent_term_taxonomy_id, |
|
359 | + ) |
|
360 | + ); |
|
361 | + $term_taxonomy->save(); |
|
362 | + } else { |
|
363 | + $term_taxonomy->set_count($term_taxonomy->count() + 1); |
|
364 | + $term_taxonomy->save(); |
|
365 | + } |
|
366 | + return $this->add_relationship_to($cpt_model_object, $term_taxonomy, 'Term_Taxonomy'); |
|
367 | + } |
|
368 | + |
|
369 | + |
|
370 | + /** |
|
371 | + * Removed the category specified by name as having a relation to this event. |
|
372 | + * Does not remove the term or term_taxonomy. |
|
373 | + * |
|
374 | + * @param EE_CPT_Base $cpt_model_object_event |
|
375 | + * @param string $category_name name of the event category (term) |
|
376 | + * @return bool |
|
377 | + */ |
|
378 | + public function remove_event_category(EE_CPT_Base $cpt_model_object_event, $category_name) |
|
379 | + { |
|
380 | + // find the term_taxonomy by that name |
|
381 | + $term_taxonomy = $this->get_first_related( |
|
382 | + $cpt_model_object_event, |
|
383 | + 'Term_Taxonomy', |
|
384 | + array(array('Term.name' => $category_name, 'taxonomy' => self::EVENT_CATEGORY_TAXONOMY)) |
|
385 | + ); |
|
386 | + /** @var $term_taxonomy EE_Term_Taxonomy */ |
|
387 | + if ($term_taxonomy) { |
|
388 | + $term_taxonomy->set_count($term_taxonomy->count() - 1); |
|
389 | + $term_taxonomy->save(); |
|
390 | + } |
|
391 | + return $this->remove_relationship_to($cpt_model_object_event, $term_taxonomy, 'Term_Taxonomy'); |
|
392 | + } |
|
393 | + |
|
394 | + |
|
395 | + /** |
|
396 | + * This is a wrapper for the WordPress get_the_post_thumbnail() function that returns the feature image for the |
|
397 | + * given CPT ID. It accepts the same params as what get_the_post_thumbnail() accepts. |
|
398 | + * |
|
399 | + * @link http://codex.wordpress.org/Function_Reference/get_the_post_thumbnail |
|
400 | + * @access public |
|
401 | + * @param int $id the ID for the cpt we want the feature image for |
|
402 | + * @param string|array $size (optional) Image size. Defaults to 'post-thumbnail' but can also be a 2-item array |
|
403 | + * representing width and height in pixels (i.e. array(32,32) ). |
|
404 | + * @param string|array $attr Optional. Query string or array of attributes. |
|
405 | + * @return string HTML image element |
|
406 | + */ |
|
407 | + public function get_feature_image($id, $size = 'thumbnail', $attr = '') |
|
408 | + { |
|
409 | + return get_the_post_thumbnail($id, $size, $attr); |
|
410 | + } |
|
411 | + |
|
412 | + |
|
413 | + /** |
|
414 | + * Just a handy way to get the list of post statuses currently registered with WP. |
|
415 | + * |
|
416 | + * @global array $wp_post_statuses set in wp core for storing all the post stati |
|
417 | + * @return array |
|
418 | + */ |
|
419 | + public function get_post_statuses() |
|
420 | + { |
|
421 | + global $wp_post_statuses; |
|
422 | + $statuses = array(); |
|
423 | + foreach ($wp_post_statuses as $post_status => $args_object) { |
|
424 | + $statuses[ $post_status ] = $args_object->label; |
|
425 | + } |
|
426 | + return $statuses; |
|
427 | + } |
|
428 | + |
|
429 | + |
|
430 | + /** |
|
431 | + * public method that can be used to retrieve the protected status array on the instantiated cpt model |
|
432 | + * |
|
433 | + * @return array array of statuses. |
|
434 | + */ |
|
435 | + public function get_status_array() |
|
436 | + { |
|
437 | + $statuses = $this->get_post_statuses(); |
|
438 | + // first the global filter |
|
439 | + $statuses = apply_filters('FHEE_EEM_CPT_Base__get_status_array', $statuses); |
|
440 | + // now the class specific filter |
|
441 | + $statuses = apply_filters('FHEE_EEM_' . get_class($this) . '__get_status_array', $statuses); |
|
442 | + return $statuses; |
|
443 | + } |
|
444 | + |
|
445 | + |
|
446 | + /** |
|
447 | + * this returns the post statuses that are NOT the default wordpress status |
|
448 | + * |
|
449 | + * @return array |
|
450 | + */ |
|
451 | + public function get_custom_post_statuses() |
|
452 | + { |
|
453 | + $new_stati = array(); |
|
454 | + foreach ($this->_custom_stati as $status => $props) { |
|
455 | + $new_stati[ $status ] = $props['label']; |
|
456 | + } |
|
457 | + return $new_stati; |
|
458 | + } |
|
459 | + |
|
460 | + |
|
461 | + /** |
|
462 | + * Creates a child of EE_CPT_Base given a WP_Post or array of wpdb results which |
|
463 | + * are a row from the posts table. If we're missing any fields required for the model, |
|
464 | + * we just fetch the entire entry from the DB (ie, if you want to use this to save DB queries, |
|
465 | + * make sure you are attaching all the model's fields onto the post) |
|
466 | + * |
|
467 | + * @param WP_Post|array $post |
|
468 | + * @return EE_Base_Class|EE_Soft_Delete_Base_Class |
|
469 | + */ |
|
470 | + public function instantiate_class_from_post_object_orig($post) |
|
471 | + { |
|
472 | + $post = (array) $post; |
|
473 | + $has_all_necessary_fields_for_table = true; |
|
474 | + // check if the post has fields on the meta table already |
|
475 | + foreach ($this->_get_other_tables() as $table_obj) { |
|
476 | + $fields_for_that_table = $this->_get_fields_for_table($table_obj->get_table_alias()); |
|
477 | + foreach ($fields_for_that_table as $field_obj) { |
|
478 | + if (! isset($post[ $field_obj->get_table_column() ]) |
|
479 | + && ! isset($post[ $field_obj->get_qualified_column() ]) |
|
480 | + ) { |
|
481 | + $has_all_necessary_fields_for_table = false; |
|
482 | + } |
|
483 | + } |
|
484 | + } |
|
485 | + // if we don't have all the fields we need, then just fetch the proper model from the DB |
|
486 | + if (! $has_all_necessary_fields_for_table) { |
|
487 | + return $this->get_one_by_ID($post['ID']); |
|
488 | + } else { |
|
489 | + return $this->instantiate_class_from_array_or_object($post); |
|
490 | + } |
|
491 | + } |
|
492 | + |
|
493 | + |
|
494 | + /** |
|
495 | + * @param null $post |
|
496 | + * @return EE_Base_Class|EE_Soft_Delete_Base_Class |
|
497 | + */ |
|
498 | + public function instantiate_class_from_post_object($post = null) |
|
499 | + { |
|
500 | + if (empty($post)) { |
|
501 | + global $post; |
|
502 | + } |
|
503 | + $post = (array) $post; |
|
504 | + $tables_needing_to_be_queried = array(); |
|
505 | + // check if the post has fields on the meta table already |
|
506 | + foreach ($this->get_tables() as $table_obj) { |
|
507 | + $fields_for_that_table = $this->_get_fields_for_table($table_obj->get_table_alias()); |
|
508 | + foreach ($fields_for_that_table as $field_obj) { |
|
509 | + if (! isset($post[ $field_obj->get_table_column() ]) |
|
510 | + && ! isset($post[ $field_obj->get_qualified_column() ]) |
|
511 | + ) { |
|
512 | + $tables_needing_to_be_queried[ $table_obj->get_table_alias() ] = $table_obj; |
|
513 | + } |
|
514 | + } |
|
515 | + } |
|
516 | + // if we don't have all the fields we need, then just fetch the proper model from the DB |
|
517 | + if ($tables_needing_to_be_queried) { |
|
518 | + if (count($tables_needing_to_be_queried) == 1 |
|
519 | + && reset($tables_needing_to_be_queried) |
|
520 | + instanceof |
|
521 | + EE_Secondary_Table |
|
522 | + ) { |
|
523 | + // so we're only missing data from a secondary table. Well that's not too hard to query for |
|
524 | + $table_to_query = reset($tables_needing_to_be_queried); |
|
525 | + $missing_data = $this->_do_wpdb_query( |
|
526 | + 'get_row', |
|
527 | + array( |
|
528 | + 'SELECT * FROM ' |
|
529 | + . $table_to_query->get_table_name() |
|
530 | + . ' WHERE ' |
|
531 | + . $table_to_query->get_fk_on_table() |
|
532 | + . ' = ' |
|
533 | + . $post['ID'], |
|
534 | + ARRAY_A, |
|
535 | + ) |
|
536 | + ); |
|
537 | + if (! empty($missing_data)) { |
|
538 | + $post = array_merge($post, $missing_data); |
|
539 | + } |
|
540 | + } else { |
|
541 | + return $this->get_one_by_ID($post['ID']); |
|
542 | + } |
|
543 | + } |
|
544 | + return $this->instantiate_class_from_array_or_object($post); |
|
545 | + } |
|
546 | + |
|
547 | + |
|
548 | + /** |
|
549 | + * Gets the post type associated with this |
|
550 | + * |
|
551 | + * @throws EE_Error |
|
552 | + * @return string |
|
553 | + */ |
|
554 | + public function post_type() |
|
555 | + { |
|
556 | + $post_type_field = null; |
|
557 | + foreach ($this->field_settings(true) as $field_obj) { |
|
558 | + if ($field_obj instanceof EE_WP_Post_Type_Field) { |
|
559 | + $post_type_field = $field_obj; |
|
560 | + break; |
|
561 | + } |
|
562 | + } |
|
563 | + if ($post_type_field == null) { |
|
564 | + throw new EE_Error( |
|
565 | + sprintf( |
|
566 | + __( |
|
567 | + "CPT Model %s should have a field of type EE_WP_Post_Type, but doesnt", |
|
568 | + "event_espresso" |
|
569 | + ), |
|
570 | + get_class($this) |
|
571 | + ) |
|
572 | + ); |
|
573 | + } |
|
574 | + return $post_type_field->get_default_value(); |
|
575 | + } |
|
576 | 576 | } |
@@ -20,216 +20,216 @@ |
||
20 | 20 | abstract class Block implements BlockInterface |
21 | 21 | { |
22 | 22 | |
23 | - /** |
|
24 | - * BlockAssetManager that this editor block uses for asset registration |
|
25 | - * |
|
26 | - * @var BlockAssetManagerInterface $block_asset_manager |
|
27 | - */ |
|
28 | - protected $block_asset_manager; |
|
29 | - |
|
30 | - /** |
|
31 | - * @var array $attributes |
|
32 | - */ |
|
33 | - private $attributes; |
|
34 | - |
|
35 | - /** |
|
36 | - * If set to true, then the block will render its content client side |
|
37 | - * If false, then the block will render its content server side using the renderBlock() method |
|
38 | - * |
|
39 | - * @var bool $dynamic |
|
40 | - */ |
|
41 | - private $dynamic = false; |
|
42 | - |
|
43 | - /** |
|
44 | - * @var string $block_type |
|
45 | - */ |
|
46 | - private $block_type; |
|
47 | - |
|
48 | - /** |
|
49 | - * @var array $supported_post_types |
|
50 | - */ |
|
51 | - private $supported_post_types; |
|
52 | - |
|
53 | - /** |
|
54 | - * @var WP_Block_Type $wp_block_type |
|
55 | - */ |
|
56 | - private $wp_block_type; |
|
57 | - |
|
58 | - |
|
59 | - /** |
|
60 | - * BlockLoader constructor. |
|
61 | - * |
|
62 | - * @param BlockAssetManagerInterface $block_asset_manager |
|
63 | - */ |
|
64 | - public function __construct(BlockAssetManagerInterface $block_asset_manager) |
|
65 | - { |
|
66 | - $this->block_asset_manager = $block_asset_manager; |
|
67 | - } |
|
68 | - |
|
69 | - |
|
70 | - /** |
|
71 | - * @return string |
|
72 | - */ |
|
73 | - public function blockType() |
|
74 | - { |
|
75 | - return $this->block_type; |
|
76 | - } |
|
77 | - |
|
78 | - |
|
79 | - /** |
|
80 | - * @return string |
|
81 | - */ |
|
82 | - public function namespacedBlockType() |
|
83 | - { |
|
84 | - return self::NAME_SPACE . '/' . $this->block_type; |
|
85 | - } |
|
86 | - |
|
87 | - |
|
88 | - /** |
|
89 | - * @param string $block_type |
|
90 | - */ |
|
91 | - protected function setBlockType($block_type) |
|
92 | - { |
|
93 | - $this->block_type = $block_type; |
|
94 | - } |
|
95 | - |
|
96 | - |
|
97 | - /** |
|
98 | - * BlockAssetManager that this editor block uses for asset registration |
|
99 | - * |
|
100 | - * @return BlockAssetManagerInterface |
|
101 | - */ |
|
102 | - public function assetManager() |
|
103 | - { |
|
104 | - return $this->block_asset_manager; |
|
105 | - } |
|
106 | - |
|
107 | - |
|
108 | - /** |
|
109 | - * @param WP_Block_Type $wp_block_type |
|
110 | - */ |
|
111 | - protected function setWpBlockType($wp_block_type) |
|
112 | - { |
|
113 | - $this->wp_block_type = $wp_block_type; |
|
114 | - } |
|
115 | - |
|
116 | - |
|
117 | - /** |
|
118 | - * @param array $supported_post_types |
|
119 | - */ |
|
120 | - protected function setSupportedPostTypes(array $supported_post_types) |
|
121 | - { |
|
122 | - $this->supported_post_types = $supported_post_types; |
|
123 | - } |
|
124 | - |
|
125 | - |
|
126 | - /** |
|
127 | - * @return array |
|
128 | - */ |
|
129 | - public function attributes() |
|
130 | - { |
|
131 | - return $this->attributes; |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - /** |
|
136 | - * @param array $attributes |
|
137 | - */ |
|
138 | - public function setAttributes(array $attributes) |
|
139 | - { |
|
140 | - $this->attributes = $attributes; |
|
141 | - } |
|
142 | - |
|
143 | - |
|
144 | - /** |
|
145 | - * @return bool |
|
146 | - */ |
|
147 | - public function isDynamic() |
|
148 | - { |
|
149 | - return $this->dynamic; |
|
150 | - } |
|
151 | - |
|
152 | - |
|
153 | - /** |
|
154 | - * @param bool $dynamic |
|
155 | - */ |
|
156 | - public function setDynamic($dynamic = true) |
|
157 | - { |
|
158 | - $this->dynamic = filter_var($dynamic, FILTER_VALIDATE_BOOLEAN); |
|
159 | - } |
|
160 | - |
|
161 | - |
|
162 | - /** |
|
163 | - * Registers the Editor Block with WP core; |
|
164 | - * Returns the registered block type on success, or false on failure. |
|
165 | - * |
|
166 | - * @return WP_Block_Type|false |
|
167 | - */ |
|
168 | - public function registerBlock() |
|
169 | - { |
|
170 | - $args = array( |
|
171 | - 'attributes' => $this->attributes(), |
|
172 | - 'editor_script' => $this->block_asset_manager->getEditorScriptHandle(), |
|
173 | - 'editor_style' => $this->block_asset_manager->getEditorStyleHandle(), |
|
174 | - 'script' => $this->block_asset_manager->getScriptHandle(), |
|
175 | - 'style' => $this->block_asset_manager->getStyleHandle(), |
|
176 | - ); |
|
177 | - if (! $this->isDynamic()) { |
|
178 | - $args['render_callback'] = $this->renderBlock(); |
|
179 | - } |
|
180 | - $wp_block_type = register_block_type( |
|
181 | - new WP_Block_Type( |
|
182 | - $this->namespacedBlockType(), |
|
183 | - $args |
|
184 | - ) |
|
185 | - ); |
|
186 | - $this->setWpBlockType($wp_block_type); |
|
187 | - return $wp_block_type; |
|
188 | - } |
|
189 | - |
|
190 | - |
|
191 | - /** |
|
192 | - * @return WP_Block_Type|false The registered block type on success, or false on failure. |
|
193 | - */ |
|
194 | - public function unRegisterBlock() |
|
195 | - { |
|
196 | - return unregister_block_type($this->namespacedBlockType()); |
|
197 | - } |
|
198 | - |
|
199 | - |
|
200 | - /** |
|
201 | - * returns true if the block type applies for the supplied post type |
|
202 | - * and should be added to that post type's editor |
|
203 | - * |
|
204 | - * @param string $post_type |
|
205 | - * @return boolean |
|
206 | - */ |
|
207 | - public function appliesToPostType($post_type) |
|
208 | - { |
|
209 | - return in_array($post_type, $this->supported_post_types, true); |
|
210 | - } |
|
211 | - |
|
212 | - |
|
213 | - /** |
|
214 | - * @return array |
|
215 | - */ |
|
216 | - public function getEditorContainer() |
|
217 | - { |
|
218 | - return array( |
|
219 | - $this->namespacedBlockType(), |
|
220 | - array(), |
|
221 | - ); |
|
222 | - } |
|
223 | - |
|
224 | - |
|
225 | - /** |
|
226 | - * returns the rendered HTML for the block |
|
227 | - * |
|
228 | - * @param array $attributes |
|
229 | - * @return string |
|
230 | - */ |
|
231 | - public function renderBlock(array $attributes = array()) |
|
232 | - { |
|
233 | - return ''; |
|
234 | - } |
|
23 | + /** |
|
24 | + * BlockAssetManager that this editor block uses for asset registration |
|
25 | + * |
|
26 | + * @var BlockAssetManagerInterface $block_asset_manager |
|
27 | + */ |
|
28 | + protected $block_asset_manager; |
|
29 | + |
|
30 | + /** |
|
31 | + * @var array $attributes |
|
32 | + */ |
|
33 | + private $attributes; |
|
34 | + |
|
35 | + /** |
|
36 | + * If set to true, then the block will render its content client side |
|
37 | + * If false, then the block will render its content server side using the renderBlock() method |
|
38 | + * |
|
39 | + * @var bool $dynamic |
|
40 | + */ |
|
41 | + private $dynamic = false; |
|
42 | + |
|
43 | + /** |
|
44 | + * @var string $block_type |
|
45 | + */ |
|
46 | + private $block_type; |
|
47 | + |
|
48 | + /** |
|
49 | + * @var array $supported_post_types |
|
50 | + */ |
|
51 | + private $supported_post_types; |
|
52 | + |
|
53 | + /** |
|
54 | + * @var WP_Block_Type $wp_block_type |
|
55 | + */ |
|
56 | + private $wp_block_type; |
|
57 | + |
|
58 | + |
|
59 | + /** |
|
60 | + * BlockLoader constructor. |
|
61 | + * |
|
62 | + * @param BlockAssetManagerInterface $block_asset_manager |
|
63 | + */ |
|
64 | + public function __construct(BlockAssetManagerInterface $block_asset_manager) |
|
65 | + { |
|
66 | + $this->block_asset_manager = $block_asset_manager; |
|
67 | + } |
|
68 | + |
|
69 | + |
|
70 | + /** |
|
71 | + * @return string |
|
72 | + */ |
|
73 | + public function blockType() |
|
74 | + { |
|
75 | + return $this->block_type; |
|
76 | + } |
|
77 | + |
|
78 | + |
|
79 | + /** |
|
80 | + * @return string |
|
81 | + */ |
|
82 | + public function namespacedBlockType() |
|
83 | + { |
|
84 | + return self::NAME_SPACE . '/' . $this->block_type; |
|
85 | + } |
|
86 | + |
|
87 | + |
|
88 | + /** |
|
89 | + * @param string $block_type |
|
90 | + */ |
|
91 | + protected function setBlockType($block_type) |
|
92 | + { |
|
93 | + $this->block_type = $block_type; |
|
94 | + } |
|
95 | + |
|
96 | + |
|
97 | + /** |
|
98 | + * BlockAssetManager that this editor block uses for asset registration |
|
99 | + * |
|
100 | + * @return BlockAssetManagerInterface |
|
101 | + */ |
|
102 | + public function assetManager() |
|
103 | + { |
|
104 | + return $this->block_asset_manager; |
|
105 | + } |
|
106 | + |
|
107 | + |
|
108 | + /** |
|
109 | + * @param WP_Block_Type $wp_block_type |
|
110 | + */ |
|
111 | + protected function setWpBlockType($wp_block_type) |
|
112 | + { |
|
113 | + $this->wp_block_type = $wp_block_type; |
|
114 | + } |
|
115 | + |
|
116 | + |
|
117 | + /** |
|
118 | + * @param array $supported_post_types |
|
119 | + */ |
|
120 | + protected function setSupportedPostTypes(array $supported_post_types) |
|
121 | + { |
|
122 | + $this->supported_post_types = $supported_post_types; |
|
123 | + } |
|
124 | + |
|
125 | + |
|
126 | + /** |
|
127 | + * @return array |
|
128 | + */ |
|
129 | + public function attributes() |
|
130 | + { |
|
131 | + return $this->attributes; |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + /** |
|
136 | + * @param array $attributes |
|
137 | + */ |
|
138 | + public function setAttributes(array $attributes) |
|
139 | + { |
|
140 | + $this->attributes = $attributes; |
|
141 | + } |
|
142 | + |
|
143 | + |
|
144 | + /** |
|
145 | + * @return bool |
|
146 | + */ |
|
147 | + public function isDynamic() |
|
148 | + { |
|
149 | + return $this->dynamic; |
|
150 | + } |
|
151 | + |
|
152 | + |
|
153 | + /** |
|
154 | + * @param bool $dynamic |
|
155 | + */ |
|
156 | + public function setDynamic($dynamic = true) |
|
157 | + { |
|
158 | + $this->dynamic = filter_var($dynamic, FILTER_VALIDATE_BOOLEAN); |
|
159 | + } |
|
160 | + |
|
161 | + |
|
162 | + /** |
|
163 | + * Registers the Editor Block with WP core; |
|
164 | + * Returns the registered block type on success, or false on failure. |
|
165 | + * |
|
166 | + * @return WP_Block_Type|false |
|
167 | + */ |
|
168 | + public function registerBlock() |
|
169 | + { |
|
170 | + $args = array( |
|
171 | + 'attributes' => $this->attributes(), |
|
172 | + 'editor_script' => $this->block_asset_manager->getEditorScriptHandle(), |
|
173 | + 'editor_style' => $this->block_asset_manager->getEditorStyleHandle(), |
|
174 | + 'script' => $this->block_asset_manager->getScriptHandle(), |
|
175 | + 'style' => $this->block_asset_manager->getStyleHandle(), |
|
176 | + ); |
|
177 | + if (! $this->isDynamic()) { |
|
178 | + $args['render_callback'] = $this->renderBlock(); |
|
179 | + } |
|
180 | + $wp_block_type = register_block_type( |
|
181 | + new WP_Block_Type( |
|
182 | + $this->namespacedBlockType(), |
|
183 | + $args |
|
184 | + ) |
|
185 | + ); |
|
186 | + $this->setWpBlockType($wp_block_type); |
|
187 | + return $wp_block_type; |
|
188 | + } |
|
189 | + |
|
190 | + |
|
191 | + /** |
|
192 | + * @return WP_Block_Type|false The registered block type on success, or false on failure. |
|
193 | + */ |
|
194 | + public function unRegisterBlock() |
|
195 | + { |
|
196 | + return unregister_block_type($this->namespacedBlockType()); |
|
197 | + } |
|
198 | + |
|
199 | + |
|
200 | + /** |
|
201 | + * returns true if the block type applies for the supplied post type |
|
202 | + * and should be added to that post type's editor |
|
203 | + * |
|
204 | + * @param string $post_type |
|
205 | + * @return boolean |
|
206 | + */ |
|
207 | + public function appliesToPostType($post_type) |
|
208 | + { |
|
209 | + return in_array($post_type, $this->supported_post_types, true); |
|
210 | + } |
|
211 | + |
|
212 | + |
|
213 | + /** |
|
214 | + * @return array |
|
215 | + */ |
|
216 | + public function getEditorContainer() |
|
217 | + { |
|
218 | + return array( |
|
219 | + $this->namespacedBlockType(), |
|
220 | + array(), |
|
221 | + ); |
|
222 | + } |
|
223 | + |
|
224 | + |
|
225 | + /** |
|
226 | + * returns the rendered HTML for the block |
|
227 | + * |
|
228 | + * @param array $attributes |
|
229 | + * @return string |
|
230 | + */ |
|
231 | + public function renderBlock(array $attributes = array()) |
|
232 | + { |
|
233 | + return ''; |
|
234 | + } |
|
235 | 235 | } |
@@ -81,7 +81,7 @@ discard block |
||
81 | 81 | */ |
82 | 82 | public function namespacedBlockType() |
83 | 83 | { |
84 | - return self::NAME_SPACE . '/' . $this->block_type; |
|
84 | + return self::NAME_SPACE.'/'.$this->block_type; |
|
85 | 85 | } |
86 | 86 | |
87 | 87 | |
@@ -174,7 +174,7 @@ discard block |
||
174 | 174 | 'script' => $this->block_asset_manager->getScriptHandle(), |
175 | 175 | 'style' => $this->block_asset_manager->getStyleHandle(), |
176 | 176 | ); |
177 | - if (! $this->isDynamic()) { |
|
177 | + if ( ! $this->isDynamic()) { |
|
178 | 178 | $args['render_callback'] = $this->renderBlock(); |
179 | 179 | } |
180 | 180 | $wp_block_type = register_block_type( |
@@ -22,70 +22,70 @@ |
||
22 | 22 | interface BlockInterface |
23 | 23 | { |
24 | 24 | |
25 | - const NAME_SPACE = 'eventespresso'; |
|
26 | - |
|
27 | - /** |
|
28 | - * Perform any early setup required by the block |
|
29 | - * including setting the block type and supported post types |
|
30 | - * |
|
31 | - * @return void |
|
32 | - */ |
|
33 | - public function initialize(); |
|
34 | - |
|
35 | - |
|
36 | - /** |
|
37 | - * @return string |
|
38 | - */ |
|
39 | - public function blockType(); |
|
40 | - |
|
41 | - |
|
42 | - /** |
|
43 | - * AssetRegister that this editor block uses for asset registration |
|
44 | - * |
|
45 | - * @return BlockAssetManagerInterface |
|
46 | - */ |
|
47 | - public function assetManager(); |
|
48 | - |
|
49 | - |
|
50 | - /** |
|
51 | - * Registers the Editor Block with WP core; |
|
52 | - * Returns the registered block type on success, or false on failure. |
|
53 | - * |
|
54 | - * @return WP_Block_Type|false |
|
55 | - */ |
|
56 | - public function registerBlock(); |
|
57 | - |
|
58 | - |
|
59 | - /** |
|
60 | - * Un-registers the Editor Block with WP core; |
|
61 | - * Returns the registered block type on success, or false on failure. |
|
62 | - * |
|
63 | - * @return WP_Block_Type|false |
|
64 | - */ |
|
65 | - public function unRegisterBlock(); |
|
66 | - |
|
67 | - |
|
68 | - /** |
|
69 | - * returns true if the block type applies for the supplied post type |
|
70 | - * and should be added to that post type's editor |
|
71 | - * |
|
72 | - * @param string $post_type |
|
73 | - * @return boolean |
|
74 | - */ |
|
75 | - public function appliesToPostType($post_type); |
|
76 | - |
|
77 | - |
|
78 | - /** |
|
79 | - * @return array |
|
80 | - */ |
|
81 | - public function getEditorContainer(); |
|
82 | - |
|
83 | - |
|
84 | - /** |
|
85 | - * returns the rendered HTML for the block |
|
86 | - * |
|
87 | - * @param array $attributes |
|
88 | - * @return string |
|
89 | - */ |
|
90 | - public function renderBlock(array $attributes = array()); |
|
25 | + const NAME_SPACE = 'eventespresso'; |
|
26 | + |
|
27 | + /** |
|
28 | + * Perform any early setup required by the block |
|
29 | + * including setting the block type and supported post types |
|
30 | + * |
|
31 | + * @return void |
|
32 | + */ |
|
33 | + public function initialize(); |
|
34 | + |
|
35 | + |
|
36 | + /** |
|
37 | + * @return string |
|
38 | + */ |
|
39 | + public function blockType(); |
|
40 | + |
|
41 | + |
|
42 | + /** |
|
43 | + * AssetRegister that this editor block uses for asset registration |
|
44 | + * |
|
45 | + * @return BlockAssetManagerInterface |
|
46 | + */ |
|
47 | + public function assetManager(); |
|
48 | + |
|
49 | + |
|
50 | + /** |
|
51 | + * Registers the Editor Block with WP core; |
|
52 | + * Returns the registered block type on success, or false on failure. |
|
53 | + * |
|
54 | + * @return WP_Block_Type|false |
|
55 | + */ |
|
56 | + public function registerBlock(); |
|
57 | + |
|
58 | + |
|
59 | + /** |
|
60 | + * Un-registers the Editor Block with WP core; |
|
61 | + * Returns the registered block type on success, or false on failure. |
|
62 | + * |
|
63 | + * @return WP_Block_Type|false |
|
64 | + */ |
|
65 | + public function unRegisterBlock(); |
|
66 | + |
|
67 | + |
|
68 | + /** |
|
69 | + * returns true if the block type applies for the supplied post type |
|
70 | + * and should be added to that post type's editor |
|
71 | + * |
|
72 | + * @param string $post_type |
|
73 | + * @return boolean |
|
74 | + */ |
|
75 | + public function appliesToPostType($post_type); |
|
76 | + |
|
77 | + |
|
78 | + /** |
|
79 | + * @return array |
|
80 | + */ |
|
81 | + public function getEditorContainer(); |
|
82 | + |
|
83 | + |
|
84 | + /** |
|
85 | + * returns the rendered HTML for the block |
|
86 | + * |
|
87 | + * @param array $attributes |
|
88 | + * @return string |
|
89 | + */ |
|
90 | + public function renderBlock(array $attributes = array()); |
|
91 | 91 | } |
@@ -13,257 +13,257 @@ |
||
13 | 13 | class EE_Register_CPT implements EEI_Plugin_API |
14 | 14 | { |
15 | 15 | |
16 | - /** |
|
17 | - * Holds values for registered variations |
|
18 | - * |
|
19 | - * @since 4.5.0 |
|
20 | - * |
|
21 | - * @var array[][][] |
|
22 | - */ |
|
23 | - protected static $_registry = array(); |
|
16 | + /** |
|
17 | + * Holds values for registered variations |
|
18 | + * |
|
19 | + * @since 4.5.0 |
|
20 | + * |
|
21 | + * @var array[][][] |
|
22 | + */ |
|
23 | + protected static $_registry = array(); |
|
24 | 24 | |
25 | 25 | |
26 | - /** |
|
27 | - * Used to register new CPTs and Taxonomies. |
|
28 | - * |
|
29 | - * @param string $cpt_ref reference used for the addon registering cpts and cts |
|
30 | - * @param array $setup_args { |
|
31 | - * An array of required values for registering the cpts and taxonomies |
|
32 | - * @type array $cpts { |
|
33 | - * An array of cpts and their arguments.(short example below) |
|
34 | - * @see CustomPostTypeDefinitions::setDefinitions for a more complete example. |
|
35 | - * 'people' => array( |
|
36 | - * 'singular_name' => __('People', 'event_espresso'), |
|
37 | - * 'plural_name' => __('People', 'event_espresso'), |
|
38 | - * 'singular_slug' => __('people', 'event_espresso'), |
|
39 | - * 'plural_slug' => __('peoples', 'event_espresso'), |
|
40 | - * 'class_name' => 'EE_People' |
|
41 | - * ) |
|
42 | - * }, |
|
43 | - * @type array $cts { |
|
44 | - * An array of custom taxonomies and their arguments (short example below). |
|
45 | - * @see CustomTaxonomyDefinitions::setTaxonomies() for a more complete example. |
|
46 | - * 'espresso_people_type' => array( |
|
47 | - * 'singular_name' => __('People Type', 'event_espresso'), |
|
48 | - * 'plural_name' => __('People Types', 'event_espresso'), |
|
49 | - * 'args' => array() |
|
50 | - * ) |
|
51 | - * }, |
|
52 | - * @type array $default_terms { |
|
53 | - * An array of terms to set as the default for a given taxonomy and the |
|
54 | - * custom post types applied to. |
|
55 | - * 'taxonomy_name' => array( |
|
56 | - * 'term' => array( 'cpt_a_name', 'cpt_b_name' ) |
|
57 | - * ) |
|
58 | - * } |
|
59 | - * } |
|
60 | - * @throws EE_Error |
|
61 | - * @return void |
|
62 | - */ |
|
63 | - public static function register($cpt_ref = null, $setup_args = array()) |
|
64 | - { |
|
26 | + /** |
|
27 | + * Used to register new CPTs and Taxonomies. |
|
28 | + * |
|
29 | + * @param string $cpt_ref reference used for the addon registering cpts and cts |
|
30 | + * @param array $setup_args { |
|
31 | + * An array of required values for registering the cpts and taxonomies |
|
32 | + * @type array $cpts { |
|
33 | + * An array of cpts and their arguments.(short example below) |
|
34 | + * @see CustomPostTypeDefinitions::setDefinitions for a more complete example. |
|
35 | + * 'people' => array( |
|
36 | + * 'singular_name' => __('People', 'event_espresso'), |
|
37 | + * 'plural_name' => __('People', 'event_espresso'), |
|
38 | + * 'singular_slug' => __('people', 'event_espresso'), |
|
39 | + * 'plural_slug' => __('peoples', 'event_espresso'), |
|
40 | + * 'class_name' => 'EE_People' |
|
41 | + * ) |
|
42 | + * }, |
|
43 | + * @type array $cts { |
|
44 | + * An array of custom taxonomies and their arguments (short example below). |
|
45 | + * @see CustomTaxonomyDefinitions::setTaxonomies() for a more complete example. |
|
46 | + * 'espresso_people_type' => array( |
|
47 | + * 'singular_name' => __('People Type', 'event_espresso'), |
|
48 | + * 'plural_name' => __('People Types', 'event_espresso'), |
|
49 | + * 'args' => array() |
|
50 | + * ) |
|
51 | + * }, |
|
52 | + * @type array $default_terms { |
|
53 | + * An array of terms to set as the default for a given taxonomy and the |
|
54 | + * custom post types applied to. |
|
55 | + * 'taxonomy_name' => array( |
|
56 | + * 'term' => array( 'cpt_a_name', 'cpt_b_name' ) |
|
57 | + * ) |
|
58 | + * } |
|
59 | + * } |
|
60 | + * @throws EE_Error |
|
61 | + * @return void |
|
62 | + */ |
|
63 | + public static function register($cpt_ref = null, $setup_args = array()) |
|
64 | + { |
|
65 | 65 | |
66 | - // check for required params |
|
67 | - if (empty($cpt_ref)) { |
|
68 | - throw new EE_Error( |
|
69 | - __( |
|
70 | - 'In order to register custom post types and custom taxonomies, you must include a value to reference what had been registered', |
|
71 | - 'event_espresso' |
|
72 | - ) |
|
73 | - ); |
|
74 | - } |
|
66 | + // check for required params |
|
67 | + if (empty($cpt_ref)) { |
|
68 | + throw new EE_Error( |
|
69 | + __( |
|
70 | + 'In order to register custom post types and custom taxonomies, you must include a value to reference what had been registered', |
|
71 | + 'event_espresso' |
|
72 | + ) |
|
73 | + ); |
|
74 | + } |
|
75 | 75 | |
76 | - if (! is_array($setup_args) || (empty($setup_args['cpts']) && empty($setup_args['cts']))) { |
|
77 | - throw new EE_Error( |
|
78 | - __( |
|
79 | - 'In order to register custom post types or custom taxonomies, you must include an array containing either an array of custom post types to register (key "cpts"), an array of custom taxonomies ("cts") or both.', |
|
80 | - 'event_espresso' |
|
81 | - ) |
|
82 | - ); |
|
83 | - } |
|
76 | + if (! is_array($setup_args) || (empty($setup_args['cpts']) && empty($setup_args['cts']))) { |
|
77 | + throw new EE_Error( |
|
78 | + __( |
|
79 | + 'In order to register custom post types or custom taxonomies, you must include an array containing either an array of custom post types to register (key "cpts"), an array of custom taxonomies ("cts") or both.', |
|
80 | + 'event_espresso' |
|
81 | + ) |
|
82 | + ); |
|
83 | + } |
|
84 | 84 | |
85 | - // make sure we don't register twice |
|
86 | - if (isset(self::$_registry[ $cpt_ref ])) { |
|
87 | - return; |
|
88 | - } |
|
85 | + // make sure we don't register twice |
|
86 | + if (isset(self::$_registry[ $cpt_ref ])) { |
|
87 | + return; |
|
88 | + } |
|
89 | 89 | |
90 | - // make sure cpt ref is unique. |
|
91 | - if (isset(self::$_registry[ $cpt_ref ])) { |
|
92 | - $cpt_ref = uniqid() . '_' . $cpt_ref; |
|
93 | - } |
|
90 | + // make sure cpt ref is unique. |
|
91 | + if (isset(self::$_registry[ $cpt_ref ])) { |
|
92 | + $cpt_ref = uniqid() . '_' . $cpt_ref; |
|
93 | + } |
|
94 | 94 | |
95 | - // make sure this was called in the right place! |
|
96 | - if (did_action('AHEE__EE_System__load_CPTs_and_session__complete')) { |
|
97 | - EE_Error::doing_it_wrong( |
|
98 | - __METHOD__, |
|
99 | - sprintf( |
|
100 | - __( |
|
101 | - 'EE_Register_CPT has been called and given a reference of "%s". It may or may not work because it should be called on or before "AHEE__EE_System__load_CPTs_and_session__complete" action hook.', |
|
102 | - 'event_espresso' |
|
103 | - ), |
|
104 | - $cpt_ref |
|
105 | - ), |
|
106 | - '4.5.0' |
|
107 | - ); |
|
108 | - } |
|
109 | - // validate incoming args |
|
110 | - $validated = array( |
|
111 | - 'cpts' => isset($setup_args['cpts']) |
|
112 | - ? (array) $setup_args['cpts'] |
|
113 | - : array(), |
|
114 | - 'cts' => isset($setup_args['cts']) |
|
115 | - ? (array) $setup_args['cts'] |
|
116 | - : array(), |
|
117 | - 'default_terms' => isset($setup_args['default_terms']) |
|
118 | - ? (array) $setup_args['default_terms'] |
|
119 | - : array(), |
|
120 | - ); |
|
95 | + // make sure this was called in the right place! |
|
96 | + if (did_action('AHEE__EE_System__load_CPTs_and_session__complete')) { |
|
97 | + EE_Error::doing_it_wrong( |
|
98 | + __METHOD__, |
|
99 | + sprintf( |
|
100 | + __( |
|
101 | + 'EE_Register_CPT has been called and given a reference of "%s". It may or may not work because it should be called on or before "AHEE__EE_System__load_CPTs_and_session__complete" action hook.', |
|
102 | + 'event_espresso' |
|
103 | + ), |
|
104 | + $cpt_ref |
|
105 | + ), |
|
106 | + '4.5.0' |
|
107 | + ); |
|
108 | + } |
|
109 | + // validate incoming args |
|
110 | + $validated = array( |
|
111 | + 'cpts' => isset($setup_args['cpts']) |
|
112 | + ? (array) $setup_args['cpts'] |
|
113 | + : array(), |
|
114 | + 'cts' => isset($setup_args['cts']) |
|
115 | + ? (array) $setup_args['cts'] |
|
116 | + : array(), |
|
117 | + 'default_terms' => isset($setup_args['default_terms']) |
|
118 | + ? (array) $setup_args['default_terms'] |
|
119 | + : array(), |
|
120 | + ); |
|
121 | 121 | |
122 | - self::$_registry[ $cpt_ref ] = $validated; |
|
122 | + self::$_registry[ $cpt_ref ] = $validated; |
|
123 | 123 | |
124 | - // hook into to cpt system |
|
125 | - add_filter( |
|
126 | - 'FHEE__EventEspresso_core_domain_entities_custom_post_types_CustomPostTypeDefinitions__getCustomPostTypes', |
|
127 | - array(__CLASS__, 'filterCustomPostTypeDefinitions'), |
|
128 | - 5 |
|
129 | - ); |
|
130 | - add_filter( |
|
131 | - 'FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies', |
|
132 | - array(__CLASS__, 'filterCustomTaxonomyDefinitions'), |
|
133 | - 5 |
|
134 | - ); |
|
135 | - add_action( |
|
136 | - 'AHEE__EventEspresso_core_domain_services_custom_post_types_RegisterCustomTaxonomyTerms__construct_end', |
|
137 | - array(__CLASS__, 'registerCustomTaxonomyTerm'), |
|
138 | - 5 |
|
139 | - ); |
|
140 | - } |
|
124 | + // hook into to cpt system |
|
125 | + add_filter( |
|
126 | + 'FHEE__EventEspresso_core_domain_entities_custom_post_types_CustomPostTypeDefinitions__getCustomPostTypes', |
|
127 | + array(__CLASS__, 'filterCustomPostTypeDefinitions'), |
|
128 | + 5 |
|
129 | + ); |
|
130 | + add_filter( |
|
131 | + 'FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies', |
|
132 | + array(__CLASS__, 'filterCustomTaxonomyDefinitions'), |
|
133 | + 5 |
|
134 | + ); |
|
135 | + add_action( |
|
136 | + 'AHEE__EventEspresso_core_domain_services_custom_post_types_RegisterCustomTaxonomyTerms__construct_end', |
|
137 | + array(__CLASS__, 'registerCustomTaxonomyTerm'), |
|
138 | + 5 |
|
139 | + ); |
|
140 | + } |
|
141 | 141 | |
142 | 142 | |
143 | - /** |
|
144 | - * Callback for |
|
145 | - * FHEE__EventEspresso_core_domain_entities_custom_post_types_CustomPostTypeDefinitions__getCustomPostTypes |
|
146 | - * that adds additional custom post types to be registered. |
|
147 | - * |
|
148 | - * @param array $custom_post_type_definitions array of cpts that are already set |
|
149 | - * @return array new array of cpts and their registration information |
|
150 | - */ |
|
151 | - public static function filterCustomPostTypeDefinitions($custom_post_type_definitions) |
|
152 | - { |
|
153 | - foreach (self::$_registry as $registries) { |
|
154 | - foreach ($registries['cpts'] as $cpt_name => $cpt_settings) { |
|
155 | - $custom_post_type_definitions[ $cpt_name ] = $cpt_settings; |
|
156 | - } |
|
157 | - } |
|
158 | - return $custom_post_type_definitions; |
|
159 | - } |
|
143 | + /** |
|
144 | + * Callback for |
|
145 | + * FHEE__EventEspresso_core_domain_entities_custom_post_types_CustomPostTypeDefinitions__getCustomPostTypes |
|
146 | + * that adds additional custom post types to be registered. |
|
147 | + * |
|
148 | + * @param array $custom_post_type_definitions array of cpts that are already set |
|
149 | + * @return array new array of cpts and their registration information |
|
150 | + */ |
|
151 | + public static function filterCustomPostTypeDefinitions($custom_post_type_definitions) |
|
152 | + { |
|
153 | + foreach (self::$_registry as $registries) { |
|
154 | + foreach ($registries['cpts'] as $cpt_name => $cpt_settings) { |
|
155 | + $custom_post_type_definitions[ $cpt_name ] = $cpt_settings; |
|
156 | + } |
|
157 | + } |
|
158 | + return $custom_post_type_definitions; |
|
159 | + } |
|
160 | 160 | |
161 | 161 | |
162 | - /** |
|
163 | - * Callback for |
|
164 | - * FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies |
|
165 | - * that adds additional custom taxonomies to be registered. |
|
166 | - * |
|
167 | - * @param array $custom_taxonomy_definitions array of cts that are already set. |
|
168 | - * @return array new array of cts and their registration information. |
|
169 | - */ |
|
170 | - public static function filterCustomTaxonomyDefinitions($custom_taxonomy_definitions) |
|
171 | - { |
|
172 | - foreach (self::$_registry as $registries) { |
|
173 | - foreach ($registries['cts'] as $ct_name => $ct_settings) { |
|
174 | - $custom_taxonomy_definitions[ $ct_name ] = $ct_settings; |
|
175 | - } |
|
176 | - } |
|
177 | - return $custom_taxonomy_definitions; |
|
178 | - } |
|
162 | + /** |
|
163 | + * Callback for |
|
164 | + * FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies |
|
165 | + * that adds additional custom taxonomies to be registered. |
|
166 | + * |
|
167 | + * @param array $custom_taxonomy_definitions array of cts that are already set. |
|
168 | + * @return array new array of cts and their registration information. |
|
169 | + */ |
|
170 | + public static function filterCustomTaxonomyDefinitions($custom_taxonomy_definitions) |
|
171 | + { |
|
172 | + foreach (self::$_registry as $registries) { |
|
173 | + foreach ($registries['cts'] as $ct_name => $ct_settings) { |
|
174 | + $custom_taxonomy_definitions[ $ct_name ] = $ct_settings; |
|
175 | + } |
|
176 | + } |
|
177 | + return $custom_taxonomy_definitions; |
|
178 | + } |
|
179 | 179 | |
180 | 180 | |
181 | - /** |
|
182 | - * Callback for |
|
183 | - * AHEE__EventEspresso_core_domain_services_custom_post_types_RegisterCustomTaxonomyTerms__construct_end |
|
184 | - * which is used to set the default terms |
|
185 | - * |
|
186 | - * @param RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms |
|
187 | - * @return void |
|
188 | - */ |
|
189 | - public static function registerCustomTaxonomyTerm(RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms) |
|
190 | - { |
|
191 | - foreach (self::$_registry as $registries) { |
|
192 | - foreach ($registries['default_terms'] as $taxonomy => $terms) { |
|
193 | - foreach ($terms as $term => $cpts) { |
|
194 | - $register_custom_taxonomy_terms->registerCustomTaxonomyTerm( |
|
195 | - $taxonomy, |
|
196 | - $term, |
|
197 | - $cpts |
|
198 | - ); |
|
199 | - } |
|
200 | - } |
|
201 | - } |
|
202 | - } |
|
181 | + /** |
|
182 | + * Callback for |
|
183 | + * AHEE__EventEspresso_core_domain_services_custom_post_types_RegisterCustomTaxonomyTerms__construct_end |
|
184 | + * which is used to set the default terms |
|
185 | + * |
|
186 | + * @param RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms |
|
187 | + * @return void |
|
188 | + */ |
|
189 | + public static function registerCustomTaxonomyTerm(RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms) |
|
190 | + { |
|
191 | + foreach (self::$_registry as $registries) { |
|
192 | + foreach ($registries['default_terms'] as $taxonomy => $terms) { |
|
193 | + foreach ($terms as $term => $cpts) { |
|
194 | + $register_custom_taxonomy_terms->registerCustomTaxonomyTerm( |
|
195 | + $taxonomy, |
|
196 | + $term, |
|
197 | + $cpts |
|
198 | + ); |
|
199 | + } |
|
200 | + } |
|
201 | + } |
|
202 | + } |
|
203 | 203 | |
204 | 204 | |
205 | - /** |
|
206 | - * @deprecated 4.9.62.p |
|
207 | - * @param array $cpts array of cpts that are already set |
|
208 | - * @return array new array of cpts and their registration information |
|
209 | - */ |
|
210 | - public static function filter_cpts($cpts) |
|
211 | - { |
|
212 | - foreach (self::$_registry as $registries) { |
|
213 | - foreach ($registries['cpts'] as $cpt_name => $cpt_settings) { |
|
214 | - $cpts[ $cpt_name ] = $cpt_settings; |
|
215 | - } |
|
216 | - } |
|
217 | - return $cpts; |
|
218 | - } |
|
205 | + /** |
|
206 | + * @deprecated 4.9.62.p |
|
207 | + * @param array $cpts array of cpts that are already set |
|
208 | + * @return array new array of cpts and their registration information |
|
209 | + */ |
|
210 | + public static function filter_cpts($cpts) |
|
211 | + { |
|
212 | + foreach (self::$_registry as $registries) { |
|
213 | + foreach ($registries['cpts'] as $cpt_name => $cpt_settings) { |
|
214 | + $cpts[ $cpt_name ] = $cpt_settings; |
|
215 | + } |
|
216 | + } |
|
217 | + return $cpts; |
|
218 | + } |
|
219 | 219 | |
220 | 220 | |
221 | - /** |
|
222 | - * @deprecated 4.9.62.p |
|
223 | - * @param array $cts array of cts that are already set. |
|
224 | - * @return array new array of cts and their registration information. |
|
225 | - */ |
|
226 | - public static function filter_cts($cts) |
|
227 | - { |
|
228 | - foreach (self::$_registry as $registries) { |
|
229 | - foreach ($registries['cts'] as $ct_name => $ct_settings) { |
|
230 | - $cts[ $ct_name ] = $ct_settings; |
|
231 | - } |
|
232 | - } |
|
233 | - return $cts; |
|
234 | - } |
|
221 | + /** |
|
222 | + * @deprecated 4.9.62.p |
|
223 | + * @param array $cts array of cts that are already set. |
|
224 | + * @return array new array of cts and their registration information. |
|
225 | + */ |
|
226 | + public static function filter_cts($cts) |
|
227 | + { |
|
228 | + foreach (self::$_registry as $registries) { |
|
229 | + foreach ($registries['cts'] as $ct_name => $ct_settings) { |
|
230 | + $cts[ $ct_name ] = $ct_settings; |
|
231 | + } |
|
232 | + } |
|
233 | + return $cts; |
|
234 | + } |
|
235 | 235 | |
236 | 236 | |
237 | - /** |
|
238 | - * @deprecated 4.9.62.p |
|
239 | - * @param EE_Register_CPTs $cpt_class |
|
240 | - * @return void |
|
241 | - */ |
|
242 | - public static function default_terms(EE_Register_CPTs $cpt_class) |
|
243 | - { |
|
244 | - foreach (self::$_registry as $registries) { |
|
245 | - foreach ($registries['default_terms'] as $taxonomy => $terms) { |
|
246 | - foreach ($terms as $term => $cpts) { |
|
247 | - $cpt_class->set_default_term($taxonomy, $term, $cpts); |
|
248 | - } |
|
249 | - } |
|
250 | - } |
|
251 | - } |
|
237 | + /** |
|
238 | + * @deprecated 4.9.62.p |
|
239 | + * @param EE_Register_CPTs $cpt_class |
|
240 | + * @return void |
|
241 | + */ |
|
242 | + public static function default_terms(EE_Register_CPTs $cpt_class) |
|
243 | + { |
|
244 | + foreach (self::$_registry as $registries) { |
|
245 | + foreach ($registries['default_terms'] as $taxonomy => $terms) { |
|
246 | + foreach ($terms as $term => $cpts) { |
|
247 | + $cpt_class->set_default_term($taxonomy, $term, $cpts); |
|
248 | + } |
|
249 | + } |
|
250 | + } |
|
251 | + } |
|
252 | 252 | |
253 | 253 | |
254 | - /** |
|
255 | - * This deregisters whats been registered on this class (for the given slug). |
|
256 | - * |
|
257 | - * @since 4.5.0 |
|
258 | - * |
|
259 | - * @param string $cpt_ref The reference for the item registered to be removed. |
|
260 | - * |
|
261 | - * @return void |
|
262 | - */ |
|
263 | - public static function deregister($cpt_ref = null) |
|
264 | - { |
|
265 | - if (! empty(self::$_registry[ $cpt_ref ])) { |
|
266 | - unset(self::$_registry[ $cpt_ref ]); |
|
267 | - } |
|
268 | - } |
|
254 | + /** |
|
255 | + * This deregisters whats been registered on this class (for the given slug). |
|
256 | + * |
|
257 | + * @since 4.5.0 |
|
258 | + * |
|
259 | + * @param string $cpt_ref The reference for the item registered to be removed. |
|
260 | + * |
|
261 | + * @return void |
|
262 | + */ |
|
263 | + public static function deregister($cpt_ref = null) |
|
264 | + { |
|
265 | + if (! empty(self::$_registry[ $cpt_ref ])) { |
|
266 | + unset(self::$_registry[ $cpt_ref ]); |
|
267 | + } |
|
268 | + } |
|
269 | 269 | } |
@@ -23,1664 +23,1664 @@ |
||
23 | 23 | class EE_Registry implements ResettableInterface |
24 | 24 | { |
25 | 25 | |
26 | - /** |
|
27 | - * @var EE_Registry $_instance |
|
28 | - */ |
|
29 | - private static $_instance; |
|
30 | - |
|
31 | - /** |
|
32 | - * @var EE_Dependency_Map $_dependency_map |
|
33 | - */ |
|
34 | - protected $_dependency_map; |
|
35 | - |
|
36 | - /** |
|
37 | - * @var Mirror |
|
38 | - */ |
|
39 | - private $mirror; |
|
40 | - |
|
41 | - /** |
|
42 | - * @var ClassInterfaceCache $class_cache |
|
43 | - */ |
|
44 | - private $class_cache; |
|
45 | - |
|
46 | - /** |
|
47 | - * @var array $_class_abbreviations |
|
48 | - */ |
|
49 | - protected $_class_abbreviations = array(); |
|
50 | - |
|
51 | - /** |
|
52 | - * @var CommandBusInterface $BUS |
|
53 | - */ |
|
54 | - public $BUS; |
|
55 | - |
|
56 | - /** |
|
57 | - * @var EE_Cart $CART |
|
58 | - */ |
|
59 | - public $CART; |
|
60 | - |
|
61 | - /** |
|
62 | - * @var EE_Config $CFG |
|
63 | - */ |
|
64 | - public $CFG; |
|
65 | - |
|
66 | - /** |
|
67 | - * @var EE_Network_Config $NET_CFG |
|
68 | - */ |
|
69 | - public $NET_CFG; |
|
70 | - |
|
71 | - /** |
|
72 | - * StdClass object for storing library classes in |
|
73 | - * |
|
74 | - * @var RegistryContainer $LIB |
|
75 | - */ |
|
76 | - public $LIB; |
|
77 | - |
|
78 | - /** |
|
79 | - * @var EE_Request_Handler $REQ |
|
80 | - */ |
|
81 | - public $REQ; |
|
82 | - |
|
83 | - /** |
|
84 | - * @var EE_Session $SSN |
|
85 | - */ |
|
86 | - public $SSN; |
|
87 | - |
|
88 | - /** |
|
89 | - * @since 4.5.0 |
|
90 | - * @var EE_Capabilities $CAP |
|
91 | - */ |
|
92 | - public $CAP; |
|
93 | - |
|
94 | - /** |
|
95 | - * @since 4.9.0 |
|
96 | - * @var EE_Message_Resource_Manager $MRM |
|
97 | - */ |
|
98 | - public $MRM; |
|
99 | - |
|
100 | - /** |
|
101 | - * @var Registry $AssetsRegistry |
|
102 | - */ |
|
103 | - public $AssetsRegistry; |
|
104 | - |
|
105 | - /** |
|
106 | - * StdClass object for holding addons which have registered themselves to work with EE core |
|
107 | - * |
|
108 | - * @var EE_Addon[] $addons |
|
109 | - */ |
|
110 | - public $addons; |
|
111 | - |
|
112 | - /** |
|
113 | - * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event') |
|
114 | - * |
|
115 | - * @var EEM_Base[] $models |
|
116 | - */ |
|
117 | - public $models = array(); |
|
118 | - |
|
119 | - /** |
|
120 | - * @var EED_Module[] $modules |
|
121 | - */ |
|
122 | - public $modules; |
|
123 | - |
|
124 | - /** |
|
125 | - * @var EES_Shortcode[] $shortcodes |
|
126 | - */ |
|
127 | - public $shortcodes; |
|
128 | - |
|
129 | - /** |
|
130 | - * @var WP_Widget[] $widgets |
|
131 | - */ |
|
132 | - public $widgets; |
|
133 | - |
|
134 | - /** |
|
135 | - * this is an array of all implemented model names (i.e. not the parent abstract models, or models |
|
136 | - * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)). |
|
137 | - * Keys are model "short names" (eg "Event") as used in model relations, and values are |
|
138 | - * classnames (eg "EEM_Event") |
|
139 | - * |
|
140 | - * @var array $non_abstract_db_models |
|
141 | - */ |
|
142 | - public $non_abstract_db_models = array(); |
|
143 | - |
|
144 | - /** |
|
145 | - * internationalization for JS strings |
|
146 | - * usage: EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' ); |
|
147 | - * in js file: var translatedString = eei18n.string_key; |
|
148 | - * |
|
149 | - * @var array $i18n_js_strings |
|
150 | - */ |
|
151 | - public static $i18n_js_strings = array(); |
|
152 | - |
|
153 | - /** |
|
154 | - * $main_file - path to espresso.php |
|
155 | - * |
|
156 | - * @var array $main_file |
|
157 | - */ |
|
158 | - public $main_file; |
|
159 | - |
|
160 | - /** |
|
161 | - * array of ReflectionClass objects where the key is the class name |
|
162 | - * |
|
163 | - * @deprecated 4.9.62.p |
|
164 | - * @var ReflectionClass[] $_reflectors |
|
165 | - */ |
|
166 | - public $_reflectors; |
|
167 | - |
|
168 | - /** |
|
169 | - * boolean flag to indicate whether or not to load/save dependencies from/to the cache |
|
170 | - * |
|
171 | - * @var boolean $_cache_on |
|
172 | - */ |
|
173 | - protected $_cache_on = true; |
|
174 | - |
|
175 | - /** |
|
176 | - * @var ObjectIdentifier |
|
177 | - */ |
|
178 | - private $object_identifier; |
|
179 | - |
|
180 | - |
|
181 | - /** |
|
182 | - * @singleton method used to instantiate class object |
|
183 | - * @param EE_Dependency_Map|null $dependency_map |
|
184 | - * @param Mirror|null $mirror |
|
185 | - * @param ClassInterfaceCache|null $class_cache |
|
186 | - * @param ObjectIdentifier|null $object_identifier |
|
187 | - * @return EE_Registry instance |
|
188 | - */ |
|
189 | - public static function instance( |
|
190 | - EE_Dependency_Map $dependency_map = null, |
|
191 | - Mirror $mirror = null, |
|
192 | - ClassInterfaceCache $class_cache = null, |
|
193 | - ObjectIdentifier $object_identifier = null |
|
194 | - ) { |
|
195 | - // check if class object is instantiated |
|
196 | - if (! self::$_instance instanceof EE_Registry |
|
197 | - && $dependency_map instanceof EE_Dependency_Map |
|
198 | - && $mirror instanceof Mirror |
|
199 | - && $class_cache instanceof ClassInterfaceCache |
|
200 | - && $object_identifier instanceof ObjectIdentifier |
|
201 | - ) { |
|
202 | - self::$_instance = new self( |
|
203 | - $dependency_map, |
|
204 | - $mirror, |
|
205 | - $class_cache, |
|
206 | - $object_identifier |
|
207 | - ); |
|
208 | - } |
|
209 | - return self::$_instance; |
|
210 | - } |
|
211 | - |
|
212 | - |
|
213 | - /** |
|
214 | - * protected constructor to prevent direct creation |
|
215 | - * |
|
216 | - * @Constructor |
|
217 | - * @param EE_Dependency_Map $dependency_map |
|
218 | - * @param Mirror $mirror |
|
219 | - * @param ClassInterfaceCache $class_cache |
|
220 | - * @param ObjectIdentifier $object_identifier |
|
221 | - */ |
|
222 | - protected function __construct( |
|
223 | - EE_Dependency_Map $dependency_map, |
|
224 | - Mirror $mirror, |
|
225 | - ClassInterfaceCache $class_cache, |
|
226 | - ObjectIdentifier $object_identifier |
|
227 | - ) { |
|
228 | - $this->_dependency_map = $dependency_map; |
|
229 | - $this->mirror = $mirror; |
|
230 | - $this->class_cache = $class_cache; |
|
231 | - $this->object_identifier = $object_identifier; |
|
232 | - // $registry_container = new RegistryContainer(); |
|
233 | - $this->LIB = new RegistryContainer(); |
|
234 | - $this->addons = new RegistryContainer(); |
|
235 | - $this->modules = new RegistryContainer(); |
|
236 | - $this->shortcodes = new RegistryContainer(); |
|
237 | - $this->widgets = new RegistryContainer(); |
|
238 | - add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize')); |
|
239 | - } |
|
240 | - |
|
241 | - |
|
242 | - /** |
|
243 | - * initialize |
|
244 | - * |
|
245 | - * @throws OutOfBoundsException |
|
246 | - * @throws InvalidArgumentException |
|
247 | - * @throws InvalidInterfaceException |
|
248 | - * @throws InvalidDataTypeException |
|
249 | - * @throws EE_Error |
|
250 | - * @throws ReflectionException |
|
251 | - */ |
|
252 | - public function initialize() |
|
253 | - { |
|
254 | - $this->_class_abbreviations = apply_filters( |
|
255 | - 'FHEE__EE_Registry____construct___class_abbreviations', |
|
256 | - array( |
|
257 | - 'EE_Config' => 'CFG', |
|
258 | - 'EE_Session' => 'SSN', |
|
259 | - 'EE_Capabilities' => 'CAP', |
|
260 | - 'EE_Cart' => 'CART', |
|
261 | - 'EE_Network_Config' => 'NET_CFG', |
|
262 | - 'EE_Request_Handler' => 'REQ', |
|
263 | - 'EE_Message_Resource_Manager' => 'MRM', |
|
264 | - 'EventEspresso\core\services\commands\CommandBus' => 'BUS', |
|
265 | - 'EventEspresso\core\services\assets\Registry' => 'AssetsRegistry', |
|
266 | - ) |
|
267 | - ); |
|
268 | - $this->load_core('Base', array(), true); |
|
269 | - // add our request and response objects to the cache |
|
270 | - $request_loader = $this->_dependency_map->class_loader( |
|
271 | - 'EventEspresso\core\services\request\Request' |
|
272 | - ); |
|
273 | - $this->_set_cached_class( |
|
274 | - $request_loader(), |
|
275 | - 'EventEspresso\core\services\request\Request' |
|
276 | - ); |
|
277 | - $response_loader = $this->_dependency_map->class_loader( |
|
278 | - 'EventEspresso\core\services\request\Response' |
|
279 | - ); |
|
280 | - $this->_set_cached_class( |
|
281 | - $response_loader(), |
|
282 | - 'EventEspresso\core\services\request\Response' |
|
283 | - ); |
|
284 | - add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init')); |
|
285 | - } |
|
286 | - |
|
287 | - |
|
288 | - /** |
|
289 | - * @return void |
|
290 | - */ |
|
291 | - public function init() |
|
292 | - { |
|
293 | - // Get current page protocol |
|
294 | - $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://'; |
|
295 | - // Output admin-ajax.php URL with same protocol as current page |
|
296 | - self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol); |
|
297 | - self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false; |
|
298 | - } |
|
299 | - |
|
300 | - |
|
301 | - /** |
|
302 | - * localize_i18n_js_strings |
|
303 | - * |
|
304 | - * @return string |
|
305 | - */ |
|
306 | - public static function localize_i18n_js_strings() |
|
307 | - { |
|
308 | - $i18n_js_strings = (array) self::$i18n_js_strings; |
|
309 | - foreach ($i18n_js_strings as $key => $value) { |
|
310 | - if (is_scalar($value)) { |
|
311 | - $i18n_js_strings[ $key ] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8'); |
|
312 | - } |
|
313 | - } |
|
314 | - return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */'; |
|
315 | - } |
|
316 | - |
|
317 | - |
|
318 | - /** |
|
319 | - * @param mixed string | EED_Module $module |
|
320 | - * @throws OutOfBoundsException |
|
321 | - * @throws InvalidArgumentException |
|
322 | - * @throws InvalidInterfaceException |
|
323 | - * @throws InvalidDataTypeException |
|
324 | - * @throws EE_Error |
|
325 | - * @throws ReflectionException |
|
326 | - */ |
|
327 | - public function add_module($module) |
|
328 | - { |
|
329 | - if ($module instanceof EED_Module) { |
|
330 | - $module_class = get_class($module); |
|
331 | - $this->modules->{$module_class} = $module; |
|
332 | - } else { |
|
333 | - if (! class_exists('EE_Module_Request_Router', false)) { |
|
334 | - $this->load_core('Module_Request_Router'); |
|
335 | - } |
|
336 | - EE_Module_Request_Router::module_factory($module); |
|
337 | - } |
|
338 | - } |
|
339 | - |
|
340 | - |
|
341 | - /** |
|
342 | - * @param string $module_name |
|
343 | - * @return mixed EED_Module | NULL |
|
344 | - */ |
|
345 | - public function get_module($module_name = '') |
|
346 | - { |
|
347 | - return isset($this->modules->{$module_name}) |
|
348 | - ? $this->modules->{$module_name} |
|
349 | - : null; |
|
350 | - } |
|
351 | - |
|
352 | - |
|
353 | - /** |
|
354 | - * loads core classes - must be singletons |
|
355 | - * |
|
356 | - * @param string $class_name - simple class name ie: session |
|
357 | - * @param mixed $arguments |
|
358 | - * @param bool $load_only |
|
359 | - * @return mixed |
|
360 | - * @throws InvalidInterfaceException |
|
361 | - * @throws InvalidDataTypeException |
|
362 | - * @throws EE_Error |
|
363 | - * @throws ReflectionException |
|
364 | - * @throws InvalidArgumentException |
|
365 | - */ |
|
366 | - public function load_core($class_name, $arguments = array(), $load_only = false) |
|
367 | - { |
|
368 | - $core_paths = apply_filters( |
|
369 | - 'FHEE__EE_Registry__load_core__core_paths', |
|
370 | - array( |
|
371 | - EE_CORE, |
|
372 | - EE_ADMIN, |
|
373 | - EE_CPTS, |
|
374 | - EE_CORE . 'data_migration_scripts' . DS, |
|
375 | - EE_CORE . 'capabilities' . DS, |
|
376 | - EE_CORE . 'request_stack' . DS, |
|
377 | - EE_CORE . 'middleware' . DS, |
|
378 | - ) |
|
379 | - ); |
|
380 | - // retrieve instantiated class |
|
381 | - return $this->_load( |
|
382 | - $core_paths, |
|
383 | - 'EE_', |
|
384 | - $class_name, |
|
385 | - 'core', |
|
386 | - $arguments, |
|
387 | - false, |
|
388 | - true, |
|
389 | - $load_only |
|
390 | - ); |
|
391 | - } |
|
392 | - |
|
393 | - |
|
394 | - /** |
|
395 | - * loads service classes |
|
396 | - * |
|
397 | - * @param string $class_name - simple class name ie: session |
|
398 | - * @param mixed $arguments |
|
399 | - * @param bool $load_only |
|
400 | - * @return mixed |
|
401 | - * @throws InvalidInterfaceException |
|
402 | - * @throws InvalidDataTypeException |
|
403 | - * @throws EE_Error |
|
404 | - * @throws ReflectionException |
|
405 | - * @throws InvalidArgumentException |
|
406 | - */ |
|
407 | - public function load_service($class_name, $arguments = array(), $load_only = false) |
|
408 | - { |
|
409 | - $service_paths = apply_filters( |
|
410 | - 'FHEE__EE_Registry__load_service__service_paths', |
|
411 | - array( |
|
412 | - EE_CORE . 'services' . DS, |
|
413 | - ) |
|
414 | - ); |
|
415 | - // retrieve instantiated class |
|
416 | - return $this->_load( |
|
417 | - $service_paths, |
|
418 | - 'EE_', |
|
419 | - $class_name, |
|
420 | - 'class', |
|
421 | - $arguments, |
|
422 | - false, |
|
423 | - true, |
|
424 | - $load_only |
|
425 | - ); |
|
426 | - } |
|
427 | - |
|
428 | - |
|
429 | - /** |
|
430 | - * loads data_migration_scripts |
|
431 | - * |
|
432 | - * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0 |
|
433 | - * @param mixed $arguments |
|
434 | - * @return EE_Data_Migration_Script_Base|mixed |
|
435 | - * @throws InvalidInterfaceException |
|
436 | - * @throws InvalidDataTypeException |
|
437 | - * @throws EE_Error |
|
438 | - * @throws ReflectionException |
|
439 | - * @throws InvalidArgumentException |
|
440 | - */ |
|
441 | - public function load_dms($class_name, $arguments = array()) |
|
442 | - { |
|
443 | - // retrieve instantiated class |
|
444 | - return $this->_load( |
|
445 | - EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(), |
|
446 | - 'EE_DMS_', |
|
447 | - $class_name, |
|
448 | - 'dms', |
|
449 | - $arguments, |
|
450 | - false, |
|
451 | - false |
|
452 | - ); |
|
453 | - } |
|
454 | - |
|
455 | - |
|
456 | - /** |
|
457 | - * loads object creating classes - must be singletons |
|
458 | - * |
|
459 | - * @param string $class_name - simple class name ie: attendee |
|
460 | - * @param mixed $arguments - an array of arguments to pass to the class |
|
461 | - * @param bool $from_db - some classes are instantiated from the db and thus call a different method to |
|
462 | - * instantiate |
|
463 | - * @param bool $cache if you don't want the class to be stored in the internal cache (non-persistent) then |
|
464 | - * set this to FALSE (ie. when instantiating model objects from client in a loop) |
|
465 | - * @param bool $load_only whether or not to just load the file and NOT instantiate, or load AND instantiate |
|
466 | - * (default) |
|
467 | - * @return EE_Base_Class | bool |
|
468 | - * @throws InvalidInterfaceException |
|
469 | - * @throws InvalidDataTypeException |
|
470 | - * @throws EE_Error |
|
471 | - * @throws ReflectionException |
|
472 | - * @throws InvalidArgumentException |
|
473 | - */ |
|
474 | - public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false) |
|
475 | - { |
|
476 | - $paths = apply_filters( |
|
477 | - 'FHEE__EE_Registry__load_class__paths', |
|
478 | - array( |
|
479 | - EE_CORE, |
|
480 | - EE_CLASSES, |
|
481 | - EE_BUSINESS, |
|
482 | - ) |
|
483 | - ); |
|
484 | - // retrieve instantiated class |
|
485 | - return $this->_load( |
|
486 | - $paths, |
|
487 | - 'EE_', |
|
488 | - $class_name, |
|
489 | - 'class', |
|
490 | - $arguments, |
|
491 | - $from_db, |
|
492 | - $cache, |
|
493 | - $load_only |
|
494 | - ); |
|
495 | - } |
|
496 | - |
|
497 | - |
|
498 | - /** |
|
499 | - * loads helper classes - must be singletons |
|
500 | - * |
|
501 | - * @param string $class_name - simple class name ie: price |
|
502 | - * @param mixed $arguments |
|
503 | - * @param bool $load_only |
|
504 | - * @return EEH_Base | bool |
|
505 | - * @throws InvalidInterfaceException |
|
506 | - * @throws InvalidDataTypeException |
|
507 | - * @throws EE_Error |
|
508 | - * @throws ReflectionException |
|
509 | - * @throws InvalidArgumentException |
|
510 | - */ |
|
511 | - public function load_helper($class_name, $arguments = array(), $load_only = true) |
|
512 | - { |
|
513 | - // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed |
|
514 | - $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS)); |
|
515 | - // retrieve instantiated class |
|
516 | - return $this->_load( |
|
517 | - $helper_paths, |
|
518 | - 'EEH_', |
|
519 | - $class_name, |
|
520 | - 'helper', |
|
521 | - $arguments, |
|
522 | - false, |
|
523 | - true, |
|
524 | - $load_only |
|
525 | - ); |
|
526 | - } |
|
527 | - |
|
528 | - |
|
529 | - /** |
|
530 | - * loads core classes - must be singletons |
|
531 | - * |
|
532 | - * @param string $class_name - simple class name ie: session |
|
533 | - * @param mixed $arguments |
|
534 | - * @param bool $load_only |
|
535 | - * @param bool $cache whether to cache the object or not. |
|
536 | - * @return mixed |
|
537 | - * @throws InvalidInterfaceException |
|
538 | - * @throws InvalidDataTypeException |
|
539 | - * @throws EE_Error |
|
540 | - * @throws ReflectionException |
|
541 | - * @throws InvalidArgumentException |
|
542 | - */ |
|
543 | - public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true) |
|
544 | - { |
|
545 | - $paths = array( |
|
546 | - EE_LIBRARIES, |
|
547 | - EE_LIBRARIES . 'messages' . DS, |
|
548 | - EE_LIBRARIES . 'shortcodes' . DS, |
|
549 | - EE_LIBRARIES . 'qtips' . DS, |
|
550 | - EE_LIBRARIES . 'payment_methods' . DS, |
|
551 | - ); |
|
552 | - // retrieve instantiated class |
|
553 | - return $this->_load( |
|
554 | - $paths, |
|
555 | - 'EE_', |
|
556 | - $class_name, |
|
557 | - 'lib', |
|
558 | - $arguments, |
|
559 | - false, |
|
560 | - $cache, |
|
561 | - $load_only |
|
562 | - ); |
|
563 | - } |
|
564 | - |
|
565 | - |
|
566 | - /** |
|
567 | - * loads model classes - must be singletons |
|
568 | - * |
|
569 | - * @param string $class_name - simple class name ie: price |
|
570 | - * @param mixed $arguments |
|
571 | - * @param bool $load_only |
|
572 | - * @return EEM_Base | bool |
|
573 | - * @throws InvalidInterfaceException |
|
574 | - * @throws InvalidDataTypeException |
|
575 | - * @throws EE_Error |
|
576 | - * @throws ReflectionException |
|
577 | - * @throws InvalidArgumentException |
|
578 | - */ |
|
579 | - public function load_model($class_name, $arguments = array(), $load_only = false) |
|
580 | - { |
|
581 | - $paths = apply_filters( |
|
582 | - 'FHEE__EE_Registry__load_model__paths', |
|
583 | - array( |
|
584 | - EE_MODELS, |
|
585 | - EE_CORE, |
|
586 | - ) |
|
587 | - ); |
|
588 | - // retrieve instantiated class |
|
589 | - return $this->_load( |
|
590 | - $paths, |
|
591 | - 'EEM_', |
|
592 | - $class_name, |
|
593 | - 'model', |
|
594 | - $arguments, |
|
595 | - false, |
|
596 | - true, |
|
597 | - $load_only |
|
598 | - ); |
|
599 | - } |
|
600 | - |
|
601 | - |
|
602 | - /** |
|
603 | - * loads model classes - must be singletons |
|
604 | - * |
|
605 | - * @param string $class_name - simple class name ie: price |
|
606 | - * @param mixed $arguments |
|
607 | - * @param bool $load_only |
|
608 | - * @return mixed | bool |
|
609 | - * @throws InvalidInterfaceException |
|
610 | - * @throws InvalidDataTypeException |
|
611 | - * @throws EE_Error |
|
612 | - * @throws ReflectionException |
|
613 | - * @throws InvalidArgumentException |
|
614 | - */ |
|
615 | - public function load_model_class($class_name, $arguments = array(), $load_only = true) |
|
616 | - { |
|
617 | - $paths = array( |
|
618 | - EE_MODELS . 'fields' . DS, |
|
619 | - EE_MODELS . 'helpers' . DS, |
|
620 | - EE_MODELS . 'relations' . DS, |
|
621 | - EE_MODELS . 'strategies' . DS, |
|
622 | - ); |
|
623 | - // retrieve instantiated class |
|
624 | - return $this->_load( |
|
625 | - $paths, |
|
626 | - 'EE_', |
|
627 | - $class_name, |
|
628 | - '', |
|
629 | - $arguments, |
|
630 | - false, |
|
631 | - true, |
|
632 | - $load_only |
|
633 | - ); |
|
634 | - } |
|
635 | - |
|
636 | - |
|
637 | - /** |
|
638 | - * Determines if $model_name is the name of an actual EE model. |
|
639 | - * |
|
640 | - * @param string $model_name like Event, Attendee, Question_Group_Question, etc. |
|
641 | - * @return boolean |
|
642 | - */ |
|
643 | - public function is_model_name($model_name) |
|
644 | - { |
|
645 | - return isset($this->models[ $model_name ]); |
|
646 | - } |
|
647 | - |
|
648 | - |
|
649 | - /** |
|
650 | - * generic class loader |
|
651 | - * |
|
652 | - * @param string $path_to_file - directory path to file location, not including filename |
|
653 | - * @param string $file_name - file name ie: my_file.php, including extension |
|
654 | - * @param string $type - file type - core? class? helper? model? |
|
655 | - * @param mixed $arguments |
|
656 | - * @param bool $load_only |
|
657 | - * @return mixed |
|
658 | - * @throws InvalidInterfaceException |
|
659 | - * @throws InvalidDataTypeException |
|
660 | - * @throws EE_Error |
|
661 | - * @throws ReflectionException |
|
662 | - * @throws InvalidArgumentException |
|
663 | - */ |
|
664 | - public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true) |
|
665 | - { |
|
666 | - // retrieve instantiated class |
|
667 | - return $this->_load( |
|
668 | - $path_to_file, |
|
669 | - '', |
|
670 | - $file_name, |
|
671 | - $type, |
|
672 | - $arguments, |
|
673 | - false, |
|
674 | - true, |
|
675 | - $load_only |
|
676 | - ); |
|
677 | - } |
|
678 | - |
|
679 | - |
|
680 | - /** |
|
681 | - * @param string $path_to_file - directory path to file location, not including filename |
|
682 | - * @param string $class_name - full class name ie: My_Class |
|
683 | - * @param string $type - file type - core? class? helper? model? |
|
684 | - * @param mixed $arguments |
|
685 | - * @param bool $load_only |
|
686 | - * @return bool|EE_Addon|object |
|
687 | - * @throws InvalidInterfaceException |
|
688 | - * @throws InvalidDataTypeException |
|
689 | - * @throws EE_Error |
|
690 | - * @throws ReflectionException |
|
691 | - * @throws InvalidArgumentException |
|
692 | - */ |
|
693 | - public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false) |
|
694 | - { |
|
695 | - // retrieve instantiated class |
|
696 | - return $this->_load( |
|
697 | - $path_to_file, |
|
698 | - 'addon', |
|
699 | - $class_name, |
|
700 | - $type, |
|
701 | - $arguments, |
|
702 | - false, |
|
703 | - true, |
|
704 | - $load_only |
|
705 | - ); |
|
706 | - } |
|
707 | - |
|
708 | - |
|
709 | - /** |
|
710 | - * instantiates, caches, and automatically resolves dependencies |
|
711 | - * for classes that use a Fully Qualified Class Name. |
|
712 | - * if the class is not capable of being loaded using PSR-4 autoloading, |
|
713 | - * then you need to use one of the existing load_*() methods |
|
714 | - * which can resolve the classname and filepath from the passed arguments |
|
715 | - * |
|
716 | - * @param bool|string $class_name Fully Qualified Class Name |
|
717 | - * @param array $arguments an argument, or array of arguments to pass to the class upon instantiation |
|
718 | - * @param bool $cache whether to cache the instantiated object for reuse |
|
719 | - * @param bool $from_db some classes are instantiated from the db |
|
720 | - * and thus call a different method to instantiate |
|
721 | - * @param bool $load_only if true, will only load the file, but will NOT instantiate an object |
|
722 | - * @param bool|string $addon if true, will cache the object in the EE_Registry->$addons array |
|
723 | - * @return bool|null|mixed null = failure to load or instantiate class object. |
|
724 | - * object = class loaded and instantiated successfully. |
|
725 | - * bool = fail or success when $load_only is true |
|
726 | - * @throws InvalidInterfaceException |
|
727 | - * @throws InvalidDataTypeException |
|
728 | - * @throws EE_Error |
|
729 | - * @throws ReflectionException |
|
730 | - * @throws InvalidArgumentException |
|
731 | - */ |
|
732 | - public function create( |
|
733 | - $class_name = false, |
|
734 | - $arguments = array(), |
|
735 | - $cache = false, |
|
736 | - $from_db = false, |
|
737 | - $load_only = false, |
|
738 | - $addon = false |
|
739 | - ) { |
|
740 | - $class_name = ltrim($class_name, '\\'); |
|
741 | - $class_name = $this->class_cache->getFqnForAlias($class_name); |
|
742 | - $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments); |
|
743 | - // if a non-FQCN was passed, then |
|
744 | - // verifyClassExists() might return an object |
|
745 | - // or it could return null if the class just could not be found anywhere |
|
746 | - if ($class_exists instanceof $class_name || $class_exists === null) { |
|
747 | - // either way, return the results |
|
748 | - return $class_exists; |
|
749 | - } |
|
750 | - $class_name = $class_exists; |
|
751 | - // if we're only loading the class and it already exists, then let's just return true immediately |
|
752 | - if ($load_only) { |
|
753 | - return true; |
|
754 | - } |
|
755 | - $addon = $addon ? 'addon' : ''; |
|
756 | - // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection |
|
757 | - // $cache is controlled by individual calls to separate Registry loader methods like load_class() |
|
758 | - // $load_only is also controlled by individual calls to separate Registry loader methods like load_file() |
|
759 | - if ($this->_cache_on && $cache && ! $load_only) { |
|
760 | - // return object if it's already cached |
|
761 | - $cached_class = $this->_get_cached_class($class_name, $addon, $arguments); |
|
762 | - if ($cached_class !== null) { |
|
763 | - return $cached_class; |
|
764 | - } |
|
765 | - }// obtain the loader method from the dependency map |
|
766 | - $loader = $this->_dependency_map->class_loader($class_name);// instantiate the requested object |
|
767 | - if ($loader instanceof Closure) { |
|
768 | - $class_obj = $loader($arguments); |
|
769 | - } else { |
|
770 | - if ($loader && method_exists($this, $loader)) { |
|
771 | - $class_obj = $this->{$loader}($class_name, $arguments); |
|
772 | - } else { |
|
773 | - $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db); |
|
774 | - } |
|
775 | - } |
|
776 | - if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) { |
|
777 | - // save it for later... kinda like gum { : $ |
|
778 | - $this->_set_cached_class( |
|
779 | - $class_obj, |
|
780 | - $class_name, |
|
781 | - $addon, |
|
782 | - $from_db, |
|
783 | - $arguments |
|
784 | - ); |
|
785 | - } |
|
786 | - $this->_cache_on = true; |
|
787 | - return $class_obj; |
|
788 | - } |
|
789 | - |
|
790 | - |
|
791 | - /** |
|
792 | - * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs |
|
793 | - * |
|
794 | - * @param string|object $class_name |
|
795 | - * @param array $arguments |
|
796 | - * @param int $attempt |
|
797 | - * @return mixed |
|
798 | - */ |
|
799 | - private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1) |
|
800 | - { |
|
801 | - if (is_object($class_name) || class_exists($class_name)) { |
|
802 | - return $class_name; |
|
803 | - } |
|
804 | - switch ($attempt) { |
|
805 | - case 1: |
|
806 | - // if it's a FQCN then maybe the class is registered with a preceding \ |
|
807 | - $class_name = strpos($class_name, '\\') !== false |
|
808 | - ? '\\' . ltrim($class_name, '\\') |
|
809 | - : $class_name; |
|
810 | - break; |
|
811 | - case 2: |
|
812 | - // |
|
813 | - $loader = $this->_dependency_map->class_loader($class_name); |
|
814 | - if ($loader && method_exists($this, $loader)) { |
|
815 | - return $this->{$loader}($class_name, $arguments); |
|
816 | - } |
|
817 | - break; |
|
818 | - case 3: |
|
819 | - default: |
|
820 | - return null; |
|
821 | - } |
|
822 | - $attempt++; |
|
823 | - return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt); |
|
824 | - } |
|
825 | - |
|
826 | - |
|
827 | - /** |
|
828 | - * instantiates, caches, and injects dependencies for classes |
|
829 | - * |
|
830 | - * @param array $file_paths an array of paths to folders to look in |
|
831 | - * @param string $class_prefix EE or EEM or... ??? |
|
832 | - * @param bool|string $class_name $class name |
|
833 | - * @param string $type file type - core? class? helper? model? |
|
834 | - * @param mixed $arguments an argument or array of arguments to pass to the class upon instantiation |
|
835 | - * @param bool $from_db some classes are instantiated from the db |
|
836 | - * and thus call a different method to instantiate |
|
837 | - * @param bool $cache whether to cache the instantiated object for reuse |
|
838 | - * @param bool $load_only if true, will only load the file, but will NOT instantiate an object |
|
839 | - * @return bool|null|object null = failure to load or instantiate class object. |
|
840 | - * object = class loaded and instantiated successfully. |
|
841 | - * bool = fail or success when $load_only is true |
|
842 | - * @throws EE_Error |
|
843 | - * @throws ReflectionException |
|
844 | - * @throws InvalidInterfaceException |
|
845 | - * @throws InvalidDataTypeException |
|
846 | - * @throws InvalidArgumentException |
|
847 | - */ |
|
848 | - protected function _load( |
|
849 | - $file_paths = array(), |
|
850 | - $class_prefix = 'EE_', |
|
851 | - $class_name = false, |
|
852 | - $type = 'class', |
|
853 | - $arguments = array(), |
|
854 | - $from_db = false, |
|
855 | - $cache = true, |
|
856 | - $load_only = false |
|
857 | - ) { |
|
858 | - $class_name = ltrim($class_name, '\\'); |
|
859 | - // strip php file extension |
|
860 | - $class_name = str_replace('.php', '', trim($class_name)); |
|
861 | - // does the class have a prefix ? |
|
862 | - if (! empty($class_prefix) && $class_prefix !== 'addon') { |
|
863 | - // make sure $class_prefix is uppercase |
|
864 | - $class_prefix = strtoupper(trim($class_prefix)); |
|
865 | - // add class prefix ONCE!!! |
|
866 | - $class_name = $class_prefix . str_replace($class_prefix, '', $class_name); |
|
867 | - } |
|
868 | - $class_name = $this->class_cache->getFqnForAlias($class_name); |
|
869 | - $class_exists = class_exists($class_name, false); |
|
870 | - // if we're only loading the class and it already exists, then let's just return true immediately |
|
871 | - if ($load_only && $class_exists) { |
|
872 | - return true; |
|
873 | - } |
|
874 | - $arguments = is_array($arguments) ? $arguments : array($arguments); |
|
875 | - // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection |
|
876 | - // $cache is controlled by individual calls to separate Registry loader methods like load_class() |
|
877 | - // $load_only is also controlled by individual calls to separate Registry loader methods like load_file() |
|
878 | - if ($this->_cache_on && $cache && ! $load_only) { |
|
879 | - // return object if it's already cached |
|
880 | - $cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments); |
|
881 | - if ($cached_class !== null) { |
|
882 | - return $cached_class; |
|
883 | - } |
|
884 | - } |
|
885 | - // if the class doesn't already exist.. then we need to try and find the file and load it |
|
886 | - if (! $class_exists) { |
|
887 | - // get full path to file |
|
888 | - $path = $this->_resolve_path($class_name, $type, $file_paths); |
|
889 | - // load the file |
|
890 | - $loaded = $this->_require_file($path, $class_name, $type, $file_paths); |
|
891 | - // if we are only loading a file but NOT instantiating an object |
|
892 | - // then return boolean for whether class was loaded or not |
|
893 | - if ($load_only) { |
|
894 | - return $loaded; |
|
895 | - } |
|
896 | - // if an object was expected but loading failed, then return nothing |
|
897 | - if (! $loaded) { |
|
898 | - return null; |
|
899 | - } |
|
900 | - } |
|
901 | - // instantiate the requested object |
|
902 | - $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db); |
|
903 | - if ($this->_cache_on && $cache) { |
|
904 | - // save it for later... kinda like gum { : $ |
|
905 | - $this->_set_cached_class( |
|
906 | - $class_obj, |
|
907 | - $class_name, |
|
908 | - $class_prefix, |
|
909 | - $from_db, |
|
910 | - $arguments |
|
911 | - ); |
|
912 | - } |
|
913 | - $this->_cache_on = true; |
|
914 | - return $class_obj; |
|
915 | - } |
|
916 | - |
|
917 | - |
|
918 | - /** |
|
919 | - * @param string $class_name |
|
920 | - * @param string $default have to specify something, but not anything that will conflict |
|
921 | - * @return mixed|string |
|
922 | - */ |
|
923 | - protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS') |
|
924 | - { |
|
925 | - return isset($this->_class_abbreviations[ $class_name ]) |
|
926 | - ? $this->_class_abbreviations[ $class_name ] |
|
927 | - : $default; |
|
928 | - } |
|
929 | - |
|
930 | - |
|
931 | - /** |
|
932 | - * attempts to find a cached version of the requested class |
|
933 | - * by looking in the following places: |
|
934 | - * $this->{$class_abbreviation} ie: $this->CART |
|
935 | - * $this->{$class_name} ie: $this->Some_Class |
|
936 | - * $this->LIB->{$class_name} ie: $this->LIB->Some_Class |
|
937 | - * $this->addon->{$class_name} ie: $this->addon->Some_Addon_Class |
|
938 | - * |
|
939 | - * @param string $class_name |
|
940 | - * @param string $class_prefix |
|
941 | - * @param array $arguments |
|
942 | - * @return mixed |
|
943 | - */ |
|
944 | - protected function _get_cached_class( |
|
945 | - $class_name, |
|
946 | - $class_prefix = '', |
|
947 | - $arguments = array() |
|
948 | - ) { |
|
949 | - if ($class_name === 'EE_Registry') { |
|
950 | - return $this; |
|
951 | - } |
|
952 | - $class_abbreviation = $this->get_class_abbreviation($class_name); |
|
953 | - // check if class has already been loaded, and return it if it has been |
|
954 | - if (isset($this->{$class_abbreviation})) { |
|
955 | - return $this->{$class_abbreviation}; |
|
956 | - } |
|
957 | - $class_name = str_replace('\\', '_', $class_name); |
|
958 | - if (isset($this->{$class_name})) { |
|
959 | - return $this->{$class_name}; |
|
960 | - } |
|
961 | - if ($class_prefix === 'addon' && isset($this->addons->{$class_name})) { |
|
962 | - return $this->addons->{$class_name}; |
|
963 | - } |
|
964 | - $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments); |
|
965 | - if (isset($this->LIB->{$object_identifier})) { |
|
966 | - return $this->LIB->{$object_identifier}; |
|
967 | - } |
|
968 | - foreach ($this->LIB as $key => $object) { |
|
969 | - if (// request does not contain new arguments and therefore no args identifier |
|
970 | - ! $this->object_identifier->hasArguments($object_identifier) |
|
971 | - // but previously cached class with args was found |
|
972 | - && $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key) |
|
973 | - ) { |
|
974 | - return $object; |
|
975 | - } |
|
976 | - } |
|
977 | - return null; |
|
978 | - } |
|
979 | - |
|
980 | - |
|
981 | - /** |
|
982 | - * removes a cached version of the requested class |
|
983 | - * |
|
984 | - * @param string $class_name |
|
985 | - * @param boolean $addon |
|
986 | - * @param array $arguments |
|
987 | - * @return boolean |
|
988 | - */ |
|
989 | - public function clear_cached_class( |
|
990 | - $class_name, |
|
991 | - $addon = false, |
|
992 | - $arguments = array() |
|
993 | - ) { |
|
994 | - $class_abbreviation = $this->get_class_abbreviation($class_name); |
|
995 | - // check if class has already been loaded, and return it if it has been |
|
996 | - if (isset($this->{$class_abbreviation})) { |
|
997 | - $this->{$class_abbreviation} = null; |
|
998 | - return true; |
|
999 | - } |
|
1000 | - $class_name = str_replace('\\', '_', $class_name); |
|
1001 | - if (isset($this->{$class_name})) { |
|
1002 | - $this->{$class_name} = null; |
|
1003 | - return true; |
|
1004 | - } |
|
1005 | - if ($addon && isset($this->addons->{$class_name})) { |
|
1006 | - unset($this->addons->{$class_name}); |
|
1007 | - return true; |
|
1008 | - } |
|
1009 | - $class_name = $this->object_identifier->getIdentifier($class_name, $arguments); |
|
1010 | - if (isset($this->LIB->{$class_name})) { |
|
1011 | - unset($this->LIB->{$class_name}); |
|
1012 | - return true; |
|
1013 | - } |
|
1014 | - return false; |
|
1015 | - } |
|
1016 | - |
|
1017 | - |
|
1018 | - /** |
|
1019 | - * _set_cached_class |
|
1020 | - * attempts to cache the instantiated class locally |
|
1021 | - * in one of the following places, in the following order: |
|
1022 | - * $this->{class_abbreviation} ie: $this->CART |
|
1023 | - * $this->{$class_name} ie: $this->Some_Class |
|
1024 | - * $this->addon->{$$class_name} ie: $this->addon->Some_Addon_Class |
|
1025 | - * $this->LIB->{$class_name} ie: $this->LIB->Some_Class |
|
1026 | - * |
|
1027 | - * @param object $class_obj |
|
1028 | - * @param string $class_name |
|
1029 | - * @param string $class_prefix |
|
1030 | - * @param bool $from_db |
|
1031 | - * @param array $arguments |
|
1032 | - * @return void |
|
1033 | - */ |
|
1034 | - protected function _set_cached_class( |
|
1035 | - $class_obj, |
|
1036 | - $class_name, |
|
1037 | - $class_prefix = '', |
|
1038 | - $from_db = false, |
|
1039 | - $arguments = array() |
|
1040 | - ) { |
|
1041 | - if ($class_name === 'EE_Registry' || empty($class_obj)) { |
|
1042 | - return; |
|
1043 | - } |
|
1044 | - // return newly instantiated class |
|
1045 | - $class_abbreviation = $this->get_class_abbreviation($class_name, ''); |
|
1046 | - if ($class_abbreviation) { |
|
1047 | - $this->{$class_abbreviation} = $class_obj; |
|
1048 | - return; |
|
1049 | - } |
|
1050 | - $class_name = str_replace('\\', '_', $class_name); |
|
1051 | - if (property_exists($this, $class_name)) { |
|
1052 | - $this->{$class_name} = $class_obj; |
|
1053 | - return; |
|
1054 | - } |
|
1055 | - if ($class_prefix === 'addon') { |
|
1056 | - $this->addons->{$class_name} = $class_obj; |
|
1057 | - return; |
|
1058 | - } |
|
1059 | - if (! $from_db) { |
|
1060 | - $class_name = $this->object_identifier->getIdentifier($class_name, $arguments); |
|
1061 | - $this->LIB->{$class_name} = $class_obj; |
|
1062 | - } |
|
1063 | - } |
|
1064 | - |
|
1065 | - |
|
1066 | - /** |
|
1067 | - * attempts to find a full valid filepath for the requested class. |
|
1068 | - * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php" |
|
1069 | - * then returns that path if the target file has been found and is readable |
|
1070 | - * |
|
1071 | - * @param string $class_name |
|
1072 | - * @param string $type |
|
1073 | - * @param array $file_paths |
|
1074 | - * @return string | bool |
|
1075 | - */ |
|
1076 | - protected function _resolve_path($class_name, $type = '', $file_paths = array()) |
|
1077 | - { |
|
1078 | - // make sure $file_paths is an array |
|
1079 | - $file_paths = is_array($file_paths) |
|
1080 | - ? $file_paths |
|
1081 | - : array($file_paths); |
|
1082 | - // cycle thru paths |
|
1083 | - foreach ($file_paths as $key => $file_path) { |
|
1084 | - // convert all separators to proper DS, if no filepath, then use EE_CLASSES |
|
1085 | - $file_path = $file_path |
|
1086 | - ? str_replace(array('/', '\\'), DS, $file_path) |
|
1087 | - : EE_CLASSES; |
|
1088 | - // prep file type |
|
1089 | - $type = ! empty($type) |
|
1090 | - ? trim($type, '.') . '.' |
|
1091 | - : ''; |
|
1092 | - // build full file path |
|
1093 | - $file_paths[ $key ] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php'; |
|
1094 | - // does the file exist and can be read ? |
|
1095 | - if (is_readable($file_paths[ $key ])) { |
|
1096 | - return $file_paths[ $key ]; |
|
1097 | - } |
|
1098 | - } |
|
1099 | - return false; |
|
1100 | - } |
|
1101 | - |
|
1102 | - |
|
1103 | - /** |
|
1104 | - * basically just performs a require_once() |
|
1105 | - * but with some error handling |
|
1106 | - * |
|
1107 | - * @param string $path |
|
1108 | - * @param string $class_name |
|
1109 | - * @param string $type |
|
1110 | - * @param array $file_paths |
|
1111 | - * @return bool |
|
1112 | - * @throws EE_Error |
|
1113 | - * @throws ReflectionException |
|
1114 | - */ |
|
1115 | - protected function _require_file($path, $class_name, $type = '', $file_paths = array()) |
|
1116 | - { |
|
1117 | - $this->resolve_legacy_class_parent($class_name); |
|
1118 | - // don't give up! you gotta... |
|
1119 | - try { |
|
1120 | - // does the file exist and can it be read ? |
|
1121 | - if (! $path) { |
|
1122 | - // just in case the file has already been autoloaded, |
|
1123 | - // but discrepancies in the naming schema are preventing it from |
|
1124 | - // being loaded via one of the EE_Registry::load_*() methods, |
|
1125 | - // then let's try one last hail mary before throwing an exception |
|
1126 | - // and call class_exists() again, but with autoloading turned ON |
|
1127 | - if (class_exists($class_name)) { |
|
1128 | - return true; |
|
1129 | - } |
|
1130 | - // so sorry, can't find the file |
|
1131 | - throw new EE_Error( |
|
1132 | - sprintf( |
|
1133 | - esc_html__( |
|
1134 | - 'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s', |
|
1135 | - 'event_espresso' |
|
1136 | - ), |
|
1137 | - trim($type, '.'), |
|
1138 | - $class_name, |
|
1139 | - '<br />' . implode(',<br />', $file_paths) |
|
1140 | - ) |
|
1141 | - ); |
|
1142 | - } |
|
1143 | - // get the file |
|
1144 | - require_once($path); |
|
1145 | - // if the class isn't already declared somewhere |
|
1146 | - if (class_exists($class_name, false) === false) { |
|
1147 | - // so sorry, not a class |
|
1148 | - throw new EE_Error( |
|
1149 | - sprintf( |
|
1150 | - esc_html__( |
|
1151 | - 'The %s file %s does not appear to contain the %s Class.', |
|
1152 | - 'event_espresso' |
|
1153 | - ), |
|
1154 | - $type, |
|
1155 | - $path, |
|
1156 | - $class_name |
|
1157 | - ) |
|
1158 | - ); |
|
1159 | - } |
|
1160 | - } catch (EE_Error $e) { |
|
1161 | - $e->get_error(); |
|
1162 | - return false; |
|
1163 | - } |
|
1164 | - return true; |
|
1165 | - } |
|
1166 | - |
|
1167 | - |
|
1168 | - /** |
|
1169 | - * Some of our legacy classes that extended a parent class would simply use a require() statement |
|
1170 | - * before their class declaration in order to ensure that the parent class was loaded. |
|
1171 | - * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class, |
|
1172 | - * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist. |
|
1173 | - * |
|
1174 | - * @param string $class_name |
|
1175 | - */ |
|
1176 | - protected function resolve_legacy_class_parent($class_name = '') |
|
1177 | - { |
|
1178 | - try { |
|
1179 | - $legacy_parent_class_map = array( |
|
1180 | - 'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php', |
|
1181 | - ); |
|
1182 | - if (isset($legacy_parent_class_map[ $class_name ])) { |
|
1183 | - require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ]; |
|
1184 | - } |
|
1185 | - } catch (Exception $exception) { |
|
1186 | - } |
|
1187 | - } |
|
1188 | - |
|
1189 | - |
|
1190 | - /** |
|
1191 | - * _create_object |
|
1192 | - * Attempts to instantiate the requested class via any of the |
|
1193 | - * commonly used instantiation methods employed throughout EE. |
|
1194 | - * The priority for instantiation is as follows: |
|
1195 | - * - abstract classes or any class flagged as "load only" (no instantiation occurs) |
|
1196 | - * - model objects via their 'new_instance_from_db' method |
|
1197 | - * - model objects via their 'new_instance' method |
|
1198 | - * - "singleton" classes" via their 'instance' method |
|
1199 | - * - standard instantiable classes via their __constructor |
|
1200 | - * Prior to instantiation, if the classname exists in the dependency_map, |
|
1201 | - * then the constructor for the requested class will be examined to determine |
|
1202 | - * if any dependencies exist, and if they can be injected. |
|
1203 | - * If so, then those classes will be added to the array of arguments passed to the constructor |
|
1204 | - * |
|
1205 | - * @param string $class_name |
|
1206 | - * @param array $arguments |
|
1207 | - * @param string $type |
|
1208 | - * @param bool $from_db |
|
1209 | - * @return null|object|bool |
|
1210 | - * @throws InvalidArgumentException |
|
1211 | - * @throws InvalidInterfaceException |
|
1212 | - * @throws EE_Error |
|
1213 | - * @throws ReflectionException |
|
1214 | - * @throws InvalidDataTypeException |
|
1215 | - */ |
|
1216 | - protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false) |
|
1217 | - { |
|
1218 | - // create reflection |
|
1219 | - $reflector = $this->mirror->getReflectionClass($class_name); |
|
1220 | - // make sure arguments are an array |
|
1221 | - $arguments = is_array($arguments) |
|
1222 | - ? $arguments |
|
1223 | - : array($arguments); |
|
1224 | - // and if arguments array is numerically and sequentially indexed, then we want it to remain as is, |
|
1225 | - // else wrap it in an additional array so that it doesn't get split into multiple parameters |
|
1226 | - $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments) |
|
1227 | - ? $arguments |
|
1228 | - : array($arguments); |
|
1229 | - // attempt to inject dependencies ? |
|
1230 | - if ($this->_dependency_map->has($class_name)) { |
|
1231 | - $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments); |
|
1232 | - } |
|
1233 | - // instantiate the class if possible |
|
1234 | - if ($reflector->isAbstract()) { |
|
1235 | - // nothing to instantiate, loading file was enough |
|
1236 | - // does not throw an exception so $instantiation_mode is unused |
|
1237 | - // $instantiation_mode = "1) no constructor abstract class"; |
|
1238 | - return true; |
|
1239 | - } |
|
1240 | - if (empty($arguments) |
|
1241 | - && $this->mirror->getConstructorFromReflection($reflector) === null |
|
1242 | - && $reflector->isInstantiable() |
|
1243 | - ) { |
|
1244 | - // no constructor = static methods only... nothing to instantiate, loading file was enough |
|
1245 | - // $instantiation_mode = "2) no constructor but instantiable"; |
|
1246 | - return $reflector->newInstance(); |
|
1247 | - } |
|
1248 | - if ($from_db && method_exists($class_name, 'new_instance_from_db')) { |
|
1249 | - // $instantiation_mode = "3) new_instance_from_db()"; |
|
1250 | - return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments); |
|
1251 | - } |
|
1252 | - if (method_exists($class_name, 'new_instance')) { |
|
1253 | - // $instantiation_mode = "4) new_instance()"; |
|
1254 | - return call_user_func_array(array($class_name, 'new_instance'), $arguments); |
|
1255 | - } |
|
1256 | - if (method_exists($class_name, 'instance')) { |
|
1257 | - // $instantiation_mode = "5) instance()"; |
|
1258 | - return call_user_func_array(array($class_name, 'instance'), $arguments); |
|
1259 | - } |
|
1260 | - if ($reflector->isInstantiable()) { |
|
1261 | - // $instantiation_mode = "6) constructor"; |
|
1262 | - return $reflector->newInstanceArgs($arguments); |
|
1263 | - } |
|
1264 | - // heh ? something's not right ! |
|
1265 | - throw new EE_Error( |
|
1266 | - sprintf( |
|
1267 | - __('The %s file %s could not be instantiated.', 'event_espresso'), |
|
1268 | - $type, |
|
1269 | - $class_name |
|
1270 | - ) |
|
1271 | - ); |
|
1272 | - } |
|
1273 | - |
|
1274 | - |
|
1275 | - /** |
|
1276 | - * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential |
|
1277 | - * @param array $array |
|
1278 | - * @return bool |
|
1279 | - */ |
|
1280 | - protected function _array_is_numerically_and_sequentially_indexed(array $array) |
|
1281 | - { |
|
1282 | - return ! empty($array) |
|
1283 | - ? array_keys($array) === range(0, count($array) - 1) |
|
1284 | - : true; |
|
1285 | - } |
|
1286 | - |
|
1287 | - |
|
1288 | - /** |
|
1289 | - * _resolve_dependencies |
|
1290 | - * examines the constructor for the requested class to determine |
|
1291 | - * if any dependencies exist, and if they can be injected. |
|
1292 | - * If so, then those classes will be added to the array of arguments passed to the constructor |
|
1293 | - * PLZ NOTE: this is achieved by type hinting the constructor params |
|
1294 | - * For example: |
|
1295 | - * if attempting to load a class "Foo" with the following constructor: |
|
1296 | - * __construct( Bar $bar_class, Fighter $grohl_class ) |
|
1297 | - * then $bar_class and $grohl_class will be added to the $arguments array, |
|
1298 | - * but only IF they are NOT already present in the incoming arguments array, |
|
1299 | - * and the correct classes can be loaded |
|
1300 | - * |
|
1301 | - * @param ReflectionClass $reflector |
|
1302 | - * @param string $class_name |
|
1303 | - * @param array $arguments |
|
1304 | - * @return array |
|
1305 | - * @throws InvalidArgumentException |
|
1306 | - * @throws InvalidDataTypeException |
|
1307 | - * @throws InvalidInterfaceException |
|
1308 | - * @throws ReflectionException |
|
1309 | - */ |
|
1310 | - protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array()) |
|
1311 | - { |
|
1312 | - // let's examine the constructor |
|
1313 | - $constructor = $this->mirror->getConstructorFromReflection($reflector); |
|
1314 | - // whu? huh? nothing? |
|
1315 | - if (! $constructor) { |
|
1316 | - return $arguments; |
|
1317 | - } |
|
1318 | - // get constructor parameters |
|
1319 | - $params = $this->mirror->getParametersFromReflection($reflector); |
|
1320 | - // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected |
|
1321 | - $argument_keys = array_keys($arguments); |
|
1322 | - // now loop thru all of the constructors expected parameters |
|
1323 | - foreach ($params as $index => $param) { |
|
1324 | - // is this a dependency for a specific class ? |
|
1325 | - $param_class = $this->mirror->getParameterClassName($param, $class_name, $index); |
|
1326 | - // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime) |
|
1327 | - $param_class = $this->class_cache->isAlias($param_class, $class_name) |
|
1328 | - ? $this->class_cache->getFqnForAlias($param_class, $class_name) |
|
1329 | - : $param_class; |
|
1330 | - if (// param is not even a class |
|
1331 | - $param_class === null |
|
1332 | - // and something already exists in the incoming arguments for this param |
|
1333 | - && array_key_exists($index, $argument_keys) |
|
1334 | - && array_key_exists($argument_keys[ $index ], $arguments) |
|
1335 | - ) { |
|
1336 | - // so let's skip this argument and move on to the next |
|
1337 | - continue; |
|
1338 | - } |
|
1339 | - if (// parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class |
|
1340 | - $param_class !== null |
|
1341 | - && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ]) |
|
1342 | - && $arguments[ $argument_keys[ $index ] ] instanceof $param_class |
|
1343 | - ) { |
|
1344 | - // skip this argument and move on to the next |
|
1345 | - continue; |
|
1346 | - } |
|
1347 | - if (// parameter is type hinted as a class, and should be injected |
|
1348 | - $param_class !== null |
|
1349 | - && $this->_dependency_map->has_dependency_for_class($class_name, $param_class) |
|
1350 | - ) { |
|
1351 | - $arguments = $this->_resolve_dependency( |
|
1352 | - $class_name, |
|
1353 | - $param_class, |
|
1354 | - $arguments, |
|
1355 | - $index |
|
1356 | - ); |
|
1357 | - } else { |
|
1358 | - $arguments[ $index ] = $this->mirror->getParameterDefaultValue( |
|
1359 | - $param, |
|
1360 | - $class_name, |
|
1361 | - $index |
|
1362 | - ); |
|
1363 | - } |
|
1364 | - } |
|
1365 | - return $arguments; |
|
1366 | - } |
|
1367 | - |
|
1368 | - |
|
1369 | - /** |
|
1370 | - * @param string $class_name |
|
1371 | - * @param string $param_class |
|
1372 | - * @param array $arguments |
|
1373 | - * @param mixed $index |
|
1374 | - * @return array |
|
1375 | - * @throws InvalidArgumentException |
|
1376 | - * @throws InvalidInterfaceException |
|
1377 | - * @throws InvalidDataTypeException |
|
1378 | - */ |
|
1379 | - protected function _resolve_dependency($class_name, $param_class, $arguments, $index) |
|
1380 | - { |
|
1381 | - $dependency = null; |
|
1382 | - // should dependency be loaded from cache ? |
|
1383 | - $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency( |
|
1384 | - $class_name, |
|
1385 | - $param_class |
|
1386 | - ); |
|
1387 | - $cache_on = $cache_on !== EE_Dependency_Map::load_new_object; |
|
1388 | - // we might have a dependency... |
|
1389 | - // let's MAYBE try and find it in our cache if that's what's been requested |
|
1390 | - $cached_class = $cache_on |
|
1391 | - ? $this->_get_cached_class($param_class) |
|
1392 | - : null; |
|
1393 | - // and grab it if it exists |
|
1394 | - if ($cached_class instanceof $param_class) { |
|
1395 | - $dependency = $cached_class; |
|
1396 | - } elseif ($param_class !== $class_name) { |
|
1397 | - // obtain the loader method from the dependency map |
|
1398 | - $loader = $this->_dependency_map->class_loader($param_class); |
|
1399 | - // is loader a custom closure ? |
|
1400 | - if ($loader instanceof Closure) { |
|
1401 | - $dependency = $loader($arguments); |
|
1402 | - } else { |
|
1403 | - // set the cache on property for the recursive loading call |
|
1404 | - $this->_cache_on = $cache_on; |
|
1405 | - // if not, then let's try and load it via the registry |
|
1406 | - if ($loader && method_exists($this, $loader)) { |
|
1407 | - $dependency = $this->{$loader}($param_class); |
|
1408 | - } else { |
|
1409 | - $dependency = LoaderFactory::getLoader()->load( |
|
1410 | - $param_class, |
|
1411 | - array(), |
|
1412 | - $cache_on |
|
1413 | - ); |
|
1414 | - } |
|
1415 | - } |
|
1416 | - } |
|
1417 | - // did we successfully find the correct dependency ? |
|
1418 | - if ($dependency instanceof $param_class) { |
|
1419 | - // then let's inject it into the incoming array of arguments at the correct location |
|
1420 | - $arguments[ $index ] = $dependency; |
|
1421 | - } |
|
1422 | - return $arguments; |
|
1423 | - } |
|
1424 | - |
|
1425 | - |
|
1426 | - /** |
|
1427 | - * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array |
|
1428 | - * |
|
1429 | - * @param string $classname PLEASE NOTE: the class name needs to match what's registered |
|
1430 | - * in the EE_Dependency_Map::$_class_loaders array, |
|
1431 | - * including the class prefix, ie: "EE_", "EEM_", "EEH_", etc |
|
1432 | - * @param array $arguments |
|
1433 | - * @return object |
|
1434 | - */ |
|
1435 | - public static function factory($classname, $arguments = array()) |
|
1436 | - { |
|
1437 | - $loader = self::instance()->_dependency_map->class_loader($classname); |
|
1438 | - if ($loader instanceof Closure) { |
|
1439 | - return $loader($arguments); |
|
1440 | - } |
|
1441 | - if (method_exists(self::instance(), $loader)) { |
|
1442 | - return self::instance()->{$loader}($classname, $arguments); |
|
1443 | - } |
|
1444 | - return null; |
|
1445 | - } |
|
1446 | - |
|
1447 | - |
|
1448 | - /** |
|
1449 | - * Gets the addon by its class name |
|
1450 | - * |
|
1451 | - * @param string $class_name |
|
1452 | - * @return EE_Addon |
|
1453 | - */ |
|
1454 | - public function getAddon($class_name) |
|
1455 | - { |
|
1456 | - $class_name = str_replace('\\', '_', $class_name); |
|
1457 | - return $this->addons->{$class_name}; |
|
1458 | - } |
|
1459 | - |
|
1460 | - |
|
1461 | - /** |
|
1462 | - * removes the addon from the internal cache |
|
1463 | - * |
|
1464 | - * @param string $class_name |
|
1465 | - * @return void |
|
1466 | - */ |
|
1467 | - public function removeAddon($class_name) |
|
1468 | - { |
|
1469 | - $class_name = str_replace('\\', '_', $class_name); |
|
1470 | - unset($this->addons->{$class_name}); |
|
1471 | - } |
|
1472 | - |
|
1473 | - |
|
1474 | - /** |
|
1475 | - * Gets the addon by its name/slug (not classname. For that, just |
|
1476 | - * use the get_addon() method above |
|
1477 | - * |
|
1478 | - * @param string $name |
|
1479 | - * @return EE_Addon |
|
1480 | - */ |
|
1481 | - public function get_addon_by_name($name) |
|
1482 | - { |
|
1483 | - foreach ($this->addons as $addon) { |
|
1484 | - if ($addon->name() === $name) { |
|
1485 | - return $addon; |
|
1486 | - } |
|
1487 | - } |
|
1488 | - return null; |
|
1489 | - } |
|
1490 | - |
|
1491 | - |
|
1492 | - /** |
|
1493 | - * Gets an array of all the registered addons, where the keys are their names. |
|
1494 | - * (ie, what each returns for their name() function) |
|
1495 | - * They're already available on EE_Registry::instance()->addons as properties, |
|
1496 | - * where each property's name is the addon's classname, |
|
1497 | - * So if you just want to get the addon by classname, |
|
1498 | - * OR use the get_addon() method above. |
|
1499 | - * PLEASE NOTE: |
|
1500 | - * addons with Fully Qualified Class Names |
|
1501 | - * have had the namespace separators converted to underscores, |
|
1502 | - * so a classname like Fully\Qualified\ClassName |
|
1503 | - * would have been converted to Fully_Qualified_ClassName |
|
1504 | - * |
|
1505 | - * @return EE_Addon[] where the KEYS are the addon's name() |
|
1506 | - */ |
|
1507 | - public function get_addons_by_name() |
|
1508 | - { |
|
1509 | - $addons = array(); |
|
1510 | - foreach ($this->addons as $addon) { |
|
1511 | - $addons[ $addon->name() ] = $addon; |
|
1512 | - } |
|
1513 | - return $addons; |
|
1514 | - } |
|
1515 | - |
|
1516 | - |
|
1517 | - /** |
|
1518 | - * Resets the specified model's instance AND makes sure EE_Registry doesn't keep |
|
1519 | - * a stale copy of it around |
|
1520 | - * |
|
1521 | - * @param string $model_name |
|
1522 | - * @return \EEM_Base |
|
1523 | - * @throws \EE_Error |
|
1524 | - */ |
|
1525 | - public function reset_model($model_name) |
|
1526 | - { |
|
1527 | - $model_class_name = strpos($model_name, 'EEM_') !== 0 |
|
1528 | - ? "EEM_{$model_name}" |
|
1529 | - : $model_name; |
|
1530 | - if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) { |
|
1531 | - return null; |
|
1532 | - } |
|
1533 | - // get that model reset it and make sure we nuke the old reference to it |
|
1534 | - if ($this->LIB->{$model_class_name} instanceof $model_class_name |
|
1535 | - && is_callable( |
|
1536 | - array($model_class_name, 'reset') |
|
1537 | - )) { |
|
1538 | - $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset(); |
|
1539 | - } else { |
|
1540 | - throw new EE_Error( |
|
1541 | - sprintf( |
|
1542 | - esc_html__('Model %s does not have a method "reset"', 'event_espresso'), |
|
1543 | - $model_name |
|
1544 | - ) |
|
1545 | - ); |
|
1546 | - } |
|
1547 | - return $this->LIB->{$model_class_name}; |
|
1548 | - } |
|
1549 | - |
|
1550 | - |
|
1551 | - /** |
|
1552 | - * Resets the registry. |
|
1553 | - * The criteria for what gets reset is based on what can be shared between sites on the same request when |
|
1554 | - * switch_to_blog is used in a multisite install. Here is a list of things that are NOT reset. |
|
1555 | - * - $_dependency_map |
|
1556 | - * - $_class_abbreviations |
|
1557 | - * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset. |
|
1558 | - * - $REQ: Still on the same request so no need to change. |
|
1559 | - * - $CAP: There is no site specific state in the EE_Capability class. |
|
1560 | - * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only |
|
1561 | - * one Session can be active in a single request. Resetting could resolve in "headers already sent" errors. |
|
1562 | - * - $addons: In multisite, the state of the addons is something controlled via hooks etc in a normal request. So |
|
1563 | - * for now, we won't reset the addons because it could break calls to an add-ons class/methods in the |
|
1564 | - * switch or on the restore. |
|
1565 | - * - $modules |
|
1566 | - * - $shortcodes |
|
1567 | - * - $widgets |
|
1568 | - * |
|
1569 | - * @param boolean $hard [deprecated] |
|
1570 | - * @param boolean $reinstantiate whether to create new instances of EE_Registry's singletons too, |
|
1571 | - * or just reset without re-instantiating (handy to set to FALSE if you're not |
|
1572 | - * sure if you CAN currently reinstantiate the singletons at the moment) |
|
1573 | - * @param bool $reset_models Defaults to true. When false, then the models are not reset. This is so |
|
1574 | - * client |
|
1575 | - * code instead can just change the model context to a different blog id if |
|
1576 | - * necessary |
|
1577 | - * @return EE_Registry |
|
1578 | - * @throws InvalidInterfaceException |
|
1579 | - * @throws InvalidDataTypeException |
|
1580 | - * @throws EE_Error |
|
1581 | - * @throws ReflectionException |
|
1582 | - * @throws InvalidArgumentException |
|
1583 | - */ |
|
1584 | - public static function reset($hard = false, $reinstantiate = true, $reset_models = true) |
|
1585 | - { |
|
1586 | - $instance = self::instance(); |
|
1587 | - $instance->_cache_on = true; |
|
1588 | - // reset some "special" classes |
|
1589 | - EEH_Activation::reset(); |
|
1590 | - $hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard); |
|
1591 | - $instance->CFG = EE_Config::reset($hard, $reinstantiate); |
|
1592 | - $instance->CART = null; |
|
1593 | - $instance->MRM = null; |
|
1594 | - $instance->AssetsRegistry = LoaderFactory::getLoader()->getShared( |
|
1595 | - 'EventEspresso\core\services\assets\Registry' |
|
1596 | - ); |
|
1597 | - // messages reset |
|
1598 | - EED_Messages::reset(); |
|
1599 | - // handle of objects cached on LIB |
|
1600 | - foreach (array('LIB', 'modules') as $cache) { |
|
1601 | - foreach ($instance->{$cache} as $class_name => $class) { |
|
1602 | - if (self::_reset_and_unset_object($class, $reset_models)) { |
|
1603 | - unset($instance->{$cache}->{$class_name}); |
|
1604 | - } |
|
1605 | - } |
|
1606 | - } |
|
1607 | - return $instance; |
|
1608 | - } |
|
1609 | - |
|
1610 | - |
|
1611 | - /** |
|
1612 | - * if passed object implements ResettableInterface, then call it's reset() method |
|
1613 | - * if passed object implements InterminableInterface, then return false, |
|
1614 | - * to indicate that it should NOT be cleared from the Registry cache |
|
1615 | - * |
|
1616 | - * @param $object |
|
1617 | - * @param bool $reset_models |
|
1618 | - * @return bool returns true if cached object should be unset |
|
1619 | - */ |
|
1620 | - private static function _reset_and_unset_object($object, $reset_models) |
|
1621 | - { |
|
1622 | - if (! is_object($object)) { |
|
1623 | - // don't unset anything that's not an object |
|
1624 | - return false; |
|
1625 | - } |
|
1626 | - if ($object instanceof EED_Module) { |
|
1627 | - $object::reset(); |
|
1628 | - // don't unset modules |
|
1629 | - return false; |
|
1630 | - } |
|
1631 | - if ($object instanceof ResettableInterface) { |
|
1632 | - if ($object instanceof EEM_Base) { |
|
1633 | - if ($reset_models) { |
|
1634 | - $object->reset(); |
|
1635 | - return true; |
|
1636 | - } |
|
1637 | - return false; |
|
1638 | - } |
|
1639 | - $object->reset(); |
|
1640 | - return true; |
|
1641 | - } |
|
1642 | - if (! $object instanceof InterminableInterface) { |
|
1643 | - return true; |
|
1644 | - } |
|
1645 | - return false; |
|
1646 | - } |
|
1647 | - |
|
1648 | - |
|
1649 | - /** |
|
1650 | - * Gets all the custom post type models defined |
|
1651 | - * |
|
1652 | - * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event") |
|
1653 | - */ |
|
1654 | - public function cpt_models() |
|
1655 | - { |
|
1656 | - $cpt_models = array(); |
|
1657 | - foreach ($this->non_abstract_db_models as $short_name => $classname) { |
|
1658 | - if (is_subclass_of($classname, 'EEM_CPT_Base')) { |
|
1659 | - $cpt_models[ $short_name ] = $classname; |
|
1660 | - } |
|
1661 | - } |
|
1662 | - return $cpt_models; |
|
1663 | - } |
|
1664 | - |
|
1665 | - |
|
1666 | - /** |
|
1667 | - * @return \EE_Config |
|
1668 | - */ |
|
1669 | - public static function CFG() |
|
1670 | - { |
|
1671 | - return self::instance()->CFG; |
|
1672 | - } |
|
1673 | - |
|
1674 | - |
|
1675 | - /** |
|
1676 | - * @deprecated 4.9.62.p |
|
1677 | - * @param string $class_name |
|
1678 | - * @return ReflectionClass |
|
1679 | - * @throws ReflectionException |
|
1680 | - * @throws InvalidDataTypeException |
|
1681 | - */ |
|
1682 | - public function get_ReflectionClass($class_name) |
|
1683 | - { |
|
1684 | - return $this->mirror->getReflectionClass($class_name); |
|
1685 | - } |
|
26 | + /** |
|
27 | + * @var EE_Registry $_instance |
|
28 | + */ |
|
29 | + private static $_instance; |
|
30 | + |
|
31 | + /** |
|
32 | + * @var EE_Dependency_Map $_dependency_map |
|
33 | + */ |
|
34 | + protected $_dependency_map; |
|
35 | + |
|
36 | + /** |
|
37 | + * @var Mirror |
|
38 | + */ |
|
39 | + private $mirror; |
|
40 | + |
|
41 | + /** |
|
42 | + * @var ClassInterfaceCache $class_cache |
|
43 | + */ |
|
44 | + private $class_cache; |
|
45 | + |
|
46 | + /** |
|
47 | + * @var array $_class_abbreviations |
|
48 | + */ |
|
49 | + protected $_class_abbreviations = array(); |
|
50 | + |
|
51 | + /** |
|
52 | + * @var CommandBusInterface $BUS |
|
53 | + */ |
|
54 | + public $BUS; |
|
55 | + |
|
56 | + /** |
|
57 | + * @var EE_Cart $CART |
|
58 | + */ |
|
59 | + public $CART; |
|
60 | + |
|
61 | + /** |
|
62 | + * @var EE_Config $CFG |
|
63 | + */ |
|
64 | + public $CFG; |
|
65 | + |
|
66 | + /** |
|
67 | + * @var EE_Network_Config $NET_CFG |
|
68 | + */ |
|
69 | + public $NET_CFG; |
|
70 | + |
|
71 | + /** |
|
72 | + * StdClass object for storing library classes in |
|
73 | + * |
|
74 | + * @var RegistryContainer $LIB |
|
75 | + */ |
|
76 | + public $LIB; |
|
77 | + |
|
78 | + /** |
|
79 | + * @var EE_Request_Handler $REQ |
|
80 | + */ |
|
81 | + public $REQ; |
|
82 | + |
|
83 | + /** |
|
84 | + * @var EE_Session $SSN |
|
85 | + */ |
|
86 | + public $SSN; |
|
87 | + |
|
88 | + /** |
|
89 | + * @since 4.5.0 |
|
90 | + * @var EE_Capabilities $CAP |
|
91 | + */ |
|
92 | + public $CAP; |
|
93 | + |
|
94 | + /** |
|
95 | + * @since 4.9.0 |
|
96 | + * @var EE_Message_Resource_Manager $MRM |
|
97 | + */ |
|
98 | + public $MRM; |
|
99 | + |
|
100 | + /** |
|
101 | + * @var Registry $AssetsRegistry |
|
102 | + */ |
|
103 | + public $AssetsRegistry; |
|
104 | + |
|
105 | + /** |
|
106 | + * StdClass object for holding addons which have registered themselves to work with EE core |
|
107 | + * |
|
108 | + * @var EE_Addon[] $addons |
|
109 | + */ |
|
110 | + public $addons; |
|
111 | + |
|
112 | + /** |
|
113 | + * keys are 'short names' (eg Event), values are class names (eg 'EEM_Event') |
|
114 | + * |
|
115 | + * @var EEM_Base[] $models |
|
116 | + */ |
|
117 | + public $models = array(); |
|
118 | + |
|
119 | + /** |
|
120 | + * @var EED_Module[] $modules |
|
121 | + */ |
|
122 | + public $modules; |
|
123 | + |
|
124 | + /** |
|
125 | + * @var EES_Shortcode[] $shortcodes |
|
126 | + */ |
|
127 | + public $shortcodes; |
|
128 | + |
|
129 | + /** |
|
130 | + * @var WP_Widget[] $widgets |
|
131 | + */ |
|
132 | + public $widgets; |
|
133 | + |
|
134 | + /** |
|
135 | + * this is an array of all implemented model names (i.e. not the parent abstract models, or models |
|
136 | + * which don't actually fetch items from the DB in the normal way (ie, are not children of EEM_Base)). |
|
137 | + * Keys are model "short names" (eg "Event") as used in model relations, and values are |
|
138 | + * classnames (eg "EEM_Event") |
|
139 | + * |
|
140 | + * @var array $non_abstract_db_models |
|
141 | + */ |
|
142 | + public $non_abstract_db_models = array(); |
|
143 | + |
|
144 | + /** |
|
145 | + * internationalization for JS strings |
|
146 | + * usage: EE_Registry::i18n_js_strings['string_key'] = esc_html__( 'string to translate.', 'event_espresso' ); |
|
147 | + * in js file: var translatedString = eei18n.string_key; |
|
148 | + * |
|
149 | + * @var array $i18n_js_strings |
|
150 | + */ |
|
151 | + public static $i18n_js_strings = array(); |
|
152 | + |
|
153 | + /** |
|
154 | + * $main_file - path to espresso.php |
|
155 | + * |
|
156 | + * @var array $main_file |
|
157 | + */ |
|
158 | + public $main_file; |
|
159 | + |
|
160 | + /** |
|
161 | + * array of ReflectionClass objects where the key is the class name |
|
162 | + * |
|
163 | + * @deprecated 4.9.62.p |
|
164 | + * @var ReflectionClass[] $_reflectors |
|
165 | + */ |
|
166 | + public $_reflectors; |
|
167 | + |
|
168 | + /** |
|
169 | + * boolean flag to indicate whether or not to load/save dependencies from/to the cache |
|
170 | + * |
|
171 | + * @var boolean $_cache_on |
|
172 | + */ |
|
173 | + protected $_cache_on = true; |
|
174 | + |
|
175 | + /** |
|
176 | + * @var ObjectIdentifier |
|
177 | + */ |
|
178 | + private $object_identifier; |
|
179 | + |
|
180 | + |
|
181 | + /** |
|
182 | + * @singleton method used to instantiate class object |
|
183 | + * @param EE_Dependency_Map|null $dependency_map |
|
184 | + * @param Mirror|null $mirror |
|
185 | + * @param ClassInterfaceCache|null $class_cache |
|
186 | + * @param ObjectIdentifier|null $object_identifier |
|
187 | + * @return EE_Registry instance |
|
188 | + */ |
|
189 | + public static function instance( |
|
190 | + EE_Dependency_Map $dependency_map = null, |
|
191 | + Mirror $mirror = null, |
|
192 | + ClassInterfaceCache $class_cache = null, |
|
193 | + ObjectIdentifier $object_identifier = null |
|
194 | + ) { |
|
195 | + // check if class object is instantiated |
|
196 | + if (! self::$_instance instanceof EE_Registry |
|
197 | + && $dependency_map instanceof EE_Dependency_Map |
|
198 | + && $mirror instanceof Mirror |
|
199 | + && $class_cache instanceof ClassInterfaceCache |
|
200 | + && $object_identifier instanceof ObjectIdentifier |
|
201 | + ) { |
|
202 | + self::$_instance = new self( |
|
203 | + $dependency_map, |
|
204 | + $mirror, |
|
205 | + $class_cache, |
|
206 | + $object_identifier |
|
207 | + ); |
|
208 | + } |
|
209 | + return self::$_instance; |
|
210 | + } |
|
211 | + |
|
212 | + |
|
213 | + /** |
|
214 | + * protected constructor to prevent direct creation |
|
215 | + * |
|
216 | + * @Constructor |
|
217 | + * @param EE_Dependency_Map $dependency_map |
|
218 | + * @param Mirror $mirror |
|
219 | + * @param ClassInterfaceCache $class_cache |
|
220 | + * @param ObjectIdentifier $object_identifier |
|
221 | + */ |
|
222 | + protected function __construct( |
|
223 | + EE_Dependency_Map $dependency_map, |
|
224 | + Mirror $mirror, |
|
225 | + ClassInterfaceCache $class_cache, |
|
226 | + ObjectIdentifier $object_identifier |
|
227 | + ) { |
|
228 | + $this->_dependency_map = $dependency_map; |
|
229 | + $this->mirror = $mirror; |
|
230 | + $this->class_cache = $class_cache; |
|
231 | + $this->object_identifier = $object_identifier; |
|
232 | + // $registry_container = new RegistryContainer(); |
|
233 | + $this->LIB = new RegistryContainer(); |
|
234 | + $this->addons = new RegistryContainer(); |
|
235 | + $this->modules = new RegistryContainer(); |
|
236 | + $this->shortcodes = new RegistryContainer(); |
|
237 | + $this->widgets = new RegistryContainer(); |
|
238 | + add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize')); |
|
239 | + } |
|
240 | + |
|
241 | + |
|
242 | + /** |
|
243 | + * initialize |
|
244 | + * |
|
245 | + * @throws OutOfBoundsException |
|
246 | + * @throws InvalidArgumentException |
|
247 | + * @throws InvalidInterfaceException |
|
248 | + * @throws InvalidDataTypeException |
|
249 | + * @throws EE_Error |
|
250 | + * @throws ReflectionException |
|
251 | + */ |
|
252 | + public function initialize() |
|
253 | + { |
|
254 | + $this->_class_abbreviations = apply_filters( |
|
255 | + 'FHEE__EE_Registry____construct___class_abbreviations', |
|
256 | + array( |
|
257 | + 'EE_Config' => 'CFG', |
|
258 | + 'EE_Session' => 'SSN', |
|
259 | + 'EE_Capabilities' => 'CAP', |
|
260 | + 'EE_Cart' => 'CART', |
|
261 | + 'EE_Network_Config' => 'NET_CFG', |
|
262 | + 'EE_Request_Handler' => 'REQ', |
|
263 | + 'EE_Message_Resource_Manager' => 'MRM', |
|
264 | + 'EventEspresso\core\services\commands\CommandBus' => 'BUS', |
|
265 | + 'EventEspresso\core\services\assets\Registry' => 'AssetsRegistry', |
|
266 | + ) |
|
267 | + ); |
|
268 | + $this->load_core('Base', array(), true); |
|
269 | + // add our request and response objects to the cache |
|
270 | + $request_loader = $this->_dependency_map->class_loader( |
|
271 | + 'EventEspresso\core\services\request\Request' |
|
272 | + ); |
|
273 | + $this->_set_cached_class( |
|
274 | + $request_loader(), |
|
275 | + 'EventEspresso\core\services\request\Request' |
|
276 | + ); |
|
277 | + $response_loader = $this->_dependency_map->class_loader( |
|
278 | + 'EventEspresso\core\services\request\Response' |
|
279 | + ); |
|
280 | + $this->_set_cached_class( |
|
281 | + $response_loader(), |
|
282 | + 'EventEspresso\core\services\request\Response' |
|
283 | + ); |
|
284 | + add_action('AHEE__EE_System__set_hooks_for_core', array($this, 'init')); |
|
285 | + } |
|
286 | + |
|
287 | + |
|
288 | + /** |
|
289 | + * @return void |
|
290 | + */ |
|
291 | + public function init() |
|
292 | + { |
|
293 | + // Get current page protocol |
|
294 | + $protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://'; |
|
295 | + // Output admin-ajax.php URL with same protocol as current page |
|
296 | + self::$i18n_js_strings['ajax_url'] = admin_url('admin-ajax.php', $protocol); |
|
297 | + self::$i18n_js_strings['wp_debug'] = defined('WP_DEBUG') ? WP_DEBUG : false; |
|
298 | + } |
|
299 | + |
|
300 | + |
|
301 | + /** |
|
302 | + * localize_i18n_js_strings |
|
303 | + * |
|
304 | + * @return string |
|
305 | + */ |
|
306 | + public static function localize_i18n_js_strings() |
|
307 | + { |
|
308 | + $i18n_js_strings = (array) self::$i18n_js_strings; |
|
309 | + foreach ($i18n_js_strings as $key => $value) { |
|
310 | + if (is_scalar($value)) { |
|
311 | + $i18n_js_strings[ $key ] = html_entity_decode((string) $value, ENT_QUOTES, 'UTF-8'); |
|
312 | + } |
|
313 | + } |
|
314 | + return '/* <![CDATA[ */ var eei18n = ' . wp_json_encode($i18n_js_strings) . '; /* ]]> */'; |
|
315 | + } |
|
316 | + |
|
317 | + |
|
318 | + /** |
|
319 | + * @param mixed string | EED_Module $module |
|
320 | + * @throws OutOfBoundsException |
|
321 | + * @throws InvalidArgumentException |
|
322 | + * @throws InvalidInterfaceException |
|
323 | + * @throws InvalidDataTypeException |
|
324 | + * @throws EE_Error |
|
325 | + * @throws ReflectionException |
|
326 | + */ |
|
327 | + public function add_module($module) |
|
328 | + { |
|
329 | + if ($module instanceof EED_Module) { |
|
330 | + $module_class = get_class($module); |
|
331 | + $this->modules->{$module_class} = $module; |
|
332 | + } else { |
|
333 | + if (! class_exists('EE_Module_Request_Router', false)) { |
|
334 | + $this->load_core('Module_Request_Router'); |
|
335 | + } |
|
336 | + EE_Module_Request_Router::module_factory($module); |
|
337 | + } |
|
338 | + } |
|
339 | + |
|
340 | + |
|
341 | + /** |
|
342 | + * @param string $module_name |
|
343 | + * @return mixed EED_Module | NULL |
|
344 | + */ |
|
345 | + public function get_module($module_name = '') |
|
346 | + { |
|
347 | + return isset($this->modules->{$module_name}) |
|
348 | + ? $this->modules->{$module_name} |
|
349 | + : null; |
|
350 | + } |
|
351 | + |
|
352 | + |
|
353 | + /** |
|
354 | + * loads core classes - must be singletons |
|
355 | + * |
|
356 | + * @param string $class_name - simple class name ie: session |
|
357 | + * @param mixed $arguments |
|
358 | + * @param bool $load_only |
|
359 | + * @return mixed |
|
360 | + * @throws InvalidInterfaceException |
|
361 | + * @throws InvalidDataTypeException |
|
362 | + * @throws EE_Error |
|
363 | + * @throws ReflectionException |
|
364 | + * @throws InvalidArgumentException |
|
365 | + */ |
|
366 | + public function load_core($class_name, $arguments = array(), $load_only = false) |
|
367 | + { |
|
368 | + $core_paths = apply_filters( |
|
369 | + 'FHEE__EE_Registry__load_core__core_paths', |
|
370 | + array( |
|
371 | + EE_CORE, |
|
372 | + EE_ADMIN, |
|
373 | + EE_CPTS, |
|
374 | + EE_CORE . 'data_migration_scripts' . DS, |
|
375 | + EE_CORE . 'capabilities' . DS, |
|
376 | + EE_CORE . 'request_stack' . DS, |
|
377 | + EE_CORE . 'middleware' . DS, |
|
378 | + ) |
|
379 | + ); |
|
380 | + // retrieve instantiated class |
|
381 | + return $this->_load( |
|
382 | + $core_paths, |
|
383 | + 'EE_', |
|
384 | + $class_name, |
|
385 | + 'core', |
|
386 | + $arguments, |
|
387 | + false, |
|
388 | + true, |
|
389 | + $load_only |
|
390 | + ); |
|
391 | + } |
|
392 | + |
|
393 | + |
|
394 | + /** |
|
395 | + * loads service classes |
|
396 | + * |
|
397 | + * @param string $class_name - simple class name ie: session |
|
398 | + * @param mixed $arguments |
|
399 | + * @param bool $load_only |
|
400 | + * @return mixed |
|
401 | + * @throws InvalidInterfaceException |
|
402 | + * @throws InvalidDataTypeException |
|
403 | + * @throws EE_Error |
|
404 | + * @throws ReflectionException |
|
405 | + * @throws InvalidArgumentException |
|
406 | + */ |
|
407 | + public function load_service($class_name, $arguments = array(), $load_only = false) |
|
408 | + { |
|
409 | + $service_paths = apply_filters( |
|
410 | + 'FHEE__EE_Registry__load_service__service_paths', |
|
411 | + array( |
|
412 | + EE_CORE . 'services' . DS, |
|
413 | + ) |
|
414 | + ); |
|
415 | + // retrieve instantiated class |
|
416 | + return $this->_load( |
|
417 | + $service_paths, |
|
418 | + 'EE_', |
|
419 | + $class_name, |
|
420 | + 'class', |
|
421 | + $arguments, |
|
422 | + false, |
|
423 | + true, |
|
424 | + $load_only |
|
425 | + ); |
|
426 | + } |
|
427 | + |
|
428 | + |
|
429 | + /** |
|
430 | + * loads data_migration_scripts |
|
431 | + * |
|
432 | + * @param string $class_name - class name for the DMS ie: EE_DMS_Core_4_2_0 |
|
433 | + * @param mixed $arguments |
|
434 | + * @return EE_Data_Migration_Script_Base|mixed |
|
435 | + * @throws InvalidInterfaceException |
|
436 | + * @throws InvalidDataTypeException |
|
437 | + * @throws EE_Error |
|
438 | + * @throws ReflectionException |
|
439 | + * @throws InvalidArgumentException |
|
440 | + */ |
|
441 | + public function load_dms($class_name, $arguments = array()) |
|
442 | + { |
|
443 | + // retrieve instantiated class |
|
444 | + return $this->_load( |
|
445 | + EE_Data_Migration_Manager::instance()->get_data_migration_script_folders(), |
|
446 | + 'EE_DMS_', |
|
447 | + $class_name, |
|
448 | + 'dms', |
|
449 | + $arguments, |
|
450 | + false, |
|
451 | + false |
|
452 | + ); |
|
453 | + } |
|
454 | + |
|
455 | + |
|
456 | + /** |
|
457 | + * loads object creating classes - must be singletons |
|
458 | + * |
|
459 | + * @param string $class_name - simple class name ie: attendee |
|
460 | + * @param mixed $arguments - an array of arguments to pass to the class |
|
461 | + * @param bool $from_db - some classes are instantiated from the db and thus call a different method to |
|
462 | + * instantiate |
|
463 | + * @param bool $cache if you don't want the class to be stored in the internal cache (non-persistent) then |
|
464 | + * set this to FALSE (ie. when instantiating model objects from client in a loop) |
|
465 | + * @param bool $load_only whether or not to just load the file and NOT instantiate, or load AND instantiate |
|
466 | + * (default) |
|
467 | + * @return EE_Base_Class | bool |
|
468 | + * @throws InvalidInterfaceException |
|
469 | + * @throws InvalidDataTypeException |
|
470 | + * @throws EE_Error |
|
471 | + * @throws ReflectionException |
|
472 | + * @throws InvalidArgumentException |
|
473 | + */ |
|
474 | + public function load_class($class_name, $arguments = array(), $from_db = false, $cache = true, $load_only = false) |
|
475 | + { |
|
476 | + $paths = apply_filters( |
|
477 | + 'FHEE__EE_Registry__load_class__paths', |
|
478 | + array( |
|
479 | + EE_CORE, |
|
480 | + EE_CLASSES, |
|
481 | + EE_BUSINESS, |
|
482 | + ) |
|
483 | + ); |
|
484 | + // retrieve instantiated class |
|
485 | + return $this->_load( |
|
486 | + $paths, |
|
487 | + 'EE_', |
|
488 | + $class_name, |
|
489 | + 'class', |
|
490 | + $arguments, |
|
491 | + $from_db, |
|
492 | + $cache, |
|
493 | + $load_only |
|
494 | + ); |
|
495 | + } |
|
496 | + |
|
497 | + |
|
498 | + /** |
|
499 | + * loads helper classes - must be singletons |
|
500 | + * |
|
501 | + * @param string $class_name - simple class name ie: price |
|
502 | + * @param mixed $arguments |
|
503 | + * @param bool $load_only |
|
504 | + * @return EEH_Base | bool |
|
505 | + * @throws InvalidInterfaceException |
|
506 | + * @throws InvalidDataTypeException |
|
507 | + * @throws EE_Error |
|
508 | + * @throws ReflectionException |
|
509 | + * @throws InvalidArgumentException |
|
510 | + */ |
|
511 | + public function load_helper($class_name, $arguments = array(), $load_only = true) |
|
512 | + { |
|
513 | + // todo: add doing_it_wrong() in a few versions after all addons have had calls to this method removed |
|
514 | + $helper_paths = apply_filters('FHEE__EE_Registry__load_helper__helper_paths', array(EE_HELPERS)); |
|
515 | + // retrieve instantiated class |
|
516 | + return $this->_load( |
|
517 | + $helper_paths, |
|
518 | + 'EEH_', |
|
519 | + $class_name, |
|
520 | + 'helper', |
|
521 | + $arguments, |
|
522 | + false, |
|
523 | + true, |
|
524 | + $load_only |
|
525 | + ); |
|
526 | + } |
|
527 | + |
|
528 | + |
|
529 | + /** |
|
530 | + * loads core classes - must be singletons |
|
531 | + * |
|
532 | + * @param string $class_name - simple class name ie: session |
|
533 | + * @param mixed $arguments |
|
534 | + * @param bool $load_only |
|
535 | + * @param bool $cache whether to cache the object or not. |
|
536 | + * @return mixed |
|
537 | + * @throws InvalidInterfaceException |
|
538 | + * @throws InvalidDataTypeException |
|
539 | + * @throws EE_Error |
|
540 | + * @throws ReflectionException |
|
541 | + * @throws InvalidArgumentException |
|
542 | + */ |
|
543 | + public function load_lib($class_name, $arguments = array(), $load_only = false, $cache = true) |
|
544 | + { |
|
545 | + $paths = array( |
|
546 | + EE_LIBRARIES, |
|
547 | + EE_LIBRARIES . 'messages' . DS, |
|
548 | + EE_LIBRARIES . 'shortcodes' . DS, |
|
549 | + EE_LIBRARIES . 'qtips' . DS, |
|
550 | + EE_LIBRARIES . 'payment_methods' . DS, |
|
551 | + ); |
|
552 | + // retrieve instantiated class |
|
553 | + return $this->_load( |
|
554 | + $paths, |
|
555 | + 'EE_', |
|
556 | + $class_name, |
|
557 | + 'lib', |
|
558 | + $arguments, |
|
559 | + false, |
|
560 | + $cache, |
|
561 | + $load_only |
|
562 | + ); |
|
563 | + } |
|
564 | + |
|
565 | + |
|
566 | + /** |
|
567 | + * loads model classes - must be singletons |
|
568 | + * |
|
569 | + * @param string $class_name - simple class name ie: price |
|
570 | + * @param mixed $arguments |
|
571 | + * @param bool $load_only |
|
572 | + * @return EEM_Base | bool |
|
573 | + * @throws InvalidInterfaceException |
|
574 | + * @throws InvalidDataTypeException |
|
575 | + * @throws EE_Error |
|
576 | + * @throws ReflectionException |
|
577 | + * @throws InvalidArgumentException |
|
578 | + */ |
|
579 | + public function load_model($class_name, $arguments = array(), $load_only = false) |
|
580 | + { |
|
581 | + $paths = apply_filters( |
|
582 | + 'FHEE__EE_Registry__load_model__paths', |
|
583 | + array( |
|
584 | + EE_MODELS, |
|
585 | + EE_CORE, |
|
586 | + ) |
|
587 | + ); |
|
588 | + // retrieve instantiated class |
|
589 | + return $this->_load( |
|
590 | + $paths, |
|
591 | + 'EEM_', |
|
592 | + $class_name, |
|
593 | + 'model', |
|
594 | + $arguments, |
|
595 | + false, |
|
596 | + true, |
|
597 | + $load_only |
|
598 | + ); |
|
599 | + } |
|
600 | + |
|
601 | + |
|
602 | + /** |
|
603 | + * loads model classes - must be singletons |
|
604 | + * |
|
605 | + * @param string $class_name - simple class name ie: price |
|
606 | + * @param mixed $arguments |
|
607 | + * @param bool $load_only |
|
608 | + * @return mixed | bool |
|
609 | + * @throws InvalidInterfaceException |
|
610 | + * @throws InvalidDataTypeException |
|
611 | + * @throws EE_Error |
|
612 | + * @throws ReflectionException |
|
613 | + * @throws InvalidArgumentException |
|
614 | + */ |
|
615 | + public function load_model_class($class_name, $arguments = array(), $load_only = true) |
|
616 | + { |
|
617 | + $paths = array( |
|
618 | + EE_MODELS . 'fields' . DS, |
|
619 | + EE_MODELS . 'helpers' . DS, |
|
620 | + EE_MODELS . 'relations' . DS, |
|
621 | + EE_MODELS . 'strategies' . DS, |
|
622 | + ); |
|
623 | + // retrieve instantiated class |
|
624 | + return $this->_load( |
|
625 | + $paths, |
|
626 | + 'EE_', |
|
627 | + $class_name, |
|
628 | + '', |
|
629 | + $arguments, |
|
630 | + false, |
|
631 | + true, |
|
632 | + $load_only |
|
633 | + ); |
|
634 | + } |
|
635 | + |
|
636 | + |
|
637 | + /** |
|
638 | + * Determines if $model_name is the name of an actual EE model. |
|
639 | + * |
|
640 | + * @param string $model_name like Event, Attendee, Question_Group_Question, etc. |
|
641 | + * @return boolean |
|
642 | + */ |
|
643 | + public function is_model_name($model_name) |
|
644 | + { |
|
645 | + return isset($this->models[ $model_name ]); |
|
646 | + } |
|
647 | + |
|
648 | + |
|
649 | + /** |
|
650 | + * generic class loader |
|
651 | + * |
|
652 | + * @param string $path_to_file - directory path to file location, not including filename |
|
653 | + * @param string $file_name - file name ie: my_file.php, including extension |
|
654 | + * @param string $type - file type - core? class? helper? model? |
|
655 | + * @param mixed $arguments |
|
656 | + * @param bool $load_only |
|
657 | + * @return mixed |
|
658 | + * @throws InvalidInterfaceException |
|
659 | + * @throws InvalidDataTypeException |
|
660 | + * @throws EE_Error |
|
661 | + * @throws ReflectionException |
|
662 | + * @throws InvalidArgumentException |
|
663 | + */ |
|
664 | + public function load_file($path_to_file, $file_name, $type = '', $arguments = array(), $load_only = true) |
|
665 | + { |
|
666 | + // retrieve instantiated class |
|
667 | + return $this->_load( |
|
668 | + $path_to_file, |
|
669 | + '', |
|
670 | + $file_name, |
|
671 | + $type, |
|
672 | + $arguments, |
|
673 | + false, |
|
674 | + true, |
|
675 | + $load_only |
|
676 | + ); |
|
677 | + } |
|
678 | + |
|
679 | + |
|
680 | + /** |
|
681 | + * @param string $path_to_file - directory path to file location, not including filename |
|
682 | + * @param string $class_name - full class name ie: My_Class |
|
683 | + * @param string $type - file type - core? class? helper? model? |
|
684 | + * @param mixed $arguments |
|
685 | + * @param bool $load_only |
|
686 | + * @return bool|EE_Addon|object |
|
687 | + * @throws InvalidInterfaceException |
|
688 | + * @throws InvalidDataTypeException |
|
689 | + * @throws EE_Error |
|
690 | + * @throws ReflectionException |
|
691 | + * @throws InvalidArgumentException |
|
692 | + */ |
|
693 | + public function load_addon($path_to_file, $class_name, $type = 'class', $arguments = array(), $load_only = false) |
|
694 | + { |
|
695 | + // retrieve instantiated class |
|
696 | + return $this->_load( |
|
697 | + $path_to_file, |
|
698 | + 'addon', |
|
699 | + $class_name, |
|
700 | + $type, |
|
701 | + $arguments, |
|
702 | + false, |
|
703 | + true, |
|
704 | + $load_only |
|
705 | + ); |
|
706 | + } |
|
707 | + |
|
708 | + |
|
709 | + /** |
|
710 | + * instantiates, caches, and automatically resolves dependencies |
|
711 | + * for classes that use a Fully Qualified Class Name. |
|
712 | + * if the class is not capable of being loaded using PSR-4 autoloading, |
|
713 | + * then you need to use one of the existing load_*() methods |
|
714 | + * which can resolve the classname and filepath from the passed arguments |
|
715 | + * |
|
716 | + * @param bool|string $class_name Fully Qualified Class Name |
|
717 | + * @param array $arguments an argument, or array of arguments to pass to the class upon instantiation |
|
718 | + * @param bool $cache whether to cache the instantiated object for reuse |
|
719 | + * @param bool $from_db some classes are instantiated from the db |
|
720 | + * and thus call a different method to instantiate |
|
721 | + * @param bool $load_only if true, will only load the file, but will NOT instantiate an object |
|
722 | + * @param bool|string $addon if true, will cache the object in the EE_Registry->$addons array |
|
723 | + * @return bool|null|mixed null = failure to load or instantiate class object. |
|
724 | + * object = class loaded and instantiated successfully. |
|
725 | + * bool = fail or success when $load_only is true |
|
726 | + * @throws InvalidInterfaceException |
|
727 | + * @throws InvalidDataTypeException |
|
728 | + * @throws EE_Error |
|
729 | + * @throws ReflectionException |
|
730 | + * @throws InvalidArgumentException |
|
731 | + */ |
|
732 | + public function create( |
|
733 | + $class_name = false, |
|
734 | + $arguments = array(), |
|
735 | + $cache = false, |
|
736 | + $from_db = false, |
|
737 | + $load_only = false, |
|
738 | + $addon = false |
|
739 | + ) { |
|
740 | + $class_name = ltrim($class_name, '\\'); |
|
741 | + $class_name = $this->class_cache->getFqnForAlias($class_name); |
|
742 | + $class_exists = $this->loadOrVerifyClassExists($class_name, $arguments); |
|
743 | + // if a non-FQCN was passed, then |
|
744 | + // verifyClassExists() might return an object |
|
745 | + // or it could return null if the class just could not be found anywhere |
|
746 | + if ($class_exists instanceof $class_name || $class_exists === null) { |
|
747 | + // either way, return the results |
|
748 | + return $class_exists; |
|
749 | + } |
|
750 | + $class_name = $class_exists; |
|
751 | + // if we're only loading the class and it already exists, then let's just return true immediately |
|
752 | + if ($load_only) { |
|
753 | + return true; |
|
754 | + } |
|
755 | + $addon = $addon ? 'addon' : ''; |
|
756 | + // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection |
|
757 | + // $cache is controlled by individual calls to separate Registry loader methods like load_class() |
|
758 | + // $load_only is also controlled by individual calls to separate Registry loader methods like load_file() |
|
759 | + if ($this->_cache_on && $cache && ! $load_only) { |
|
760 | + // return object if it's already cached |
|
761 | + $cached_class = $this->_get_cached_class($class_name, $addon, $arguments); |
|
762 | + if ($cached_class !== null) { |
|
763 | + return $cached_class; |
|
764 | + } |
|
765 | + }// obtain the loader method from the dependency map |
|
766 | + $loader = $this->_dependency_map->class_loader($class_name);// instantiate the requested object |
|
767 | + if ($loader instanceof Closure) { |
|
768 | + $class_obj = $loader($arguments); |
|
769 | + } else { |
|
770 | + if ($loader && method_exists($this, $loader)) { |
|
771 | + $class_obj = $this->{$loader}($class_name, $arguments); |
|
772 | + } else { |
|
773 | + $class_obj = $this->_create_object($class_name, $arguments, $addon, $from_db); |
|
774 | + } |
|
775 | + } |
|
776 | + if (($this->_cache_on && $cache) || $this->get_class_abbreviation($class_name, '')) { |
|
777 | + // save it for later... kinda like gum { : $ |
|
778 | + $this->_set_cached_class( |
|
779 | + $class_obj, |
|
780 | + $class_name, |
|
781 | + $addon, |
|
782 | + $from_db, |
|
783 | + $arguments |
|
784 | + ); |
|
785 | + } |
|
786 | + $this->_cache_on = true; |
|
787 | + return $class_obj; |
|
788 | + } |
|
789 | + |
|
790 | + |
|
791 | + /** |
|
792 | + * Recursively checks that a class exists and potentially attempts to load classes with non-FQCNs |
|
793 | + * |
|
794 | + * @param string|object $class_name |
|
795 | + * @param array $arguments |
|
796 | + * @param int $attempt |
|
797 | + * @return mixed |
|
798 | + */ |
|
799 | + private function loadOrVerifyClassExists($class_name, array $arguments, $attempt = 1) |
|
800 | + { |
|
801 | + if (is_object($class_name) || class_exists($class_name)) { |
|
802 | + return $class_name; |
|
803 | + } |
|
804 | + switch ($attempt) { |
|
805 | + case 1: |
|
806 | + // if it's a FQCN then maybe the class is registered with a preceding \ |
|
807 | + $class_name = strpos($class_name, '\\') !== false |
|
808 | + ? '\\' . ltrim($class_name, '\\') |
|
809 | + : $class_name; |
|
810 | + break; |
|
811 | + case 2: |
|
812 | + // |
|
813 | + $loader = $this->_dependency_map->class_loader($class_name); |
|
814 | + if ($loader && method_exists($this, $loader)) { |
|
815 | + return $this->{$loader}($class_name, $arguments); |
|
816 | + } |
|
817 | + break; |
|
818 | + case 3: |
|
819 | + default: |
|
820 | + return null; |
|
821 | + } |
|
822 | + $attempt++; |
|
823 | + return $this->loadOrVerifyClassExists($class_name, $arguments, $attempt); |
|
824 | + } |
|
825 | + |
|
826 | + |
|
827 | + /** |
|
828 | + * instantiates, caches, and injects dependencies for classes |
|
829 | + * |
|
830 | + * @param array $file_paths an array of paths to folders to look in |
|
831 | + * @param string $class_prefix EE or EEM or... ??? |
|
832 | + * @param bool|string $class_name $class name |
|
833 | + * @param string $type file type - core? class? helper? model? |
|
834 | + * @param mixed $arguments an argument or array of arguments to pass to the class upon instantiation |
|
835 | + * @param bool $from_db some classes are instantiated from the db |
|
836 | + * and thus call a different method to instantiate |
|
837 | + * @param bool $cache whether to cache the instantiated object for reuse |
|
838 | + * @param bool $load_only if true, will only load the file, but will NOT instantiate an object |
|
839 | + * @return bool|null|object null = failure to load or instantiate class object. |
|
840 | + * object = class loaded and instantiated successfully. |
|
841 | + * bool = fail or success when $load_only is true |
|
842 | + * @throws EE_Error |
|
843 | + * @throws ReflectionException |
|
844 | + * @throws InvalidInterfaceException |
|
845 | + * @throws InvalidDataTypeException |
|
846 | + * @throws InvalidArgumentException |
|
847 | + */ |
|
848 | + protected function _load( |
|
849 | + $file_paths = array(), |
|
850 | + $class_prefix = 'EE_', |
|
851 | + $class_name = false, |
|
852 | + $type = 'class', |
|
853 | + $arguments = array(), |
|
854 | + $from_db = false, |
|
855 | + $cache = true, |
|
856 | + $load_only = false |
|
857 | + ) { |
|
858 | + $class_name = ltrim($class_name, '\\'); |
|
859 | + // strip php file extension |
|
860 | + $class_name = str_replace('.php', '', trim($class_name)); |
|
861 | + // does the class have a prefix ? |
|
862 | + if (! empty($class_prefix) && $class_prefix !== 'addon') { |
|
863 | + // make sure $class_prefix is uppercase |
|
864 | + $class_prefix = strtoupper(trim($class_prefix)); |
|
865 | + // add class prefix ONCE!!! |
|
866 | + $class_name = $class_prefix . str_replace($class_prefix, '', $class_name); |
|
867 | + } |
|
868 | + $class_name = $this->class_cache->getFqnForAlias($class_name); |
|
869 | + $class_exists = class_exists($class_name, false); |
|
870 | + // if we're only loading the class and it already exists, then let's just return true immediately |
|
871 | + if ($load_only && $class_exists) { |
|
872 | + return true; |
|
873 | + } |
|
874 | + $arguments = is_array($arguments) ? $arguments : array($arguments); |
|
875 | + // $this->_cache_on is toggled during the recursive loading that can occur with dependency injection |
|
876 | + // $cache is controlled by individual calls to separate Registry loader methods like load_class() |
|
877 | + // $load_only is also controlled by individual calls to separate Registry loader methods like load_file() |
|
878 | + if ($this->_cache_on && $cache && ! $load_only) { |
|
879 | + // return object if it's already cached |
|
880 | + $cached_class = $this->_get_cached_class($class_name, $class_prefix, $arguments); |
|
881 | + if ($cached_class !== null) { |
|
882 | + return $cached_class; |
|
883 | + } |
|
884 | + } |
|
885 | + // if the class doesn't already exist.. then we need to try and find the file and load it |
|
886 | + if (! $class_exists) { |
|
887 | + // get full path to file |
|
888 | + $path = $this->_resolve_path($class_name, $type, $file_paths); |
|
889 | + // load the file |
|
890 | + $loaded = $this->_require_file($path, $class_name, $type, $file_paths); |
|
891 | + // if we are only loading a file but NOT instantiating an object |
|
892 | + // then return boolean for whether class was loaded or not |
|
893 | + if ($load_only) { |
|
894 | + return $loaded; |
|
895 | + } |
|
896 | + // if an object was expected but loading failed, then return nothing |
|
897 | + if (! $loaded) { |
|
898 | + return null; |
|
899 | + } |
|
900 | + } |
|
901 | + // instantiate the requested object |
|
902 | + $class_obj = $this->_create_object($class_name, $arguments, $type, $from_db); |
|
903 | + if ($this->_cache_on && $cache) { |
|
904 | + // save it for later... kinda like gum { : $ |
|
905 | + $this->_set_cached_class( |
|
906 | + $class_obj, |
|
907 | + $class_name, |
|
908 | + $class_prefix, |
|
909 | + $from_db, |
|
910 | + $arguments |
|
911 | + ); |
|
912 | + } |
|
913 | + $this->_cache_on = true; |
|
914 | + return $class_obj; |
|
915 | + } |
|
916 | + |
|
917 | + |
|
918 | + /** |
|
919 | + * @param string $class_name |
|
920 | + * @param string $default have to specify something, but not anything that will conflict |
|
921 | + * @return mixed|string |
|
922 | + */ |
|
923 | + protected function get_class_abbreviation($class_name, $default = 'FANCY_BATMAN_PANTS') |
|
924 | + { |
|
925 | + return isset($this->_class_abbreviations[ $class_name ]) |
|
926 | + ? $this->_class_abbreviations[ $class_name ] |
|
927 | + : $default; |
|
928 | + } |
|
929 | + |
|
930 | + |
|
931 | + /** |
|
932 | + * attempts to find a cached version of the requested class |
|
933 | + * by looking in the following places: |
|
934 | + * $this->{$class_abbreviation} ie: $this->CART |
|
935 | + * $this->{$class_name} ie: $this->Some_Class |
|
936 | + * $this->LIB->{$class_name} ie: $this->LIB->Some_Class |
|
937 | + * $this->addon->{$class_name} ie: $this->addon->Some_Addon_Class |
|
938 | + * |
|
939 | + * @param string $class_name |
|
940 | + * @param string $class_prefix |
|
941 | + * @param array $arguments |
|
942 | + * @return mixed |
|
943 | + */ |
|
944 | + protected function _get_cached_class( |
|
945 | + $class_name, |
|
946 | + $class_prefix = '', |
|
947 | + $arguments = array() |
|
948 | + ) { |
|
949 | + if ($class_name === 'EE_Registry') { |
|
950 | + return $this; |
|
951 | + } |
|
952 | + $class_abbreviation = $this->get_class_abbreviation($class_name); |
|
953 | + // check if class has already been loaded, and return it if it has been |
|
954 | + if (isset($this->{$class_abbreviation})) { |
|
955 | + return $this->{$class_abbreviation}; |
|
956 | + } |
|
957 | + $class_name = str_replace('\\', '_', $class_name); |
|
958 | + if (isset($this->{$class_name})) { |
|
959 | + return $this->{$class_name}; |
|
960 | + } |
|
961 | + if ($class_prefix === 'addon' && isset($this->addons->{$class_name})) { |
|
962 | + return $this->addons->{$class_name}; |
|
963 | + } |
|
964 | + $object_identifier = $this->object_identifier->getIdentifier($class_name, $arguments); |
|
965 | + if (isset($this->LIB->{$object_identifier})) { |
|
966 | + return $this->LIB->{$object_identifier}; |
|
967 | + } |
|
968 | + foreach ($this->LIB as $key => $object) { |
|
969 | + if (// request does not contain new arguments and therefore no args identifier |
|
970 | + ! $this->object_identifier->hasArguments($object_identifier) |
|
971 | + // but previously cached class with args was found |
|
972 | + && $this->object_identifier->fqcnMatchesObjectIdentifier($class_name, $key) |
|
973 | + ) { |
|
974 | + return $object; |
|
975 | + } |
|
976 | + } |
|
977 | + return null; |
|
978 | + } |
|
979 | + |
|
980 | + |
|
981 | + /** |
|
982 | + * removes a cached version of the requested class |
|
983 | + * |
|
984 | + * @param string $class_name |
|
985 | + * @param boolean $addon |
|
986 | + * @param array $arguments |
|
987 | + * @return boolean |
|
988 | + */ |
|
989 | + public function clear_cached_class( |
|
990 | + $class_name, |
|
991 | + $addon = false, |
|
992 | + $arguments = array() |
|
993 | + ) { |
|
994 | + $class_abbreviation = $this->get_class_abbreviation($class_name); |
|
995 | + // check if class has already been loaded, and return it if it has been |
|
996 | + if (isset($this->{$class_abbreviation})) { |
|
997 | + $this->{$class_abbreviation} = null; |
|
998 | + return true; |
|
999 | + } |
|
1000 | + $class_name = str_replace('\\', '_', $class_name); |
|
1001 | + if (isset($this->{$class_name})) { |
|
1002 | + $this->{$class_name} = null; |
|
1003 | + return true; |
|
1004 | + } |
|
1005 | + if ($addon && isset($this->addons->{$class_name})) { |
|
1006 | + unset($this->addons->{$class_name}); |
|
1007 | + return true; |
|
1008 | + } |
|
1009 | + $class_name = $this->object_identifier->getIdentifier($class_name, $arguments); |
|
1010 | + if (isset($this->LIB->{$class_name})) { |
|
1011 | + unset($this->LIB->{$class_name}); |
|
1012 | + return true; |
|
1013 | + } |
|
1014 | + return false; |
|
1015 | + } |
|
1016 | + |
|
1017 | + |
|
1018 | + /** |
|
1019 | + * _set_cached_class |
|
1020 | + * attempts to cache the instantiated class locally |
|
1021 | + * in one of the following places, in the following order: |
|
1022 | + * $this->{class_abbreviation} ie: $this->CART |
|
1023 | + * $this->{$class_name} ie: $this->Some_Class |
|
1024 | + * $this->addon->{$$class_name} ie: $this->addon->Some_Addon_Class |
|
1025 | + * $this->LIB->{$class_name} ie: $this->LIB->Some_Class |
|
1026 | + * |
|
1027 | + * @param object $class_obj |
|
1028 | + * @param string $class_name |
|
1029 | + * @param string $class_prefix |
|
1030 | + * @param bool $from_db |
|
1031 | + * @param array $arguments |
|
1032 | + * @return void |
|
1033 | + */ |
|
1034 | + protected function _set_cached_class( |
|
1035 | + $class_obj, |
|
1036 | + $class_name, |
|
1037 | + $class_prefix = '', |
|
1038 | + $from_db = false, |
|
1039 | + $arguments = array() |
|
1040 | + ) { |
|
1041 | + if ($class_name === 'EE_Registry' || empty($class_obj)) { |
|
1042 | + return; |
|
1043 | + } |
|
1044 | + // return newly instantiated class |
|
1045 | + $class_abbreviation = $this->get_class_abbreviation($class_name, ''); |
|
1046 | + if ($class_abbreviation) { |
|
1047 | + $this->{$class_abbreviation} = $class_obj; |
|
1048 | + return; |
|
1049 | + } |
|
1050 | + $class_name = str_replace('\\', '_', $class_name); |
|
1051 | + if (property_exists($this, $class_name)) { |
|
1052 | + $this->{$class_name} = $class_obj; |
|
1053 | + return; |
|
1054 | + } |
|
1055 | + if ($class_prefix === 'addon') { |
|
1056 | + $this->addons->{$class_name} = $class_obj; |
|
1057 | + return; |
|
1058 | + } |
|
1059 | + if (! $from_db) { |
|
1060 | + $class_name = $this->object_identifier->getIdentifier($class_name, $arguments); |
|
1061 | + $this->LIB->{$class_name} = $class_obj; |
|
1062 | + } |
|
1063 | + } |
|
1064 | + |
|
1065 | + |
|
1066 | + /** |
|
1067 | + * attempts to find a full valid filepath for the requested class. |
|
1068 | + * loops thru each of the base paths in the $file_paths array and appends : "{classname} . {file type} . php" |
|
1069 | + * then returns that path if the target file has been found and is readable |
|
1070 | + * |
|
1071 | + * @param string $class_name |
|
1072 | + * @param string $type |
|
1073 | + * @param array $file_paths |
|
1074 | + * @return string | bool |
|
1075 | + */ |
|
1076 | + protected function _resolve_path($class_name, $type = '', $file_paths = array()) |
|
1077 | + { |
|
1078 | + // make sure $file_paths is an array |
|
1079 | + $file_paths = is_array($file_paths) |
|
1080 | + ? $file_paths |
|
1081 | + : array($file_paths); |
|
1082 | + // cycle thru paths |
|
1083 | + foreach ($file_paths as $key => $file_path) { |
|
1084 | + // convert all separators to proper DS, if no filepath, then use EE_CLASSES |
|
1085 | + $file_path = $file_path |
|
1086 | + ? str_replace(array('/', '\\'), DS, $file_path) |
|
1087 | + : EE_CLASSES; |
|
1088 | + // prep file type |
|
1089 | + $type = ! empty($type) |
|
1090 | + ? trim($type, '.') . '.' |
|
1091 | + : ''; |
|
1092 | + // build full file path |
|
1093 | + $file_paths[ $key ] = rtrim($file_path, DS) . DS . $class_name . '.' . $type . 'php'; |
|
1094 | + // does the file exist and can be read ? |
|
1095 | + if (is_readable($file_paths[ $key ])) { |
|
1096 | + return $file_paths[ $key ]; |
|
1097 | + } |
|
1098 | + } |
|
1099 | + return false; |
|
1100 | + } |
|
1101 | + |
|
1102 | + |
|
1103 | + /** |
|
1104 | + * basically just performs a require_once() |
|
1105 | + * but with some error handling |
|
1106 | + * |
|
1107 | + * @param string $path |
|
1108 | + * @param string $class_name |
|
1109 | + * @param string $type |
|
1110 | + * @param array $file_paths |
|
1111 | + * @return bool |
|
1112 | + * @throws EE_Error |
|
1113 | + * @throws ReflectionException |
|
1114 | + */ |
|
1115 | + protected function _require_file($path, $class_name, $type = '', $file_paths = array()) |
|
1116 | + { |
|
1117 | + $this->resolve_legacy_class_parent($class_name); |
|
1118 | + // don't give up! you gotta... |
|
1119 | + try { |
|
1120 | + // does the file exist and can it be read ? |
|
1121 | + if (! $path) { |
|
1122 | + // just in case the file has already been autoloaded, |
|
1123 | + // but discrepancies in the naming schema are preventing it from |
|
1124 | + // being loaded via one of the EE_Registry::load_*() methods, |
|
1125 | + // then let's try one last hail mary before throwing an exception |
|
1126 | + // and call class_exists() again, but with autoloading turned ON |
|
1127 | + if (class_exists($class_name)) { |
|
1128 | + return true; |
|
1129 | + } |
|
1130 | + // so sorry, can't find the file |
|
1131 | + throw new EE_Error( |
|
1132 | + sprintf( |
|
1133 | + esc_html__( |
|
1134 | + 'The %1$s file %2$s could not be located or is not readable due to file permissions. Please ensure that the following filepath(s) are correct: %3$s', |
|
1135 | + 'event_espresso' |
|
1136 | + ), |
|
1137 | + trim($type, '.'), |
|
1138 | + $class_name, |
|
1139 | + '<br />' . implode(',<br />', $file_paths) |
|
1140 | + ) |
|
1141 | + ); |
|
1142 | + } |
|
1143 | + // get the file |
|
1144 | + require_once($path); |
|
1145 | + // if the class isn't already declared somewhere |
|
1146 | + if (class_exists($class_name, false) === false) { |
|
1147 | + // so sorry, not a class |
|
1148 | + throw new EE_Error( |
|
1149 | + sprintf( |
|
1150 | + esc_html__( |
|
1151 | + 'The %s file %s does not appear to contain the %s Class.', |
|
1152 | + 'event_espresso' |
|
1153 | + ), |
|
1154 | + $type, |
|
1155 | + $path, |
|
1156 | + $class_name |
|
1157 | + ) |
|
1158 | + ); |
|
1159 | + } |
|
1160 | + } catch (EE_Error $e) { |
|
1161 | + $e->get_error(); |
|
1162 | + return false; |
|
1163 | + } |
|
1164 | + return true; |
|
1165 | + } |
|
1166 | + |
|
1167 | + |
|
1168 | + /** |
|
1169 | + * Some of our legacy classes that extended a parent class would simply use a require() statement |
|
1170 | + * before their class declaration in order to ensure that the parent class was loaded. |
|
1171 | + * This is not ideal, but it's nearly impossible to determine the parent class of a non-namespaced class, |
|
1172 | + * without triggering a fatal error because the parent class has yet to be loaded and therefore doesn't exist. |
|
1173 | + * |
|
1174 | + * @param string $class_name |
|
1175 | + */ |
|
1176 | + protected function resolve_legacy_class_parent($class_name = '') |
|
1177 | + { |
|
1178 | + try { |
|
1179 | + $legacy_parent_class_map = array( |
|
1180 | + 'EE_Payment_Processor' => 'core/business/EE_Processor_Base.class.php', |
|
1181 | + ); |
|
1182 | + if (isset($legacy_parent_class_map[ $class_name ])) { |
|
1183 | + require_once EE_PLUGIN_DIR_PATH . $legacy_parent_class_map[ $class_name ]; |
|
1184 | + } |
|
1185 | + } catch (Exception $exception) { |
|
1186 | + } |
|
1187 | + } |
|
1188 | + |
|
1189 | + |
|
1190 | + /** |
|
1191 | + * _create_object |
|
1192 | + * Attempts to instantiate the requested class via any of the |
|
1193 | + * commonly used instantiation methods employed throughout EE. |
|
1194 | + * The priority for instantiation is as follows: |
|
1195 | + * - abstract classes or any class flagged as "load only" (no instantiation occurs) |
|
1196 | + * - model objects via their 'new_instance_from_db' method |
|
1197 | + * - model objects via their 'new_instance' method |
|
1198 | + * - "singleton" classes" via their 'instance' method |
|
1199 | + * - standard instantiable classes via their __constructor |
|
1200 | + * Prior to instantiation, if the classname exists in the dependency_map, |
|
1201 | + * then the constructor for the requested class will be examined to determine |
|
1202 | + * if any dependencies exist, and if they can be injected. |
|
1203 | + * If so, then those classes will be added to the array of arguments passed to the constructor |
|
1204 | + * |
|
1205 | + * @param string $class_name |
|
1206 | + * @param array $arguments |
|
1207 | + * @param string $type |
|
1208 | + * @param bool $from_db |
|
1209 | + * @return null|object|bool |
|
1210 | + * @throws InvalidArgumentException |
|
1211 | + * @throws InvalidInterfaceException |
|
1212 | + * @throws EE_Error |
|
1213 | + * @throws ReflectionException |
|
1214 | + * @throws InvalidDataTypeException |
|
1215 | + */ |
|
1216 | + protected function _create_object($class_name, $arguments = array(), $type = '', $from_db = false) |
|
1217 | + { |
|
1218 | + // create reflection |
|
1219 | + $reflector = $this->mirror->getReflectionClass($class_name); |
|
1220 | + // make sure arguments are an array |
|
1221 | + $arguments = is_array($arguments) |
|
1222 | + ? $arguments |
|
1223 | + : array($arguments); |
|
1224 | + // and if arguments array is numerically and sequentially indexed, then we want it to remain as is, |
|
1225 | + // else wrap it in an additional array so that it doesn't get split into multiple parameters |
|
1226 | + $arguments = $this->_array_is_numerically_and_sequentially_indexed($arguments) |
|
1227 | + ? $arguments |
|
1228 | + : array($arguments); |
|
1229 | + // attempt to inject dependencies ? |
|
1230 | + if ($this->_dependency_map->has($class_name)) { |
|
1231 | + $arguments = $this->_resolve_dependencies($reflector, $class_name, $arguments); |
|
1232 | + } |
|
1233 | + // instantiate the class if possible |
|
1234 | + if ($reflector->isAbstract()) { |
|
1235 | + // nothing to instantiate, loading file was enough |
|
1236 | + // does not throw an exception so $instantiation_mode is unused |
|
1237 | + // $instantiation_mode = "1) no constructor abstract class"; |
|
1238 | + return true; |
|
1239 | + } |
|
1240 | + if (empty($arguments) |
|
1241 | + && $this->mirror->getConstructorFromReflection($reflector) === null |
|
1242 | + && $reflector->isInstantiable() |
|
1243 | + ) { |
|
1244 | + // no constructor = static methods only... nothing to instantiate, loading file was enough |
|
1245 | + // $instantiation_mode = "2) no constructor but instantiable"; |
|
1246 | + return $reflector->newInstance(); |
|
1247 | + } |
|
1248 | + if ($from_db && method_exists($class_name, 'new_instance_from_db')) { |
|
1249 | + // $instantiation_mode = "3) new_instance_from_db()"; |
|
1250 | + return call_user_func_array(array($class_name, 'new_instance_from_db'), $arguments); |
|
1251 | + } |
|
1252 | + if (method_exists($class_name, 'new_instance')) { |
|
1253 | + // $instantiation_mode = "4) new_instance()"; |
|
1254 | + return call_user_func_array(array($class_name, 'new_instance'), $arguments); |
|
1255 | + } |
|
1256 | + if (method_exists($class_name, 'instance')) { |
|
1257 | + // $instantiation_mode = "5) instance()"; |
|
1258 | + return call_user_func_array(array($class_name, 'instance'), $arguments); |
|
1259 | + } |
|
1260 | + if ($reflector->isInstantiable()) { |
|
1261 | + // $instantiation_mode = "6) constructor"; |
|
1262 | + return $reflector->newInstanceArgs($arguments); |
|
1263 | + } |
|
1264 | + // heh ? something's not right ! |
|
1265 | + throw new EE_Error( |
|
1266 | + sprintf( |
|
1267 | + __('The %s file %s could not be instantiated.', 'event_espresso'), |
|
1268 | + $type, |
|
1269 | + $class_name |
|
1270 | + ) |
|
1271 | + ); |
|
1272 | + } |
|
1273 | + |
|
1274 | + |
|
1275 | + /** |
|
1276 | + * @see http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential |
|
1277 | + * @param array $array |
|
1278 | + * @return bool |
|
1279 | + */ |
|
1280 | + protected function _array_is_numerically_and_sequentially_indexed(array $array) |
|
1281 | + { |
|
1282 | + return ! empty($array) |
|
1283 | + ? array_keys($array) === range(0, count($array) - 1) |
|
1284 | + : true; |
|
1285 | + } |
|
1286 | + |
|
1287 | + |
|
1288 | + /** |
|
1289 | + * _resolve_dependencies |
|
1290 | + * examines the constructor for the requested class to determine |
|
1291 | + * if any dependencies exist, and if they can be injected. |
|
1292 | + * If so, then those classes will be added to the array of arguments passed to the constructor |
|
1293 | + * PLZ NOTE: this is achieved by type hinting the constructor params |
|
1294 | + * For example: |
|
1295 | + * if attempting to load a class "Foo" with the following constructor: |
|
1296 | + * __construct( Bar $bar_class, Fighter $grohl_class ) |
|
1297 | + * then $bar_class and $grohl_class will be added to the $arguments array, |
|
1298 | + * but only IF they are NOT already present in the incoming arguments array, |
|
1299 | + * and the correct classes can be loaded |
|
1300 | + * |
|
1301 | + * @param ReflectionClass $reflector |
|
1302 | + * @param string $class_name |
|
1303 | + * @param array $arguments |
|
1304 | + * @return array |
|
1305 | + * @throws InvalidArgumentException |
|
1306 | + * @throws InvalidDataTypeException |
|
1307 | + * @throws InvalidInterfaceException |
|
1308 | + * @throws ReflectionException |
|
1309 | + */ |
|
1310 | + protected function _resolve_dependencies(ReflectionClass $reflector, $class_name, array $arguments = array()) |
|
1311 | + { |
|
1312 | + // let's examine the constructor |
|
1313 | + $constructor = $this->mirror->getConstructorFromReflection($reflector); |
|
1314 | + // whu? huh? nothing? |
|
1315 | + if (! $constructor) { |
|
1316 | + return $arguments; |
|
1317 | + } |
|
1318 | + // get constructor parameters |
|
1319 | + $params = $this->mirror->getParametersFromReflection($reflector); |
|
1320 | + // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected |
|
1321 | + $argument_keys = array_keys($arguments); |
|
1322 | + // now loop thru all of the constructors expected parameters |
|
1323 | + foreach ($params as $index => $param) { |
|
1324 | + // is this a dependency for a specific class ? |
|
1325 | + $param_class = $this->mirror->getParameterClassName($param, $class_name, $index); |
|
1326 | + // BUT WAIT !!! This class may be an alias for something else (or getting replaced at runtime) |
|
1327 | + $param_class = $this->class_cache->isAlias($param_class, $class_name) |
|
1328 | + ? $this->class_cache->getFqnForAlias($param_class, $class_name) |
|
1329 | + : $param_class; |
|
1330 | + if (// param is not even a class |
|
1331 | + $param_class === null |
|
1332 | + // and something already exists in the incoming arguments for this param |
|
1333 | + && array_key_exists($index, $argument_keys) |
|
1334 | + && array_key_exists($argument_keys[ $index ], $arguments) |
|
1335 | + ) { |
|
1336 | + // so let's skip this argument and move on to the next |
|
1337 | + continue; |
|
1338 | + } |
|
1339 | + if (// parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class |
|
1340 | + $param_class !== null |
|
1341 | + && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ]) |
|
1342 | + && $arguments[ $argument_keys[ $index ] ] instanceof $param_class |
|
1343 | + ) { |
|
1344 | + // skip this argument and move on to the next |
|
1345 | + continue; |
|
1346 | + } |
|
1347 | + if (// parameter is type hinted as a class, and should be injected |
|
1348 | + $param_class !== null |
|
1349 | + && $this->_dependency_map->has_dependency_for_class($class_name, $param_class) |
|
1350 | + ) { |
|
1351 | + $arguments = $this->_resolve_dependency( |
|
1352 | + $class_name, |
|
1353 | + $param_class, |
|
1354 | + $arguments, |
|
1355 | + $index |
|
1356 | + ); |
|
1357 | + } else { |
|
1358 | + $arguments[ $index ] = $this->mirror->getParameterDefaultValue( |
|
1359 | + $param, |
|
1360 | + $class_name, |
|
1361 | + $index |
|
1362 | + ); |
|
1363 | + } |
|
1364 | + } |
|
1365 | + return $arguments; |
|
1366 | + } |
|
1367 | + |
|
1368 | + |
|
1369 | + /** |
|
1370 | + * @param string $class_name |
|
1371 | + * @param string $param_class |
|
1372 | + * @param array $arguments |
|
1373 | + * @param mixed $index |
|
1374 | + * @return array |
|
1375 | + * @throws InvalidArgumentException |
|
1376 | + * @throws InvalidInterfaceException |
|
1377 | + * @throws InvalidDataTypeException |
|
1378 | + */ |
|
1379 | + protected function _resolve_dependency($class_name, $param_class, $arguments, $index) |
|
1380 | + { |
|
1381 | + $dependency = null; |
|
1382 | + // should dependency be loaded from cache ? |
|
1383 | + $cache_on = $this->_dependency_map->loading_strategy_for_class_dependency( |
|
1384 | + $class_name, |
|
1385 | + $param_class |
|
1386 | + ); |
|
1387 | + $cache_on = $cache_on !== EE_Dependency_Map::load_new_object; |
|
1388 | + // we might have a dependency... |
|
1389 | + // let's MAYBE try and find it in our cache if that's what's been requested |
|
1390 | + $cached_class = $cache_on |
|
1391 | + ? $this->_get_cached_class($param_class) |
|
1392 | + : null; |
|
1393 | + // and grab it if it exists |
|
1394 | + if ($cached_class instanceof $param_class) { |
|
1395 | + $dependency = $cached_class; |
|
1396 | + } elseif ($param_class !== $class_name) { |
|
1397 | + // obtain the loader method from the dependency map |
|
1398 | + $loader = $this->_dependency_map->class_loader($param_class); |
|
1399 | + // is loader a custom closure ? |
|
1400 | + if ($loader instanceof Closure) { |
|
1401 | + $dependency = $loader($arguments); |
|
1402 | + } else { |
|
1403 | + // set the cache on property for the recursive loading call |
|
1404 | + $this->_cache_on = $cache_on; |
|
1405 | + // if not, then let's try and load it via the registry |
|
1406 | + if ($loader && method_exists($this, $loader)) { |
|
1407 | + $dependency = $this->{$loader}($param_class); |
|
1408 | + } else { |
|
1409 | + $dependency = LoaderFactory::getLoader()->load( |
|
1410 | + $param_class, |
|
1411 | + array(), |
|
1412 | + $cache_on |
|
1413 | + ); |
|
1414 | + } |
|
1415 | + } |
|
1416 | + } |
|
1417 | + // did we successfully find the correct dependency ? |
|
1418 | + if ($dependency instanceof $param_class) { |
|
1419 | + // then let's inject it into the incoming array of arguments at the correct location |
|
1420 | + $arguments[ $index ] = $dependency; |
|
1421 | + } |
|
1422 | + return $arguments; |
|
1423 | + } |
|
1424 | + |
|
1425 | + |
|
1426 | + /** |
|
1427 | + * call any loader that's been registered in the EE_Dependency_Map::$_class_loaders array |
|
1428 | + * |
|
1429 | + * @param string $classname PLEASE NOTE: the class name needs to match what's registered |
|
1430 | + * in the EE_Dependency_Map::$_class_loaders array, |
|
1431 | + * including the class prefix, ie: "EE_", "EEM_", "EEH_", etc |
|
1432 | + * @param array $arguments |
|
1433 | + * @return object |
|
1434 | + */ |
|
1435 | + public static function factory($classname, $arguments = array()) |
|
1436 | + { |
|
1437 | + $loader = self::instance()->_dependency_map->class_loader($classname); |
|
1438 | + if ($loader instanceof Closure) { |
|
1439 | + return $loader($arguments); |
|
1440 | + } |
|
1441 | + if (method_exists(self::instance(), $loader)) { |
|
1442 | + return self::instance()->{$loader}($classname, $arguments); |
|
1443 | + } |
|
1444 | + return null; |
|
1445 | + } |
|
1446 | + |
|
1447 | + |
|
1448 | + /** |
|
1449 | + * Gets the addon by its class name |
|
1450 | + * |
|
1451 | + * @param string $class_name |
|
1452 | + * @return EE_Addon |
|
1453 | + */ |
|
1454 | + public function getAddon($class_name) |
|
1455 | + { |
|
1456 | + $class_name = str_replace('\\', '_', $class_name); |
|
1457 | + return $this->addons->{$class_name}; |
|
1458 | + } |
|
1459 | + |
|
1460 | + |
|
1461 | + /** |
|
1462 | + * removes the addon from the internal cache |
|
1463 | + * |
|
1464 | + * @param string $class_name |
|
1465 | + * @return void |
|
1466 | + */ |
|
1467 | + public function removeAddon($class_name) |
|
1468 | + { |
|
1469 | + $class_name = str_replace('\\', '_', $class_name); |
|
1470 | + unset($this->addons->{$class_name}); |
|
1471 | + } |
|
1472 | + |
|
1473 | + |
|
1474 | + /** |
|
1475 | + * Gets the addon by its name/slug (not classname. For that, just |
|
1476 | + * use the get_addon() method above |
|
1477 | + * |
|
1478 | + * @param string $name |
|
1479 | + * @return EE_Addon |
|
1480 | + */ |
|
1481 | + public function get_addon_by_name($name) |
|
1482 | + { |
|
1483 | + foreach ($this->addons as $addon) { |
|
1484 | + if ($addon->name() === $name) { |
|
1485 | + return $addon; |
|
1486 | + } |
|
1487 | + } |
|
1488 | + return null; |
|
1489 | + } |
|
1490 | + |
|
1491 | + |
|
1492 | + /** |
|
1493 | + * Gets an array of all the registered addons, where the keys are their names. |
|
1494 | + * (ie, what each returns for their name() function) |
|
1495 | + * They're already available on EE_Registry::instance()->addons as properties, |
|
1496 | + * where each property's name is the addon's classname, |
|
1497 | + * So if you just want to get the addon by classname, |
|
1498 | + * OR use the get_addon() method above. |
|
1499 | + * PLEASE NOTE: |
|
1500 | + * addons with Fully Qualified Class Names |
|
1501 | + * have had the namespace separators converted to underscores, |
|
1502 | + * so a classname like Fully\Qualified\ClassName |
|
1503 | + * would have been converted to Fully_Qualified_ClassName |
|
1504 | + * |
|
1505 | + * @return EE_Addon[] where the KEYS are the addon's name() |
|
1506 | + */ |
|
1507 | + public function get_addons_by_name() |
|
1508 | + { |
|
1509 | + $addons = array(); |
|
1510 | + foreach ($this->addons as $addon) { |
|
1511 | + $addons[ $addon->name() ] = $addon; |
|
1512 | + } |
|
1513 | + return $addons; |
|
1514 | + } |
|
1515 | + |
|
1516 | + |
|
1517 | + /** |
|
1518 | + * Resets the specified model's instance AND makes sure EE_Registry doesn't keep |
|
1519 | + * a stale copy of it around |
|
1520 | + * |
|
1521 | + * @param string $model_name |
|
1522 | + * @return \EEM_Base |
|
1523 | + * @throws \EE_Error |
|
1524 | + */ |
|
1525 | + public function reset_model($model_name) |
|
1526 | + { |
|
1527 | + $model_class_name = strpos($model_name, 'EEM_') !== 0 |
|
1528 | + ? "EEM_{$model_name}" |
|
1529 | + : $model_name; |
|
1530 | + if (! isset($this->LIB->{$model_class_name}) || ! $this->LIB->{$model_class_name} instanceof EEM_Base) { |
|
1531 | + return null; |
|
1532 | + } |
|
1533 | + // get that model reset it and make sure we nuke the old reference to it |
|
1534 | + if ($this->LIB->{$model_class_name} instanceof $model_class_name |
|
1535 | + && is_callable( |
|
1536 | + array($model_class_name, 'reset') |
|
1537 | + )) { |
|
1538 | + $this->LIB->{$model_class_name} = $this->LIB->{$model_class_name}->reset(); |
|
1539 | + } else { |
|
1540 | + throw new EE_Error( |
|
1541 | + sprintf( |
|
1542 | + esc_html__('Model %s does not have a method "reset"', 'event_espresso'), |
|
1543 | + $model_name |
|
1544 | + ) |
|
1545 | + ); |
|
1546 | + } |
|
1547 | + return $this->LIB->{$model_class_name}; |
|
1548 | + } |
|
1549 | + |
|
1550 | + |
|
1551 | + /** |
|
1552 | + * Resets the registry. |
|
1553 | + * The criteria for what gets reset is based on what can be shared between sites on the same request when |
|
1554 | + * switch_to_blog is used in a multisite install. Here is a list of things that are NOT reset. |
|
1555 | + * - $_dependency_map |
|
1556 | + * - $_class_abbreviations |
|
1557 | + * - $NET_CFG (EE_Network_Config): The config is shared network wide so no need to reset. |
|
1558 | + * - $REQ: Still on the same request so no need to change. |
|
1559 | + * - $CAP: There is no site specific state in the EE_Capability class. |
|
1560 | + * - $SSN: Although ideally, the session should not be shared between site switches, we can't reset it because only |
|
1561 | + * one Session can be active in a single request. Resetting could resolve in "headers already sent" errors. |
|
1562 | + * - $addons: In multisite, the state of the addons is something controlled via hooks etc in a normal request. So |
|
1563 | + * for now, we won't reset the addons because it could break calls to an add-ons class/methods in the |
|
1564 | + * switch or on the restore. |
|
1565 | + * - $modules |
|
1566 | + * - $shortcodes |
|
1567 | + * - $widgets |
|
1568 | + * |
|
1569 | + * @param boolean $hard [deprecated] |
|
1570 | + * @param boolean $reinstantiate whether to create new instances of EE_Registry's singletons too, |
|
1571 | + * or just reset without re-instantiating (handy to set to FALSE if you're not |
|
1572 | + * sure if you CAN currently reinstantiate the singletons at the moment) |
|
1573 | + * @param bool $reset_models Defaults to true. When false, then the models are not reset. This is so |
|
1574 | + * client |
|
1575 | + * code instead can just change the model context to a different blog id if |
|
1576 | + * necessary |
|
1577 | + * @return EE_Registry |
|
1578 | + * @throws InvalidInterfaceException |
|
1579 | + * @throws InvalidDataTypeException |
|
1580 | + * @throws EE_Error |
|
1581 | + * @throws ReflectionException |
|
1582 | + * @throws InvalidArgumentException |
|
1583 | + */ |
|
1584 | + public static function reset($hard = false, $reinstantiate = true, $reset_models = true) |
|
1585 | + { |
|
1586 | + $instance = self::instance(); |
|
1587 | + $instance->_cache_on = true; |
|
1588 | + // reset some "special" classes |
|
1589 | + EEH_Activation::reset(); |
|
1590 | + $hard = apply_filters('FHEE__EE_Registry__reset__hard', $hard); |
|
1591 | + $instance->CFG = EE_Config::reset($hard, $reinstantiate); |
|
1592 | + $instance->CART = null; |
|
1593 | + $instance->MRM = null; |
|
1594 | + $instance->AssetsRegistry = LoaderFactory::getLoader()->getShared( |
|
1595 | + 'EventEspresso\core\services\assets\Registry' |
|
1596 | + ); |
|
1597 | + // messages reset |
|
1598 | + EED_Messages::reset(); |
|
1599 | + // handle of objects cached on LIB |
|
1600 | + foreach (array('LIB', 'modules') as $cache) { |
|
1601 | + foreach ($instance->{$cache} as $class_name => $class) { |
|
1602 | + if (self::_reset_and_unset_object($class, $reset_models)) { |
|
1603 | + unset($instance->{$cache}->{$class_name}); |
|
1604 | + } |
|
1605 | + } |
|
1606 | + } |
|
1607 | + return $instance; |
|
1608 | + } |
|
1609 | + |
|
1610 | + |
|
1611 | + /** |
|
1612 | + * if passed object implements ResettableInterface, then call it's reset() method |
|
1613 | + * if passed object implements InterminableInterface, then return false, |
|
1614 | + * to indicate that it should NOT be cleared from the Registry cache |
|
1615 | + * |
|
1616 | + * @param $object |
|
1617 | + * @param bool $reset_models |
|
1618 | + * @return bool returns true if cached object should be unset |
|
1619 | + */ |
|
1620 | + private static function _reset_and_unset_object($object, $reset_models) |
|
1621 | + { |
|
1622 | + if (! is_object($object)) { |
|
1623 | + // don't unset anything that's not an object |
|
1624 | + return false; |
|
1625 | + } |
|
1626 | + if ($object instanceof EED_Module) { |
|
1627 | + $object::reset(); |
|
1628 | + // don't unset modules |
|
1629 | + return false; |
|
1630 | + } |
|
1631 | + if ($object instanceof ResettableInterface) { |
|
1632 | + if ($object instanceof EEM_Base) { |
|
1633 | + if ($reset_models) { |
|
1634 | + $object->reset(); |
|
1635 | + return true; |
|
1636 | + } |
|
1637 | + return false; |
|
1638 | + } |
|
1639 | + $object->reset(); |
|
1640 | + return true; |
|
1641 | + } |
|
1642 | + if (! $object instanceof InterminableInterface) { |
|
1643 | + return true; |
|
1644 | + } |
|
1645 | + return false; |
|
1646 | + } |
|
1647 | + |
|
1648 | + |
|
1649 | + /** |
|
1650 | + * Gets all the custom post type models defined |
|
1651 | + * |
|
1652 | + * @return array keys are model "short names" (Eg "Event") and keys are classnames (eg "EEM_Event") |
|
1653 | + */ |
|
1654 | + public function cpt_models() |
|
1655 | + { |
|
1656 | + $cpt_models = array(); |
|
1657 | + foreach ($this->non_abstract_db_models as $short_name => $classname) { |
|
1658 | + if (is_subclass_of($classname, 'EEM_CPT_Base')) { |
|
1659 | + $cpt_models[ $short_name ] = $classname; |
|
1660 | + } |
|
1661 | + } |
|
1662 | + return $cpt_models; |
|
1663 | + } |
|
1664 | + |
|
1665 | + |
|
1666 | + /** |
|
1667 | + * @return \EE_Config |
|
1668 | + */ |
|
1669 | + public static function CFG() |
|
1670 | + { |
|
1671 | + return self::instance()->CFG; |
|
1672 | + } |
|
1673 | + |
|
1674 | + |
|
1675 | + /** |
|
1676 | + * @deprecated 4.9.62.p |
|
1677 | + * @param string $class_name |
|
1678 | + * @return ReflectionClass |
|
1679 | + * @throws ReflectionException |
|
1680 | + * @throws InvalidDataTypeException |
|
1681 | + */ |
|
1682 | + public function get_ReflectionClass($class_name) |
|
1683 | + { |
|
1684 | + return $this->mirror->getReflectionClass($class_name); |
|
1685 | + } |
|
1686 | 1686 | } |
@@ -20,85 +20,85 @@ |
||
20 | 20 | interface AssetManagerInterface |
21 | 21 | { |
22 | 22 | |
23 | - /** |
|
24 | - * @since 4.9.62.p |
|
25 | - */ |
|
26 | - public function addAssets(); |
|
27 | - |
|
28 | - |
|
29 | - /** |
|
30 | - * @return ManifestFile |
|
31 | - * @throws DuplicateCollectionIdentifierException |
|
32 | - * @throws InvalidDataTypeException |
|
33 | - * @throws InvalidEntityException |
|
34 | - * @since 4.9.62.p |
|
35 | - */ |
|
36 | - public function addManifestFile(); |
|
37 | - |
|
38 | - |
|
39 | - /** |
|
40 | - * @return ManifestFile[] |
|
41 | - * @since 4.9.62.p |
|
42 | - */ |
|
43 | - public function getManifestFile(); |
|
44 | - |
|
45 | - |
|
46 | - /** |
|
47 | - * @param string $handle |
|
48 | - * @param string $source |
|
49 | - * @param array $dependencies |
|
50 | - * @param bool $load_in_footer |
|
51 | - * @return JavascriptAsset |
|
52 | - * @throws DuplicateCollectionIdentifierException |
|
53 | - * @throws InvalidDataTypeException |
|
54 | - * @throws InvalidEntityException |
|
55 | - * @since 4.9.62.p |
|
56 | - */ |
|
57 | - public function addJavascript( |
|
58 | - $handle, |
|
59 | - $source, |
|
60 | - array $dependencies = array(), |
|
61 | - $load_in_footer = true |
|
62 | - ); |
|
63 | - |
|
64 | - |
|
65 | - /** |
|
66 | - * @return JavascriptAsset[] |
|
67 | - * @since 4.9.62.p |
|
68 | - */ |
|
69 | - public function getJavascriptAssets(); |
|
70 | - |
|
71 | - |
|
72 | - /** |
|
73 | - * @param string $handle |
|
74 | - * @param string $source |
|
75 | - * @param array $dependencies |
|
76 | - * @param string $media |
|
77 | - * @return StylesheetAsset |
|
78 | - * @throws DuplicateCollectionIdentifierException |
|
79 | - * @throws InvalidDataTypeException |
|
80 | - * @throws InvalidEntityException |
|
81 | - * @since 4.9.62.p |
|
82 | - */ |
|
83 | - public function addStylesheet( |
|
84 | - $handle, |
|
85 | - $source, |
|
86 | - array $dependencies = array(), |
|
87 | - $media = 'all' |
|
88 | - ); |
|
89 | - |
|
90 | - |
|
91 | - /** |
|
92 | - * @return StylesheetAsset[] |
|
93 | - * @since 4.9.62.p |
|
94 | - */ |
|
95 | - public function getStylesheetAssets(); |
|
96 | - |
|
97 | - |
|
98 | - /** |
|
99 | - * @param string $handle |
|
100 | - * @return bool |
|
101 | - * @since 4.9.62.p |
|
102 | - */ |
|
103 | - public function enqueueAsset($handle); |
|
23 | + /** |
|
24 | + * @since 4.9.62.p |
|
25 | + */ |
|
26 | + public function addAssets(); |
|
27 | + |
|
28 | + |
|
29 | + /** |
|
30 | + * @return ManifestFile |
|
31 | + * @throws DuplicateCollectionIdentifierException |
|
32 | + * @throws InvalidDataTypeException |
|
33 | + * @throws InvalidEntityException |
|
34 | + * @since 4.9.62.p |
|
35 | + */ |
|
36 | + public function addManifestFile(); |
|
37 | + |
|
38 | + |
|
39 | + /** |
|
40 | + * @return ManifestFile[] |
|
41 | + * @since 4.9.62.p |
|
42 | + */ |
|
43 | + public function getManifestFile(); |
|
44 | + |
|
45 | + |
|
46 | + /** |
|
47 | + * @param string $handle |
|
48 | + * @param string $source |
|
49 | + * @param array $dependencies |
|
50 | + * @param bool $load_in_footer |
|
51 | + * @return JavascriptAsset |
|
52 | + * @throws DuplicateCollectionIdentifierException |
|
53 | + * @throws InvalidDataTypeException |
|
54 | + * @throws InvalidEntityException |
|
55 | + * @since 4.9.62.p |
|
56 | + */ |
|
57 | + public function addJavascript( |
|
58 | + $handle, |
|
59 | + $source, |
|
60 | + array $dependencies = array(), |
|
61 | + $load_in_footer = true |
|
62 | + ); |
|
63 | + |
|
64 | + |
|
65 | + /** |
|
66 | + * @return JavascriptAsset[] |
|
67 | + * @since 4.9.62.p |
|
68 | + */ |
|
69 | + public function getJavascriptAssets(); |
|
70 | + |
|
71 | + |
|
72 | + /** |
|
73 | + * @param string $handle |
|
74 | + * @param string $source |
|
75 | + * @param array $dependencies |
|
76 | + * @param string $media |
|
77 | + * @return StylesheetAsset |
|
78 | + * @throws DuplicateCollectionIdentifierException |
|
79 | + * @throws InvalidDataTypeException |
|
80 | + * @throws InvalidEntityException |
|
81 | + * @since 4.9.62.p |
|
82 | + */ |
|
83 | + public function addStylesheet( |
|
84 | + $handle, |
|
85 | + $source, |
|
86 | + array $dependencies = array(), |
|
87 | + $media = 'all' |
|
88 | + ); |
|
89 | + |
|
90 | + |
|
91 | + /** |
|
92 | + * @return StylesheetAsset[] |
|
93 | + * @since 4.9.62.p |
|
94 | + */ |
|
95 | + public function getStylesheetAssets(); |
|
96 | + |
|
97 | + |
|
98 | + /** |
|
99 | + * @param string $handle |
|
100 | + * @return bool |
|
101 | + * @since 4.9.62.p |
|
102 | + */ |
|
103 | + public function enqueueAsset($handle); |
|
104 | 104 | } |
@@ -21,161 +21,161 @@ |
||
21 | 21 | abstract class AssetManager implements AssetManagerInterface |
22 | 22 | { |
23 | 23 | |
24 | - /** |
|
25 | - * @var AssetCollection $assets |
|
26 | - */ |
|
27 | - protected $assets; |
|
28 | - |
|
29 | - /** |
|
30 | - * @var DomainInterface |
|
31 | - */ |
|
32 | - protected $domain; |
|
33 | - |
|
34 | - /** |
|
35 | - * @var Registry $registry |
|
36 | - */ |
|
37 | - protected $registry; |
|
38 | - |
|
39 | - |
|
40 | - /** |
|
41 | - * AssetRegister constructor. |
|
42 | - * |
|
43 | - * @param DomainInterface $domain |
|
44 | - * @param AssetCollection $assets |
|
45 | - * @param Registry $registry |
|
46 | - */ |
|
47 | - public function __construct(DomainInterface $domain, AssetCollection $assets, Registry $registry) |
|
48 | - { |
|
49 | - $this->domain = $domain; |
|
50 | - $this->assets = $assets; |
|
51 | - $this->registry = $registry; |
|
52 | - add_action('wp_enqueue_scripts', array($this, 'addManifestFile'), 0); |
|
53 | - add_action('admin_enqueue_scripts', array($this, 'addManifestFile'), 0); |
|
54 | - add_action('wp_enqueue_scripts', array($this, 'addAssets'), 2); |
|
55 | - add_action('admin_enqueue_scripts', array($this, 'addAssets'), 2); |
|
56 | - } |
|
57 | - |
|
58 | - |
|
59 | - /** |
|
60 | - * @return void |
|
61 | - * @throws DuplicateCollectionIdentifierException |
|
62 | - * @throws InvalidDataTypeException |
|
63 | - * @throws InvalidEntityException |
|
64 | - * @since 4.9.62.p |
|
65 | - */ |
|
66 | - public function addManifestFile() |
|
67 | - { |
|
68 | - // if a manifest file has already been added for this domain, then just return that one |
|
69 | - if ($this->assets->has($this->domain->assetNamespace())) { |
|
70 | - return; |
|
71 | - } |
|
72 | - $asset = new ManifestFile($this->domain); |
|
73 | - $this->assets->add($asset, $this->domain->assetNamespace()); |
|
74 | - } |
|
75 | - |
|
76 | - |
|
77 | - /** |
|
78 | - * @return ManifestFile[] |
|
79 | - * @since 4.9.62.p |
|
80 | - */ |
|
81 | - public function getManifestFile() |
|
82 | - { |
|
83 | - return $this->assets->getManifestFiles(); |
|
84 | - } |
|
85 | - |
|
86 | - |
|
87 | - /** |
|
88 | - * @param string $handle |
|
89 | - * @param string $source |
|
90 | - * @param array $dependencies |
|
91 | - * @param bool $load_in_footer |
|
92 | - * @return JavascriptAsset |
|
93 | - * @throws DuplicateCollectionIdentifierException |
|
94 | - * @throws InvalidDataTypeException |
|
95 | - * @throws InvalidEntityException |
|
96 | - * @since 4.9.62.p |
|
97 | - */ |
|
98 | - public function addJavascript( |
|
99 | - $handle, |
|
100 | - $source, |
|
101 | - array $dependencies = array(), |
|
102 | - $load_in_footer = true |
|
103 | - ) { |
|
104 | - $asset = new JavascriptAsset( |
|
105 | - $handle, |
|
106 | - $source, |
|
107 | - $dependencies, |
|
108 | - $load_in_footer, |
|
109 | - $this->domain |
|
110 | - ); |
|
111 | - $this->assets->add($asset, $handle); |
|
112 | - return $asset; |
|
113 | - } |
|
114 | - |
|
115 | - |
|
116 | - /** |
|
117 | - * @return JavascriptAsset[] |
|
118 | - * @since 4.9.62.p |
|
119 | - */ |
|
120 | - public function getJavascriptAssets() |
|
121 | - { |
|
122 | - return $this->assets->getJavascriptAssets(); |
|
123 | - } |
|
124 | - |
|
125 | - |
|
126 | - /** |
|
127 | - * @param string $handle |
|
128 | - * @param string $source |
|
129 | - * @param array $dependencies |
|
130 | - * @param string $media |
|
131 | - * @return StylesheetAsset |
|
132 | - * @throws DuplicateCollectionIdentifierException |
|
133 | - * @throws InvalidDataTypeException |
|
134 | - * @throws InvalidEntityException |
|
135 | - * @since 4.9.62.p |
|
136 | - */ |
|
137 | - public function addStylesheet( |
|
138 | - $handle, |
|
139 | - $source, |
|
140 | - array $dependencies = array(), |
|
141 | - $media = 'all' |
|
142 | - ) { |
|
143 | - $asset = new StylesheetAsset( |
|
144 | - $handle, |
|
145 | - $source, |
|
146 | - $dependencies, |
|
147 | - $this->domain, |
|
148 | - $media |
|
149 | - ); |
|
150 | - $this->assets->add($asset, $handle); |
|
151 | - return $asset; |
|
152 | - } |
|
153 | - |
|
154 | - |
|
155 | - /** |
|
156 | - * @return StylesheetAsset[] |
|
157 | - * @since 4.9.62.p |
|
158 | - */ |
|
159 | - public function getStylesheetAssets() |
|
160 | - { |
|
161 | - return $this->assets->getStylesheetAssets(); |
|
162 | - } |
|
163 | - |
|
164 | - |
|
165 | - /** |
|
166 | - * @param string $handle |
|
167 | - * @return bool |
|
168 | - * @since 4.9.62.p |
|
169 | - */ |
|
170 | - public function enqueueAsset($handle) |
|
171 | - { |
|
172 | - if ($this->assets->has($handle)) { |
|
173 | - $asset = $this->assets->get($handle); |
|
174 | - if ($asset->isRegistered()) { |
|
175 | - $asset->enqueueAsset(); |
|
176 | - return true; |
|
177 | - } |
|
178 | - } |
|
179 | - return false; |
|
180 | - } |
|
24 | + /** |
|
25 | + * @var AssetCollection $assets |
|
26 | + */ |
|
27 | + protected $assets; |
|
28 | + |
|
29 | + /** |
|
30 | + * @var DomainInterface |
|
31 | + */ |
|
32 | + protected $domain; |
|
33 | + |
|
34 | + /** |
|
35 | + * @var Registry $registry |
|
36 | + */ |
|
37 | + protected $registry; |
|
38 | + |
|
39 | + |
|
40 | + /** |
|
41 | + * AssetRegister constructor. |
|
42 | + * |
|
43 | + * @param DomainInterface $domain |
|
44 | + * @param AssetCollection $assets |
|
45 | + * @param Registry $registry |
|
46 | + */ |
|
47 | + public function __construct(DomainInterface $domain, AssetCollection $assets, Registry $registry) |
|
48 | + { |
|
49 | + $this->domain = $domain; |
|
50 | + $this->assets = $assets; |
|
51 | + $this->registry = $registry; |
|
52 | + add_action('wp_enqueue_scripts', array($this, 'addManifestFile'), 0); |
|
53 | + add_action('admin_enqueue_scripts', array($this, 'addManifestFile'), 0); |
|
54 | + add_action('wp_enqueue_scripts', array($this, 'addAssets'), 2); |
|
55 | + add_action('admin_enqueue_scripts', array($this, 'addAssets'), 2); |
|
56 | + } |
|
57 | + |
|
58 | + |
|
59 | + /** |
|
60 | + * @return void |
|
61 | + * @throws DuplicateCollectionIdentifierException |
|
62 | + * @throws InvalidDataTypeException |
|
63 | + * @throws InvalidEntityException |
|
64 | + * @since 4.9.62.p |
|
65 | + */ |
|
66 | + public function addManifestFile() |
|
67 | + { |
|
68 | + // if a manifest file has already been added for this domain, then just return that one |
|
69 | + if ($this->assets->has($this->domain->assetNamespace())) { |
|
70 | + return; |
|
71 | + } |
|
72 | + $asset = new ManifestFile($this->domain); |
|
73 | + $this->assets->add($asset, $this->domain->assetNamespace()); |
|
74 | + } |
|
75 | + |
|
76 | + |
|
77 | + /** |
|
78 | + * @return ManifestFile[] |
|
79 | + * @since 4.9.62.p |
|
80 | + */ |
|
81 | + public function getManifestFile() |
|
82 | + { |
|
83 | + return $this->assets->getManifestFiles(); |
|
84 | + } |
|
85 | + |
|
86 | + |
|
87 | + /** |
|
88 | + * @param string $handle |
|
89 | + * @param string $source |
|
90 | + * @param array $dependencies |
|
91 | + * @param bool $load_in_footer |
|
92 | + * @return JavascriptAsset |
|
93 | + * @throws DuplicateCollectionIdentifierException |
|
94 | + * @throws InvalidDataTypeException |
|
95 | + * @throws InvalidEntityException |
|
96 | + * @since 4.9.62.p |
|
97 | + */ |
|
98 | + public function addJavascript( |
|
99 | + $handle, |
|
100 | + $source, |
|
101 | + array $dependencies = array(), |
|
102 | + $load_in_footer = true |
|
103 | + ) { |
|
104 | + $asset = new JavascriptAsset( |
|
105 | + $handle, |
|
106 | + $source, |
|
107 | + $dependencies, |
|
108 | + $load_in_footer, |
|
109 | + $this->domain |
|
110 | + ); |
|
111 | + $this->assets->add($asset, $handle); |
|
112 | + return $asset; |
|
113 | + } |
|
114 | + |
|
115 | + |
|
116 | + /** |
|
117 | + * @return JavascriptAsset[] |
|
118 | + * @since 4.9.62.p |
|
119 | + */ |
|
120 | + public function getJavascriptAssets() |
|
121 | + { |
|
122 | + return $this->assets->getJavascriptAssets(); |
|
123 | + } |
|
124 | + |
|
125 | + |
|
126 | + /** |
|
127 | + * @param string $handle |
|
128 | + * @param string $source |
|
129 | + * @param array $dependencies |
|
130 | + * @param string $media |
|
131 | + * @return StylesheetAsset |
|
132 | + * @throws DuplicateCollectionIdentifierException |
|
133 | + * @throws InvalidDataTypeException |
|
134 | + * @throws InvalidEntityException |
|
135 | + * @since 4.9.62.p |
|
136 | + */ |
|
137 | + public function addStylesheet( |
|
138 | + $handle, |
|
139 | + $source, |
|
140 | + array $dependencies = array(), |
|
141 | + $media = 'all' |
|
142 | + ) { |
|
143 | + $asset = new StylesheetAsset( |
|
144 | + $handle, |
|
145 | + $source, |
|
146 | + $dependencies, |
|
147 | + $this->domain, |
|
148 | + $media |
|
149 | + ); |
|
150 | + $this->assets->add($asset, $handle); |
|
151 | + return $asset; |
|
152 | + } |
|
153 | + |
|
154 | + |
|
155 | + /** |
|
156 | + * @return StylesheetAsset[] |
|
157 | + * @since 4.9.62.p |
|
158 | + */ |
|
159 | + public function getStylesheetAssets() |
|
160 | + { |
|
161 | + return $this->assets->getStylesheetAssets(); |
|
162 | + } |
|
163 | + |
|
164 | + |
|
165 | + /** |
|
166 | + * @param string $handle |
|
167 | + * @return bool |
|
168 | + * @since 4.9.62.p |
|
169 | + */ |
|
170 | + public function enqueueAsset($handle) |
|
171 | + { |
|
172 | + if ($this->assets->has($handle)) { |
|
173 | + $asset = $this->assets->get($handle); |
|
174 | + if ($asset->isRegistered()) { |
|
175 | + $asset->enqueueAsset(); |
|
176 | + return true; |
|
177 | + } |
|
178 | + } |
|
179 | + return false; |
|
180 | + } |
|
181 | 181 | } |
@@ -17,154 +17,154 @@ |
||
17 | 17 | class CachingLoader extends CachingLoaderDecorator |
18 | 18 | { |
19 | 19 | |
20 | - /** |
|
21 | - * @var string $identifier |
|
22 | - */ |
|
23 | - protected $identifier; |
|
24 | - |
|
25 | - /** |
|
26 | - * @var CollectionInterface $cache |
|
27 | - */ |
|
28 | - protected $cache; |
|
29 | - |
|
30 | - /** |
|
31 | - * @var ObjectIdentifier |
|
32 | - */ |
|
33 | - private $object_identifier; |
|
34 | - |
|
35 | - |
|
36 | - /** |
|
37 | - * CachingLoader constructor. |
|
38 | - * |
|
39 | - * @param LoaderDecoratorInterface $loader |
|
40 | - * @param CollectionInterface $cache |
|
41 | - * @param ObjectIdentifier $object_identifier |
|
42 | - * @param string $identifier |
|
43 | - * @throws InvalidDataTypeException |
|
44 | - */ |
|
45 | - public function __construct( |
|
46 | - LoaderDecoratorInterface $loader, |
|
47 | - CollectionInterface $cache, |
|
48 | - ObjectIdentifier $object_identifier, |
|
49 | - $identifier = '' |
|
50 | - ) { |
|
51 | - parent::__construct($loader); |
|
52 | - $this->cache = $cache; |
|
53 | - $this->object_identifier = $object_identifier; |
|
54 | - $this->setIdentifier($identifier); |
|
55 | - if ($this->identifier !== '') { |
|
56 | - // to only clear this cache, and assuming an identifier has been set, simply do the following: |
|
57 | - // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__IDENTIFIER'); |
|
58 | - // where "IDENTIFIER" = the string that was set during construction |
|
59 | - add_action( |
|
60 | - "AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__{$identifier}", |
|
61 | - array($this, 'reset') |
|
62 | - ); |
|
63 | - } |
|
64 | - // to clear ALL caches, simply do the following: |
|
65 | - // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache'); |
|
66 | - add_action( |
|
67 | - 'AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache', |
|
68 | - array($this, 'reset') |
|
69 | - ); |
|
70 | - } |
|
71 | - |
|
72 | - |
|
73 | - /** |
|
74 | - * @return string |
|
75 | - */ |
|
76 | - public function identifier() |
|
77 | - { |
|
78 | - return $this->identifier; |
|
79 | - } |
|
80 | - |
|
81 | - |
|
82 | - /** |
|
83 | - * @param string $identifier |
|
84 | - * @throws InvalidDataTypeException |
|
85 | - */ |
|
86 | - private function setIdentifier($identifier) |
|
87 | - { |
|
88 | - if (! is_string($identifier)) { |
|
89 | - throw new InvalidDataTypeException('$identifier', $identifier, 'string'); |
|
90 | - } |
|
91 | - $this->identifier = $identifier; |
|
92 | - } |
|
93 | - |
|
94 | - |
|
95 | - /** |
|
96 | - * @param FullyQualifiedName|string $fqcn |
|
97 | - * @param mixed $object |
|
98 | - * @return bool |
|
99 | - * @throws InvalidArgumentException |
|
100 | - */ |
|
101 | - public function share($fqcn, $object) |
|
102 | - { |
|
103 | - if ($object instanceof $fqcn) { |
|
104 | - return $this->cache->add($object, md5($fqcn)); |
|
105 | - } |
|
106 | - throw new InvalidArgumentException( |
|
107 | - sprintf( |
|
108 | - esc_html__( |
|
109 | - 'The supplied class name "%1$s" must match the class of the supplied object.', |
|
110 | - 'event_espresso' |
|
111 | - ), |
|
112 | - $fqcn |
|
113 | - ) |
|
114 | - ); |
|
115 | - } |
|
116 | - |
|
117 | - |
|
118 | - /** |
|
119 | - * @param FullyQualifiedName|string $fqcn |
|
120 | - * @param array $arguments |
|
121 | - * @param bool $shared |
|
122 | - * @param array $interfaces |
|
123 | - * @return mixed |
|
124 | - */ |
|
125 | - public function load($fqcn, $arguments = array(), $shared = true, array $interfaces = array()) |
|
126 | - { |
|
127 | - $fqcn = ltrim($fqcn, '\\'); |
|
128 | - // caching can be turned off via the following code: |
|
129 | - // add_filter('FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache', '__return_true'); |
|
130 | - if (apply_filters( |
|
131 | - 'FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache', |
|
132 | - false, |
|
133 | - $this |
|
134 | - )) { |
|
135 | - // even though $shared might be true, caching could be bypassed for whatever reason, |
|
136 | - // so we don't want the core loader to cache anything, therefore caching is turned off |
|
137 | - return $this->loader->load($fqcn, $arguments, false); |
|
138 | - } |
|
139 | - $object_identifier = $this->object_identifier->getIdentifier($fqcn, $arguments); |
|
140 | - if ($this->cache->has($object_identifier)) { |
|
141 | - return $this->cache->get($object_identifier); |
|
142 | - } |
|
143 | - $object = $this->loader->load($fqcn, $arguments, $shared); |
|
144 | - if ($object instanceof $fqcn) { |
|
145 | - $this->cache->add($object, $object_identifier); |
|
146 | - } |
|
147 | - return $object; |
|
148 | - } |
|
149 | - |
|
150 | - |
|
151 | - /** |
|
152 | - * empties cache and calls reset() on loader if method exists |
|
153 | - */ |
|
154 | - public function reset() |
|
155 | - { |
|
156 | - $this->clearCache(); |
|
157 | - $this->loader->reset(); |
|
158 | - } |
|
159 | - |
|
160 | - |
|
161 | - /** |
|
162 | - * unsets and detaches ALL objects from the cache |
|
163 | - * |
|
164 | - * @since 4.9.62.p |
|
165 | - */ |
|
166 | - public function clearCache() |
|
167 | - { |
|
168 | - $this->cache->trashAndDetachAll(); |
|
169 | - } |
|
20 | + /** |
|
21 | + * @var string $identifier |
|
22 | + */ |
|
23 | + protected $identifier; |
|
24 | + |
|
25 | + /** |
|
26 | + * @var CollectionInterface $cache |
|
27 | + */ |
|
28 | + protected $cache; |
|
29 | + |
|
30 | + /** |
|
31 | + * @var ObjectIdentifier |
|
32 | + */ |
|
33 | + private $object_identifier; |
|
34 | + |
|
35 | + |
|
36 | + /** |
|
37 | + * CachingLoader constructor. |
|
38 | + * |
|
39 | + * @param LoaderDecoratorInterface $loader |
|
40 | + * @param CollectionInterface $cache |
|
41 | + * @param ObjectIdentifier $object_identifier |
|
42 | + * @param string $identifier |
|
43 | + * @throws InvalidDataTypeException |
|
44 | + */ |
|
45 | + public function __construct( |
|
46 | + LoaderDecoratorInterface $loader, |
|
47 | + CollectionInterface $cache, |
|
48 | + ObjectIdentifier $object_identifier, |
|
49 | + $identifier = '' |
|
50 | + ) { |
|
51 | + parent::__construct($loader); |
|
52 | + $this->cache = $cache; |
|
53 | + $this->object_identifier = $object_identifier; |
|
54 | + $this->setIdentifier($identifier); |
|
55 | + if ($this->identifier !== '') { |
|
56 | + // to only clear this cache, and assuming an identifier has been set, simply do the following: |
|
57 | + // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__IDENTIFIER'); |
|
58 | + // where "IDENTIFIER" = the string that was set during construction |
|
59 | + add_action( |
|
60 | + "AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache__{$identifier}", |
|
61 | + array($this, 'reset') |
|
62 | + ); |
|
63 | + } |
|
64 | + // to clear ALL caches, simply do the following: |
|
65 | + // do_action('AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache'); |
|
66 | + add_action( |
|
67 | + 'AHEE__EventEspresso_core_services_loaders_CachingLoader__resetCache', |
|
68 | + array($this, 'reset') |
|
69 | + ); |
|
70 | + } |
|
71 | + |
|
72 | + |
|
73 | + /** |
|
74 | + * @return string |
|
75 | + */ |
|
76 | + public function identifier() |
|
77 | + { |
|
78 | + return $this->identifier; |
|
79 | + } |
|
80 | + |
|
81 | + |
|
82 | + /** |
|
83 | + * @param string $identifier |
|
84 | + * @throws InvalidDataTypeException |
|
85 | + */ |
|
86 | + private function setIdentifier($identifier) |
|
87 | + { |
|
88 | + if (! is_string($identifier)) { |
|
89 | + throw new InvalidDataTypeException('$identifier', $identifier, 'string'); |
|
90 | + } |
|
91 | + $this->identifier = $identifier; |
|
92 | + } |
|
93 | + |
|
94 | + |
|
95 | + /** |
|
96 | + * @param FullyQualifiedName|string $fqcn |
|
97 | + * @param mixed $object |
|
98 | + * @return bool |
|
99 | + * @throws InvalidArgumentException |
|
100 | + */ |
|
101 | + public function share($fqcn, $object) |
|
102 | + { |
|
103 | + if ($object instanceof $fqcn) { |
|
104 | + return $this->cache->add($object, md5($fqcn)); |
|
105 | + } |
|
106 | + throw new InvalidArgumentException( |
|
107 | + sprintf( |
|
108 | + esc_html__( |
|
109 | + 'The supplied class name "%1$s" must match the class of the supplied object.', |
|
110 | + 'event_espresso' |
|
111 | + ), |
|
112 | + $fqcn |
|
113 | + ) |
|
114 | + ); |
|
115 | + } |
|
116 | + |
|
117 | + |
|
118 | + /** |
|
119 | + * @param FullyQualifiedName|string $fqcn |
|
120 | + * @param array $arguments |
|
121 | + * @param bool $shared |
|
122 | + * @param array $interfaces |
|
123 | + * @return mixed |
|
124 | + */ |
|
125 | + public function load($fqcn, $arguments = array(), $shared = true, array $interfaces = array()) |
|
126 | + { |
|
127 | + $fqcn = ltrim($fqcn, '\\'); |
|
128 | + // caching can be turned off via the following code: |
|
129 | + // add_filter('FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache', '__return_true'); |
|
130 | + if (apply_filters( |
|
131 | + 'FHEE__EventEspresso_core_services_loaders_CachingLoader__load__bypass_cache', |
|
132 | + false, |
|
133 | + $this |
|
134 | + )) { |
|
135 | + // even though $shared might be true, caching could be bypassed for whatever reason, |
|
136 | + // so we don't want the core loader to cache anything, therefore caching is turned off |
|
137 | + return $this->loader->load($fqcn, $arguments, false); |
|
138 | + } |
|
139 | + $object_identifier = $this->object_identifier->getIdentifier($fqcn, $arguments); |
|
140 | + if ($this->cache->has($object_identifier)) { |
|
141 | + return $this->cache->get($object_identifier); |
|
142 | + } |
|
143 | + $object = $this->loader->load($fqcn, $arguments, $shared); |
|
144 | + if ($object instanceof $fqcn) { |
|
145 | + $this->cache->add($object, $object_identifier); |
|
146 | + } |
|
147 | + return $object; |
|
148 | + } |
|
149 | + |
|
150 | + |
|
151 | + /** |
|
152 | + * empties cache and calls reset() on loader if method exists |
|
153 | + */ |
|
154 | + public function reset() |
|
155 | + { |
|
156 | + $this->clearCache(); |
|
157 | + $this->loader->reset(); |
|
158 | + } |
|
159 | + |
|
160 | + |
|
161 | + /** |
|
162 | + * unsets and detaches ALL objects from the cache |
|
163 | + * |
|
164 | + * @since 4.9.62.p |
|
165 | + */ |
|
166 | + public function clearCache() |
|
167 | + { |
|
168 | + $this->cache->trashAndDetachAll(); |
|
169 | + } |
|
170 | 170 | } |