Completed
Branch sideload-incorrect-upload-from (81f0fb)
by
unknown
17:20 queued 08:52
created
modules/core_rest_api/EED_Core_Rest_Api.module.php 1 patch
Indentation   +1221 added lines, -1221 removed lines patch added patch discarded remove patch
@@ -23,1225 +23,1225 @@
 block discarded – undo
23 23
 class EED_Core_Rest_Api extends \EED_Module
24 24
 {
25 25
 
26
-    const ee_api_namespace = Domain::API_NAMESPACE;
27
-
28
-    const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
-
30
-    const saved_routes_option_names = 'ee_core_routes';
31
-
32
-    /**
33
-     * string used in _links response bodies to make them globally unique.
34
-     *
35
-     * @see http://v2.wp-api.org/extending/linking/
36
-     */
37
-    const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
-
39
-    /**
40
-     * @var CalculatedModelFields
41
-     */
42
-    protected static $_field_calculator;
43
-
44
-
45
-    /**
46
-     * @return EED_Core_Rest_Api|EED_Module
47
-     */
48
-    public static function instance()
49
-    {
50
-        self::$_field_calculator = LoaderFactory::getLoader()->load('EventEspresso\core\libraries\rest_api\CalculatedModelFields');
51
-        return parent::get_instance(__CLASS__);
52
-    }
53
-
54
-
55
-    /**
56
-     *    set_hooks - for hooking into EE Core, other modules, etc
57
-     *
58
-     * @access    public
59
-     * @return    void
60
-     */
61
-    public static function set_hooks()
62
-    {
63
-        self::set_hooks_both();
64
-    }
65
-
66
-
67
-    /**
68
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
69
-     *
70
-     * @access    public
71
-     * @return    void
72
-     */
73
-    public static function set_hooks_admin()
74
-    {
75
-        self::set_hooks_both();
76
-    }
77
-
78
-
79
-    public static function set_hooks_both()
80
-    {
81
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
82
-        add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
83
-        add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
84
-        add_filter(
85
-            'rest_index',
86
-            array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex')
87
-        );
88
-        EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
89
-    }
90
-
91
-
92
-    /**
93
-     * sets up hooks which only need to be included as part of REST API requests;
94
-     * other requests like to the frontend or admin etc don't need them
95
-     *
96
-     * @throws \EE_Error
97
-     */
98
-    public static function set_hooks_rest_api()
99
-    {
100
-        // set hooks which account for changes made to the API
101
-        EED_Core_Rest_Api::_set_hooks_for_changes();
102
-    }
103
-
104
-
105
-    /**
106
-     * public wrapper of _set_hooks_for_changes.
107
-     * Loads all the hooks which make requests to old versions of the API
108
-     * appear the same as they always did
109
-     *
110
-     * @throws EE_Error
111
-     */
112
-    public static function set_hooks_for_changes()
113
-    {
114
-        self::_set_hooks_for_changes();
115
-    }
116
-
117
-
118
-    /**
119
-     * Loads all the hooks which make requests to old versions of the API
120
-     * appear the same as they always did
121
-     *
122
-     * @throws EE_Error
123
-     */
124
-    protected static function _set_hooks_for_changes()
125
-    {
126
-        $folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
127
-        foreach ($folder_contents as $classname_in_namespace => $filepath) {
128
-            // ignore the base parent class
129
-            // and legacy named classes
130
-            if ($classname_in_namespace === 'ChangesInBase'
131
-                || strpos($classname_in_namespace, 'Changes_In_') === 0
132
-            ) {
133
-                continue;
134
-            }
135
-            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
136
-            if (class_exists($full_classname)) {
137
-                $instance_of_class = new $full_classname;
138
-                if ($instance_of_class instanceof ChangesInBase) {
139
-                    $instance_of_class->setHooks();
140
-                }
141
-            }
142
-        }
143
-    }
144
-
145
-
146
-    /**
147
-     * Filters the WP routes to add our EE-related ones. This takes a bit of time
148
-     * so we actually prefer to only do it when an EE plugin is activated or upgraded
149
-     *
150
-     * @throws \EE_Error
151
-     */
152
-    public static function register_routes()
153
-    {
154
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
155
-            foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
156
-                /**
157
-                 * @var array     $data_for_multiple_endpoints numerically indexed array
158
-                 *                                         but can also contain route options like {
159
-                 * @type array    $schema                      {
160
-                 * @type callable $schema_callback
161
-                 * @type array    $callback_args               arguments that will be passed to the callback, after the
162
-                 * WP_REST_Request of course
163
-                 * }
164
-                 * }
165
-                 */
166
-                // when registering routes, register all the endpoints' data at the same time
167
-                $multiple_endpoint_args = array();
168
-                foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
169
-                    /**
170
-                     * @var array     $data_for_single_endpoint {
171
-                     * @type callable $callback
172
-                     * @type string methods
173
-                     * @type array args
174
-                     * @type array _links
175
-                     * @type array    $callback_args            arguments that will be passed to the callback, after the
176
-                     * WP_REST_Request of course
177
-                     * }
178
-                     */
179
-                    // skip route options
180
-                    if (! is_numeric($endpoint_key)) {
181
-                        continue;
182
-                    }
183
-                    if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
184
-                        throw new EE_Error(
185
-                            esc_html__(
186
-                            // @codingStandardsIgnoreStart
187
-                                'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
188
-                                // @codingStandardsIgnoreEnd
189
-                                'event_espresso'
190
-                            )
191
-                        );
192
-                    }
193
-                    $callback = $data_for_single_endpoint['callback'];
194
-                    $single_endpoint_args = array(
195
-                        'methods' => $data_for_single_endpoint['methods'],
196
-                        'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
197
-                            : array(),
198
-                    );
199
-                    if (isset($data_for_single_endpoint['_links'])) {
200
-                        $single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
201
-                    }
202
-                    if (isset($data_for_single_endpoint['callback_args'])) {
203
-                        $callback_args = $data_for_single_endpoint['callback_args'];
204
-                        $single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
205
-                            $callback,
206
-                            $callback_args
207
-                        ) {
208
-                            array_unshift($callback_args, $request);
209
-                            return call_user_func_array(
210
-                                $callback,
211
-                                $callback_args
212
-                            );
213
-                        };
214
-                    } else {
215
-                        $single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
216
-                    }
217
-                    $multiple_endpoint_args[] = $single_endpoint_args;
218
-                }
219
-                if (isset($data_for_multiple_endpoints['schema'])) {
220
-                    $schema_route_data = $data_for_multiple_endpoints['schema'];
221
-                    $schema_callback = $schema_route_data['schema_callback'];
222
-                    $callback_args = $schema_route_data['callback_args'];
223
-                    $multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
224
-                        return call_user_func_array(
225
-                            $schema_callback,
226
-                            $callback_args
227
-                        );
228
-                    };
229
-                }
230
-                register_rest_route(
231
-                    $namespace,
232
-                    $relative_route,
233
-                    $multiple_endpoint_args
234
-                );
235
-            }
236
-        }
237
-    }
238
-
239
-
240
-    /**
241
-     * Checks if there was a version change or something that merits invalidating the cached
242
-     * route data. If so, invalidates the cached route data so that it gets refreshed
243
-     * next time the WP API is used
244
-     */
245
-    public static function invalidate_cached_route_data_on_version_change()
246
-    {
247
-        if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
248
-            EED_Core_Rest_Api::invalidate_cached_route_data();
249
-        }
250
-        foreach (EE_Registry::instance()->addons as $addon) {
251
-            if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
252
-                EED_Core_Rest_Api::invalidate_cached_route_data();
253
-            }
254
-        }
255
-    }
256
-
257
-
258
-    /**
259
-     * Removes the cached route data so it will get refreshed next time the WP API is used
260
-     */
261
-    public static function invalidate_cached_route_data()
262
-    {
263
-        // delete the saved EE REST API routes
264
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
265
-            delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
266
-        }
267
-    }
268
-
269
-
270
-    /**
271
-     * Gets the EE route data
272
-     *
273
-     * @return array top-level key is the namespace, next-level key is the route and its value is array{
274
-     * @throws \EE_Error
275
-     * @type string|array $callback
276
-     * @type string       $methods
277
-     * @type boolean      $hidden_endpoint
278
-     * }
279
-     */
280
-    public static function get_ee_route_data()
281
-    {
282
-        $ee_routes = array();
283
-        foreach (self::versions_served() as $version => $hidden_endpoints) {
284
-            $ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version(
285
-                $version,
286
-                $hidden_endpoints
287
-            );
288
-        }
289
-        return $ee_routes;
290
-    }
291
-
292
-
293
-    /**
294
-     * Gets the EE route data from the wp options if it exists already,
295
-     * otherwise re-generates it and saves it to the option
296
-     *
297
-     * @param string  $version
298
-     * @param boolean $hidden_endpoints
299
-     * @return array
300
-     * @throws \EE_Error
301
-     */
302
-    protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
303
-    {
304
-        $ee_routes = get_option(self::saved_routes_option_names . $version, null);
305
-        if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
306
-            $ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
307
-        }
308
-        return $ee_routes;
309
-    }
310
-
311
-
312
-    /**
313
-     * Saves the EE REST API route data to a wp option and returns it
314
-     *
315
-     * @param string  $version
316
-     * @param boolean $hidden_endpoints
317
-     * @return mixed|null
318
-     * @throws \EE_Error
319
-     */
320
-    protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
321
-    {
322
-        $instance = self::instance();
323
-        $routes = apply_filters(
324
-            'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
325
-            array_replace_recursive(
326
-                $instance->_get_config_route_data_for_version($version, $hidden_endpoints),
327
-                $instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
328
-                $instance->_get_model_route_data_for_version($version, $hidden_endpoints),
329
-                $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
330
-            )
331
-        );
332
-        $option_name = self::saved_routes_option_names . $version;
333
-        if (get_option($option_name)) {
334
-            update_option($option_name, $routes, true);
335
-        } else {
336
-            add_option($option_name, $routes, null, 'no');
337
-        }
338
-        return $routes;
339
-    }
340
-
341
-
342
-    /**
343
-     * Calculates all the EE routes and saves it to a WordPress option so we don't
344
-     * need to calculate it on every request
345
-     *
346
-     * @deprecated since version 4.9.1
347
-     * @return void
348
-     */
349
-    public static function save_ee_routes()
350
-    {
351
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
352
-            $instance = self::instance();
353
-            $routes = apply_filters(
354
-                'EED_Core_Rest_Api__save_ee_routes__routes',
355
-                array_replace_recursive(
356
-                    $instance->_register_config_routes(),
357
-                    $instance->_register_meta_routes(),
358
-                    $instance->_register_model_routes(),
359
-                    $instance->_register_rpc_routes()
360
-                )
361
-            );
362
-            update_option(self::saved_routes_option_names, $routes, true);
363
-        }
364
-    }
365
-
366
-
367
-    /**
368
-     * Gets all the route information relating to EE models
369
-     *
370
-     * @return array @see get_ee_route_data
371
-     * @deprecated since version 4.9.1
372
-     */
373
-    protected function _register_model_routes()
374
-    {
375
-        $model_routes = array();
376
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
377
-            $model_routes[ EED_Core_Rest_Api::ee_api_namespace
378
-                           . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
379
-        }
380
-        return $model_routes;
381
-    }
382
-
383
-
384
-    /**
385
-     * Decides whether or not to add write endpoints for this model.
386
-     *
387
-     * Currently, this defaults to exclude all global tables and models
388
-     * which would allow inserting WP core data (we don't want to duplicate
389
-     * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
390
-     *
391
-     * @param EEM_Base $model
392
-     * @return bool
393
-     */
394
-    public static function should_have_write_endpoints(EEM_Base $model)
395
-    {
396
-        if ($model->is_wp_core_model()) {
397
-            return false;
398
-        }
399
-        foreach ($model->get_tables() as $table) {
400
-            if ($table->is_global()) {
401
-                return false;
402
-            }
403
-        }
404
-        return true;
405
-    }
406
-
407
-
408
-    /**
409
-     * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
410
-     * in this versioned namespace of EE4
411
-     *
412
-     * @param $version
413
-     * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
414
-     */
415
-    public static function model_names_with_plural_routes($version)
416
-    {
417
-        $model_version_info = new ModelVersionInfo($version);
418
-        $models_to_register = $model_version_info->modelsForRequestedVersion();
419
-        // let's not bother having endpoints for extra metas
420
-        unset(
421
-            $models_to_register['Extra_Meta'],
422
-            $models_to_register['Extra_Join'],
423
-            $models_to_register['Post_Meta']
424
-        );
425
-        return apply_filters(
426
-            'FHEE__EED_Core_REST_API___register_model_routes',
427
-            $models_to_register
428
-        );
429
-    }
430
-
431
-
432
-    /**
433
-     * Gets the route data for EE models in the specified version
434
-     *
435
-     * @param string  $version
436
-     * @param boolean $hidden_endpoint
437
-     * @return array
438
-     * @throws EE_Error
439
-     */
440
-    protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
441
-    {
442
-        $model_routes = array();
443
-        $model_version_info = new ModelVersionInfo($version);
444
-        foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
445
-            $model = \EE_Registry::instance()->load_model($model_name);
446
-            // if this isn't a valid model then let's skip iterate to the next item in the loop.
447
-            if (! $model instanceof EEM_Base) {
448
-                continue;
449
-            }
450
-            // yes we could just register one route for ALL models, but then they wouldn't show up in the index
451
-            $plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
452
-            $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
453
-            $model_routes[ $plural_model_route ] = array(
454
-                array(
455
-                    'callback'        => array(
456
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
457
-                        'handleRequestGetAll',
458
-                    ),
459
-                    'callback_args'   => array($version, $model_name),
460
-                    'methods'         => WP_REST_Server::READABLE,
461
-                    'hidden_endpoint' => $hidden_endpoint,
462
-                    'args'            => $this->_get_read_query_params($model, $version),
463
-                    '_links'          => array(
464
-                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
465
-                    ),
466
-                ),
467
-                'schema' => array(
468
-                    'schema_callback' => array(
469
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
470
-                        'handleSchemaRequest',
471
-                    ),
472
-                    'callback_args'   => array($version, $model_name),
473
-                ),
474
-            );
475
-            $model_routes[ $singular_model_route ] = array(
476
-                array(
477
-                    'callback'        => array(
478
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
479
-                        'handleRequestGetOne',
480
-                    ),
481
-                    'callback_args'   => array($version, $model_name),
482
-                    'methods'         => WP_REST_Server::READABLE,
483
-                    'hidden_endpoint' => $hidden_endpoint,
484
-                    'args'            => $this->_get_response_selection_query_params($model, $version),
485
-                ),
486
-            );
487
-            if (apply_filters(
488
-                'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
489
-                EED_Core_Rest_Api::should_have_write_endpoints($model),
490
-                $model
491
-            )) {
492
-                $model_routes[ $plural_model_route ][] = array(
493
-                    'callback'        => array(
494
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Write',
495
-                        'handleRequestInsert',
496
-                    ),
497
-                    'callback_args'   => array($version, $model_name),
498
-                    'methods'         => WP_REST_Server::CREATABLE,
499
-                    'hidden_endpoint' => $hidden_endpoint,
500
-                    'args'            => $this->_get_write_params($model_name, $model_version_info, true),
501
-                );
502
-                $model_routes[ $singular_model_route ] = array_merge(
503
-                    $model_routes[ $singular_model_route ],
504
-                    array(
505
-                        array(
506
-                            'callback'        => array(
507
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
508
-                                'handleRequestUpdate',
509
-                            ),
510
-                            'callback_args'   => array($version, $model_name),
511
-                            'methods'         => WP_REST_Server::EDITABLE,
512
-                            'hidden_endpoint' => $hidden_endpoint,
513
-                            'args'            => $this->_get_write_params($model_name, $model_version_info),
514
-                        ),
515
-                        array(
516
-                            'callback'        => array(
517
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
518
-                                'handleRequestDelete',
519
-                            ),
520
-                            'callback_args'   => array($version, $model_name),
521
-                            'methods'         => WP_REST_Server::DELETABLE,
522
-                            'hidden_endpoint' => $hidden_endpoint,
523
-                            'args'            => $this->_get_delete_query_params($model, $version),
524
-                        ),
525
-                    )
526
-                );
527
-            }
528
-            foreach ($model->relation_settings() as $relation_name => $relation_obj) {
529
-                $related_route = EED_Core_Rest_Api::get_relation_route_via(
530
-                    $model,
531
-                    '(?P<id>[^\/]+)',
532
-                    $relation_obj
533
-                );
534
-                $endpoints = array(
535
-                    array(
536
-                        'callback'        => array(
537
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Read',
538
-                            'handleRequestGetRelated',
539
-                        ),
540
-                        'callback_args'   => array($version, $model_name, $relation_name),
541
-                        'methods'         => WP_REST_Server::READABLE,
542
-                        'hidden_endpoint' => $hidden_endpoint,
543
-                        'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
544
-                    ),
545
-                );
546
-                $model_routes[ $related_route ] = $endpoints;
547
-            }
548
-        }
549
-        return $model_routes;
550
-    }
551
-
552
-
553
-    /**
554
-     * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
555
-     * excluding the preceding slash.
556
-     * Eg you pass get_plural_route_to('Event') = 'events'
557
-     *
558
-     * @param EEM_Base $model
559
-     * @return string
560
-     */
561
-    public static function get_collection_route(EEM_Base $model)
562
-    {
563
-        return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
564
-    }
565
-
566
-
567
-    /**
568
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
569
-     * excluding the preceding slash.
570
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
571
-     *
572
-     * @param EEM_Base $model eg Event or Venue
573
-     * @param string   $id
574
-     * @return string
575
-     */
576
-    public static function get_entity_route($model, $id)
577
-    {
578
-        return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
579
-    }
580
-
581
-
582
-    /**
583
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
-     * excluding the preceding slash.
585
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
-     *
587
-     * @param EEM_Base               $model eg Event or Venue
588
-     * @param string                 $id
589
-     * @param EE_Model_Relation_Base $relation_obj
590
-     * @return string
591
-     */
592
-    public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
593
-    {
594
-        $related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
595
-            $relation_obj->get_other_model()->get_this_model_name(),
596
-            $relation_obj
597
-        );
598
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
599
-    }
600
-
601
-
602
-    /**
603
-     * Adds onto the $relative_route the EE4 REST API versioned namespace.
604
-     * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
605
-     *
606
-     * @param string $relative_route
607
-     * @param string $version
608
-     * @return string
609
-     */
610
-    public static function get_versioned_route_to($relative_route, $version = '4.8.36')
611
-    {
612
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
613
-    }
614
-
615
-
616
-    /**
617
-     * Adds all the RPC-style routes (remote procedure call-like routes, ie
618
-     * routes that don't conform to the traditional REST CRUD-style).
619
-     *
620
-     * @deprecated since 4.9.1
621
-     */
622
-    protected function _register_rpc_routes()
623
-    {
624
-        $routes = array();
625
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
626
-            $routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
627
-                $version,
628
-                $hidden_endpoint
629
-            );
630
-        }
631
-        return $routes;
632
-    }
633
-
634
-
635
-    /**
636
-     * @param string  $version
637
-     * @param boolean $hidden_endpoint
638
-     * @return array
639
-     */
640
-    protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
641
-    {
642
-        $this_versions_routes = array();
643
-        // checkin endpoint
644
-        $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
645
-            array(
646
-                'callback'        => array(
647
-                    'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
648
-                    'handleRequestToggleCheckin',
649
-                ),
650
-                'methods'         => WP_REST_Server::CREATABLE,
651
-                'hidden_endpoint' => $hidden_endpoint,
652
-                'args'            => array(
653
-                    'force' => array(
654
-                        'required'    => false,
655
-                        'default'     => false,
656
-                        'description' => __(
657
-                        // @codingStandardsIgnoreStart
658
-                            'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
659
-                            // @codingStandardsIgnoreEnd
660
-                            'event_espresso'
661
-                        ),
662
-                    ),
663
-                ),
664
-                'callback_args'   => array($version),
665
-            ),
666
-        );
667
-        return apply_filters(
668
-            'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
669
-            $this_versions_routes,
670
-            $version,
671
-            $hidden_endpoint
672
-        );
673
-    }
674
-
675
-
676
-    /**
677
-     * Gets the query params that can be used when request one or many
678
-     *
679
-     * @param EEM_Base $model
680
-     * @param string   $version
681
-     * @return array
682
-     */
683
-    protected function _get_response_selection_query_params(\EEM_Base $model, $version)
684
-    {
685
-        return apply_filters(
686
-            'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
687
-            array(
688
-                'include'   => array(
689
-                    'required' => false,
690
-                    'default'  => '*',
691
-                    'type'     => 'string',
692
-                ),
693
-                'calculate' => array(
694
-                    'required'          => false,
695
-                    'default'           => '',
696
-                    'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
697
-                    'type'              => 'string',
698
-                    // because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
699
-                    // freaks out. We'll just validate this argument while handling the request
700
-                    'validate_callback' => null,
701
-                    'sanitize_callback' => null,
702
-                ),
703
-            ),
704
-            $model,
705
-            $version
706
-        );
707
-    }
708
-
709
-
710
-    /**
711
-     * Gets the parameters acceptable for delete requests
712
-     *
713
-     * @param \EEM_Base $model
714
-     * @param string    $version
715
-     * @return array
716
-     */
717
-    protected function _get_delete_query_params(\EEM_Base $model, $version)
718
-    {
719
-        $params_for_delete = array(
720
-            'allow_blocking' => array(
721
-                'required' => false,
722
-                'default'  => true,
723
-                'type'     => 'boolean',
724
-            ),
725
-        );
726
-        $params_for_delete['force'] = array(
727
-            'required' => false,
728
-            'default'  => false,
729
-            'type'     => 'boolean',
730
-        );
731
-        return apply_filters(
732
-            'FHEE__EED_Core_Rest_Api___get_delete_query_params',
733
-            $params_for_delete,
734
-            $model,
735
-            $version
736
-        );
737
-    }
738
-
739
-
740
-    /**
741
-     * Gets info about reading query params that are acceptable
742
-     *
743
-     * @param \EEM_Base $model eg 'Event' or 'Venue'
744
-     * @param  string   $version
745
-     * @return array    describing the args acceptable when querying this model
746
-     * @throws EE_Error
747
-     */
748
-    protected function _get_read_query_params(\EEM_Base $model, $version)
749
-    {
750
-        $default_orderby = array();
751
-        foreach ($model->get_combined_primary_key_fields() as $key_field) {
752
-            $default_orderby[ $key_field->get_name() ] = 'ASC';
753
-        }
754
-        return array_merge(
755
-            $this->_get_response_selection_query_params($model, $version),
756
-            array(
757
-                'where'    => array(
758
-                    'required'          => false,
759
-                    'default'           => array(),
760
-                    'type'              => 'object',
761
-                    // because we accept an almost infinite list of possible where conditions, WP
762
-                    // core validation and sanitization freaks out. We'll just validate this argument
763
-                    // while handling the request
764
-                    'validate_callback' => null,
765
-                    'sanitize_callback' => null,
766
-                ),
767
-                'limit'    => array(
768
-                    'required'          => false,
769
-                    'default'           => EED_Core_Rest_Api::get_default_query_limit(),
770
-                    'type'              => array(
771
-                        'array',
772
-                        'string',
773
-                        'integer',
774
-                    ),
775
-                    // because we accept a variety of types, WP core validation and sanitization
776
-                    // freaks out. We'll just validate this argument while handling the request
777
-                    'validate_callback' => null,
778
-                    'sanitize_callback' => null,
779
-                ),
780
-                'order_by' => array(
781
-                    'required'          => false,
782
-                    'default'           => $default_orderby,
783
-                    'type'              => array(
784
-                        'object',
785
-                        'string',
786
-                    ),// because we accept a variety of types, WP core validation and sanitization
787
-                    // freaks out. We'll just validate this argument while handling the request
788
-                    'validate_callback' => null,
789
-                    'sanitize_callback' => null,
790
-                ),
791
-                'group_by' => array(
792
-                    'required'          => false,
793
-                    'default'           => null,
794
-                    'type'              => array(
795
-                        'object',
796
-                        'string',
797
-                    ),
798
-                    // because we accept  an almost infinite list of possible groupings,
799
-                    // WP core validation and sanitization
800
-                    // freaks out. We'll just validate this argument while handling the request
801
-                    'validate_callback' => null,
802
-                    'sanitize_callback' => null,
803
-                ),
804
-                'having'   => array(
805
-                    'required'          => false,
806
-                    'default'           => null,
807
-                    'type'              => 'object',
808
-                    // because we accept an almost infinite list of possible where conditions, WP
809
-                    // core validation and sanitization freaks out. We'll just validate this argument
810
-                    // while handling the request
811
-                    'validate_callback' => null,
812
-                    'sanitize_callback' => null,
813
-                ),
814
-                'caps'     => array(
815
-                    'required' => false,
816
-                    'default'  => EEM_Base::caps_read,
817
-                    'type'     => 'string',
818
-                    'enum'     => array(
819
-                        EEM_Base::caps_read,
820
-                        EEM_Base::caps_read_admin,
821
-                        EEM_Base::caps_edit,
822
-                        EEM_Base::caps_delete,
823
-                    ),
824
-                ),
825
-            )
826
-        );
827
-    }
828
-
829
-
830
-    /**
831
-     * Gets parameter information for a model regarding writing data
832
-     *
833
-     * @param string           $model_name
834
-     * @param ModelVersionInfo $model_version_info
835
-     * @param boolean          $create                                       whether this is for request to create (in
836
-     *                                                                       which case we need all required params) or
837
-     *                                                                       just to update (in which case we don't
838
-     *                                                                       need those on every request)
839
-     * @return array
840
-     */
841
-    protected function _get_write_params(
842
-        $model_name,
843
-        ModelVersionInfo $model_version_info,
844
-        $create = false
845
-    ) {
846
-        $model = EE_Registry::instance()->load_model($model_name);
847
-        $fields = $model_version_info->fieldsOnModelInThisVersion($model);
848
-        $args_info = array();
849
-        foreach ($fields as $field_name => $field_obj) {
850
-            if ($field_obj->is_auto_increment()) {
851
-                // totally ignore auto increment IDs
852
-                continue;
853
-            }
854
-            $arg_info = $field_obj->getSchema();
855
-            $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
856
-            $arg_info['required'] = $required;
857
-            // remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
858
-            unset($arg_info['readonly']);
859
-            $schema_properties = $field_obj->getSchemaProperties();
860
-            if (isset($schema_properties['raw'])
861
-                && $field_obj->getSchemaType() === 'object'
862
-            ) {
863
-                // if there's a "raw" form of this argument, use those properties instead
864
-                $arg_info = array_replace(
865
-                    $arg_info,
866
-                    $schema_properties['raw']
867
-                );
868
-            }
869
-            $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
870
-                $field_obj,
871
-                $field_obj->get_default_value(),
872
-                $model_version_info->requestedVersion()
873
-            );
874
-            // we do our own validation and sanitization within the controller
875
-            if (function_exists('rest_validate_value_from_schema')) {
876
-                $sanitize_callback = array(
877
-                    'EED_Core_Rest_Api',
878
-                    'default_sanitize_callback',
879
-                );
880
-            } else {
881
-                $sanitize_callback = null;
882
-            }
883
-            $arg_info['sanitize_callback'] = $sanitize_callback;
884
-            $args_info[ $field_name ] = $arg_info;
885
-            if ($field_obj instanceof EE_Datetime_Field) {
886
-                $gmt_arg_info = $arg_info;
887
-                $gmt_arg_info['description'] = sprintf(
888
-                    esc_html__(
889
-                        '%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
890
-                        'event_espresso'
891
-                    ),
892
-                    $field_obj->get_nicename(),
893
-                    $field_name
894
-                );
895
-                $args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
896
-            }
897
-        }
898
-        return $args_info;
899
-    }
900
-
901
-
902
-    /**
903
-     * Replacement for WP API's 'rest_parse_request_arg'.
904
-     * If the value is blank but not required, don't bother validating it.
905
-     * Also, it uses our email validation instead of WP API's default.
906
-     *
907
-     * @param                 $value
908
-     * @param WP_REST_Request $request
909
-     * @param                 $param
910
-     * @return bool|true|WP_Error
911
-     * @throws InvalidArgumentException
912
-     * @throws InvalidInterfaceException
913
-     * @throws InvalidDataTypeException
914
-     */
915
-    public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
916
-    {
917
-        $attributes = $request->get_attributes();
918
-        if (! isset($attributes['args'][ $param ])
919
-            || ! is_array($attributes['args'][ $param ])) {
920
-            $validation_result = true;
921
-        } else {
922
-            $args = $attributes['args'][ $param ];
923
-            if ((
924
-                    $value === ''
925
-                    || $value === null
926
-                )
927
-                && (! isset($args['required'])
928
-                    || $args['required'] === false
929
-                )
930
-            ) {
931
-                // not required and not provided? that's cool
932
-                $validation_result = true;
933
-            } elseif (isset($args['format'])
934
-                      && $args['format'] === 'email'
935
-            ) {
936
-                $validation_result = true;
937
-                if (! self::_validate_email($value)) {
938
-                    $validation_result = new WP_Error(
939
-                        'rest_invalid_param',
940
-                        esc_html__(
941
-                            'The email address is not valid or does not exist.',
942
-                            'event_espresso'
943
-                        )
944
-                    );
945
-                }
946
-            } else {
947
-                $validation_result = rest_validate_value_from_schema($value, $args, $param);
948
-            }
949
-        }
950
-        if (is_wp_error($validation_result)) {
951
-            return $validation_result;
952
-        }
953
-        return rest_sanitize_request_arg($value, $request, $param);
954
-    }
955
-
956
-
957
-    /**
958
-     * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
959
-     *
960
-     * @param $email
961
-     * @return bool
962
-     * @throws InvalidArgumentException
963
-     * @throws InvalidInterfaceException
964
-     * @throws InvalidDataTypeException
965
-     */
966
-    protected static function _validate_email($email)
967
-    {
968
-        try {
969
-            EmailAddressFactory::create($email);
970
-            return true;
971
-        } catch (EmailValidationException $e) {
972
-            return false;
973
-        }
974
-    }
975
-
976
-
977
-    /**
978
-     * Gets routes for the config
979
-     *
980
-     * @return array @see _register_model_routes
981
-     * @deprecated since version 4.9.1
982
-     */
983
-    protected function _register_config_routes()
984
-    {
985
-        $config_routes = array();
986
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
987
-            $config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
988
-                $version,
989
-                $hidden_endpoint
990
-            );
991
-        }
992
-        return $config_routes;
993
-    }
994
-
995
-
996
-    /**
997
-     * Gets routes for the config for the specified version
998
-     *
999
-     * @param string  $version
1000
-     * @param boolean $hidden_endpoint
1001
-     * @return array
1002
-     */
1003
-    protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1004
-    {
1005
-        return array(
1006
-            'config'    => array(
1007
-                array(
1008
-                    'callback'        => array(
1009
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1010
-                        'handleRequest',
1011
-                    ),
1012
-                    'methods'         => WP_REST_Server::READABLE,
1013
-                    'hidden_endpoint' => $hidden_endpoint,
1014
-                    'callback_args'   => array($version),
1015
-                ),
1016
-            ),
1017
-            'site_info' => array(
1018
-                array(
1019
-                    'callback'        => array(
1020
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1021
-                        'handleRequestSiteInfo',
1022
-                    ),
1023
-                    'methods'         => WP_REST_Server::READABLE,
1024
-                    'hidden_endpoint' => $hidden_endpoint,
1025
-                    'callback_args'   => array($version),
1026
-                ),
1027
-            ),
1028
-        );
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * Gets the meta info routes
1034
-     *
1035
-     * @return array @see _register_model_routes
1036
-     * @deprecated since version 4.9.1
1037
-     */
1038
-    protected function _register_meta_routes()
1039
-    {
1040
-        $meta_routes = array();
1041
-        foreach (self::versions_served() as $version => $hidden_endpoint) {
1042
-            $meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1043
-                $version,
1044
-                $hidden_endpoint
1045
-            );
1046
-        }
1047
-        return $meta_routes;
1048
-    }
1049
-
1050
-
1051
-    /**
1052
-     * @param string  $version
1053
-     * @param boolean $hidden_endpoint
1054
-     * @return array
1055
-     */
1056
-    protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1057
-    {
1058
-        return array(
1059
-            'resources' => array(
1060
-                array(
1061
-                    'callback'        => array(
1062
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1063
-                        'handleRequestModelsMeta',
1064
-                    ),
1065
-                    'methods'         => WP_REST_Server::READABLE,
1066
-                    'hidden_endpoint' => $hidden_endpoint,
1067
-                    'callback_args'   => array($version),
1068
-                ),
1069
-            ),
1070
-        );
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * Tries to hide old 4.6 endpoints from the
1076
-     *
1077
-     * @param array $route_data
1078
-     * @return array
1079
-     * @throws \EE_Error
1080
-     */
1081
-    public static function hide_old_endpoints($route_data)
1082
-    {
1083
-        // allow API clients to override which endpoints get hidden, in case
1084
-        // they want to discover particular endpoints
1085
-        // also, we don't have access to the request so we have to just grab it from the superglobal
1086
-        $force_show_ee_namespace = ltrim(
1087
-            EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1088
-            '/'
1089
-        );
1090
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1091
-            foreach ($relative_urls as $resource_name => $endpoints) {
1092
-                foreach ($endpoints as $key => $endpoint) {
1093
-                    // skip schema and other route options
1094
-                    if (! is_numeric($key)) {
1095
-                        continue;
1096
-                    }
1097
-                    // by default, hide "hidden_endpoint"s, unless the request indicates
1098
-                    // to $force_show_ee_namespace, in which case only show that one
1099
-                    // namespace's endpoints (and hide all others)
1100
-                    if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1101
-                        || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1102
-                    ) {
1103
-                        $full_route = '/' . ltrim($namespace, '/');
1104
-                        $full_route .= '/' . ltrim($resource_name, '/');
1105
-                        unset($route_data[ $full_route ]);
1106
-                    }
1107
-                }
1108
-            }
1109
-        }
1110
-        return $route_data;
1111
-    }
1112
-
1113
-
1114
-    /**
1115
-     * Returns an array describing which versions of core support serving requests for.
1116
-     * Keys are core versions' major and minor version, and values are the
1117
-     * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1118
-     * data by just removing a few models and fields from the responses. However, 4.15 might remove
1119
-     * the answers table entirely, in which case it would be very difficult for
1120
-     * it to serve 4.6-style responses.
1121
-     * Versions of core that are missing from this array are unknowns.
1122
-     * previous ver
1123
-     *
1124
-     * @return array
1125
-     */
1126
-    public static function version_compatibilities()
1127
-    {
1128
-        return apply_filters(
1129
-            'FHEE__EED_Core_REST_API__version_compatibilities',
1130
-            array(
1131
-                '4.8.29' => '4.8.29',
1132
-                '4.8.33' => '4.8.29',
1133
-                '4.8.34' => '4.8.29',
1134
-                '4.8.36' => '4.8.29',
1135
-            )
1136
-        );
1137
-    }
1138
-
1139
-
1140
-    /**
1141
-     * Gets the latest API version served. Eg if there
1142
-     * are two versions served of the API, 4.8.29 and 4.8.32, and
1143
-     * we are on core version 4.8.34, it will return the string "4.8.32"
1144
-     *
1145
-     * @return string
1146
-     */
1147
-    public static function latest_rest_api_version()
1148
-    {
1149
-        $versions_served = \EED_Core_Rest_Api::versions_served();
1150
-        $versions_served_keys = array_keys($versions_served);
1151
-        return end($versions_served_keys);
1152
-    }
1153
-
1154
-
1155
-    /**
1156
-     * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1157
-     * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1158
-     * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1159
-     * We also indicate whether or not this version should be put in the index or not
1160
-     *
1161
-     * @return array keys are API version numbers (just major and minor numbers), and values
1162
-     * are whether or not they should be hidden
1163
-     */
1164
-    public static function versions_served()
1165
-    {
1166
-        $versions_served = array();
1167
-        $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1168
-        $lowest_compatible_version = end($possibly_served_versions);
1169
-        reset($possibly_served_versions);
1170
-        $versions_served_historically = array_keys($possibly_served_versions);
1171
-        $latest_version = end($versions_served_historically);
1172
-        reset($versions_served_historically);
1173
-        // for each version of core we have ever served:
1174
-        foreach ($versions_served_historically as $key_versioned_endpoint) {
1175
-            // if it's not above the current core version, and it's compatible with the current version of core
1176
-            if ($key_versioned_endpoint === $latest_version) {
1177
-                // don't hide the latest version in the index
1178
-                $versions_served[ $key_versioned_endpoint ] = false;
1179
-            } elseif ($key_versioned_endpoint >= $lowest_compatible_version
1180
-                && $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1181
-            ) {
1182
-                // include, but hide, previous versions which are still supported
1183
-                $versions_served[ $key_versioned_endpoint ] = true;
1184
-            } elseif (apply_filters(
1185
-                'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1186
-                false,
1187
-                $possibly_served_versions
1188
-            )) {
1189
-                // if a version is no longer supported, don't include it in index or list of versions served
1190
-                $versions_served[ $key_versioned_endpoint ] = true;
1191
-            }
1192
-        }
1193
-        return $versions_served;
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * Gets the major and minor version of EE core's version string
1199
-     *
1200
-     * @return string
1201
-     */
1202
-    public static function core_version()
1203
-    {
1204
-        return apply_filters(
1205
-            'FHEE__EED_Core_REST_API__core_version',
1206
-            implode(
1207
-                '.',
1208
-                array_slice(
1209
-                    explode(
1210
-                        '.',
1211
-                        espresso_version()
1212
-                    ),
1213
-                    0,
1214
-                    3
1215
-                )
1216
-            )
1217
-        );
1218
-    }
1219
-
1220
-
1221
-    /**
1222
-     * Gets the default limit that should be used when querying for resources
1223
-     *
1224
-     * @return int
1225
-     */
1226
-    public static function get_default_query_limit()
1227
-    {
1228
-        // we actually don't use a const because we want folks to always use
1229
-        // this method, not the const directly
1230
-        return apply_filters(
1231
-            'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1232
-            50
1233
-        );
1234
-    }
1235
-
1236
-
1237
-    /**
1238
-     *    run - initial module setup
1239
-     *
1240
-     * @access    public
1241
-     * @param  WP $WP
1242
-     * @return    void
1243
-     */
1244
-    public function run($WP)
1245
-    {
1246
-    }
26
+	const ee_api_namespace = Domain::API_NAMESPACE;
27
+
28
+	const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
29
+
30
+	const saved_routes_option_names = 'ee_core_routes';
31
+
32
+	/**
33
+	 * string used in _links response bodies to make them globally unique.
34
+	 *
35
+	 * @see http://v2.wp-api.org/extending/linking/
36
+	 */
37
+	const ee_api_link_namespace = 'https://api.eventespresso.com/';
38
+
39
+	/**
40
+	 * @var CalculatedModelFields
41
+	 */
42
+	protected static $_field_calculator;
43
+
44
+
45
+	/**
46
+	 * @return EED_Core_Rest_Api|EED_Module
47
+	 */
48
+	public static function instance()
49
+	{
50
+		self::$_field_calculator = LoaderFactory::getLoader()->load('EventEspresso\core\libraries\rest_api\CalculatedModelFields');
51
+		return parent::get_instance(__CLASS__);
52
+	}
53
+
54
+
55
+	/**
56
+	 *    set_hooks - for hooking into EE Core, other modules, etc
57
+	 *
58
+	 * @access    public
59
+	 * @return    void
60
+	 */
61
+	public static function set_hooks()
62
+	{
63
+		self::set_hooks_both();
64
+	}
65
+
66
+
67
+	/**
68
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
69
+	 *
70
+	 * @access    public
71
+	 * @return    void
72
+	 */
73
+	public static function set_hooks_admin()
74
+	{
75
+		self::set_hooks_both();
76
+	}
77
+
78
+
79
+	public static function set_hooks_both()
80
+	{
81
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'register_routes'), 10);
82
+		add_action('rest_api_init', array('EED_Core_Rest_Api', 'set_hooks_rest_api'), 5);
83
+		add_filter('rest_route_data', array('EED_Core_Rest_Api', 'hide_old_endpoints'), 10, 2);
84
+		add_filter(
85
+			'rest_index',
86
+			array('EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex')
87
+		);
88
+		EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
89
+	}
90
+
91
+
92
+	/**
93
+	 * sets up hooks which only need to be included as part of REST API requests;
94
+	 * other requests like to the frontend or admin etc don't need them
95
+	 *
96
+	 * @throws \EE_Error
97
+	 */
98
+	public static function set_hooks_rest_api()
99
+	{
100
+		// set hooks which account for changes made to the API
101
+		EED_Core_Rest_Api::_set_hooks_for_changes();
102
+	}
103
+
104
+
105
+	/**
106
+	 * public wrapper of _set_hooks_for_changes.
107
+	 * Loads all the hooks which make requests to old versions of the API
108
+	 * appear the same as they always did
109
+	 *
110
+	 * @throws EE_Error
111
+	 */
112
+	public static function set_hooks_for_changes()
113
+	{
114
+		self::_set_hooks_for_changes();
115
+	}
116
+
117
+
118
+	/**
119
+	 * Loads all the hooks which make requests to old versions of the API
120
+	 * appear the same as they always did
121
+	 *
122
+	 * @throws EE_Error
123
+	 */
124
+	protected static function _set_hooks_for_changes()
125
+	{
126
+		$folder_contents = EEH_File::get_contents_of_folders(array(EE_LIBRARIES . 'rest_api' . DS . 'changes'), false);
127
+		foreach ($folder_contents as $classname_in_namespace => $filepath) {
128
+			// ignore the base parent class
129
+			// and legacy named classes
130
+			if ($classname_in_namespace === 'ChangesInBase'
131
+				|| strpos($classname_in_namespace, 'Changes_In_') === 0
132
+			) {
133
+				continue;
134
+			}
135
+			$full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
136
+			if (class_exists($full_classname)) {
137
+				$instance_of_class = new $full_classname;
138
+				if ($instance_of_class instanceof ChangesInBase) {
139
+					$instance_of_class->setHooks();
140
+				}
141
+			}
142
+		}
143
+	}
144
+
145
+
146
+	/**
147
+	 * Filters the WP routes to add our EE-related ones. This takes a bit of time
148
+	 * so we actually prefer to only do it when an EE plugin is activated or upgraded
149
+	 *
150
+	 * @throws \EE_Error
151
+	 */
152
+	public static function register_routes()
153
+	{
154
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
155
+			foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
156
+				/**
157
+				 * @var array     $data_for_multiple_endpoints numerically indexed array
158
+				 *                                         but can also contain route options like {
159
+				 * @type array    $schema                      {
160
+				 * @type callable $schema_callback
161
+				 * @type array    $callback_args               arguments that will be passed to the callback, after the
162
+				 * WP_REST_Request of course
163
+				 * }
164
+				 * }
165
+				 */
166
+				// when registering routes, register all the endpoints' data at the same time
167
+				$multiple_endpoint_args = array();
168
+				foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
169
+					/**
170
+					 * @var array     $data_for_single_endpoint {
171
+					 * @type callable $callback
172
+					 * @type string methods
173
+					 * @type array args
174
+					 * @type array _links
175
+					 * @type array    $callback_args            arguments that will be passed to the callback, after the
176
+					 * WP_REST_Request of course
177
+					 * }
178
+					 */
179
+					// skip route options
180
+					if (! is_numeric($endpoint_key)) {
181
+						continue;
182
+					}
183
+					if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
184
+						throw new EE_Error(
185
+							esc_html__(
186
+							// @codingStandardsIgnoreStart
187
+								'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
188
+								// @codingStandardsIgnoreEnd
189
+								'event_espresso'
190
+							)
191
+						);
192
+					}
193
+					$callback = $data_for_single_endpoint['callback'];
194
+					$single_endpoint_args = array(
195
+						'methods' => $data_for_single_endpoint['methods'],
196
+						'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
197
+							: array(),
198
+					);
199
+					if (isset($data_for_single_endpoint['_links'])) {
200
+						$single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
201
+					}
202
+					if (isset($data_for_single_endpoint['callback_args'])) {
203
+						$callback_args = $data_for_single_endpoint['callback_args'];
204
+						$single_endpoint_args['callback'] = function (\WP_REST_Request $request) use (
205
+							$callback,
206
+							$callback_args
207
+						) {
208
+							array_unshift($callback_args, $request);
209
+							return call_user_func_array(
210
+								$callback,
211
+								$callback_args
212
+							);
213
+						};
214
+					} else {
215
+						$single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
216
+					}
217
+					$multiple_endpoint_args[] = $single_endpoint_args;
218
+				}
219
+				if (isset($data_for_multiple_endpoints['schema'])) {
220
+					$schema_route_data = $data_for_multiple_endpoints['schema'];
221
+					$schema_callback = $schema_route_data['schema_callback'];
222
+					$callback_args = $schema_route_data['callback_args'];
223
+					$multiple_endpoint_args['schema'] = function () use ($schema_callback, $callback_args) {
224
+						return call_user_func_array(
225
+							$schema_callback,
226
+							$callback_args
227
+						);
228
+					};
229
+				}
230
+				register_rest_route(
231
+					$namespace,
232
+					$relative_route,
233
+					$multiple_endpoint_args
234
+				);
235
+			}
236
+		}
237
+	}
238
+
239
+
240
+	/**
241
+	 * Checks if there was a version change or something that merits invalidating the cached
242
+	 * route data. If so, invalidates the cached route data so that it gets refreshed
243
+	 * next time the WP API is used
244
+	 */
245
+	public static function invalidate_cached_route_data_on_version_change()
246
+	{
247
+		if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
248
+			EED_Core_Rest_Api::invalidate_cached_route_data();
249
+		}
250
+		foreach (EE_Registry::instance()->addons as $addon) {
251
+			if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
252
+				EED_Core_Rest_Api::invalidate_cached_route_data();
253
+			}
254
+		}
255
+	}
256
+
257
+
258
+	/**
259
+	 * Removes the cached route data so it will get refreshed next time the WP API is used
260
+	 */
261
+	public static function invalidate_cached_route_data()
262
+	{
263
+		// delete the saved EE REST API routes
264
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
265
+			delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
266
+		}
267
+	}
268
+
269
+
270
+	/**
271
+	 * Gets the EE route data
272
+	 *
273
+	 * @return array top-level key is the namespace, next-level key is the route and its value is array{
274
+	 * @throws \EE_Error
275
+	 * @type string|array $callback
276
+	 * @type string       $methods
277
+	 * @type boolean      $hidden_endpoint
278
+	 * }
279
+	 */
280
+	public static function get_ee_route_data()
281
+	{
282
+		$ee_routes = array();
283
+		foreach (self::versions_served() as $version => $hidden_endpoints) {
284
+			$ee_routes[ self::ee_api_namespace . $version ] = self::_get_ee_route_data_for_version(
285
+				$version,
286
+				$hidden_endpoints
287
+			);
288
+		}
289
+		return $ee_routes;
290
+	}
291
+
292
+
293
+	/**
294
+	 * Gets the EE route data from the wp options if it exists already,
295
+	 * otherwise re-generates it and saves it to the option
296
+	 *
297
+	 * @param string  $version
298
+	 * @param boolean $hidden_endpoints
299
+	 * @return array
300
+	 * @throws \EE_Error
301
+	 */
302
+	protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
303
+	{
304
+		$ee_routes = get_option(self::saved_routes_option_names . $version, null);
305
+		if (! $ee_routes || (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE)) {
306
+			$ee_routes = self::_save_ee_route_data_for_version($version, $hidden_endpoints);
307
+		}
308
+		return $ee_routes;
309
+	}
310
+
311
+
312
+	/**
313
+	 * Saves the EE REST API route data to a wp option and returns it
314
+	 *
315
+	 * @param string  $version
316
+	 * @param boolean $hidden_endpoints
317
+	 * @return mixed|null
318
+	 * @throws \EE_Error
319
+	 */
320
+	protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
321
+	{
322
+		$instance = self::instance();
323
+		$routes = apply_filters(
324
+			'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
325
+			array_replace_recursive(
326
+				$instance->_get_config_route_data_for_version($version, $hidden_endpoints),
327
+				$instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
328
+				$instance->_get_model_route_data_for_version($version, $hidden_endpoints),
329
+				$instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
330
+			)
331
+		);
332
+		$option_name = self::saved_routes_option_names . $version;
333
+		if (get_option($option_name)) {
334
+			update_option($option_name, $routes, true);
335
+		} else {
336
+			add_option($option_name, $routes, null, 'no');
337
+		}
338
+		return $routes;
339
+	}
340
+
341
+
342
+	/**
343
+	 * Calculates all the EE routes and saves it to a WordPress option so we don't
344
+	 * need to calculate it on every request
345
+	 *
346
+	 * @deprecated since version 4.9.1
347
+	 * @return void
348
+	 */
349
+	public static function save_ee_routes()
350
+	{
351
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
352
+			$instance = self::instance();
353
+			$routes = apply_filters(
354
+				'EED_Core_Rest_Api__save_ee_routes__routes',
355
+				array_replace_recursive(
356
+					$instance->_register_config_routes(),
357
+					$instance->_register_meta_routes(),
358
+					$instance->_register_model_routes(),
359
+					$instance->_register_rpc_routes()
360
+				)
361
+			);
362
+			update_option(self::saved_routes_option_names, $routes, true);
363
+		}
364
+	}
365
+
366
+
367
+	/**
368
+	 * Gets all the route information relating to EE models
369
+	 *
370
+	 * @return array @see get_ee_route_data
371
+	 * @deprecated since version 4.9.1
372
+	 */
373
+	protected function _register_model_routes()
374
+	{
375
+		$model_routes = array();
376
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
377
+			$model_routes[ EED_Core_Rest_Api::ee_api_namespace
378
+						   . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
379
+		}
380
+		return $model_routes;
381
+	}
382
+
383
+
384
+	/**
385
+	 * Decides whether or not to add write endpoints for this model.
386
+	 *
387
+	 * Currently, this defaults to exclude all global tables and models
388
+	 * which would allow inserting WP core data (we don't want to duplicate
389
+	 * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
390
+	 *
391
+	 * @param EEM_Base $model
392
+	 * @return bool
393
+	 */
394
+	public static function should_have_write_endpoints(EEM_Base $model)
395
+	{
396
+		if ($model->is_wp_core_model()) {
397
+			return false;
398
+		}
399
+		foreach ($model->get_tables() as $table) {
400
+			if ($table->is_global()) {
401
+				return false;
402
+			}
403
+		}
404
+		return true;
405
+	}
406
+
407
+
408
+	/**
409
+	 * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
410
+	 * in this versioned namespace of EE4
411
+	 *
412
+	 * @param $version
413
+	 * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
414
+	 */
415
+	public static function model_names_with_plural_routes($version)
416
+	{
417
+		$model_version_info = new ModelVersionInfo($version);
418
+		$models_to_register = $model_version_info->modelsForRequestedVersion();
419
+		// let's not bother having endpoints for extra metas
420
+		unset(
421
+			$models_to_register['Extra_Meta'],
422
+			$models_to_register['Extra_Join'],
423
+			$models_to_register['Post_Meta']
424
+		);
425
+		return apply_filters(
426
+			'FHEE__EED_Core_REST_API___register_model_routes',
427
+			$models_to_register
428
+		);
429
+	}
430
+
431
+
432
+	/**
433
+	 * Gets the route data for EE models in the specified version
434
+	 *
435
+	 * @param string  $version
436
+	 * @param boolean $hidden_endpoint
437
+	 * @return array
438
+	 * @throws EE_Error
439
+	 */
440
+	protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
441
+	{
442
+		$model_routes = array();
443
+		$model_version_info = new ModelVersionInfo($version);
444
+		foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
445
+			$model = \EE_Registry::instance()->load_model($model_name);
446
+			// if this isn't a valid model then let's skip iterate to the next item in the loop.
447
+			if (! $model instanceof EEM_Base) {
448
+				continue;
449
+			}
450
+			// yes we could just register one route for ALL models, but then they wouldn't show up in the index
451
+			$plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
452
+			$singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
453
+			$model_routes[ $plural_model_route ] = array(
454
+				array(
455
+					'callback'        => array(
456
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
457
+						'handleRequestGetAll',
458
+					),
459
+					'callback_args'   => array($version, $model_name),
460
+					'methods'         => WP_REST_Server::READABLE,
461
+					'hidden_endpoint' => $hidden_endpoint,
462
+					'args'            => $this->_get_read_query_params($model, $version),
463
+					'_links'          => array(
464
+						'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
465
+					),
466
+				),
467
+				'schema' => array(
468
+					'schema_callback' => array(
469
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
470
+						'handleSchemaRequest',
471
+					),
472
+					'callback_args'   => array($version, $model_name),
473
+				),
474
+			);
475
+			$model_routes[ $singular_model_route ] = array(
476
+				array(
477
+					'callback'        => array(
478
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
479
+						'handleRequestGetOne',
480
+					),
481
+					'callback_args'   => array($version, $model_name),
482
+					'methods'         => WP_REST_Server::READABLE,
483
+					'hidden_endpoint' => $hidden_endpoint,
484
+					'args'            => $this->_get_response_selection_query_params($model, $version),
485
+				),
486
+			);
487
+			if (apply_filters(
488
+				'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
489
+				EED_Core_Rest_Api::should_have_write_endpoints($model),
490
+				$model
491
+			)) {
492
+				$model_routes[ $plural_model_route ][] = array(
493
+					'callback'        => array(
494
+						'EventEspresso\core\libraries\rest_api\controllers\model\Write',
495
+						'handleRequestInsert',
496
+					),
497
+					'callback_args'   => array($version, $model_name),
498
+					'methods'         => WP_REST_Server::CREATABLE,
499
+					'hidden_endpoint' => $hidden_endpoint,
500
+					'args'            => $this->_get_write_params($model_name, $model_version_info, true),
501
+				);
502
+				$model_routes[ $singular_model_route ] = array_merge(
503
+					$model_routes[ $singular_model_route ],
504
+					array(
505
+						array(
506
+							'callback'        => array(
507
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
508
+								'handleRequestUpdate',
509
+							),
510
+							'callback_args'   => array($version, $model_name),
511
+							'methods'         => WP_REST_Server::EDITABLE,
512
+							'hidden_endpoint' => $hidden_endpoint,
513
+							'args'            => $this->_get_write_params($model_name, $model_version_info),
514
+						),
515
+						array(
516
+							'callback'        => array(
517
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
518
+								'handleRequestDelete',
519
+							),
520
+							'callback_args'   => array($version, $model_name),
521
+							'methods'         => WP_REST_Server::DELETABLE,
522
+							'hidden_endpoint' => $hidden_endpoint,
523
+							'args'            => $this->_get_delete_query_params($model, $version),
524
+						),
525
+					)
526
+				);
527
+			}
528
+			foreach ($model->relation_settings() as $relation_name => $relation_obj) {
529
+				$related_route = EED_Core_Rest_Api::get_relation_route_via(
530
+					$model,
531
+					'(?P<id>[^\/]+)',
532
+					$relation_obj
533
+				);
534
+				$endpoints = array(
535
+					array(
536
+						'callback'        => array(
537
+							'EventEspresso\core\libraries\rest_api\controllers\model\Read',
538
+							'handleRequestGetRelated',
539
+						),
540
+						'callback_args'   => array($version, $model_name, $relation_name),
541
+						'methods'         => WP_REST_Server::READABLE,
542
+						'hidden_endpoint' => $hidden_endpoint,
543
+						'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
544
+					),
545
+				);
546
+				$model_routes[ $related_route ] = $endpoints;
547
+			}
548
+		}
549
+		return $model_routes;
550
+	}
551
+
552
+
553
+	/**
554
+	 * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
555
+	 * excluding the preceding slash.
556
+	 * Eg you pass get_plural_route_to('Event') = 'events'
557
+	 *
558
+	 * @param EEM_Base $model
559
+	 * @return string
560
+	 */
561
+	public static function get_collection_route(EEM_Base $model)
562
+	{
563
+		return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
564
+	}
565
+
566
+
567
+	/**
568
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
569
+	 * excluding the preceding slash.
570
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
571
+	 *
572
+	 * @param EEM_Base $model eg Event or Venue
573
+	 * @param string   $id
574
+	 * @return string
575
+	 */
576
+	public static function get_entity_route($model, $id)
577
+	{
578
+		return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
579
+	}
580
+
581
+
582
+	/**
583
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
584
+	 * excluding the preceding slash.
585
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
586
+	 *
587
+	 * @param EEM_Base               $model eg Event or Venue
588
+	 * @param string                 $id
589
+	 * @param EE_Model_Relation_Base $relation_obj
590
+	 * @return string
591
+	 */
592
+	public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
593
+	{
594
+		$related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
595
+			$relation_obj->get_other_model()->get_this_model_name(),
596
+			$relation_obj
597
+		);
598
+		return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
599
+	}
600
+
601
+
602
+	/**
603
+	 * Adds onto the $relative_route the EE4 REST API versioned namespace.
604
+	 * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
605
+	 *
606
+	 * @param string $relative_route
607
+	 * @param string $version
608
+	 * @return string
609
+	 */
610
+	public static function get_versioned_route_to($relative_route, $version = '4.8.36')
611
+	{
612
+		return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
613
+	}
614
+
615
+
616
+	/**
617
+	 * Adds all the RPC-style routes (remote procedure call-like routes, ie
618
+	 * routes that don't conform to the traditional REST CRUD-style).
619
+	 *
620
+	 * @deprecated since 4.9.1
621
+	 */
622
+	protected function _register_rpc_routes()
623
+	{
624
+		$routes = array();
625
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
626
+			$routes[ self::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
627
+				$version,
628
+				$hidden_endpoint
629
+			);
630
+		}
631
+		return $routes;
632
+	}
633
+
634
+
635
+	/**
636
+	 * @param string  $version
637
+	 * @param boolean $hidden_endpoint
638
+	 * @return array
639
+	 */
640
+	protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
641
+	{
642
+		$this_versions_routes = array();
643
+		// checkin endpoint
644
+		$this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = array(
645
+			array(
646
+				'callback'        => array(
647
+					'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
648
+					'handleRequestToggleCheckin',
649
+				),
650
+				'methods'         => WP_REST_Server::CREATABLE,
651
+				'hidden_endpoint' => $hidden_endpoint,
652
+				'args'            => array(
653
+					'force' => array(
654
+						'required'    => false,
655
+						'default'     => false,
656
+						'description' => __(
657
+						// @codingStandardsIgnoreStart
658
+							'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
659
+							// @codingStandardsIgnoreEnd
660
+							'event_espresso'
661
+						),
662
+					),
663
+				),
664
+				'callback_args'   => array($version),
665
+			),
666
+		);
667
+		return apply_filters(
668
+			'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
669
+			$this_versions_routes,
670
+			$version,
671
+			$hidden_endpoint
672
+		);
673
+	}
674
+
675
+
676
+	/**
677
+	 * Gets the query params that can be used when request one or many
678
+	 *
679
+	 * @param EEM_Base $model
680
+	 * @param string   $version
681
+	 * @return array
682
+	 */
683
+	protected function _get_response_selection_query_params(\EEM_Base $model, $version)
684
+	{
685
+		return apply_filters(
686
+			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
687
+			array(
688
+				'include'   => array(
689
+					'required' => false,
690
+					'default'  => '*',
691
+					'type'     => 'string',
692
+				),
693
+				'calculate' => array(
694
+					'required'          => false,
695
+					'default'           => '',
696
+					'enum'              => self::$_field_calculator->retrieveCalculatedFieldsForModel($model),
697
+					'type'              => 'string',
698
+					// because we accept a CSV'd list of the enumerated strings, WP core validation and sanitization
699
+					// freaks out. We'll just validate this argument while handling the request
700
+					'validate_callback' => null,
701
+					'sanitize_callback' => null,
702
+				),
703
+			),
704
+			$model,
705
+			$version
706
+		);
707
+	}
708
+
709
+
710
+	/**
711
+	 * Gets the parameters acceptable for delete requests
712
+	 *
713
+	 * @param \EEM_Base $model
714
+	 * @param string    $version
715
+	 * @return array
716
+	 */
717
+	protected function _get_delete_query_params(\EEM_Base $model, $version)
718
+	{
719
+		$params_for_delete = array(
720
+			'allow_blocking' => array(
721
+				'required' => false,
722
+				'default'  => true,
723
+				'type'     => 'boolean',
724
+			),
725
+		);
726
+		$params_for_delete['force'] = array(
727
+			'required' => false,
728
+			'default'  => false,
729
+			'type'     => 'boolean',
730
+		);
731
+		return apply_filters(
732
+			'FHEE__EED_Core_Rest_Api___get_delete_query_params',
733
+			$params_for_delete,
734
+			$model,
735
+			$version
736
+		);
737
+	}
738
+
739
+
740
+	/**
741
+	 * Gets info about reading query params that are acceptable
742
+	 *
743
+	 * @param \EEM_Base $model eg 'Event' or 'Venue'
744
+	 * @param  string   $version
745
+	 * @return array    describing the args acceptable when querying this model
746
+	 * @throws EE_Error
747
+	 */
748
+	protected function _get_read_query_params(\EEM_Base $model, $version)
749
+	{
750
+		$default_orderby = array();
751
+		foreach ($model->get_combined_primary_key_fields() as $key_field) {
752
+			$default_orderby[ $key_field->get_name() ] = 'ASC';
753
+		}
754
+		return array_merge(
755
+			$this->_get_response_selection_query_params($model, $version),
756
+			array(
757
+				'where'    => array(
758
+					'required'          => false,
759
+					'default'           => array(),
760
+					'type'              => 'object',
761
+					// because we accept an almost infinite list of possible where conditions, WP
762
+					// core validation and sanitization freaks out. We'll just validate this argument
763
+					// while handling the request
764
+					'validate_callback' => null,
765
+					'sanitize_callback' => null,
766
+				),
767
+				'limit'    => array(
768
+					'required'          => false,
769
+					'default'           => EED_Core_Rest_Api::get_default_query_limit(),
770
+					'type'              => array(
771
+						'array',
772
+						'string',
773
+						'integer',
774
+					),
775
+					// because we accept a variety of types, WP core validation and sanitization
776
+					// freaks out. We'll just validate this argument while handling the request
777
+					'validate_callback' => null,
778
+					'sanitize_callback' => null,
779
+				),
780
+				'order_by' => array(
781
+					'required'          => false,
782
+					'default'           => $default_orderby,
783
+					'type'              => array(
784
+						'object',
785
+						'string',
786
+					),// because we accept a variety of types, WP core validation and sanitization
787
+					// freaks out. We'll just validate this argument while handling the request
788
+					'validate_callback' => null,
789
+					'sanitize_callback' => null,
790
+				),
791
+				'group_by' => array(
792
+					'required'          => false,
793
+					'default'           => null,
794
+					'type'              => array(
795
+						'object',
796
+						'string',
797
+					),
798
+					// because we accept  an almost infinite list of possible groupings,
799
+					// WP core validation and sanitization
800
+					// freaks out. We'll just validate this argument while handling the request
801
+					'validate_callback' => null,
802
+					'sanitize_callback' => null,
803
+				),
804
+				'having'   => array(
805
+					'required'          => false,
806
+					'default'           => null,
807
+					'type'              => 'object',
808
+					// because we accept an almost infinite list of possible where conditions, WP
809
+					// core validation and sanitization freaks out. We'll just validate this argument
810
+					// while handling the request
811
+					'validate_callback' => null,
812
+					'sanitize_callback' => null,
813
+				),
814
+				'caps'     => array(
815
+					'required' => false,
816
+					'default'  => EEM_Base::caps_read,
817
+					'type'     => 'string',
818
+					'enum'     => array(
819
+						EEM_Base::caps_read,
820
+						EEM_Base::caps_read_admin,
821
+						EEM_Base::caps_edit,
822
+						EEM_Base::caps_delete,
823
+					),
824
+				),
825
+			)
826
+		);
827
+	}
828
+
829
+
830
+	/**
831
+	 * Gets parameter information for a model regarding writing data
832
+	 *
833
+	 * @param string           $model_name
834
+	 * @param ModelVersionInfo $model_version_info
835
+	 * @param boolean          $create                                       whether this is for request to create (in
836
+	 *                                                                       which case we need all required params) or
837
+	 *                                                                       just to update (in which case we don't
838
+	 *                                                                       need those on every request)
839
+	 * @return array
840
+	 */
841
+	protected function _get_write_params(
842
+		$model_name,
843
+		ModelVersionInfo $model_version_info,
844
+		$create = false
845
+	) {
846
+		$model = EE_Registry::instance()->load_model($model_name);
847
+		$fields = $model_version_info->fieldsOnModelInThisVersion($model);
848
+		$args_info = array();
849
+		foreach ($fields as $field_name => $field_obj) {
850
+			if ($field_obj->is_auto_increment()) {
851
+				// totally ignore auto increment IDs
852
+				continue;
853
+			}
854
+			$arg_info = $field_obj->getSchema();
855
+			$required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
856
+			$arg_info['required'] = $required;
857
+			// remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
858
+			unset($arg_info['readonly']);
859
+			$schema_properties = $field_obj->getSchemaProperties();
860
+			if (isset($schema_properties['raw'])
861
+				&& $field_obj->getSchemaType() === 'object'
862
+			) {
863
+				// if there's a "raw" form of this argument, use those properties instead
864
+				$arg_info = array_replace(
865
+					$arg_info,
866
+					$schema_properties['raw']
867
+				);
868
+			}
869
+			$arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
870
+				$field_obj,
871
+				$field_obj->get_default_value(),
872
+				$model_version_info->requestedVersion()
873
+			);
874
+			// we do our own validation and sanitization within the controller
875
+			if (function_exists('rest_validate_value_from_schema')) {
876
+				$sanitize_callback = array(
877
+					'EED_Core_Rest_Api',
878
+					'default_sanitize_callback',
879
+				);
880
+			} else {
881
+				$sanitize_callback = null;
882
+			}
883
+			$arg_info['sanitize_callback'] = $sanitize_callback;
884
+			$args_info[ $field_name ] = $arg_info;
885
+			if ($field_obj instanceof EE_Datetime_Field) {
886
+				$gmt_arg_info = $arg_info;
887
+				$gmt_arg_info['description'] = sprintf(
888
+					esc_html__(
889
+						'%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
890
+						'event_espresso'
891
+					),
892
+					$field_obj->get_nicename(),
893
+					$field_name
894
+				);
895
+				$args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
896
+			}
897
+		}
898
+		return $args_info;
899
+	}
900
+
901
+
902
+	/**
903
+	 * Replacement for WP API's 'rest_parse_request_arg'.
904
+	 * If the value is blank but not required, don't bother validating it.
905
+	 * Also, it uses our email validation instead of WP API's default.
906
+	 *
907
+	 * @param                 $value
908
+	 * @param WP_REST_Request $request
909
+	 * @param                 $param
910
+	 * @return bool|true|WP_Error
911
+	 * @throws InvalidArgumentException
912
+	 * @throws InvalidInterfaceException
913
+	 * @throws InvalidDataTypeException
914
+	 */
915
+	public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
916
+	{
917
+		$attributes = $request->get_attributes();
918
+		if (! isset($attributes['args'][ $param ])
919
+			|| ! is_array($attributes['args'][ $param ])) {
920
+			$validation_result = true;
921
+		} else {
922
+			$args = $attributes['args'][ $param ];
923
+			if ((
924
+					$value === ''
925
+					|| $value === null
926
+				)
927
+				&& (! isset($args['required'])
928
+					|| $args['required'] === false
929
+				)
930
+			) {
931
+				// not required and not provided? that's cool
932
+				$validation_result = true;
933
+			} elseif (isset($args['format'])
934
+					  && $args['format'] === 'email'
935
+			) {
936
+				$validation_result = true;
937
+				if (! self::_validate_email($value)) {
938
+					$validation_result = new WP_Error(
939
+						'rest_invalid_param',
940
+						esc_html__(
941
+							'The email address is not valid or does not exist.',
942
+							'event_espresso'
943
+						)
944
+					);
945
+				}
946
+			} else {
947
+				$validation_result = rest_validate_value_from_schema($value, $args, $param);
948
+			}
949
+		}
950
+		if (is_wp_error($validation_result)) {
951
+			return $validation_result;
952
+		}
953
+		return rest_sanitize_request_arg($value, $request, $param);
954
+	}
955
+
956
+
957
+	/**
958
+	 * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
959
+	 *
960
+	 * @param $email
961
+	 * @return bool
962
+	 * @throws InvalidArgumentException
963
+	 * @throws InvalidInterfaceException
964
+	 * @throws InvalidDataTypeException
965
+	 */
966
+	protected static function _validate_email($email)
967
+	{
968
+		try {
969
+			EmailAddressFactory::create($email);
970
+			return true;
971
+		} catch (EmailValidationException $e) {
972
+			return false;
973
+		}
974
+	}
975
+
976
+
977
+	/**
978
+	 * Gets routes for the config
979
+	 *
980
+	 * @return array @see _register_model_routes
981
+	 * @deprecated since version 4.9.1
982
+	 */
983
+	protected function _register_config_routes()
984
+	{
985
+		$config_routes = array();
986
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
987
+			$config_routes[ self::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
988
+				$version,
989
+				$hidden_endpoint
990
+			);
991
+		}
992
+		return $config_routes;
993
+	}
994
+
995
+
996
+	/**
997
+	 * Gets routes for the config for the specified version
998
+	 *
999
+	 * @param string  $version
1000
+	 * @param boolean $hidden_endpoint
1001
+	 * @return array
1002
+	 */
1003
+	protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1004
+	{
1005
+		return array(
1006
+			'config'    => array(
1007
+				array(
1008
+					'callback'        => array(
1009
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1010
+						'handleRequest',
1011
+					),
1012
+					'methods'         => WP_REST_Server::READABLE,
1013
+					'hidden_endpoint' => $hidden_endpoint,
1014
+					'callback_args'   => array($version),
1015
+				),
1016
+			),
1017
+			'site_info' => array(
1018
+				array(
1019
+					'callback'        => array(
1020
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1021
+						'handleRequestSiteInfo',
1022
+					),
1023
+					'methods'         => WP_REST_Server::READABLE,
1024
+					'hidden_endpoint' => $hidden_endpoint,
1025
+					'callback_args'   => array($version),
1026
+				),
1027
+			),
1028
+		);
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * Gets the meta info routes
1034
+	 *
1035
+	 * @return array @see _register_model_routes
1036
+	 * @deprecated since version 4.9.1
1037
+	 */
1038
+	protected function _register_meta_routes()
1039
+	{
1040
+		$meta_routes = array();
1041
+		foreach (self::versions_served() as $version => $hidden_endpoint) {
1042
+			$meta_routes[ self::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1043
+				$version,
1044
+				$hidden_endpoint
1045
+			);
1046
+		}
1047
+		return $meta_routes;
1048
+	}
1049
+
1050
+
1051
+	/**
1052
+	 * @param string  $version
1053
+	 * @param boolean $hidden_endpoint
1054
+	 * @return array
1055
+	 */
1056
+	protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1057
+	{
1058
+		return array(
1059
+			'resources' => array(
1060
+				array(
1061
+					'callback'        => array(
1062
+						'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1063
+						'handleRequestModelsMeta',
1064
+					),
1065
+					'methods'         => WP_REST_Server::READABLE,
1066
+					'hidden_endpoint' => $hidden_endpoint,
1067
+					'callback_args'   => array($version),
1068
+				),
1069
+			),
1070
+		);
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * Tries to hide old 4.6 endpoints from the
1076
+	 *
1077
+	 * @param array $route_data
1078
+	 * @return array
1079
+	 * @throws \EE_Error
1080
+	 */
1081
+	public static function hide_old_endpoints($route_data)
1082
+	{
1083
+		// allow API clients to override which endpoints get hidden, in case
1084
+		// they want to discover particular endpoints
1085
+		// also, we don't have access to the request so we have to just grab it from the superglobal
1086
+		$force_show_ee_namespace = ltrim(
1087
+			EEH_Array::is_set($_REQUEST, 'force_show_ee_namespace', ''),
1088
+			'/'
1089
+		);
1090
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1091
+			foreach ($relative_urls as $resource_name => $endpoints) {
1092
+				foreach ($endpoints as $key => $endpoint) {
1093
+					// skip schema and other route options
1094
+					if (! is_numeric($key)) {
1095
+						continue;
1096
+					}
1097
+					// by default, hide "hidden_endpoint"s, unless the request indicates
1098
+					// to $force_show_ee_namespace, in which case only show that one
1099
+					// namespace's endpoints (and hide all others)
1100
+					if (($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1101
+						|| ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1102
+					) {
1103
+						$full_route = '/' . ltrim($namespace, '/');
1104
+						$full_route .= '/' . ltrim($resource_name, '/');
1105
+						unset($route_data[ $full_route ]);
1106
+					}
1107
+				}
1108
+			}
1109
+		}
1110
+		return $route_data;
1111
+	}
1112
+
1113
+
1114
+	/**
1115
+	 * Returns an array describing which versions of core support serving requests for.
1116
+	 * Keys are core versions' major and minor version, and values are the
1117
+	 * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1118
+	 * data by just removing a few models and fields from the responses. However, 4.15 might remove
1119
+	 * the answers table entirely, in which case it would be very difficult for
1120
+	 * it to serve 4.6-style responses.
1121
+	 * Versions of core that are missing from this array are unknowns.
1122
+	 * previous ver
1123
+	 *
1124
+	 * @return array
1125
+	 */
1126
+	public static function version_compatibilities()
1127
+	{
1128
+		return apply_filters(
1129
+			'FHEE__EED_Core_REST_API__version_compatibilities',
1130
+			array(
1131
+				'4.8.29' => '4.8.29',
1132
+				'4.8.33' => '4.8.29',
1133
+				'4.8.34' => '4.8.29',
1134
+				'4.8.36' => '4.8.29',
1135
+			)
1136
+		);
1137
+	}
1138
+
1139
+
1140
+	/**
1141
+	 * Gets the latest API version served. Eg if there
1142
+	 * are two versions served of the API, 4.8.29 and 4.8.32, and
1143
+	 * we are on core version 4.8.34, it will return the string "4.8.32"
1144
+	 *
1145
+	 * @return string
1146
+	 */
1147
+	public static function latest_rest_api_version()
1148
+	{
1149
+		$versions_served = \EED_Core_Rest_Api::versions_served();
1150
+		$versions_served_keys = array_keys($versions_served);
1151
+		return end($versions_served_keys);
1152
+	}
1153
+
1154
+
1155
+	/**
1156
+	 * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1157
+	 * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1158
+	 * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1159
+	 * We also indicate whether or not this version should be put in the index or not
1160
+	 *
1161
+	 * @return array keys are API version numbers (just major and minor numbers), and values
1162
+	 * are whether or not they should be hidden
1163
+	 */
1164
+	public static function versions_served()
1165
+	{
1166
+		$versions_served = array();
1167
+		$possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1168
+		$lowest_compatible_version = end($possibly_served_versions);
1169
+		reset($possibly_served_versions);
1170
+		$versions_served_historically = array_keys($possibly_served_versions);
1171
+		$latest_version = end($versions_served_historically);
1172
+		reset($versions_served_historically);
1173
+		// for each version of core we have ever served:
1174
+		foreach ($versions_served_historically as $key_versioned_endpoint) {
1175
+			// if it's not above the current core version, and it's compatible with the current version of core
1176
+			if ($key_versioned_endpoint === $latest_version) {
1177
+				// don't hide the latest version in the index
1178
+				$versions_served[ $key_versioned_endpoint ] = false;
1179
+			} elseif ($key_versioned_endpoint >= $lowest_compatible_version
1180
+				&& $key_versioned_endpoint < EED_Core_Rest_Api::core_version()
1181
+			) {
1182
+				// include, but hide, previous versions which are still supported
1183
+				$versions_served[ $key_versioned_endpoint ] = true;
1184
+			} elseif (apply_filters(
1185
+				'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1186
+				false,
1187
+				$possibly_served_versions
1188
+			)) {
1189
+				// if a version is no longer supported, don't include it in index or list of versions served
1190
+				$versions_served[ $key_versioned_endpoint ] = true;
1191
+			}
1192
+		}
1193
+		return $versions_served;
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * Gets the major and minor version of EE core's version string
1199
+	 *
1200
+	 * @return string
1201
+	 */
1202
+	public static function core_version()
1203
+	{
1204
+		return apply_filters(
1205
+			'FHEE__EED_Core_REST_API__core_version',
1206
+			implode(
1207
+				'.',
1208
+				array_slice(
1209
+					explode(
1210
+						'.',
1211
+						espresso_version()
1212
+					),
1213
+					0,
1214
+					3
1215
+				)
1216
+			)
1217
+		);
1218
+	}
1219
+
1220
+
1221
+	/**
1222
+	 * Gets the default limit that should be used when querying for resources
1223
+	 *
1224
+	 * @return int
1225
+	 */
1226
+	public static function get_default_query_limit()
1227
+	{
1228
+		// we actually don't use a const because we want folks to always use
1229
+		// this method, not the const directly
1230
+		return apply_filters(
1231
+			'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1232
+			50
1233
+		);
1234
+	}
1235
+
1236
+
1237
+	/**
1238
+	 *    run - initial module setup
1239
+	 *
1240
+	 * @access    public
1241
+	 * @param  WP $WP
1242
+	 * @return    void
1243
+	 */
1244
+	public function run($WP)
1245
+	{
1246
+	}
1247 1247
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/CalculatedModelFieldsFactory.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@  discard block
 block discarded – undo
40 40
      */
41 41
     public function createFromModel($model_name)
42 42
     {
43
-        return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\' . $model_name);
43
+        return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\'.$model_name);
44 44
     }
45 45
 
46 46
     /**
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
     public function createFromClassname($calculator_classname)
52 52
     {
53 53
         $calculator = $this->loader->getShared($calculator_classname);
54
-        if (!$calculator instanceof Base) {
54
+        if ( ! $calculator instanceof Base) {
55 55
             throw new UnexpectedEntityException(
56 56
                 $calculator_classname,
57 57
                 'EventEspresso\core\libraries\rest_api\calculations\Base'
Please login to merge, or discard this patch.
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -18,46 +18,46 @@
 block discarded – undo
18 18
  */
19 19
 class CalculatedModelFieldsFactory
20 20
 {
21
-    private $loader;
21
+	private $loader;
22 22
 
23
-    /**
24
-     * CalculatedModelFieldsFactory constructor.
25
-     * @param LoaderInterface $loader
26
-     */
27
-    public function __construct(LoaderInterface $loader)
28
-    {
29
-        $this->loader = $loader;
30
-    }
23
+	/**
24
+	 * CalculatedModelFieldsFactory constructor.
25
+	 * @param LoaderInterface $loader
26
+	 */
27
+	public function __construct(LoaderInterface $loader)
28
+	{
29
+		$this->loader = $loader;
30
+	}
31 31
 
32
-    /**
33
-     * Creates the calculator class that corresponds to that particular model
34
-     * @since 4.9.68.p
35
-     * @param string $model_name
36
-     * @return Base
37
-     * @throws UnexpectedEntityException
38
-     */
39
-    public function createFromModel($model_name)
40
-    {
41
-        return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\' . $model_name);
42
-    }
32
+	/**
33
+	 * Creates the calculator class that corresponds to that particular model
34
+	 * @since 4.9.68.p
35
+	 * @param string $model_name
36
+	 * @return Base
37
+	 * @throws UnexpectedEntityException
38
+	 */
39
+	public function createFromModel($model_name)
40
+	{
41
+		return $this->createFromClassname('EventEspresso\core\libraries\rest_api\calculations\\' . $model_name);
42
+	}
43 43
 
44
-    /**
45
-     * Creates the calculator class that corresponds to that classname and verifies it's of the correct type
46
-     * @param string $calculator_classname
47
-     * @return Base
48
-     * @throws UnexpectedEntityException
49
-     */
50
-    public function createFromClassname($calculator_classname)
51
-    {
52
-        $calculator = $this->loader->getShared($calculator_classname);
53
-        if (!$calculator instanceof Base) {
54
-            throw new UnexpectedEntityException(
55
-                $calculator_classname,
56
-                'EventEspresso\core\libraries\rest_api\calculations\Base'
57
-            );
58
-        }
59
-        return $calculator;
60
-    }
44
+	/**
45
+	 * Creates the calculator class that corresponds to that classname and verifies it's of the correct type
46
+	 * @param string $calculator_classname
47
+	 * @return Base
48
+	 * @throws UnexpectedEntityException
49
+	 */
50
+	public function createFromClassname($calculator_classname)
51
+	{
52
+		$calculator = $this->loader->getShared($calculator_classname);
53
+		if (!$calculator instanceof Base) {
54
+			throw new UnexpectedEntityException(
55
+				$calculator_classname,
56
+				'EventEspresso\core\libraries\rest_api\calculations\Base'
57
+			);
58
+		}
59
+		return $calculator;
60
+	}
61 61
 }
62 62
 // End of file CalculationsFactory.php
63 63
 // Location: EventEspresso\core\libraries\rest_api\calculations/CalculationsFactory.php
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Datetime.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
      */
88 88
     public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89 89
     {
90
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
90
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91 91
             throw new EE_Error(
92 92
                 sprintf(
93 93
                     __(
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
      */
122 122
     public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123 123
     {
124
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
124
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125 125
             throw new EE_Error(
126 126
                 sprintf(
127 127
                     __(
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
      */
157 157
     public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158 158
     {
159
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
159
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160 160
             throw new EE_Error(
161 161
                 sprintf(
162 162
                     __(
Please login to merge, or discard this patch.
Indentation   +196 added lines, -196 removed lines patch added patch discarded remove patch
@@ -17,210 +17,210 @@
 block discarded – undo
17 17
 
18 18
 class Datetime extends DatetimeCalculationBase
19 19
 {
20
-    /**
21
-     * @var EEM_Datetime
22
-     */
23
-    protected $datetime_model;
20
+	/**
21
+	 * @var EEM_Datetime
22
+	 */
23
+	protected $datetime_model;
24 24
 
25
-    /**
26
-     * @var EEM_Registration
27
-     */
28
-    protected $registration_model;
29
-    public function __construct(EEM_Datetime $datetime_model, EEM_Registration $registration_model)
30
-    {
31
-        $this->datetime_model = $datetime_model;
32
-        $this->registration_model = $registration_model;
33
-    }
25
+	/**
26
+	 * @var EEM_Registration
27
+	 */
28
+	protected $registration_model;
29
+	public function __construct(EEM_Datetime $datetime_model, EEM_Registration $registration_model)
30
+	{
31
+		$this->datetime_model = $datetime_model;
32
+		$this->registration_model = $registration_model;
33
+	}
34 34
 
35
-    /**
36
-     * Calculates the total spaces available on the datetime, taking into account
37
-     * ticket limits too.
38
-     *
39
-     * @see EE_Datetime::spaces_remaining( true )
40
-     * @param array            $wpdb_row
41
-     * @param WP_REST_Request $request
42
-     * @param DatetimeControllerBase  $controller
43
-     * @return int
44
-     * @throws EE_Error
45
-     * @throws InvalidDataTypeException
46
-     * @throws InvalidInterfaceException
47
-     * @throws InvalidArgumentException
48
-     * @throws ReflectionException
49
-     */
50
-    public function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
51
-    {
52
-        if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
53
-            $dtt_obj = $this->datetime_model->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
54
-        } else {
55
-            $dtt_obj = null;
56
-        }
57
-        if ($dtt_obj instanceof EE_Datetime) {
58
-            return $dtt_obj->spaces_remaining(true);
59
-        }
60
-        throw new EE_Error(
61
-            sprintf(
62
-                __(
63
-                // @codingStandardsIgnoreStart
64
-                    'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
65
-                    // @codingStandardsIgnoreEnd
66
-                    'event_espresso'
67
-                ),
68
-                $wpdb_row['Datetime.DTT_ID'],
69
-                print_r($wpdb_row, true)
70
-            )
71
-        );
72
-    }
35
+	/**
36
+	 * Calculates the total spaces available on the datetime, taking into account
37
+	 * ticket limits too.
38
+	 *
39
+	 * @see EE_Datetime::spaces_remaining( true )
40
+	 * @param array            $wpdb_row
41
+	 * @param WP_REST_Request $request
42
+	 * @param DatetimeControllerBase  $controller
43
+	 * @return int
44
+	 * @throws EE_Error
45
+	 * @throws InvalidDataTypeException
46
+	 * @throws InvalidInterfaceException
47
+	 * @throws InvalidArgumentException
48
+	 * @throws ReflectionException
49
+	 */
50
+	public function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
51
+	{
52
+		if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
53
+			$dtt_obj = $this->datetime_model->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
54
+		} else {
55
+			$dtt_obj = null;
56
+		}
57
+		if ($dtt_obj instanceof EE_Datetime) {
58
+			return $dtt_obj->spaces_remaining(true);
59
+		}
60
+		throw new EE_Error(
61
+			sprintf(
62
+				__(
63
+				// @codingStandardsIgnoreStart
64
+					'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
65
+					// @codingStandardsIgnoreEnd
66
+					'event_espresso'
67
+				),
68
+				$wpdb_row['Datetime.DTT_ID'],
69
+				print_r($wpdb_row, true)
70
+			)
71
+		);
72
+	}
73 73
 
74 74
 
75
-    /**
76
-     * Counts registrations who have checked into this datetime
77
-     *
78
-     * @param array           $wpdb_row
79
-     * @param WP_REST_Request $request
80
-     * @param DatetimeControllerBase $controller
81
-     * @return int
82
-     * @throws EE_Error
83
-     * @throws InvalidArgumentException
84
-     * @throws InvalidDataTypeException
85
-     * @throws InvalidInterfaceException
86
-     * @throws RestException
87
-     */
88
-    public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89
-    {
90
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91
-            throw new EE_Error(
92
-                sprintf(
93
-                    __(
94
-                    // @codingStandardsIgnoreStart
95
-                        'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
96
-                        // @codingStandardsIgnoreEnd
97
-                        'event_espresso'
98
-                    ),
99
-                    print_r($wpdb_row, true)
100
-                )
101
-            );
102
-        }
103
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
104
-        return $this->registration_model
105
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
106
-    }
75
+	/**
76
+	 * Counts registrations who have checked into this datetime
77
+	 *
78
+	 * @param array           $wpdb_row
79
+	 * @param WP_REST_Request $request
80
+	 * @param DatetimeControllerBase $controller
81
+	 * @return int
82
+	 * @throws EE_Error
83
+	 * @throws InvalidArgumentException
84
+	 * @throws InvalidDataTypeException
85
+	 * @throws InvalidInterfaceException
86
+	 * @throws RestException
87
+	 */
88
+	public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89
+	{
90
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91
+			throw new EE_Error(
92
+				sprintf(
93
+					__(
94
+					// @codingStandardsIgnoreStart
95
+						'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
96
+						// @codingStandardsIgnoreEnd
97
+						'event_espresso'
98
+					),
99
+					print_r($wpdb_row, true)
100
+				)
101
+			);
102
+		}
103
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
104
+		return $this->registration_model
105
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
106
+	}
107 107
 
108 108
 
109
-    /**
110
-     * Counts registrations who have checked out of this datetime
111
-     *
112
-     * @param array           $wpdb_row
113
-     * @param WP_REST_Request $request
114
-     * @param DatetimeControllerBase $controller
115
-     * @return int
116
-     * @throws EE_Error
117
-     * @throws InvalidArgumentException
118
-     * @throws InvalidDataTypeException
119
-     * @throws InvalidInterfaceException
120
-     * @throws RestException
121
-     */
122
-    public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123
-    {
124
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125
-            throw new EE_Error(
126
-                sprintf(
127
-                    __(
128
-                    // @codingStandardsIgnoreStart
129
-                        'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
130
-                        // @codingStandardsIgnoreEnd
131
-                        'event_espresso'
132
-                    ),
133
-                    print_r($wpdb_row, true)
134
-                )
135
-            );
136
-        }
137
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
138
-        return $this->registration_model
139
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
140
-    }
109
+	/**
110
+	 * Counts registrations who have checked out of this datetime
111
+	 *
112
+	 * @param array           $wpdb_row
113
+	 * @param WP_REST_Request $request
114
+	 * @param DatetimeControllerBase $controller
115
+	 * @return int
116
+	 * @throws EE_Error
117
+	 * @throws InvalidArgumentException
118
+	 * @throws InvalidDataTypeException
119
+	 * @throws InvalidInterfaceException
120
+	 * @throws RestException
121
+	 */
122
+	public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123
+	{
124
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125
+			throw new EE_Error(
126
+				sprintf(
127
+					__(
128
+					// @codingStandardsIgnoreStart
129
+						'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
130
+						// @codingStandardsIgnoreEnd
131
+						'event_espresso'
132
+					),
133
+					print_r($wpdb_row, true)
134
+				)
135
+			);
136
+		}
137
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
138
+		return $this->registration_model
139
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
140
+	}
141 141
 
142 142
 
143
-    /**
144
-     * Counts the number of pending-payment registrations for this event (regardless
145
-     * of how many datetimes each registrations' ticket purchase is for)
146
-     *
147
-     * @param array           $wpdb_row
148
-     * @param WP_REST_Request $request
149
-     * @param DatetimeControllerBase $controller
150
-     * @return int
151
-     * @throws EE_Error
152
-     * @throws InvalidArgumentException
153
-     * @throws InvalidDataTypeException
154
-     * @throws InvalidInterfaceException
155
-     * @throws RestException
156
-     */
157
-    public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158
-    {
159
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160
-            throw new EE_Error(
161
-                sprintf(
162
-                    __(
163
-                    // @codingStandardsIgnoreStart
164
-                        'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
165
-                        // @codingStandardsIgnoreEnd
166
-                        'event_espresso'
167
-                    ),
168
-                    print_r($wpdb_row, true)
169
-                )
170
-            );
171
-        }
172
-        $this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
173
-        return $this->registration_model->count(
174
-            array(
175
-                array(
176
-                    'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
177
-                    'STS_ID'                 => EEM_Registration::status_id_pending_payment,
178
-                ),
179
-            ),
180
-            'REG_ID',
181
-            true
182
-        );
183
-    }
143
+	/**
144
+	 * Counts the number of pending-payment registrations for this event (regardless
145
+	 * of how many datetimes each registrations' ticket purchase is for)
146
+	 *
147
+	 * @param array           $wpdb_row
148
+	 * @param WP_REST_Request $request
149
+	 * @param DatetimeControllerBase $controller
150
+	 * @return int
151
+	 * @throws EE_Error
152
+	 * @throws InvalidArgumentException
153
+	 * @throws InvalidDataTypeException
154
+	 * @throws InvalidInterfaceException
155
+	 * @throws RestException
156
+	 */
157
+	public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158
+	{
159
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160
+			throw new EE_Error(
161
+				sprintf(
162
+					__(
163
+					// @codingStandardsIgnoreStart
164
+						'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
165
+						// @codingStandardsIgnoreEnd
166
+						'event_espresso'
167
+					),
168
+					print_r($wpdb_row, true)
169
+				)
170
+			);
171
+		}
172
+		$this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
173
+		return $this->registration_model->count(
174
+			array(
175
+				array(
176
+					'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
177
+					'STS_ID'                 => EEM_Registration::status_id_pending_payment,
178
+				),
179
+			),
180
+			'REG_ID',
181
+			true
182
+		);
183
+	}
184 184
 
185 185
 
186
-    /**
187
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
188
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
189
-     *
190
-     * @since 4.9.68.p
191
-     * @return array
192
-     */
193
-    public function schemaForCalculations()
194
-    {
195
-        return array(
196
-            'spaces_remaining_considering_tickets' => array(
197
-                'description' => esc_html__(
198
-                    'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
199
-                    'event_espresso'
200
-                ),
201
-                'type' => 'number'
202
-            ),
203
-            'registrations_checked_in_count' => array(
204
-                'description' => esc_html__(
205
-                    'Counts registrations who have checked into this datetime.',
206
-                    'event_espresso'
207
-                ),
208
-                'type' => 'number'
209
-            ),
210
-            'registrations_checked_out_count' => array(
211
-                'description' => esc_html__(
212
-                    'Counts registrations who have checked out of this datetime.',
213
-                    'event_espresso'
214
-                ),
215
-                'type' => 'number'
216
-            ),
217
-            'spots_taken_pending_payment' => array(
218
-                'description' => esc_html__(
219
-                    'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
220
-                    'event_espresso'
221
-                ),
222
-                'type' => 'number'
223
-            ),
224
-        );
225
-    }
186
+	/**
187
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
188
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
189
+	 *
190
+	 * @since 4.9.68.p
191
+	 * @return array
192
+	 */
193
+	public function schemaForCalculations()
194
+	{
195
+		return array(
196
+			'spaces_remaining_considering_tickets' => array(
197
+				'description' => esc_html__(
198
+					'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
199
+					'event_espresso'
200
+				),
201
+				'type' => 'number'
202
+			),
203
+			'registrations_checked_in_count' => array(
204
+				'description' => esc_html__(
205
+					'Counts registrations who have checked into this datetime.',
206
+					'event_espresso'
207
+				),
208
+				'type' => 'number'
209
+			),
210
+			'registrations_checked_out_count' => array(
211
+				'description' => esc_html__(
212
+					'Counts registrations who have checked out of this datetime.',
213
+					'event_espresso'
214
+				),
215
+				'type' => 'number'
216
+			),
217
+			'spots_taken_pending_payment' => array(
218
+				'description' => esc_html__(
219
+					'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
220
+					'event_espresso'
221
+				),
222
+				'type' => 'number'
223
+			),
224
+		);
225
+	}
226 226
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Base.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -23,7 +23,7 @@  discard block
 block discarded – undo
23 23
      */
24 24
     protected function verifyCurrentUserCan($required_permission, $attempted_calculation)
25 25
     {
26
-        if (! current_user_can($required_permission)) {
26
+        if ( ! current_user_can($required_permission)) {
27 27
             throw new RestException(
28 28
                 'permission_denied',
29 29
                 sprintf(
@@ -75,6 +75,6 @@  discard block
 block discarded – undo
75 75
     public function schemaForCalculation($calculation_index)
76 76
     {
77 77
         $schema_map = $this->schemaForCalculations();
78
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
78
+        return isset($schema_map[$calculation_index]) ? $schema_map[$calculation_index] : array();
79 79
     }
80 80
 }
Please login to merge, or discard this patch.
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -16,65 +16,65 @@
 block discarded – undo
16 16
 class Base
17 17
 {
18 18
 
19
-    /**
20
-     * @param $required_permission
21
-     * @param $attempted_calculation
22
-     * @throws RestException
23
-     */
24
-    protected function verifyCurrentUserCan($required_permission, $attempted_calculation)
25
-    {
26
-        if (! current_user_can($required_permission)) {
27
-            throw new RestException(
28
-                'permission_denied',
29
-                sprintf(
30
-                    __(
31
-                    // @codingStandardsIgnoreStart
32
-                        'Permission denied, you cannot calculate %1$s on %2$s because you do not have the capability "%3$s"',
33
-                        // @codingStandardsIgnoreEnd
34
-                        'event_espresso'
35
-                    ),
36
-                    $attempted_calculation,
37
-                    EEH_Inflector::pluralize_and_lower($this->getResourceName()),
38
-                    $required_permission
39
-                )
40
-            );
41
-        }
42
-    }
19
+	/**
20
+	 * @param $required_permission
21
+	 * @param $attempted_calculation
22
+	 * @throws RestException
23
+	 */
24
+	protected function verifyCurrentUserCan($required_permission, $attempted_calculation)
25
+	{
26
+		if (! current_user_can($required_permission)) {
27
+			throw new RestException(
28
+				'permission_denied',
29
+				sprintf(
30
+					__(
31
+					// @codingStandardsIgnoreStart
32
+						'Permission denied, you cannot calculate %1$s on %2$s because you do not have the capability "%3$s"',
33
+						// @codingStandardsIgnoreEnd
34
+						'event_espresso'
35
+					),
36
+					$attempted_calculation,
37
+					EEH_Inflector::pluralize_and_lower($this->getResourceName()),
38
+					$required_permission
39
+				)
40
+			);
41
+		}
42
+	}
43 43
 
44 44
 
45
-    /**
46
-     * Gets the name of the resource of the called class
47
-     *
48
-     * @return string
49
-     */
50
-    public function getResourceName()
51
-    {
52
-        return substr(__CLASS__, strrpos(__CLASS__, '\\') + 1);
53
-    }
45
+	/**
46
+	 * Gets the name of the resource of the called class
47
+	 *
48
+	 * @return string
49
+	 */
50
+	public function getResourceName()
51
+	{
52
+		return substr(__CLASS__, strrpos(__CLASS__, '\\') + 1);
53
+	}
54 54
 
55
-    /**
56
-     * Returns an array to be used for the schema for the calculated fields.
57
-     * @since 4.9.68.p
58
-     * @return array keys are calculated field names (eg "optimum_sales_at_start") values are arrays {
59
-     * @type string $description
60
-     * @type string $type, eg "string", "int", "boolean", "object", "array", etc
61
-     * }
62
-     */
63
-    public function schemaForCalculations()
64
-    {
65
-        return array();
66
-    }
55
+	/**
56
+	 * Returns an array to be used for the schema for the calculated fields.
57
+	 * @since 4.9.68.p
58
+	 * @return array keys are calculated field names (eg "optimum_sales_at_start") values are arrays {
59
+	 * @type string $description
60
+	 * @type string $type, eg "string", "int", "boolean", "object", "array", etc
61
+	 * }
62
+	 */
63
+	public function schemaForCalculations()
64
+	{
65
+		return array();
66
+	}
67 67
 
68
-    /**
69
-     * Returns the json schema for the given calculation index.
70
-     *
71
-     * @since 4.9.68.p
72
-     * @param $calculation_index
73
-     * @return array
74
-     */
75
-    public function schemaForCalculation($calculation_index)
76
-    {
77
-        $schema_map = $this->schemaForCalculations();
78
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
79
-    }
68
+	/**
69
+	 * Returns the json schema for the given calculation index.
70
+	 *
71
+	 * @since 4.9.68.p
72
+	 * @param $calculation_index
73
+	 * @return array
74
+	 */
75
+	public function schemaForCalculation($calculation_index)
76
+	{
77
+		$schema_map = $this->schemaForCalculations();
78
+		return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
79
+	}
80 80
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Event.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
      */
176 176
     public function spotsTaken($wpdb_row, $request, $controller)
177 177
     {
178
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
178
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
179 179
             throw new EE_Error(
180 180
                 sprintf(
181 181
                     __(
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
      */
218 218
     public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
219 219
     {
220
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
220
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
221 221
             throw new EE_Error(
222 222
                 sprintf(
223 223
                     __(
@@ -260,7 +260,7 @@  discard block
 block discarded – undo
260 260
      */
261 261
     public function registrationsCheckedInCount($wpdb_row, $request, $controller)
262 262
     {
263
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
263
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
264 264
             throw new EE_Error(
265 265
                 sprintf(
266 266
                     __(
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
      */
295 295
     public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
296 296
     {
297
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
297
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
298 298
             throw new EE_Error(
299 299
                 sprintf(
300 300
                     __(
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
      */
414 414
     protected function calculateImageData($wpdb_row, $image_size)
415 415
     {
416
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
416
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
417 417
             throw new EE_Error(
418 418
                 sprintf(
419 419
                     __(
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
         $EVT_ID = $wpdb_row['Event_CPT.ID'];
430 430
         $attachment_id = get_post_thumbnail_id($EVT_ID);
431 431
         $data = wp_get_attachment_image_src($attachment_id, $image_size);
432
-        if (! $data) {
432
+        if ( ! $data) {
433 433
             return null;
434 434
         }
435 435
         $generated = true;
Please login to merge, or discard this patch.
Indentation   +560 added lines, -560 removed lines patch added patch discarded remove patch
@@ -26,564 +26,564 @@
 block discarded – undo
26 26
  */
27 27
 class Event extends EventCalculationBase
28 28
 {
29
-    /**
30
-     * @var EEM_Event
31
-     */
32
-    protected $event_model;
33
-
34
-    /**
35
-     * @var EEM_Registration
36
-     */
37
-    protected $registration_model;
38
-    public function __construct(EEM_Event $event_model, EEM_Registration $registration_model)
39
-    {
40
-        $this->event_model = $event_model;
41
-        $this->registration_model = $registration_model;
42
-    }
43
-
44
-    /**
45
-     * Calculates the total spaces on the event (not subtracting sales, but taking
46
-     * sales into account; so this is the optimum sales that CAN still be achieved)
47
-     * See EE_Event::total_available_spaces( true );
48
-     *
49
-     * @param array               $wpdb_row
50
-     * @param WP_REST_Request     $request
51
-     * @param EventControllerBase $controller
52
-     * @return int
53
-     * @throws EE_Error
54
-     * @throws DomainException
55
-     * @throws InvalidDataTypeException
56
-     * @throws InvalidInterfaceException
57
-     * @throws UnexpectedEntityException
58
-     * @throws InvalidArgumentException
59
-     */
60
-    public function optimumSalesAtStart($wpdb_row, $request, $controller)
61
-    {
62
-        $event_obj = null;
63
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
64
-            $event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
65
-        }
66
-        if ($event_obj instanceof EE_Event) {
67
-            return $event_obj->total_available_spaces();
68
-        }
69
-        throw new EE_Error(
70
-            sprintf(
71
-                __(
72
-                // @codingStandardsIgnoreStart
73
-                    'Cannot calculate optimum_sales_at_start because the event with ID %1$s (from database row %2$s) was not found',
74
-                    // @codingStandardsIgnoreEnd
75
-                    'event_espresso'
76
-                ),
77
-                $wpdb_row['Event_CPT.ID'],
78
-                print_r($wpdb_row, true)
79
-            )
80
-        );
81
-    }
82
-
83
-
84
-    /**
85
-     * Calculates the total spaces on the event (ignoring all sales; so this is the optimum
86
-     * sales that COULD have been achieved)
87
-     * See EE_Event::total_available_spaces( true );
88
-     *
89
-     * @param array               $wpdb_row
90
-     * @param WP_REST_Request     $request
91
-     * @param EventControllerBase $controller
92
-     * @return int
93
-     * @throws DomainException
94
-     * @throws EE_Error
95
-     * @throws InvalidArgumentException
96
-     * @throws InvalidDataTypeException
97
-     * @throws InvalidInterfaceException
98
-     * @throws UnexpectedEntityException
99
-     */
100
-    public function optimumSalesNow($wpdb_row, $request, $controller)
101
-    {
102
-        $event_obj = null;
103
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
104
-            $event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
105
-        }
106
-        if ($event_obj instanceof EE_Event) {
107
-            return $event_obj->total_available_spaces(true);
108
-        }
109
-        throw new EE_Error(
110
-            sprintf(
111
-                __(
112
-                // @codingStandardsIgnoreStart
113
-                    'Cannot calculate optimum_sales_now because the event with ID %1$s (from database row %2$s) was not found',
114
-                    // @codingStandardsIgnoreEnd
115
-                    'event_espresso'
116
-                ),
117
-                $wpdb_row['Event_CPT.ID'],
118
-                print_r($wpdb_row, true)
119
-            )
120
-        );
121
-    }
122
-
123
-
124
-    /**
125
-     * Like optimum_sales_now, but minus total sales so far.
126
-     * See EE_Event::spaces_remaining_for_sale( true );
127
-     *
128
-     * @param array               $wpdb_row
129
-     * @param WP_REST_Request     $request
130
-     * @param EventControllerBase $controller
131
-     * @return int
132
-     * @throws DomainException
133
-     * @throws EE_Error
134
-     * @throws InvalidArgumentException
135
-     * @throws InvalidDataTypeException
136
-     * @throws InvalidInterfaceException
137
-     * @throws UnexpectedEntityException
138
-     */
139
-    public function spacesRemaining($wpdb_row, $request, $controller)
140
-    {
141
-        $event_obj = null;
142
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
143
-            $event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
144
-        }
145
-        if ($event_obj instanceof EE_Event) {
146
-            return $event_obj->spaces_remaining_for_sale();
147
-        }
148
-        throw new EE_Error(
149
-            sprintf(
150
-                __(
151
-                // @codingStandardsIgnoreStart
152
-                    'Cannot calculate spaces_remaining because the event with ID %1$s (from database row %2$s) was not found',
153
-                    // @codingStandardsIgnoreEnd
154
-                    'event_espresso'
155
-                ),
156
-                $wpdb_row['Event_CPT.ID'],
157
-                print_r($wpdb_row, true)
158
-            )
159
-        );
160
-    }
161
-
162
-
163
-    /**
164
-     * Counts the number of approved registrations for this event (regardless
165
-     * of how many datetimes each registrations' ticket purchase is for)
166
-     *
167
-     * @param array               $wpdb_row
168
-     * @param WP_REST_Request     $request
169
-     * @param EventControllerBase $controller
170
-     * @return int
171
-     * @throws EE_Error
172
-     * @throws InvalidArgumentException
173
-     * @throws InvalidDataTypeException
174
-     * @throws InvalidInterfaceException
175
-     */
176
-    public function spotsTaken($wpdb_row, $request, $controller)
177
-    {
178
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
179
-            throw new EE_Error(
180
-                sprintf(
181
-                    __(
182
-                    // @codingStandardsIgnoreStart
183
-                        'Cannot calculate spots_taken because the database row %1$s does not have a valid entry for "Event_CPT.ID"',
184
-                        // @codingStandardsIgnoreEnd
185
-                        'event_espresso'
186
-                    ),
187
-                    print_r($wpdb_row, true)
188
-                )
189
-            );
190
-        }
191
-        return $this->registration_model->count(
192
-            array(
193
-                array(
194
-                    'EVT_ID' => $wpdb_row['Event_CPT.ID'],
195
-                    'STS_ID' => EEM_Registration::status_id_approved,
196
-                ),
197
-            ),
198
-            'REG_ID',
199
-            true
200
-        );
201
-    }
202
-
203
-
204
-    /**
205
-     * Counts the number of pending-payment registrations for this event (regardless
206
-     * of how many datetimes each registrations' ticket purchase is for)
207
-     *
208
-     * @param array               $wpdb_row
209
-     * @param WP_REST_Request     $request
210
-     * @param EventControllerBase $controller
211
-     * @return int
212
-     * @throws EE_Error
213
-     * @throws InvalidArgumentException
214
-     * @throws InvalidDataTypeException
215
-     * @throws InvalidInterfaceException
216
-     * @throws RestException
217
-     */
218
-    public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
219
-    {
220
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
221
-            throw new EE_Error(
222
-                sprintf(
223
-                    __(
224
-                    // @codingStandardsIgnoreStart
225
-                        'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Event_CPT.ID"',
226
-                        // @codingStandardsIgnoreEnd
227
-                        'event_espresso'
228
-                    ),
229
-                    print_r($wpdb_row, true)
230
-                )
231
-            );
232
-        }
233
-        $this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
234
-        return $this->registration_model->count(
235
-            array(
236
-                array(
237
-                    'EVT_ID' => $wpdb_row['Event_CPT.ID'],
238
-                    'STS_ID' => EEM_Registration::status_id_pending_payment,
239
-                ),
240
-            ),
241
-            'REG_ID',
242
-            true
243
-        );
244
-    }
245
-
246
-
247
-    /**
248
-     * Counts all the registrations who have checked into one of this events' datetimes
249
-     * See EE_Event::total_available_spaces( false );
250
-     *
251
-     * @param array               $wpdb_row
252
-     * @param WP_REST_Request     $request
253
-     * @param EventControllerBase $controller
254
-     * @return int|null if permission denied
255
-     * @throws EE_Error
256
-     * @throws InvalidArgumentException
257
-     * @throws InvalidDataTypeException
258
-     * @throws InvalidInterfaceException
259
-     * @throws RestException
260
-     */
261
-    public function registrationsCheckedInCount($wpdb_row, $request, $controller)
262
-    {
263
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
264
-            throw new EE_Error(
265
-                sprintf(
266
-                    __(
267
-                    // @codingStandardsIgnoreStart
268
-                        'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
269
-                        // @codingStandardsIgnoreEnd
270
-                        'event_espresso'
271
-                    ),
272
-                    print_r($wpdb_row, true)
273
-                )
274
-            );
275
-        }
276
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
277
-        return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], true);
278
-    }
279
-
280
-
281
-    /**
282
-     * Counts all the registrations who have checked out of one of this events' datetimes
283
-     * See EE_Event::total_available_spaces( false );
284
-     *
285
-     * @param array               $wpdb_row
286
-     * @param WP_REST_Request     $request
287
-     * @param EventControllerBase $controller
288
-     * @return int
289
-     * @throws EE_Error
290
-     * @throws InvalidArgumentException
291
-     * @throws InvalidDataTypeException
292
-     * @throws InvalidInterfaceException
293
-     * @throws RestException
294
-     */
295
-    public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
296
-    {
297
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
298
-            throw new EE_Error(
299
-                sprintf(
300
-                    __(
301
-                    // @codingStandardsIgnoreStart
302
-                        'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
303
-                        // @codingStandardsIgnoreEnd
304
-                        'event_espresso'
305
-                    ),
306
-                    print_r($wpdb_row, true)
307
-                )
308
-            );
309
-        }
310
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
311
-        return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], false);
312
-    }
313
-
314
-
315
-    /**
316
-     * Gets the thumbnail image
317
-     *
318
-     * @param array               $wpdb_row
319
-     * @param WP_REST_Request     $request
320
-     * @param EventControllerBase $controller
321
-     * @return array
322
-     * @throws EE_Error
323
-     */
324
-    public function imageThumbnail($wpdb_row, $request, $controller)
325
-    {
326
-        return self::calculateImageData($wpdb_row, 'thumbnail');
327
-    }
328
-
329
-
330
-    /**
331
-     * Gets the medium image
332
-     *
333
-     * @param array               $wpdb_row
334
-     * @param WP_REST_Request     $request
335
-     * @param EventControllerBase $controller
336
-     * @return array
337
-     * @throws EE_Error
338
-     */
339
-    public function imageMedium($wpdb_row, $request, $controller)
340
-    {
341
-        return self::calculateImageData($wpdb_row, 'medium');
342
-    }
343
-
344
-
345
-    /**
346
-     * Gets the medium-large image
347
-     *
348
-     * @param array               $wpdb_row
349
-     * @param WP_REST_Request     $request
350
-     * @param EventControllerBase $controller
351
-     * @return array
352
-     * @throws EE_Error
353
-     */
354
-    public function imageMediumLarge($wpdb_row, $request, $controller)
355
-    {
356
-        return self::calculateImageData($wpdb_row, 'medium_large');
357
-    }
358
-
359
-
360
-    /**
361
-     * Gets the large image
362
-     *
363
-     * @param array               $wpdb_row
364
-     * @param WP_REST_Request     $request
365
-     * @param EventControllerBase $controller
366
-     * @return array
367
-     * @throws EE_Error
368
-     */
369
-    public function imageLarge($wpdb_row, $request, $controller)
370
-    {
371
-        return self::calculateImageData($wpdb_row, 'large');
372
-    }
373
-
374
-
375
-    /**
376
-     * Gets the post-thumbnail image
377
-     *
378
-     * @param array               $wpdb_row
379
-     * @param WP_REST_Request     $request
380
-     * @param EventControllerBase $controller
381
-     * @return array
382
-     * @throws EE_Error
383
-     */
384
-    public function imagePostThumbnail($wpdb_row, $request, $controller)
385
-    {
386
-        return self::calculateImageData($wpdb_row, 'post-thumbnail');
387
-    }
388
-
389
-
390
-    /**
391
-     * Gets the full size image
392
-     *
393
-     * @param array               $wpdb_row
394
-     * @param WP_REST_Request     $request
395
-     * @param EventControllerBase $controller
396
-     * @return array
397
-     * @throws EE_Error
398
-     */
399
-    public function imageFull($wpdb_row, $request, $controller)
400
-    {
401
-        return self::calculateImageData($wpdb_row, 'full');
402
-    }
403
-
404
-
405
-    /**
406
-     * Gets image specs and formats them for the display in the API,
407
-     * according to the image size requested
408
-     *
409
-     * @param array  $wpdb_row
410
-     * @param string $image_size one of these: thumbnail, medium, medium_large, large, post-thumbnail, full
411
-     * @return array|false if no such image exists. If array it will have keys 'url', 'width', 'height' and 'original'
412
-     * @throws EE_Error
413
-     */
414
-    protected function calculateImageData($wpdb_row, $image_size)
415
-    {
416
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
417
-            throw new EE_Error(
418
-                sprintf(
419
-                    __(
420
-                    // @codingStandardsIgnoreStart
421
-                        'Cannot calculate image because the database row %1$s does not have an entry for "Event_CPT.ID"',
422
-                        // @codingStandardsIgnoreEnd
423
-                        'event_espresso'
424
-                    ),
425
-                    print_r($wpdb_row, true)
426
-                )
427
-            );
428
-        }
429
-        $EVT_ID = $wpdb_row['Event_CPT.ID'];
430
-        $attachment_id = get_post_thumbnail_id($EVT_ID);
431
-        $data = wp_get_attachment_image_src($attachment_id, $image_size);
432
-        if (! $data) {
433
-            return null;
434
-        }
435
-        $generated = true;
436
-        if (isset($data[3])) {
437
-            $generated = $data[3];
438
-        }
439
-        return array(
440
-            'url'       => $data[0],
441
-            'width'     => $data[1],
442
-            'height'    => $data[2],
443
-            'generated' => $generated,
444
-        );
445
-    }
446
-
447
-
448
-    /**
449
-     * Returns true if the array of data contains 'Event_CPT.ID'. False otherwise
450
-     *
451
-     * @param array $wpdb_row
452
-     * @return bool
453
-     */
454
-    protected function wpdbRowHasEventId($wpdb_row)
455
-    {
456
-        return (is_array($wpdb_row) && isset($wpdb_row['Event_CPT.ID']) && absint($wpdb_row['Event_CPT.ID']));
457
-    }
458
-
459
-
460
-    /**
461
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
462
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
463
-     *
464
-     * @since 4.9.68.p
465
-     * @return array
466
-     */
467
-    public function schemaForCalculations()
468
-    {
469
-        $image_object_properties = array(
470
-            'url'       => array(
471
-                'type' => 'string',
472
-            ),
473
-            'width'     => array(
474
-                'type' => 'number',
475
-            ),
476
-            'height'    => array(
477
-                'type' => 'number',
478
-            ),
479
-            'generated' => array(
480
-                'type' => 'boolean',
481
-            ),
482
-        );
483
-        return array(
484
-            'optimum_sales_at_start'          => array(
485
-                'description' => esc_html__(
486
-                    'The total spaces on the event (not subtracting sales, but taking sales into account; so this is the optimum sales that CAN still be achieved.',
487
-                    'event_espresso'
488
-                ),
489
-                'type'        => 'number',
490
-            ),
491
-            'optimum_sales_now'               => array(
492
-                'description' => esc_html__(
493
-                    'The total spaces on the event (ignoring all sales; so this is the optimum sales that could have been achieved.',
494
-                    'event_espresso'
495
-                ),
496
-                'type'        => 'number',
497
-            ),
498
-            'spaces_remaining'                => array(
499
-                'description' => esc_html__(
500
-                    'The optimum_sales_number result, minus total sales so far.',
501
-                    'event_espresso'
502
-                ),
503
-                'type'        => 'number',
504
-            ),
505
-            'spots_taken'                     => array(
506
-                'description' => esc_html__(
507
-                    'The number of approved registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
508
-                    'event_espresso'
509
-                ),
510
-                'type'        => 'number',
511
-            ),
512
-            'spots_taken_pending_payment'     => array(
513
-                'description' => esc_html__(
514
-                    'The number of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
515
-                    'event_espresso'
516
-                ),
517
-                'type'        => 'number',
518
-            ),
519
-            'registrations_checked_in_count'  => array(
520
-                'description' => esc_html__(
521
-                    'The count of all the registrations who have checked into one of this event\'s datetimes.',
522
-                    'event_espresso'
523
-                ),
524
-                'type'        => 'number',
525
-            ),
526
-            'registrations_checked_out_count' => array(
527
-                'description' => esc_html__(
528
-                    'The count of all registrations who have checked out of one of this event\'s datetimes.',
529
-                    'event_espresso'
530
-                ),
531
-                'type'        => 'number',
532
-            ),
533
-            'image_thumbnail'                 => array(
534
-                'description'          => esc_html__(
535
-                    'The thumbnail image data.',
536
-                    'event_espresso'
537
-                ),
538
-                'type'                 => 'object',
539
-                'properties'           => $image_object_properties,
540
-                'additionalProperties' => false,
541
-            ),
542
-            'image_medium'                    => array(
543
-                'description'          => esc_html__(
544
-                    'The medium image data.',
545
-                    'event_espresso'
546
-                ),
547
-                'type'                 => 'object',
548
-                'properties'           => $image_object_properties,
549
-                'additionalProperties' => false,
550
-            ),
551
-            'image_medium_large'              => array(
552
-                'description'          => esc_html__(
553
-                    'The medium-large image data.',
554
-                    'event_espresso'
555
-                ),
556
-                'type'                 => 'object',
557
-                'properties'           => $image_object_properties,
558
-                'additionalProperties' => false,
559
-            ),
560
-            'image_large'                     => array(
561
-                'description'          => esc_html__(
562
-                    'The large image data.',
563
-                    'event_espresso'
564
-                ),
565
-                'type'                 => 'object',
566
-                'properties'           => $image_object_properties,
567
-                'additionalProperties' => false,
568
-            ),
569
-            'image_post_thumbnail'            => array(
570
-                'description'          => esc_html__(
571
-                    'The post-thumbnail image data.',
572
-                    'event_espresso'
573
-                ),
574
-                'type'                 => 'object',
575
-                'properties'           => $image_object_properties,
576
-                'additionalProperties' => false,
577
-            ),
578
-            'image_full'                      => array(
579
-                'description'          => esc_html__(
580
-                    'The full size image data',
581
-                    'event_espresso'
582
-                ),
583
-                'type'                 => 'object',
584
-                'properties'           => $image_object_properties,
585
-                'additionalProperties' => false,
586
-            ),
587
-        );
588
-    }
29
+	/**
30
+	 * @var EEM_Event
31
+	 */
32
+	protected $event_model;
33
+
34
+	/**
35
+	 * @var EEM_Registration
36
+	 */
37
+	protected $registration_model;
38
+	public function __construct(EEM_Event $event_model, EEM_Registration $registration_model)
39
+	{
40
+		$this->event_model = $event_model;
41
+		$this->registration_model = $registration_model;
42
+	}
43
+
44
+	/**
45
+	 * Calculates the total spaces on the event (not subtracting sales, but taking
46
+	 * sales into account; so this is the optimum sales that CAN still be achieved)
47
+	 * See EE_Event::total_available_spaces( true );
48
+	 *
49
+	 * @param array               $wpdb_row
50
+	 * @param WP_REST_Request     $request
51
+	 * @param EventControllerBase $controller
52
+	 * @return int
53
+	 * @throws EE_Error
54
+	 * @throws DomainException
55
+	 * @throws InvalidDataTypeException
56
+	 * @throws InvalidInterfaceException
57
+	 * @throws UnexpectedEntityException
58
+	 * @throws InvalidArgumentException
59
+	 */
60
+	public function optimumSalesAtStart($wpdb_row, $request, $controller)
61
+	{
62
+		$event_obj = null;
63
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
64
+			$event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
65
+		}
66
+		if ($event_obj instanceof EE_Event) {
67
+			return $event_obj->total_available_spaces();
68
+		}
69
+		throw new EE_Error(
70
+			sprintf(
71
+				__(
72
+				// @codingStandardsIgnoreStart
73
+					'Cannot calculate optimum_sales_at_start because the event with ID %1$s (from database row %2$s) was not found',
74
+					// @codingStandardsIgnoreEnd
75
+					'event_espresso'
76
+				),
77
+				$wpdb_row['Event_CPT.ID'],
78
+				print_r($wpdb_row, true)
79
+			)
80
+		);
81
+	}
82
+
83
+
84
+	/**
85
+	 * Calculates the total spaces on the event (ignoring all sales; so this is the optimum
86
+	 * sales that COULD have been achieved)
87
+	 * See EE_Event::total_available_spaces( true );
88
+	 *
89
+	 * @param array               $wpdb_row
90
+	 * @param WP_REST_Request     $request
91
+	 * @param EventControllerBase $controller
92
+	 * @return int
93
+	 * @throws DomainException
94
+	 * @throws EE_Error
95
+	 * @throws InvalidArgumentException
96
+	 * @throws InvalidDataTypeException
97
+	 * @throws InvalidInterfaceException
98
+	 * @throws UnexpectedEntityException
99
+	 */
100
+	public function optimumSalesNow($wpdb_row, $request, $controller)
101
+	{
102
+		$event_obj = null;
103
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
104
+			$event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
105
+		}
106
+		if ($event_obj instanceof EE_Event) {
107
+			return $event_obj->total_available_spaces(true);
108
+		}
109
+		throw new EE_Error(
110
+			sprintf(
111
+				__(
112
+				// @codingStandardsIgnoreStart
113
+					'Cannot calculate optimum_sales_now because the event with ID %1$s (from database row %2$s) was not found',
114
+					// @codingStandardsIgnoreEnd
115
+					'event_espresso'
116
+				),
117
+				$wpdb_row['Event_CPT.ID'],
118
+				print_r($wpdb_row, true)
119
+			)
120
+		);
121
+	}
122
+
123
+
124
+	/**
125
+	 * Like optimum_sales_now, but minus total sales so far.
126
+	 * See EE_Event::spaces_remaining_for_sale( true );
127
+	 *
128
+	 * @param array               $wpdb_row
129
+	 * @param WP_REST_Request     $request
130
+	 * @param EventControllerBase $controller
131
+	 * @return int
132
+	 * @throws DomainException
133
+	 * @throws EE_Error
134
+	 * @throws InvalidArgumentException
135
+	 * @throws InvalidDataTypeException
136
+	 * @throws InvalidInterfaceException
137
+	 * @throws UnexpectedEntityException
138
+	 */
139
+	public function spacesRemaining($wpdb_row, $request, $controller)
140
+	{
141
+		$event_obj = null;
142
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
143
+			$event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
144
+		}
145
+		if ($event_obj instanceof EE_Event) {
146
+			return $event_obj->spaces_remaining_for_sale();
147
+		}
148
+		throw new EE_Error(
149
+			sprintf(
150
+				__(
151
+				// @codingStandardsIgnoreStart
152
+					'Cannot calculate spaces_remaining because the event with ID %1$s (from database row %2$s) was not found',
153
+					// @codingStandardsIgnoreEnd
154
+					'event_espresso'
155
+				),
156
+				$wpdb_row['Event_CPT.ID'],
157
+				print_r($wpdb_row, true)
158
+			)
159
+		);
160
+	}
161
+
162
+
163
+	/**
164
+	 * Counts the number of approved registrations for this event (regardless
165
+	 * of how many datetimes each registrations' ticket purchase is for)
166
+	 *
167
+	 * @param array               $wpdb_row
168
+	 * @param WP_REST_Request     $request
169
+	 * @param EventControllerBase $controller
170
+	 * @return int
171
+	 * @throws EE_Error
172
+	 * @throws InvalidArgumentException
173
+	 * @throws InvalidDataTypeException
174
+	 * @throws InvalidInterfaceException
175
+	 */
176
+	public function spotsTaken($wpdb_row, $request, $controller)
177
+	{
178
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
179
+			throw new EE_Error(
180
+				sprintf(
181
+					__(
182
+					// @codingStandardsIgnoreStart
183
+						'Cannot calculate spots_taken because the database row %1$s does not have a valid entry for "Event_CPT.ID"',
184
+						// @codingStandardsIgnoreEnd
185
+						'event_espresso'
186
+					),
187
+					print_r($wpdb_row, true)
188
+				)
189
+			);
190
+		}
191
+		return $this->registration_model->count(
192
+			array(
193
+				array(
194
+					'EVT_ID' => $wpdb_row['Event_CPT.ID'],
195
+					'STS_ID' => EEM_Registration::status_id_approved,
196
+				),
197
+			),
198
+			'REG_ID',
199
+			true
200
+		);
201
+	}
202
+
203
+
204
+	/**
205
+	 * Counts the number of pending-payment registrations for this event (regardless
206
+	 * of how many datetimes each registrations' ticket purchase is for)
207
+	 *
208
+	 * @param array               $wpdb_row
209
+	 * @param WP_REST_Request     $request
210
+	 * @param EventControllerBase $controller
211
+	 * @return int
212
+	 * @throws EE_Error
213
+	 * @throws InvalidArgumentException
214
+	 * @throws InvalidDataTypeException
215
+	 * @throws InvalidInterfaceException
216
+	 * @throws RestException
217
+	 */
218
+	public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
219
+	{
220
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
221
+			throw new EE_Error(
222
+				sprintf(
223
+					__(
224
+					// @codingStandardsIgnoreStart
225
+						'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Event_CPT.ID"',
226
+						// @codingStandardsIgnoreEnd
227
+						'event_espresso'
228
+					),
229
+					print_r($wpdb_row, true)
230
+				)
231
+			);
232
+		}
233
+		$this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
234
+		return $this->registration_model->count(
235
+			array(
236
+				array(
237
+					'EVT_ID' => $wpdb_row['Event_CPT.ID'],
238
+					'STS_ID' => EEM_Registration::status_id_pending_payment,
239
+				),
240
+			),
241
+			'REG_ID',
242
+			true
243
+		);
244
+	}
245
+
246
+
247
+	/**
248
+	 * Counts all the registrations who have checked into one of this events' datetimes
249
+	 * See EE_Event::total_available_spaces( false );
250
+	 *
251
+	 * @param array               $wpdb_row
252
+	 * @param WP_REST_Request     $request
253
+	 * @param EventControllerBase $controller
254
+	 * @return int|null if permission denied
255
+	 * @throws EE_Error
256
+	 * @throws InvalidArgumentException
257
+	 * @throws InvalidDataTypeException
258
+	 * @throws InvalidInterfaceException
259
+	 * @throws RestException
260
+	 */
261
+	public function registrationsCheckedInCount($wpdb_row, $request, $controller)
262
+	{
263
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
264
+			throw new EE_Error(
265
+				sprintf(
266
+					__(
267
+					// @codingStandardsIgnoreStart
268
+						'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
269
+						// @codingStandardsIgnoreEnd
270
+						'event_espresso'
271
+					),
272
+					print_r($wpdb_row, true)
273
+				)
274
+			);
275
+		}
276
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
277
+		return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], true);
278
+	}
279
+
280
+
281
+	/**
282
+	 * Counts all the registrations who have checked out of one of this events' datetimes
283
+	 * See EE_Event::total_available_spaces( false );
284
+	 *
285
+	 * @param array               $wpdb_row
286
+	 * @param WP_REST_Request     $request
287
+	 * @param EventControllerBase $controller
288
+	 * @return int
289
+	 * @throws EE_Error
290
+	 * @throws InvalidArgumentException
291
+	 * @throws InvalidDataTypeException
292
+	 * @throws InvalidInterfaceException
293
+	 * @throws RestException
294
+	 */
295
+	public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
296
+	{
297
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
298
+			throw new EE_Error(
299
+				sprintf(
300
+					__(
301
+					// @codingStandardsIgnoreStart
302
+						'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
303
+						// @codingStandardsIgnoreEnd
304
+						'event_espresso'
305
+					),
306
+					print_r($wpdb_row, true)
307
+				)
308
+			);
309
+		}
310
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
311
+		return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], false);
312
+	}
313
+
314
+
315
+	/**
316
+	 * Gets the thumbnail image
317
+	 *
318
+	 * @param array               $wpdb_row
319
+	 * @param WP_REST_Request     $request
320
+	 * @param EventControllerBase $controller
321
+	 * @return array
322
+	 * @throws EE_Error
323
+	 */
324
+	public function imageThumbnail($wpdb_row, $request, $controller)
325
+	{
326
+		return self::calculateImageData($wpdb_row, 'thumbnail');
327
+	}
328
+
329
+
330
+	/**
331
+	 * Gets the medium image
332
+	 *
333
+	 * @param array               $wpdb_row
334
+	 * @param WP_REST_Request     $request
335
+	 * @param EventControllerBase $controller
336
+	 * @return array
337
+	 * @throws EE_Error
338
+	 */
339
+	public function imageMedium($wpdb_row, $request, $controller)
340
+	{
341
+		return self::calculateImageData($wpdb_row, 'medium');
342
+	}
343
+
344
+
345
+	/**
346
+	 * Gets the medium-large image
347
+	 *
348
+	 * @param array               $wpdb_row
349
+	 * @param WP_REST_Request     $request
350
+	 * @param EventControllerBase $controller
351
+	 * @return array
352
+	 * @throws EE_Error
353
+	 */
354
+	public function imageMediumLarge($wpdb_row, $request, $controller)
355
+	{
356
+		return self::calculateImageData($wpdb_row, 'medium_large');
357
+	}
358
+
359
+
360
+	/**
361
+	 * Gets the large image
362
+	 *
363
+	 * @param array               $wpdb_row
364
+	 * @param WP_REST_Request     $request
365
+	 * @param EventControllerBase $controller
366
+	 * @return array
367
+	 * @throws EE_Error
368
+	 */
369
+	public function imageLarge($wpdb_row, $request, $controller)
370
+	{
371
+		return self::calculateImageData($wpdb_row, 'large');
372
+	}
373
+
374
+
375
+	/**
376
+	 * Gets the post-thumbnail image
377
+	 *
378
+	 * @param array               $wpdb_row
379
+	 * @param WP_REST_Request     $request
380
+	 * @param EventControllerBase $controller
381
+	 * @return array
382
+	 * @throws EE_Error
383
+	 */
384
+	public function imagePostThumbnail($wpdb_row, $request, $controller)
385
+	{
386
+		return self::calculateImageData($wpdb_row, 'post-thumbnail');
387
+	}
388
+
389
+
390
+	/**
391
+	 * Gets the full size image
392
+	 *
393
+	 * @param array               $wpdb_row
394
+	 * @param WP_REST_Request     $request
395
+	 * @param EventControllerBase $controller
396
+	 * @return array
397
+	 * @throws EE_Error
398
+	 */
399
+	public function imageFull($wpdb_row, $request, $controller)
400
+	{
401
+		return self::calculateImageData($wpdb_row, 'full');
402
+	}
403
+
404
+
405
+	/**
406
+	 * Gets image specs and formats them for the display in the API,
407
+	 * according to the image size requested
408
+	 *
409
+	 * @param array  $wpdb_row
410
+	 * @param string $image_size one of these: thumbnail, medium, medium_large, large, post-thumbnail, full
411
+	 * @return array|false if no such image exists. If array it will have keys 'url', 'width', 'height' and 'original'
412
+	 * @throws EE_Error
413
+	 */
414
+	protected function calculateImageData($wpdb_row, $image_size)
415
+	{
416
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
417
+			throw new EE_Error(
418
+				sprintf(
419
+					__(
420
+					// @codingStandardsIgnoreStart
421
+						'Cannot calculate image because the database row %1$s does not have an entry for "Event_CPT.ID"',
422
+						// @codingStandardsIgnoreEnd
423
+						'event_espresso'
424
+					),
425
+					print_r($wpdb_row, true)
426
+				)
427
+			);
428
+		}
429
+		$EVT_ID = $wpdb_row['Event_CPT.ID'];
430
+		$attachment_id = get_post_thumbnail_id($EVT_ID);
431
+		$data = wp_get_attachment_image_src($attachment_id, $image_size);
432
+		if (! $data) {
433
+			return null;
434
+		}
435
+		$generated = true;
436
+		if (isset($data[3])) {
437
+			$generated = $data[3];
438
+		}
439
+		return array(
440
+			'url'       => $data[0],
441
+			'width'     => $data[1],
442
+			'height'    => $data[2],
443
+			'generated' => $generated,
444
+		);
445
+	}
446
+
447
+
448
+	/**
449
+	 * Returns true if the array of data contains 'Event_CPT.ID'. False otherwise
450
+	 *
451
+	 * @param array $wpdb_row
452
+	 * @return bool
453
+	 */
454
+	protected function wpdbRowHasEventId($wpdb_row)
455
+	{
456
+		return (is_array($wpdb_row) && isset($wpdb_row['Event_CPT.ID']) && absint($wpdb_row['Event_CPT.ID']));
457
+	}
458
+
459
+
460
+	/**
461
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
462
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
463
+	 *
464
+	 * @since 4.9.68.p
465
+	 * @return array
466
+	 */
467
+	public function schemaForCalculations()
468
+	{
469
+		$image_object_properties = array(
470
+			'url'       => array(
471
+				'type' => 'string',
472
+			),
473
+			'width'     => array(
474
+				'type' => 'number',
475
+			),
476
+			'height'    => array(
477
+				'type' => 'number',
478
+			),
479
+			'generated' => array(
480
+				'type' => 'boolean',
481
+			),
482
+		);
483
+		return array(
484
+			'optimum_sales_at_start'          => array(
485
+				'description' => esc_html__(
486
+					'The total spaces on the event (not subtracting sales, but taking sales into account; so this is the optimum sales that CAN still be achieved.',
487
+					'event_espresso'
488
+				),
489
+				'type'        => 'number',
490
+			),
491
+			'optimum_sales_now'               => array(
492
+				'description' => esc_html__(
493
+					'The total spaces on the event (ignoring all sales; so this is the optimum sales that could have been achieved.',
494
+					'event_espresso'
495
+				),
496
+				'type'        => 'number',
497
+			),
498
+			'spaces_remaining'                => array(
499
+				'description' => esc_html__(
500
+					'The optimum_sales_number result, minus total sales so far.',
501
+					'event_espresso'
502
+				),
503
+				'type'        => 'number',
504
+			),
505
+			'spots_taken'                     => array(
506
+				'description' => esc_html__(
507
+					'The number of approved registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
508
+					'event_espresso'
509
+				),
510
+				'type'        => 'number',
511
+			),
512
+			'spots_taken_pending_payment'     => array(
513
+				'description' => esc_html__(
514
+					'The number of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
515
+					'event_espresso'
516
+				),
517
+				'type'        => 'number',
518
+			),
519
+			'registrations_checked_in_count'  => array(
520
+				'description' => esc_html__(
521
+					'The count of all the registrations who have checked into one of this event\'s datetimes.',
522
+					'event_espresso'
523
+				),
524
+				'type'        => 'number',
525
+			),
526
+			'registrations_checked_out_count' => array(
527
+				'description' => esc_html__(
528
+					'The count of all registrations who have checked out of one of this event\'s datetimes.',
529
+					'event_espresso'
530
+				),
531
+				'type'        => 'number',
532
+			),
533
+			'image_thumbnail'                 => array(
534
+				'description'          => esc_html__(
535
+					'The thumbnail image data.',
536
+					'event_espresso'
537
+				),
538
+				'type'                 => 'object',
539
+				'properties'           => $image_object_properties,
540
+				'additionalProperties' => false,
541
+			),
542
+			'image_medium'                    => array(
543
+				'description'          => esc_html__(
544
+					'The medium image data.',
545
+					'event_espresso'
546
+				),
547
+				'type'                 => 'object',
548
+				'properties'           => $image_object_properties,
549
+				'additionalProperties' => false,
550
+			),
551
+			'image_medium_large'              => array(
552
+				'description'          => esc_html__(
553
+					'The medium-large image data.',
554
+					'event_espresso'
555
+				),
556
+				'type'                 => 'object',
557
+				'properties'           => $image_object_properties,
558
+				'additionalProperties' => false,
559
+			),
560
+			'image_large'                     => array(
561
+				'description'          => esc_html__(
562
+					'The large image data.',
563
+					'event_espresso'
564
+				),
565
+				'type'                 => 'object',
566
+				'properties'           => $image_object_properties,
567
+				'additionalProperties' => false,
568
+			),
569
+			'image_post_thumbnail'            => array(
570
+				'description'          => esc_html__(
571
+					'The post-thumbnail image data.',
572
+					'event_espresso'
573
+				),
574
+				'type'                 => 'object',
575
+				'properties'           => $image_object_properties,
576
+				'additionalProperties' => false,
577
+			),
578
+			'image_full'                      => array(
579
+				'description'          => esc_html__(
580
+					'The full size image data',
581
+					'event_espresso'
582
+				),
583
+				'type'                 => 'object',
584
+				'properties'           => $image_object_properties,
585
+				'additionalProperties' => false,
586
+			),
587
+		);
588
+	}
589 589
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Write.php 2 patches
Indentation   +305 added lines, -305 removed lines patch added patch discarded remove patch
@@ -31,325 +31,325 @@
 block discarded – undo
31 31
 {
32 32
 
33 33
 
34
-    public function __construct()
35
-    {
36
-        parent::__construct();
37
-        EE_Registry::instance()->load_helper('Inflector');
38
-    }
34
+	public function __construct()
35
+	{
36
+		parent::__construct();
37
+		EE_Registry::instance()->load_helper('Inflector');
38
+	}
39 39
 
40 40
 
41
-    /**
42
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
43
-     *
44
-     * @param WP_REST_Request $request
45
-     * @param string          $version
46
-     * @param string          $model_name
47
-     * @return WP_REST_Response|\WP_Error
48
-     */
49
-    public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name)
50
-    {
51
-        $controller = new Write();
52
-        try {
53
-            $controller->setRequestedVersion($version);
54
-            return $controller->sendResponse(
55
-                $controller->insert(
56
-                    $controller->getModelVersionInfo()->loadModel($model_name),
57
-                    $request
58
-                )
59
-            );
60
-        } catch (\Exception $e) {
61
-            return $controller->sendResponse($e);
62
-        }
63
-    }
41
+	/**
42
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
43
+	 *
44
+	 * @param WP_REST_Request $request
45
+	 * @param string          $version
46
+	 * @param string          $model_name
47
+	 * @return WP_REST_Response|\WP_Error
48
+	 */
49
+	public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name)
50
+	{
51
+		$controller = new Write();
52
+		try {
53
+			$controller->setRequestedVersion($version);
54
+			return $controller->sendResponse(
55
+				$controller->insert(
56
+					$controller->getModelVersionInfo()->loadModel($model_name),
57
+					$request
58
+				)
59
+			);
60
+		} catch (\Exception $e) {
61
+			return $controller->sendResponse($e);
62
+		}
63
+	}
64 64
 
65 65
 
66
-    /**
67
-     * Handles a request from \WP_REST_Server to update an EE model
68
-     *
69
-     * @param WP_REST_Request $request
70
-     * @param string          $version
71
-     * @param string          $model_name
72
-     * @return WP_REST_Response|\WP_Error
73
-     */
74
-    public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name)
75
-    {
76
-        $controller = new Write();
77
-        try {
78
-            $controller->setRequestedVersion($version);
79
-            return $controller->sendResponse(
80
-                $controller->update(
81
-                    $controller->getModelVersionInfo()->loadModel($model_name),
82
-                    $request
83
-                )
84
-            );
85
-        } catch (\Exception $e) {
86
-            return $controller->sendResponse($e);
87
-        }
88
-    }
66
+	/**
67
+	 * Handles a request from \WP_REST_Server to update an EE model
68
+	 *
69
+	 * @param WP_REST_Request $request
70
+	 * @param string          $version
71
+	 * @param string          $model_name
72
+	 * @return WP_REST_Response|\WP_Error
73
+	 */
74
+	public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name)
75
+	{
76
+		$controller = new Write();
77
+		try {
78
+			$controller->setRequestedVersion($version);
79
+			return $controller->sendResponse(
80
+				$controller->update(
81
+					$controller->getModelVersionInfo()->loadModel($model_name),
82
+					$request
83
+				)
84
+			);
85
+		} catch (\Exception $e) {
86
+			return $controller->sendResponse($e);
87
+		}
88
+	}
89 89
 
90 90
 
91
-    /**
92
-     * Deletes a single model object and returns it. Unless
93
-     *
94
-     * @param WP_REST_Request $request
95
-     * @param string          $version
96
-     * @param string          $model_name
97
-     * @return WP_REST_Response|\WP_Error
98
-     */
99
-    public static function handleRequestDelete(WP_REST_Request $request, $version, $model_name)
100
-    {
101
-        $controller = new Write();
102
-        try {
103
-            $controller->setRequestedVersion($version);
104
-            return $controller->sendResponse(
105
-                $controller->delete(
106
-                    $controller->getModelVersionInfo()->loadModel($model_name),
107
-                    $request
108
-                )
109
-            );
110
-        } catch (\Exception $e) {
111
-            return $controller->sendResponse($e);
112
-        }
113
-    }
91
+	/**
92
+	 * Deletes a single model object and returns it. Unless
93
+	 *
94
+	 * @param WP_REST_Request $request
95
+	 * @param string          $version
96
+	 * @param string          $model_name
97
+	 * @return WP_REST_Response|\WP_Error
98
+	 */
99
+	public static function handleRequestDelete(WP_REST_Request $request, $version, $model_name)
100
+	{
101
+		$controller = new Write();
102
+		try {
103
+			$controller->setRequestedVersion($version);
104
+			return $controller->sendResponse(
105
+				$controller->delete(
106
+					$controller->getModelVersionInfo()->loadModel($model_name),
107
+					$request
108
+				)
109
+			);
110
+		} catch (\Exception $e) {
111
+			return $controller->sendResponse($e);
112
+		}
113
+	}
114 114
 
115 115
 
116
-    /**
117
-     * Inserts a new model object according to the $request
118
-     *
119
-     * @param EEM_Base        $model
120
-     * @param WP_REST_Request $request
121
-     * @return array
122
-     * @throws EE_Error
123
-     * @throws RestException
124
-     */
125
-    public function insert(EEM_Base $model, WP_REST_Request $request)
126
-    {
127
-        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
128
-        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
129
-        if (! current_user_can($default_cap_to_check_for)) {
130
-            throw new RestException(
131
-                'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
132
-                sprintf(
133
-                    esc_html__(
134
-                    // @codingStandardsIgnoreStart
135
-                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.',
136
-                        // @codingStandardsIgnoreEnd
137
-                        'event_espresso'
138
-                    ),
139
-                    $default_cap_to_check_for
140
-                ),
141
-                array('status' => 403)
142
-            );
143
-        }
144
-        $submitted_json_data = array_merge((array) $request->get_body_params(), (array) $request->get_json_params());
145
-        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
146
-            $submitted_json_data,
147
-            $model,
148
-            $this->getModelVersionInfo()->requestedVersion(),
149
-            true
150
-        );
151
-        $model_obj = EE_Registry::instance()->load_class(
152
-            $model->get_this_model_name(),
153
-            array($model_data, $model->get_timezone()),
154
-            false,
155
-            false
156
-        );
157
-        $model_obj->save();
158
-        $new_id = $model_obj->ID();
159
-        if (! $new_id) {
160
-            throw new RestException(
161
-                'rest_insertion_failed',
162
-                sprintf(__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
163
-            );
164
-        }
165
-        return $this->returnModelObjAsJsonResponse($model_obj, $request);
166
-    }
116
+	/**
117
+	 * Inserts a new model object according to the $request
118
+	 *
119
+	 * @param EEM_Base        $model
120
+	 * @param WP_REST_Request $request
121
+	 * @return array
122
+	 * @throws EE_Error
123
+	 * @throws RestException
124
+	 */
125
+	public function insert(EEM_Base $model, WP_REST_Request $request)
126
+	{
127
+		Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
128
+		$default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
129
+		if (! current_user_can($default_cap_to_check_for)) {
130
+			throw new RestException(
131
+				'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
132
+				sprintf(
133
+					esc_html__(
134
+					// @codingStandardsIgnoreStart
135
+						'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.',
136
+						// @codingStandardsIgnoreEnd
137
+						'event_espresso'
138
+					),
139
+					$default_cap_to_check_for
140
+				),
141
+				array('status' => 403)
142
+			);
143
+		}
144
+		$submitted_json_data = array_merge((array) $request->get_body_params(), (array) $request->get_json_params());
145
+		$model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
146
+			$submitted_json_data,
147
+			$model,
148
+			$this->getModelVersionInfo()->requestedVersion(),
149
+			true
150
+		);
151
+		$model_obj = EE_Registry::instance()->load_class(
152
+			$model->get_this_model_name(),
153
+			array($model_data, $model->get_timezone()),
154
+			false,
155
+			false
156
+		);
157
+		$model_obj->save();
158
+		$new_id = $model_obj->ID();
159
+		if (! $new_id) {
160
+			throw new RestException(
161
+				'rest_insertion_failed',
162
+				sprintf(__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
163
+			);
164
+		}
165
+		return $this->returnModelObjAsJsonResponse($model_obj, $request);
166
+	}
167 167
 
168 168
 
169
-    /**
170
-     * Updates an existing model object according to the $request
171
-     *
172
-     * @param EEM_Base        $model
173
-     * @param WP_REST_Request $request
174
-     * @return array
175
-     * @throws EE_Error
176
-     */
177
-    public function update(EEM_Base $model, WP_REST_Request $request)
178
-    {
179
-        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
180
-        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
181
-        if (! current_user_can($default_cap_to_check_for)) {
182
-            throw new RestException(
183
-                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
184
-                sprintf(
185
-                    esc_html__(
186
-                    // @codingStandardsIgnoreStart
187
-                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.',
188
-                        // @codingStandardsIgnoreEnd
189
-                        'event_espresso'
190
-                    ),
191
-                    $default_cap_to_check_for
192
-                ),
193
-                array('status' => 403)
194
-            );
195
-        }
196
-        $obj_id = $request->get_param('id');
197
-        if (! $obj_id) {
198
-            throw new RestException(
199
-                'rest_edit_failed',
200
-                sprintf(__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
201
-            );
202
-        }
203
-        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
204
-            $this->getBodyParams($request),
205
-            $model,
206
-            $this->getModelVersionInfo()->requestedVersion(),
207
-            true
208
-        );
209
-        $model_obj = $model->get_one_by_ID($obj_id);
210
-        if (! $model_obj instanceof EE_Base_Class) {
211
-            $lowercase_model_name = strtolower($model->get_this_model_name());
212
-            throw new RestException(
213
-                sprintf('rest_%s_invalid_id', $lowercase_model_name),
214
-                sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
215
-                array('status' => 404)
216
-            );
217
-        }
218
-        $model_obj->save($model_data);
219
-        return $this->returnModelObjAsJsonResponse($model_obj, $request);
220
-    }
169
+	/**
170
+	 * Updates an existing model object according to the $request
171
+	 *
172
+	 * @param EEM_Base        $model
173
+	 * @param WP_REST_Request $request
174
+	 * @return array
175
+	 * @throws EE_Error
176
+	 */
177
+	public function update(EEM_Base $model, WP_REST_Request $request)
178
+	{
179
+		Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
180
+		$default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
181
+		if (! current_user_can($default_cap_to_check_for)) {
182
+			throw new RestException(
183
+				'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
184
+				sprintf(
185
+					esc_html__(
186
+					// @codingStandardsIgnoreStart
187
+						'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.',
188
+						// @codingStandardsIgnoreEnd
189
+						'event_espresso'
190
+					),
191
+					$default_cap_to_check_for
192
+				),
193
+				array('status' => 403)
194
+			);
195
+		}
196
+		$obj_id = $request->get_param('id');
197
+		if (! $obj_id) {
198
+			throw new RestException(
199
+				'rest_edit_failed',
200
+				sprintf(__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
201
+			);
202
+		}
203
+		$model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
204
+			$this->getBodyParams($request),
205
+			$model,
206
+			$this->getModelVersionInfo()->requestedVersion(),
207
+			true
208
+		);
209
+		$model_obj = $model->get_one_by_ID($obj_id);
210
+		if (! $model_obj instanceof EE_Base_Class) {
211
+			$lowercase_model_name = strtolower($model->get_this_model_name());
212
+			throw new RestException(
213
+				sprintf('rest_%s_invalid_id', $lowercase_model_name),
214
+				sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
215
+				array('status' => 404)
216
+			);
217
+		}
218
+		$model_obj->save($model_data);
219
+		return $this->returnModelObjAsJsonResponse($model_obj, $request);
220
+	}
221 221
 
222 222
 
223
-    /**
224
-     * Updates an existing model object according to the $request
225
-     *
226
-     * @param EEM_Base        $model
227
-     * @param WP_REST_Request $request
228
-     * @return array of either the soft-deleted item, or
229
-     * @throws EE_Error
230
-     */
231
-    public function delete(EEM_Base $model, WP_REST_Request $request)
232
-    {
233
-        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
234
-        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
235
-        if (! current_user_can($default_cap_to_check_for)) {
236
-            throw new RestException(
237
-                'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
238
-                sprintf(
239
-                    esc_html__(
240
-                    // @codingStandardsIgnoreStart
241
-                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.',
242
-                        // @codingStandardsIgnoreEnd
243
-                        'event_espresso'
244
-                    ),
245
-                    $default_cap_to_check_for
246
-                ),
247
-                array('status' => 403)
248
-            );
249
-        }
250
-        $obj_id = $request->get_param('id');
251
-        // this is where we would apply more fine-grained caps
252
-        $model_obj = $model->get_one_by_ID($obj_id);
253
-        if (! $model_obj instanceof EE_Base_Class) {
254
-            $lowercase_model_name = strtolower($model->get_this_model_name());
255
-            throw new RestException(
256
-                sprintf('rest_%s_invalid_id', $lowercase_model_name),
257
-                sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
258
-                array('status' => 404)
259
-            );
260
-        }
261
-        $requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN);
262
-        $requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN);
263
-        if ($requested_permanent_delete) {
264
-            $previous = $this->returnModelObjAsJsonResponse($model_obj, $request);
265
-            $deleted = (bool) $model->delete_permanently_by_ID($obj_id, $requested_allow_blocking);
266
-            return array(
267
-                'deleted'  => $deleted,
268
-                'previous' => $previous,
269
-            );
270
-        } else {
271
-            if ($model instanceof EEM_Soft_Delete_Base) {
272
-                $model->delete_by_ID($obj_id, $requested_allow_blocking);
273
-                return $this->returnModelObjAsJsonResponse($model_obj, $request);
274
-            } else {
275
-                throw new RestException(
276
-                    'rest_trash_not_supported',
277
-                    501,
278
-                    sprintf(
279
-                        esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'),
280
-                        EEH_Inflector::pluralize($model->get_this_model_name())
281
-                    )
282
-                );
283
-            }
284
-        }
285
-    }
223
+	/**
224
+	 * Updates an existing model object according to the $request
225
+	 *
226
+	 * @param EEM_Base        $model
227
+	 * @param WP_REST_Request $request
228
+	 * @return array of either the soft-deleted item, or
229
+	 * @throws EE_Error
230
+	 */
231
+	public function delete(EEM_Base $model, WP_REST_Request $request)
232
+	{
233
+		Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
234
+		$default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
235
+		if (! current_user_can($default_cap_to_check_for)) {
236
+			throw new RestException(
237
+				'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
238
+				sprintf(
239
+					esc_html__(
240
+					// @codingStandardsIgnoreStart
241
+						'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.',
242
+						// @codingStandardsIgnoreEnd
243
+						'event_espresso'
244
+					),
245
+					$default_cap_to_check_for
246
+				),
247
+				array('status' => 403)
248
+			);
249
+		}
250
+		$obj_id = $request->get_param('id');
251
+		// this is where we would apply more fine-grained caps
252
+		$model_obj = $model->get_one_by_ID($obj_id);
253
+		if (! $model_obj instanceof EE_Base_Class) {
254
+			$lowercase_model_name = strtolower($model->get_this_model_name());
255
+			throw new RestException(
256
+				sprintf('rest_%s_invalid_id', $lowercase_model_name),
257
+				sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
258
+				array('status' => 404)
259
+			);
260
+		}
261
+		$requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN);
262
+		$requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN);
263
+		if ($requested_permanent_delete) {
264
+			$previous = $this->returnModelObjAsJsonResponse($model_obj, $request);
265
+			$deleted = (bool) $model->delete_permanently_by_ID($obj_id, $requested_allow_blocking);
266
+			return array(
267
+				'deleted'  => $deleted,
268
+				'previous' => $previous,
269
+			);
270
+		} else {
271
+			if ($model instanceof EEM_Soft_Delete_Base) {
272
+				$model->delete_by_ID($obj_id, $requested_allow_blocking);
273
+				return $this->returnModelObjAsJsonResponse($model_obj, $request);
274
+			} else {
275
+				throw new RestException(
276
+					'rest_trash_not_supported',
277
+					501,
278
+					sprintf(
279
+						esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'),
280
+						EEH_Inflector::pluralize($model->get_this_model_name())
281
+					)
282
+				);
283
+			}
284
+		}
285
+	}
286 286
 
287 287
 
288
-    /**
289
-     * Returns an array ready to be converted into a JSON response, based solely on the model object
290
-     *
291
-     * @param EE_Base_Class   $model_obj
292
-     * @param WP_REST_Request $request
293
-     * @return array ready for a response
294
-     */
295
-    protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request)
296
-    {
297
-        $model = $model_obj->get_model();
298
-        // create an array exactly like the wpdb results row,
299
-        // so we can pass it to controllers/model/Read::create_entity_from_wpdb_result()
300
-        $simulated_db_row = array();
301
-        foreach ($model->field_settings(true) as $field_name => $field_obj) {
302
-            // we need to reconstruct the normal wpdb results, including the db-only fields
303
-            // like a secondary table's primary key. The models expect those (but don't care what value they have)
304
-            if ($field_obj instanceof EE_DB_Only_Field_Base) {
305
-                $raw_value = true;
306
-            } elseif ($field_obj instanceof EE_Datetime_Field) {
307
-                $raw_value = $model_obj->get_DateTime_object($field_name);
308
-            } else {
309
-                $raw_value = $model_obj->get_raw($field_name);
310
-            }
311
-            $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value);
312
-        }
313
-        $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
314
-        $read_controller->setRequestedVersion($this->getRequestedVersion());
315
-        // the simulates request really doesn't need any info downstream
316
-        $simulated_request = new WP_REST_Request('GET');
317
-        return $read_controller->createEntityFromWpdbResult(
318
-            $model_obj->get_model(),
319
-            $simulated_db_row,
320
-            $simulated_request
321
-        );
322
-    }
288
+	/**
289
+	 * Returns an array ready to be converted into a JSON response, based solely on the model object
290
+	 *
291
+	 * @param EE_Base_Class   $model_obj
292
+	 * @param WP_REST_Request $request
293
+	 * @return array ready for a response
294
+	 */
295
+	protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request)
296
+	{
297
+		$model = $model_obj->get_model();
298
+		// create an array exactly like the wpdb results row,
299
+		// so we can pass it to controllers/model/Read::create_entity_from_wpdb_result()
300
+		$simulated_db_row = array();
301
+		foreach ($model->field_settings(true) as $field_name => $field_obj) {
302
+			// we need to reconstruct the normal wpdb results, including the db-only fields
303
+			// like a secondary table's primary key. The models expect those (but don't care what value they have)
304
+			if ($field_obj instanceof EE_DB_Only_Field_Base) {
305
+				$raw_value = true;
306
+			} elseif ($field_obj instanceof EE_Datetime_Field) {
307
+				$raw_value = $model_obj->get_DateTime_object($field_name);
308
+			} else {
309
+				$raw_value = $model_obj->get_raw($field_name);
310
+			}
311
+			$simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value);
312
+		}
313
+		$read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
314
+		$read_controller->setRequestedVersion($this->getRequestedVersion());
315
+		// the simulates request really doesn't need any info downstream
316
+		$simulated_request = new WP_REST_Request('GET');
317
+		return $read_controller->createEntityFromWpdbResult(
318
+			$model_obj->get_model(),
319
+			$simulated_db_row,
320
+			$simulated_request
321
+		);
322
+	}
323 323
 
324 324
 
325
-    /**
326
-     * Gets the item affected by this request
327
-     *
328
-     * @param EEM_Base        $model
329
-     * @param WP_REST_Request $request
330
-     * @param  int|string     $obj_id
331
-     * @return \WP_Error|array
332
-     */
333
-    protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id)
334
-    {
335
-        $requested_version = $this->getRequestedVersion($request->get_route());
336
-        $get_request = new WP_REST_Request(
337
-            'GET',
338
-            EED_Core_Rest_Api::ee_api_namespace
339
-            . $requested_version
340
-            . '/'
341
-            . EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
342
-            . '/'
343
-            . $obj_id
344
-        );
345
-        $get_request->set_url_params(
346
-            array(
347
-                'id'      => $obj_id,
348
-                'include' => $request->get_param('include'),
349
-            )
350
-        );
351
-        $read_controller = new Read();
352
-        $read_controller->setRequestedVersion($this->getRequestedVersion());
353
-        return $read_controller->getEntityFromModel($model, $get_request);
354
-    }
325
+	/**
326
+	 * Gets the item affected by this request
327
+	 *
328
+	 * @param EEM_Base        $model
329
+	 * @param WP_REST_Request $request
330
+	 * @param  int|string     $obj_id
331
+	 * @return \WP_Error|array
332
+	 */
333
+	protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id)
334
+	{
335
+		$requested_version = $this->getRequestedVersion($request->get_route());
336
+		$get_request = new WP_REST_Request(
337
+			'GET',
338
+			EED_Core_Rest_Api::ee_api_namespace
339
+			. $requested_version
340
+			. '/'
341
+			. EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
342
+			. '/'
343
+			. $obj_id
344
+		);
345
+		$get_request->set_url_params(
346
+			array(
347
+				'id'      => $obj_id,
348
+				'include' => $request->get_param('include'),
349
+			)
350
+		);
351
+		$read_controller = new Read();
352
+		$read_controller->setRequestedVersion($this->getRequestedVersion());
353
+		return $read_controller->getEntityFromModel($model, $get_request);
354
+	}
355 355
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -126,9 +126,9 @@  discard block
 block discarded – undo
126 126
     {
127 127
         Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
128 128
         $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
129
-        if (! current_user_can($default_cap_to_check_for)) {
129
+        if ( ! current_user_can($default_cap_to_check_for)) {
130 130
             throw new RestException(
131
-                'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
131
+                'rest_cannot_create_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
132 132
                 sprintf(
133 133
                     esc_html__(
134 134
                     // @codingStandardsIgnoreStart
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
         );
157 157
         $model_obj->save();
158 158
         $new_id = $model_obj->ID();
159
-        if (! $new_id) {
159
+        if ( ! $new_id) {
160 160
             throw new RestException(
161 161
                 'rest_insertion_failed',
162 162
                 sprintf(__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
@@ -178,9 +178,9 @@  discard block
 block discarded – undo
178 178
     {
179 179
         Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
180 180
         $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
181
-        if (! current_user_can($default_cap_to_check_for)) {
181
+        if ( ! current_user_can($default_cap_to_check_for)) {
182 182
             throw new RestException(
183
-                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
183
+                'rest_cannot_edit_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
184 184
                 sprintf(
185 185
                     esc_html__(
186 186
                     // @codingStandardsIgnoreStart
@@ -194,7 +194,7 @@  discard block
 block discarded – undo
194 194
             );
195 195
         }
196 196
         $obj_id = $request->get_param('id');
197
-        if (! $obj_id) {
197
+        if ( ! $obj_id) {
198 198
             throw new RestException(
199 199
                 'rest_edit_failed',
200 200
                 sprintf(__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
@@ -207,7 +207,7 @@  discard block
 block discarded – undo
207 207
             true
208 208
         );
209 209
         $model_obj = $model->get_one_by_ID($obj_id);
210
-        if (! $model_obj instanceof EE_Base_Class) {
210
+        if ( ! $model_obj instanceof EE_Base_Class) {
211 211
             $lowercase_model_name = strtolower($model->get_this_model_name());
212 212
             throw new RestException(
213 213
                 sprintf('rest_%s_invalid_id', $lowercase_model_name),
@@ -232,9 +232,9 @@  discard block
 block discarded – undo
232 232
     {
233 233
         Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
234 234
         $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
235
-        if (! current_user_can($default_cap_to_check_for)) {
235
+        if ( ! current_user_can($default_cap_to_check_for)) {
236 236
             throw new RestException(
237
-                'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
237
+                'rest_cannot_delete_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
238 238
                 sprintf(
239 239
                     esc_html__(
240 240
                     // @codingStandardsIgnoreStart
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
         $obj_id = $request->get_param('id');
251 251
         // this is where we would apply more fine-grained caps
252 252
         $model_obj = $model->get_one_by_ID($obj_id);
253
-        if (! $model_obj instanceof EE_Base_Class) {
253
+        if ( ! $model_obj instanceof EE_Base_Class) {
254 254
             $lowercase_model_name = strtolower($model->get_this_model_name());
255 255
             throw new RestException(
256 256
                 sprintf('rest_%s_invalid_id', $lowercase_model_name),
@@ -308,7 +308,7 @@  discard block
 block discarded – undo
308 308
             } else {
309 309
                 $raw_value = $model_obj->get_raw($field_name);
310 310
             }
311
-            $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value);
311
+            $simulated_db_row[$field_obj->get_qualified_column()] = $field_obj->prepare_for_use_in_db($raw_value);
312 312
         }
313 313
         $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
314 314
         $read_controller->setRequestedVersion($this->getRequestedVersion());
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Indentation   +1346 added lines, -1346 removed lines patch added patch discarded remove patch
@@ -40,1350 +40,1350 @@
 block discarded – undo
40 40
 {
41 41
 
42 42
 
43
-    /**
44
-     * @var CalculatedModelFields
45
-     */
46
-    protected $fields_calculator;
47
-
48
-
49
-    /**
50
-     * Read constructor.
51
-     * @param CalculatedModelFields $fields_calculator
52
-     */
53
-    public function __construct(CalculatedModelFields $fields_calculator)
54
-    {
55
-        parent::__construct();
56
-        $this->fields_calculator = $fields_calculator;
57
-    }
58
-
59
-
60
-    /**
61
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
62
-     *
63
-     * @param WP_REST_Request $request
64
-     * @param string $version
65
-     * @param string $model_name
66
-     * @return WP_REST_Response|WP_Error
67
-     * @throws InvalidArgumentException
68
-     * @throws InvalidDataTypeException
69
-     * @throws InvalidInterfaceException
70
-     */
71
-    public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
72
-    {
73
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
74
-        try {
75
-            $controller->setRequestedVersion($version);
76
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
77
-                return $controller->sendResponse(
78
-                    new WP_Error(
79
-                        'endpoint_parsing_error',
80
-                        sprintf(
81
-                            __(
82
-                                'There is no model for endpoint %s. Please contact event espresso support',
83
-                                'event_espresso'
84
-                            ),
85
-                            $model_name
86
-                        )
87
-                    )
88
-                );
89
-            }
90
-            return $controller->sendResponse(
91
-                $controller->getEntitiesFromModel(
92
-                    $controller->getModelVersionInfo()->loadModel($model_name),
93
-                    $request
94
-                )
95
-            );
96
-        } catch (Exception $e) {
97
-            return $controller->sendResponse($e);
98
-        }
99
-    }
100
-
101
-
102
-    /**
103
-     * Prepares and returns schema for any OPTIONS request.
104
-     *
105
-     * @param string $version The API endpoint version being used.
106
-     * @param string $model_name Something like `Event` or `Registration`
107
-     * @return array
108
-     * @throws InvalidArgumentException
109
-     * @throws InvalidDataTypeException
110
-     * @throws InvalidInterfaceException
111
-     */
112
-    public static function handleSchemaRequest($version, $model_name)
113
-    {
114
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
115
-        try {
116
-            $controller->setRequestedVersion($version);
117
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
118
-                return array();
119
-            }
120
-            // get the model for this version
121
-            $model = $controller->getModelVersionInfo()->loadModel($model_name);
122
-            $model_schema = new JsonModelSchema($model, LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields'));
123
-            return $model_schema->getModelSchemaForRelations(
124
-                $controller->getModelVersionInfo()->relationSettings($model),
125
-                $controller->customizeSchemaForRestResponse(
126
-                    $model,
127
-                    $model_schema->getModelSchemaForFields(
128
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
129
-                        $model_schema->getInitialSchemaStructure()
130
-                    )
131
-                )
132
-            );
133
-        } catch (Exception $e) {
134
-            return array();
135
-        }
136
-    }
137
-
138
-
139
-    /**
140
-     * This loops through each field in the given schema for the model and does the following:
141
-     * - add any extra fields that are REST API specific and related to existing fields.
142
-     * - transform default values into the correct format for a REST API response.
143
-     *
144
-     * @param EEM_Base $model
145
-     * @param array    $schema
146
-     * @return array  The final schema.
147
-     */
148
-    protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
149
-    {
150
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
151
-            $schema = $this->translateDefaultsForRestResponse(
152
-                $field_name,
153
-                $field,
154
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
155
-            );
156
-        }
157
-        return $schema;
158
-    }
159
-
160
-
161
-    /**
162
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
163
-     * response.
164
-     *
165
-     * @param                      $field_name
166
-     * @param EE_Model_Field_Base  $field
167
-     * @param array                $schema
168
-     * @return array
169
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
170
-     * did, let's know about it ASAP, so let the exception bubble up)
171
-     */
172
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
173
-    {
174
-        if (isset($schema['properties'][ $field_name ]['default'])) {
175
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
176
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
177
-                    if ($default_key === 'raw') {
178
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
179
-                            ModelDataTranslator::prepareFieldValueForJson(
180
-                                $field,
181
-                                $default_value,
182
-                                $this->getModelVersionInfo()->requestedVersion()
183
-                            );
184
-                    }
185
-                }
186
-            } else {
187
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
188
-                    $field,
189
-                    $schema['properties'][ $field_name ]['default'],
190
-                    $this->getModelVersionInfo()->requestedVersion()
191
-                );
192
-            }
193
-        }
194
-        return $schema;
195
-    }
196
-
197
-
198
-    /**
199
-     * Adds additional fields to the schema
200
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
201
-     * needs to be added to the schema.
202
-     *
203
-     * @param                      $field_name
204
-     * @param EE_Model_Field_Base  $field
205
-     * @param array                $schema
206
-     * @return array
207
-     */
208
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
209
-    {
210
-        if ($field instanceof EE_Datetime_Field) {
211
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
212
-            // modify the description
213
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
214
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
215
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
216
-            );
217
-        }
218
-        return $schema;
219
-    }
220
-
221
-
222
-    /**
223
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
224
-     *
225
-     * @return string
226
-     */
227
-    protected function getRouteFromRequest()
228
-    {
229
-        if (isset($GLOBALS['wp'])
230
-            && $GLOBALS['wp'] instanceof \WP
231
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
232
-        ) {
233
-            return $GLOBALS['wp']->query_vars['rest_route'];
234
-        } else {
235
-            return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
236
-        }
237
-    }
238
-
239
-
240
-    /**
241
-     * Gets a single entity related to the model indicated in the path and its id
242
-     *
243
-     * @param WP_REST_Request $request
244
-     * @param string $version
245
-     * @param string $model_name
246
-     * @return WP_REST_Response|WP_Error
247
-     * @throws InvalidDataTypeException
248
-     * @throws InvalidInterfaceException
249
-     * @throws InvalidArgumentException
250
-     */
251
-    public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
252
-    {
253
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
254
-        try {
255
-            $controller->setRequestedVersion($version);
256
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
257
-                return $controller->sendResponse(
258
-                    new WP_Error(
259
-                        'endpoint_parsing_error',
260
-                        sprintf(
261
-                            __(
262
-                                'There is no model for endpoint %s. Please contact event espresso support',
263
-                                'event_espresso'
264
-                            ),
265
-                            $model_name
266
-                        )
267
-                    )
268
-                );
269
-            }
270
-            return $controller->sendResponse(
271
-                $controller->getEntityFromModel(
272
-                    $controller->getModelVersionInfo()->loadModel($model_name),
273
-                    $request
274
-                )
275
-            );
276
-        } catch (Exception $e) {
277
-            return $controller->sendResponse($e);
278
-        }
279
-    }
280
-
281
-
282
-    /**
283
-     * Gets all the related entities (or if its a belongs-to relation just the one)
284
-     * to the item with the given id
285
-     *
286
-     * @param WP_REST_Request $request
287
-     * @param string $version
288
-     * @param string $model_name
289
-     * @param string $related_model_name
290
-     * @return WP_REST_Response|WP_Error
291
-     * @throws InvalidDataTypeException
292
-     * @throws InvalidInterfaceException
293
-     * @throws InvalidArgumentException
294
-     */
295
-    public static function handleRequestGetRelated(
296
-        WP_REST_Request $request,
297
-        $version,
298
-        $model_name,
299
-        $related_model_name
300
-    ) {
301
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
302
-        try {
303
-            $controller->setRequestedVersion($version);
304
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
305
-                return $controller->sendResponse(
306
-                    new WP_Error(
307
-                        'endpoint_parsing_error',
308
-                        sprintf(
309
-                            __(
310
-                                'There is no model for endpoint %s. Please contact event espresso support',
311
-                                'event_espresso'
312
-                            ),
313
-                            $model_name
314
-                        )
315
-                    )
316
-                );
317
-            }
318
-            $main_model = $controller->getModelVersionInfo()->loadModel($model_name);
319
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
320
-                return $controller->sendResponse(
321
-                    new WP_Error(
322
-                        'endpoint_parsing_error',
323
-                        sprintf(
324
-                            __(
325
-                                'There is no model for endpoint %s. Please contact event espresso support',
326
-                                'event_espresso'
327
-                            ),
328
-                            $related_model_name
329
-                        )
330
-                    )
331
-                );
332
-            }
333
-            return $controller->sendResponse(
334
-                $controller->getEntitiesFromRelation(
335
-                    $request->get_param('id'),
336
-                    $main_model->related_settings_for($related_model_name),
337
-                    $request
338
-                )
339
-            );
340
-        } catch (Exception $e) {
341
-            return $controller->sendResponse($e);
342
-        }
343
-    }
344
-
345
-
346
-    /**
347
-     * Gets a collection for the given model and filters
348
-     *
349
-     * @param EEM_Base        $model
350
-     * @param WP_REST_Request $request
351
-     * @return array|WP_Error
352
-     */
353
-    public function getEntitiesFromModel($model, $request)
354
-    {
355
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
356
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
357
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
358
-            return new WP_Error(
359
-                sprintf('rest_%s_cannot_list', $model_name_plural),
360
-                sprintf(
361
-                    __('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
362
-                    $model_name_plural,
363
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
364
-                ),
365
-                array('status' => 403)
366
-            );
367
-        }
368
-        if (! $request->get_header('no_rest_headers')) {
369
-            $this->setHeadersFromQueryParams($model, $query_params);
370
-        }
371
-        /** @type array $results */
372
-        $results = $model->get_all_wpdb_results($query_params);
373
-        $nice_results = array();
374
-        foreach ($results as $result) {
375
-            $nice_results[] = $this->createEntityFromWpdbResult(
376
-                $model,
377
-                $result,
378
-                $request
379
-            );
380
-        }
381
-        return $nice_results;
382
-    }
383
-
384
-
385
-    /**
386
-     * Gets the collection for given relation object
387
-     * The same as Read::get_entities_from_model(), except if the relation
388
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
389
-     * the join-model-object into the results
390
-     *
391
-     * @param array                   $primary_model_query_params query params for finding the item from which
392
-     *                                                            relations will be based
393
-     * @param \EE_Model_Relation_Base $relation
394
-     * @param WP_REST_Request         $request
395
-     * @return WP_Error|array
396
-     * @throws RestException
397
-     */
398
-    protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
399
-    {
400
-        $context = $this->validateContext($request->get_param('caps'));
401
-        $model = $relation->get_this_model();
402
-        $related_model = $relation->get_other_model();
403
-        if (! isset($primary_model_query_params[0])) {
404
-            $primary_model_query_params[0] = array();
405
-        }
406
-        // check if they can access the 1st model object
407
-        $primary_model_query_params = array(
408
-            0       => $primary_model_query_params[0],
409
-            'limit' => 1,
410
-        );
411
-        if ($model instanceof \EEM_Soft_Delete_Base) {
412
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
413
-                $primary_model_query_params
414
-            );
415
-        }
416
-        $restricted_query_params = $primary_model_query_params;
417
-        $restricted_query_params['caps'] = $context;
418
-        $this->setDebugInfo('main model query params', $restricted_query_params);
419
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
420
-        if (! (
421
-            Capabilities::currentUserHasPartialAccessTo($related_model, $context)
422
-            && $model->exists($restricted_query_params)
423
-        )
424
-        ) {
425
-            if ($relation instanceof EE_Belongs_To_Relation) {
426
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
427
-            } else {
428
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
429
-                    $related_model->get_this_model_name()
430
-                );
431
-            }
432
-            return new WP_Error(
433
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
434
-                sprintf(
435
-                    __(
436
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
437
-                        'event_espresso'
438
-                    ),
439
-                    $related_model_name_maybe_plural,
440
-                    $relation->get_this_model()->get_this_model_name(),
441
-                    implode(
442
-                        ',',
443
-                        array_keys(
444
-                            Capabilities::getMissingPermissions($related_model, $context)
445
-                        )
446
-                    )
447
-                ),
448
-                array('status' => 403)
449
-            );
450
-        }
451
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
452
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
453
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
454
-                              . '.'
455
-                              . $where_condition_key ] = $where_condition_value;
456
-        }
457
-        $query_params['default_where_conditions'] = 'none';
458
-        $query_params['caps'] = $context;
459
-        if (! $request->get_header('no_rest_headers')) {
460
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
461
-        }
462
-        /** @type array $results */
463
-        $results = $relation->get_other_model()->get_all_wpdb_results($query_params);
464
-        $nice_results = array();
465
-        foreach ($results as $result) {
466
-            $nice_result = $this->createEntityFromWpdbResult(
467
-                $relation->get_other_model(),
468
-                $result,
469
-                $request
470
-            );
471
-            if ($relation instanceof \EE_HABTM_Relation) {
472
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
473
-                // if there are conflicts we prefer the properties from the main model
474
-                $join_model_result = $this->createEntityFromWpdbResult(
475
-                    $relation->get_join_model(),
476
-                    $result,
477
-                    $request
478
-                );
479
-                $joined_result = array_merge($nice_result, $join_model_result);
480
-                // but keep the meta stuff from the main model
481
-                if (isset($nice_result['meta'])) {
482
-                    $joined_result['meta'] = $nice_result['meta'];
483
-                }
484
-                $nice_result = $joined_result;
485
-            }
486
-            $nice_results[] = $nice_result;
487
-        }
488
-        if ($relation instanceof EE_Belongs_To_Relation) {
489
-            return array_shift($nice_results);
490
-        } else {
491
-            return $nice_results;
492
-        }
493
-    }
494
-
495
-
496
-    /**
497
-     * Gets the collection for given relation object
498
-     * The same as Read::get_entities_from_model(), except if the relation
499
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
500
-     * the join-model-object into the results
501
-     *
502
-     * @param string                  $id the ID of the thing we are fetching related stuff from
503
-     * @param \EE_Model_Relation_Base $relation
504
-     * @param WP_REST_Request         $request
505
-     * @return array|WP_Error
506
-     * @throws EE_Error
507
-     */
508
-    public function getEntitiesFromRelation($id, $relation, $request)
509
-    {
510
-        if (! $relation->get_this_model()->has_primary_key_field()) {
511
-            throw new EE_Error(
512
-                sprintf(
513
-                    __(
514
-                    // @codingStandardsIgnoreStart
515
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
516
-                        // @codingStandardsIgnoreEnd
517
-                        'event_espresso'
518
-                    ),
519
-                    $relation->get_this_model()->get_this_model_name()
520
-                )
521
-            );
522
-        }
523
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
524
-            array(
525
-                array(
526
-                    $relation->get_this_model()->primary_key_name() => $id,
527
-                ),
528
-            ),
529
-            $relation,
530
-            $request
531
-        );
532
-    }
533
-
534
-
535
-    /**
536
-     * Sets the headers that are based on the model and query params,
537
-     * like the total records. This should only be called on the original request
538
-     * from the client, not on subsequent internal
539
-     *
540
-     * @param EEM_Base $model
541
-     * @param array    $query_params
542
-     * @return void
543
-     */
544
-    protected function setHeadersFromQueryParams($model, $query_params)
545
-    {
546
-        $this->setDebugInfo('model query params', $query_params);
547
-        $this->setDebugInfo(
548
-            'missing caps',
549
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
550
-        );
551
-        // normally the limit to a 2-part array, where the 2nd item is the limit
552
-        if (! isset($query_params['limit'])) {
553
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
554
-        }
555
-        if (is_array($query_params['limit'])) {
556
-            $limit_parts = $query_params['limit'];
557
-        } else {
558
-            $limit_parts = explode(',', $query_params['limit']);
559
-            if (count($limit_parts) == 1) {
560
-                $limit_parts = array(0, $limit_parts[0]);
561
-            }
562
-        }
563
-        // remove the group by and having parts of the query, as those will
564
-        // make the sql query return an array of values, instead of just a single value
565
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
566
-        $count = $model->count($query_params, null, true);
567
-        $pages = $count / $limit_parts[1];
568
-        $this->setResponseHeader('Total', $count, false);
569
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
570
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
571
-    }
572
-
573
-
574
-    /**
575
-     * Changes database results into REST API entities
576
-     *
577
-     * @param EEM_Base        $model
578
-     * @param array           $db_row     like results from $wpdb->get_results()
579
-     * @param WP_REST_Request $rest_request
580
-     * @param string          $deprecated no longer used
581
-     * @return array ready for being converted into json for sending to client
582
-     */
583
-    public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
584
-    {
585
-        if (! $rest_request instanceof WP_REST_Request) {
586
-            // ok so this was called in the old style, where the 3rd arg was
587
-            // $include, and the 4th arg was $context
588
-            // now setup the request just to avoid fatal errors, although we won't be able
589
-            // to truly make use of it because it's kinda devoid of info
590
-            $rest_request = new WP_REST_Request();
591
-            $rest_request->set_param('include', $rest_request);
592
-            $rest_request->set_param('caps', $deprecated);
593
-        }
594
-        if ($rest_request->get_param('caps') == null) {
595
-            $rest_request->set_param('caps', EEM_Base::caps_read);
596
-        }
597
-        $entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
598
-        $entity_array = $this->addExtraFields($model, $db_row, $entity_array);
599
-        $entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
600
-        $entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request);
601
-        $entity_array = apply_filters(
602
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
603
-            $entity_array,
604
-            $model,
605
-            $rest_request->get_param('caps'),
606
-            $rest_request,
607
-            $this
608
-        );
609
-        $entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row);
610
-        $entity_array = apply_filters(
611
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
612
-            $entity_array,
613
-            $model,
614
-            $rest_request->get_param('caps'),
615
-            $rest_request,
616
-            $this
617
-        );
618
-        $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
619
-            $entity_array,
620
-            $model,
621
-            $rest_request->get_param('caps'),
622
-            $this->getModelVersionInfo(),
623
-            $model->get_index_primary_key_string(
624
-                $model->deduce_fields_n_values_from_cols_n_values($db_row)
625
-            )
626
-        );
627
-        $this->setDebugInfo(
628
-            'inaccessible fields',
629
-            array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
630
-        );
631
-        return apply_filters(
632
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
633
-            $result_without_inaccessible_fields,
634
-            $model,
635
-            $rest_request->get_param('caps')
636
-        );
637
-    }
638
-
639
-
640
-    /**
641
-     * Creates a REST entity array (JSON object we're going to return in the response, but
642
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
643
-     * from $wpdb->get_row( $sql, ARRAY_A)
644
-     *
645
-     * @param EEM_Base $model
646
-     * @param array    $db_row
647
-     * @return array entity mostly ready for converting to JSON and sending in the response
648
-     */
649
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
650
-    {
651
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
652
-        $result = array_intersect_key(
653
-            $result,
654
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
655
-        );
656
-        // if this is a CPT, we need to set the global $post to it,
657
-        // otherwise shortcodes etc won't work properly while rendering it
658
-        if ($model instanceof \EEM_CPT_Base) {
659
-            $do_chevy_shuffle = true;
660
-        } else {
661
-            $do_chevy_shuffle = false;
662
-        }
663
-        if ($do_chevy_shuffle) {
664
-            global $post;
665
-            $old_post = $post;
666
-            $post = get_post($result[ $model->primary_key_name() ]);
667
-            if (! $post instanceof \WP_Post) {
668
-                // well that's weird, because $result is what we JUST fetched from the database
669
-                throw new RestException(
670
-                    'error_fetching_post_from_database_results',
671
-                    esc_html__(
672
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
673
-                        'event_espresso'
674
-                    )
675
-                );
676
-            }
677
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
678
-            $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
679
-                $model_object_classname,
680
-                $result,
681
-                false,
682
-                false
683
-            );
684
-        }
685
-        foreach ($result as $field_name => $field_value) {
686
-            $field_obj = $model->field_settings_for($field_name);
687
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
688
-                unset($result[ $field_name ]);
689
-            } elseif ($this->isSubclassOfOne(
690
-                $field_obj,
691
-                $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
692
-            )
693
-            ) {
694
-                $result[ $field_name ] = array(
695
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
696
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
697
-                );
698
-            } elseif ($this->isSubclassOfOne(
699
-                $field_obj,
700
-                $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
701
-            )
702
-            ) {
703
-                $result[ $field_name ] = array(
704
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
705
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
706
-                );
707
-            } elseif ($field_obj instanceof \EE_Datetime_Field) {
708
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
709
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
710
-                if (is_null($field_value)) {
711
-                    $field_value = $field_obj->getDefaultDateTimeObj();
712
-                }
713
-                if (is_null($field_value)) {
714
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
715
-                        $field_obj,
716
-                        $field_value,
717
-                        $this->getModelVersionInfo()->requestedVersion()
718
-                    );
719
-                } else {
720
-                    $timezone = $field_value->getTimezone();
721
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
722
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
723
-                        $field_obj,
724
-                        $field_value,
725
-                        $this->getModelVersionInfo()->requestedVersion()
726
-                    );
727
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
728
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
729
-                        $field_obj,
730
-                        $field_value,
731
-                        $this->getModelVersionInfo()->requestedVersion()
732
-                    );
733
-                }
734
-                $result[ $field_name . '_gmt' ] = $gmt_date;
735
-                $result[ $field_name ] = $local_date;
736
-            } else {
737
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
738
-            }
739
-        }
740
-        if ($do_chevy_shuffle) {
741
-            $post = $old_post;
742
-        }
743
-        return $result;
744
-    }
745
-
746
-
747
-    /**
748
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
749
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
750
-     * representation using $field_obj->prepare_for_set_from_db())
751
-     *
752
-     * @param EE_Model_Field_Base $field_obj
753
-     * @param mixed               $value  as it's stored on a model object
754
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
755
-     * @return mixed
756
-     * @throws ObjectDetectedException if $value contains a PHP object
757
-     */
758
-    protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
759
-    {
760
-        $value = $field_obj->prepare_for_set_from_db($value);
761
-        switch ($format) {
762
-            case 'pretty':
763
-                $value = $field_obj->prepare_for_pretty_echoing($value);
764
-                break;
765
-            case 'normal':
766
-            default:
767
-                $value = $field_obj->prepare_for_get($value);
768
-                break;
769
-        }
770
-        return ModelDataTranslator::prepareFieldValuesForJson(
771
-            $field_obj,
772
-            $value,
773
-            $this->getModelVersionInfo()->requestedVersion()
774
-        );
775
-    }
776
-
777
-
778
-    /**
779
-     * Adds a few extra fields to the entity response
780
-     *
781
-     * @param EEM_Base $model
782
-     * @param array    $db_row
783
-     * @param array    $entity_array
784
-     * @return array modified entity
785
-     */
786
-    protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
787
-    {
788
-        if ($model instanceof EEM_CPT_Base) {
789
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
790
-        }
791
-        return $entity_array;
792
-    }
793
-
794
-
795
-    /**
796
-     * Gets links we want to add to the response
797
-     *
798
-     * @global \WP_REST_Server $wp_rest_server
799
-     * @param EEM_Base         $model
800
-     * @param array            $db_row
801
-     * @param array            $entity_array
802
-     * @return array the _links item in the entity
803
-     */
804
-    protected function getEntityLinks($model, $db_row, $entity_array)
805
-    {
806
-        // add basic links
807
-        $links = array();
808
-        if ($model->has_primary_key_field()) {
809
-            $links['self'] = array(
810
-                array(
811
-                    'href' => $this->getVersionedLinkTo(
812
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
813
-                        . '/'
814
-                        . $entity_array[ $model->primary_key_name() ]
815
-                    ),
816
-                ),
817
-            );
818
-        }
819
-        $links['collection'] = array(
820
-            array(
821
-                'href' => $this->getVersionedLinkTo(
822
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
823
-                ),
824
-            ),
825
-        );
826
-        // add links to related models
827
-        if ($model->has_primary_key_field()) {
828
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
829
-                $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
830
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
831
-                    array(
832
-                        'href'   => $this->getVersionedLinkTo(
833
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
834
-                            . '/'
835
-                            . $entity_array[ $model->primary_key_name() ]
836
-                            . '/'
837
-                            . $related_model_part
838
-                        ),
839
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
840
-                    ),
841
-                );
842
-            }
843
-        }
844
-        return $links;
845
-    }
846
-
847
-
848
-    /**
849
-     * Adds the included models indicated in the request to the entity provided
850
-     *
851
-     * @param EEM_Base        $model
852
-     * @param WP_REST_Request $rest_request
853
-     * @param array           $entity_array
854
-     * @param array           $db_row
855
-     * @return array the modified entity
856
-     */
857
-    protected function includeRequestedModels(
858
-        EEM_Base $model,
859
-        WP_REST_Request $rest_request,
860
-        $entity_array,
861
-        $db_row = array()
862
-    ) {
863
-        // if $db_row not included, hope the entity array has what we need
864
-        if (! $db_row) {
865
-            $db_row = $entity_array;
866
-        }
867
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
868
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
869
-        // if they passed in * or didn't specify any includes, return everything
870
-        if (! in_array('*', $includes_for_this_model)
871
-            && ! empty($includes_for_this_model)
872
-        ) {
873
-            if ($model->has_primary_key_field()) {
874
-                // always include the primary key. ya just gotta know that at least
875
-                $includes_for_this_model[] = $model->primary_key_name();
876
-            }
877
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
878
-                $includes_for_this_model[] = '_calculated_fields';
879
-            }
880
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
881
-        }
882
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
883
-        foreach ($relation_settings as $relation_name => $relation_obj) {
884
-            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
885
-                $rest_request->get_param('include'),
886
-                $relation_name
887
-            );
888
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
889
-                $rest_request->get_param('calculate'),
890
-                $relation_name
891
-            );
892
-            // did they specify they wanted to include a related model, or
893
-            // specific fields from a related model?
894
-            // or did they specify to calculate a field from a related model?
895
-            if ($related_fields_to_include || $related_fields_to_calculate) {
896
-                // if so, we should include at least some part of the related model
897
-                $pretend_related_request = new WP_REST_Request();
898
-                $pretend_related_request->set_query_params(
899
-                    array(
900
-                        'caps'      => $rest_request->get_param('caps'),
901
-                        'include'   => $related_fields_to_include,
902
-                        'calculate' => $related_fields_to_calculate,
903
-                    )
904
-                );
905
-                $pretend_related_request->add_header('no_rest_headers', true);
906
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
907
-                    $model->get_index_primary_key_string(
908
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
909
-                    )
910
-                );
911
-                $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
912
-                    $primary_model_query_params,
913
-                    $relation_obj,
914
-                    $pretend_related_request
915
-                );
916
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
917
-                                                                                             instanceof
918
-                                                                                             WP_Error
919
-                    ? null
920
-                    : $related_results;
921
-            }
922
-        }
923
-        return $entity_array;
924
-    }
925
-
926
-
927
-    /**
928
-     * Returns a new array with all the names of models removed. Eg
929
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
930
-     *
931
-     * @param array $arr
932
-     * @return array
933
-     */
934
-    private function removeModelNamesFromArray($arr)
935
-    {
936
-        return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
937
-    }
938
-
939
-
940
-    /**
941
-     * Gets the calculated fields for the response
942
-     *
943
-     * @param EEM_Base        $model
944
-     * @param array           $wpdb_row
945
-     * @param WP_REST_Request $rest_request
946
-     * @return \stdClass the _calculations item in the entity
947
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
948
-     * did, let's know about it ASAP, so let the exception bubble up)
949
-     */
950
-    protected function getEntityCalculations($model, $wpdb_row, $rest_request)
951
-    {
952
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
953
-            $rest_request->get_param('calculate'),
954
-            ''
955
-        );
956
-        // note: setting calculate=* doesn't do anything
957
-        $calculated_fields_to_return = new \stdClass();
958
-        foreach ($calculated_fields as $field_to_calculate) {
959
-            try {
960
-                $calculated_fields_to_return->$field_to_calculate = ModelDataTranslator::prepareFieldValueForJson(
961
-                    null,
962
-                    $this->fields_calculator->retrieveCalculatedFieldValue(
963
-                        $model,
964
-                        $field_to_calculate,
965
-                        $wpdb_row,
966
-                        $rest_request,
967
-                        $this
968
-                    ),
969
-                    $this->getModelVersionInfo()->requestedVersion()
970
-                );
971
-            } catch (RestException $e) {
972
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
973
-                $this->setResponseHeader(
974
-                    'Notices-Field-Calculation-Errors['
975
-                    . $e->getStringCode()
976
-                    . ']['
977
-                    . $model->get_this_model_name()
978
-                    . ']['
979
-                    . $field_to_calculate
980
-                    . ']',
981
-                    $e->getMessage(),
982
-                    true
983
-                );
984
-            }
985
-        }
986
-        return $calculated_fields_to_return;
987
-    }
988
-
989
-
990
-    /**
991
-     * Gets the full URL to the resource, taking the requested version into account
992
-     *
993
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
994
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
995
-     */
996
-    public function getVersionedLinkTo($link_part_after_version_and_slash)
997
-    {
998
-        return rest_url(
999
-            EED_Core_Rest_Api::get_versioned_route_to(
1000
-                $link_part_after_version_and_slash,
1001
-                $this->getModelVersionInfo()->requestedVersion()
1002
-            )
1003
-        );
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * Gets the correct lowercase name for the relation in the API according
1009
-     * to the relation's type
1010
-     *
1011
-     * @param string                  $relation_name
1012
-     * @param \EE_Model_Relation_Base $relation_obj
1013
-     * @return string
1014
-     */
1015
-    public static function getRelatedEntityName($relation_name, $relation_obj)
1016
-    {
1017
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1018
-            return strtolower($relation_name);
1019
-        } else {
1020
-            return EEH_Inflector::pluralize_and_lower($relation_name);
1021
-        }
1022
-    }
1023
-
1024
-
1025
-    /**
1026
-     * Gets the one model object with the specified id for the specified model
1027
-     *
1028
-     * @param EEM_Base        $model
1029
-     * @param WP_REST_Request $request
1030
-     * @return array|WP_Error
1031
-     */
1032
-    public function getEntityFromModel($model, $request)
1033
-    {
1034
-        $context = $this->validateContext($request->get_param('caps'));
1035
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1036
-    }
1037
-
1038
-
1039
-    /**
1040
-     * If a context is provided which isn't valid, maybe it was added in a future
1041
-     * version so just treat it as a default read
1042
-     *
1043
-     * @param string $context
1044
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1045
-     */
1046
-    public function validateContext($context)
1047
-    {
1048
-        if (! $context) {
1049
-            $context = EEM_Base::caps_read;
1050
-        }
1051
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1052
-        if (in_array($context, $valid_contexts)) {
1053
-            return $context;
1054
-        } else {
1055
-            return EEM_Base::caps_read;
1056
-        }
1057
-    }
1058
-
1059
-
1060
-    /**
1061
-     * Verifies the passed in value is an allowable default where conditions value.
1062
-     *
1063
-     * @param $default_query_params
1064
-     * @return string
1065
-     */
1066
-    public function validateDefaultQueryParams($default_query_params)
1067
-    {
1068
-        $valid_default_where_conditions_for_api_calls = array(
1069
-            EEM_Base::default_where_conditions_all,
1070
-            EEM_Base::default_where_conditions_minimum_all,
1071
-            EEM_Base::default_where_conditions_minimum_others,
1072
-        );
1073
-        if (! $default_query_params) {
1074
-            $default_query_params = EEM_Base::default_where_conditions_all;
1075
-        }
1076
-        if (in_array(
1077
-            $default_query_params,
1078
-            $valid_default_where_conditions_for_api_calls,
1079
-            true
1080
-        )) {
1081
-            return $default_query_params;
1082
-        } else {
1083
-            return EEM_Base::default_where_conditions_all;
1084
-        }
1085
-    }
1086
-
1087
-
1088
-    /**
1089
-     * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1090
-     * Note: right now the query parameter keys for fields (and related fields)
1091
-     * can be left as-is, but it's quite possible this will change someday.
1092
-     * Also, this method's contents might be candidate for moving to Model_Data_Translator
1093
-     *
1094
-     * @param EEM_Base $model
1095
-     * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1096
-     * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1097
-     *                                    that absolutely no results should be returned
1098
-     * @throws EE_Error
1099
-     * @throws RestException
1100
-     */
1101
-    public function createModelQueryParams($model, $query_parameters)
1102
-    {
1103
-        $model_query_params = array();
1104
-        if (isset($query_parameters['where'])) {
1105
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1106
-                $query_parameters['where'],
1107
-                $model,
1108
-                $this->getModelVersionInfo()->requestedVersion()
1109
-            );
1110
-        }
1111
-        if (isset($query_parameters['order_by'])) {
1112
-            $order_by = $query_parameters['order_by'];
1113
-        } elseif (isset($query_parameters['orderby'])) {
1114
-            $order_by = $query_parameters['orderby'];
1115
-        } else {
1116
-            $order_by = null;
1117
-        }
1118
-        if ($order_by !== null) {
1119
-            if (is_array($order_by)) {
1120
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1121
-            } else {
1122
-                // it's a single item
1123
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1124
-            }
1125
-            $model_query_params['order_by'] = $order_by;
1126
-        }
1127
-        if (isset($query_parameters['group_by'])) {
1128
-            $group_by = $query_parameters['group_by'];
1129
-        } elseif (isset($query_parameters['groupby'])) {
1130
-            $group_by = $query_parameters['groupby'];
1131
-        } else {
1132
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1133
-        }
1134
-        // make sure they're all real names
1135
-        if (is_array($group_by)) {
1136
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1137
-        }
1138
-        if ($group_by !== null) {
1139
-            $model_query_params['group_by'] = $group_by;
1140
-        }
1141
-        if (isset($query_parameters['having'])) {
1142
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1143
-                $query_parameters['having'],
1144
-                $model,
1145
-                $this->getModelVersionInfo()->requestedVersion()
1146
-            );
1147
-        }
1148
-        if (isset($query_parameters['order'])) {
1149
-            $model_query_params['order'] = $query_parameters['order'];
1150
-        }
1151
-        if (isset($query_parameters['mine'])) {
1152
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1153
-        }
1154
-        if (isset($query_parameters['limit'])) {
1155
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1156
-            if (! is_array($query_parameters['limit'])) {
1157
-                $limit_array = explode(',', (string) $query_parameters['limit']);
1158
-            } else {
1159
-                $limit_array = $query_parameters['limit'];
1160
-            }
1161
-            $sanitized_limit = array();
1162
-            foreach ($limit_array as $key => $limit_part) {
1163
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1164
-                    throw new EE_Error(
1165
-                        sprintf(
1166
-                            __(
1167
-                            // @codingStandardsIgnoreStart
1168
-                                'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1169
-                                // @codingStandardsIgnoreEnd
1170
-                                'event_espresso'
1171
-                            ),
1172
-                            wp_json_encode($query_parameters['limit'])
1173
-                        )
1174
-                    );
1175
-                }
1176
-                $sanitized_limit[] = (int) $limit_part;
1177
-            }
1178
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1179
-        } else {
1180
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1181
-        }
1182
-        if (isset($query_parameters['caps'])) {
1183
-            $model_query_params['caps'] = $this->validateContext($query_parameters['caps']);
1184
-        } else {
1185
-            $model_query_params['caps'] = EEM_Base::caps_read;
1186
-        }
1187
-        if (isset($query_parameters['default_where_conditions'])) {
1188
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1189
-                $query_parameters['default_where_conditions']
1190
-            );
1191
-        }
1192
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1193
-    }
1194
-
1195
-
1196
-    /**
1197
-     * Changes the REST-style query params for use in the models
1198
-     *
1199
-     * @deprecated
1200
-     * @param EEM_Base $model
1201
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1202
-     * @return array
1203
-     */
1204
-    public function prepareRestQueryParamsKeyForModels($model, $query_params)
1205
-    {
1206
-        $model_ready_query_params = array();
1207
-        foreach ($query_params as $key => $value) {
1208
-            if (is_array($value)) {
1209
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1210
-            } else {
1211
-                $model_ready_query_params[ $key ] = $value;
1212
-            }
1213
-        }
1214
-        return $model_ready_query_params;
1215
-    }
1216
-
1217
-
1218
-    /**
1219
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1220
-     * @param $model
1221
-     * @param $query_params
1222
-     * @return array
1223
-     */
1224
-    public function prepareRestQueryParamsValuesForModels($model, $query_params)
1225
-    {
1226
-        $model_ready_query_params = array();
1227
-        foreach ($query_params as $key => $value) {
1228
-            if (is_array($value)) {
1229
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1230
-            } else {
1231
-                $model_ready_query_params[ $key ] = $value;
1232
-            }
1233
-        }
1234
-        return $model_ready_query_params;
1235
-    }
1236
-
1237
-
1238
-    /**
1239
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1240
-     * If no prefix is specified, returns items with no period.
1241
-     *
1242
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1243
-     * @param string       $prefix            "Event" or "foobar"
1244
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1245
-     *                                        we only return strings starting with that and a period; if no prefix was
1246
-     *                                        specified we return all items containing NO periods
1247
-     */
1248
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1249
-    {
1250
-        if (is_string($string_to_explode)) {
1251
-            $exploded_contents = explode(',', $string_to_explode);
1252
-        } elseif (is_array($string_to_explode)) {
1253
-            $exploded_contents = $string_to_explode;
1254
-        } else {
1255
-            $exploded_contents = array();
1256
-        }
1257
-        // if the string was empty, we want an empty array
1258
-        $exploded_contents = array_filter($exploded_contents);
1259
-        $contents_with_prefix = array();
1260
-        foreach ($exploded_contents as $item) {
1261
-            $item = trim($item);
1262
-            // if no prefix was provided, so we look for items with no "." in them
1263
-            if (! $prefix) {
1264
-                // does this item have a period?
1265
-                if (strpos($item, '.') === false) {
1266
-                    // if not, then its what we're looking for
1267
-                    $contents_with_prefix[] = $item;
1268
-                }
1269
-            } elseif (strpos($item, $prefix . '.') === 0) {
1270
-                // this item has the prefix and a period, grab it
1271
-                $contents_with_prefix[] = substr(
1272
-                    $item,
1273
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1274
-                );
1275
-            } elseif ($item === $prefix) {
1276
-                // this item is JUST the prefix
1277
-                // so let's grab everything after, which is a blank string
1278
-                $contents_with_prefix[] = '';
1279
-            }
1280
-        }
1281
-        return $contents_with_prefix;
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1287
-     * Deprecated because its return values were really quite confusing- sometimes it returned
1288
-     * an empty array (when the include string was blank or '*') or sometimes it returned
1289
-     * array('*') (when you provided a model and a model of that kind was found).
1290
-     * Parses the $include_string so we fetch all the field names relating to THIS model
1291
-     * (ie have NO period in them), or for the provided model (ie start with the model
1292
-     * name and then a period).
1293
-     * @param string $include_string @see Read:handle_request_get_all
1294
-     * @param string $model_name
1295
-     * @return array of fields for this model. If $model_name is provided, then
1296
-     *                               the fields for that model, with the model's name removed from each.
1297
-     *                               If $include_string was blank or '*' returns an empty array
1298
-     */
1299
-    public function extractIncludesForThisModel($include_string, $model_name = null)
1300
-    {
1301
-        if (is_array($include_string)) {
1302
-            $include_string = implode(',', $include_string);
1303
-        }
1304
-        if ($include_string === '*' || $include_string === '') {
1305
-            return array();
1306
-        }
1307
-        $includes = explode(',', $include_string);
1308
-        $extracted_fields_to_include = array();
1309
-        if ($model_name) {
1310
-            foreach ($includes as $field_to_include) {
1311
-                $field_to_include = trim($field_to_include);
1312
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1313
-                    // found the model name at the exact start
1314
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1315
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1316
-                } elseif ($field_to_include == $model_name) {
1317
-                    $extracted_fields_to_include[] = '*';
1318
-                }
1319
-            }
1320
-        } else {
1321
-            // look for ones with no period
1322
-            foreach ($includes as $field_to_include) {
1323
-                $field_to_include = trim($field_to_include);
1324
-                if (strpos($field_to_include, '.') === false
1325
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1326
-                ) {
1327
-                    $extracted_fields_to_include[] = $field_to_include;
1328
-                }
1329
-            }
1330
-        }
1331
-        return $extracted_fields_to_include;
1332
-    }
1333
-
1334
-
1335
-    /**
1336
-     * Gets the single item using the model according to the request in the context given, otherwise
1337
-     * returns that it's inaccessible to the current user
1338
-     *
1339
-     * @param EEM_Base        $model
1340
-     * @param WP_REST_Request $request
1341
-     * @param null            $context
1342
-     * @return array|WP_Error
1343
-     */
1344
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1345
-    {
1346
-        $query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1347
-        if ($model instanceof \EEM_Soft_Delete_Base) {
1348
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1349
-        }
1350
-        $restricted_query_params = $query_params;
1351
-        $restricted_query_params['caps'] = $context;
1352
-        $this->setDebugInfo('model query params', $restricted_query_params);
1353
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1354
-        if (! empty($model_rows)) {
1355
-            return $this->createEntityFromWpdbResult(
1356
-                $model,
1357
-                array_shift($model_rows),
1358
-                $request
1359
-            );
1360
-        } else {
1361
-            // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1362
-            $lowercase_model_name = strtolower($model->get_this_model_name());
1363
-            $model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1364
-            if (! empty($model_rows_found_sans_restrictions)) {
1365
-                // you got shafted- it existed but we didn't want to tell you!
1366
-                return new WP_Error(
1367
-                    'rest_user_cannot_' . $context,
1368
-                    sprintf(
1369
-                        __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1370
-                        $context,
1371
-                        strtolower($model->get_this_model_name()),
1372
-                        Capabilities::getMissingPermissionsString(
1373
-                            $model,
1374
-                            $context
1375
-                        )
1376
-                    ),
1377
-                    array('status' => 403)
1378
-                );
1379
-            } else {
1380
-                // it's not you. It just doesn't exist
1381
-                return new WP_Error(
1382
-                    sprintf('rest_%s_invalid_id', $lowercase_model_name),
1383
-                    sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1384
-                    array('status' => 404)
1385
-                );
1386
-            }
1387
-        }
1388
-    }
43
+	/**
44
+	 * @var CalculatedModelFields
45
+	 */
46
+	protected $fields_calculator;
47
+
48
+
49
+	/**
50
+	 * Read constructor.
51
+	 * @param CalculatedModelFields $fields_calculator
52
+	 */
53
+	public function __construct(CalculatedModelFields $fields_calculator)
54
+	{
55
+		parent::__construct();
56
+		$this->fields_calculator = $fields_calculator;
57
+	}
58
+
59
+
60
+	/**
61
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
62
+	 *
63
+	 * @param WP_REST_Request $request
64
+	 * @param string $version
65
+	 * @param string $model_name
66
+	 * @return WP_REST_Response|WP_Error
67
+	 * @throws InvalidArgumentException
68
+	 * @throws InvalidDataTypeException
69
+	 * @throws InvalidInterfaceException
70
+	 */
71
+	public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
72
+	{
73
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
74
+		try {
75
+			$controller->setRequestedVersion($version);
76
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
77
+				return $controller->sendResponse(
78
+					new WP_Error(
79
+						'endpoint_parsing_error',
80
+						sprintf(
81
+							__(
82
+								'There is no model for endpoint %s. Please contact event espresso support',
83
+								'event_espresso'
84
+							),
85
+							$model_name
86
+						)
87
+					)
88
+				);
89
+			}
90
+			return $controller->sendResponse(
91
+				$controller->getEntitiesFromModel(
92
+					$controller->getModelVersionInfo()->loadModel($model_name),
93
+					$request
94
+				)
95
+			);
96
+		} catch (Exception $e) {
97
+			return $controller->sendResponse($e);
98
+		}
99
+	}
100
+
101
+
102
+	/**
103
+	 * Prepares and returns schema for any OPTIONS request.
104
+	 *
105
+	 * @param string $version The API endpoint version being used.
106
+	 * @param string $model_name Something like `Event` or `Registration`
107
+	 * @return array
108
+	 * @throws InvalidArgumentException
109
+	 * @throws InvalidDataTypeException
110
+	 * @throws InvalidInterfaceException
111
+	 */
112
+	public static function handleSchemaRequest($version, $model_name)
113
+	{
114
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
115
+		try {
116
+			$controller->setRequestedVersion($version);
117
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
118
+				return array();
119
+			}
120
+			// get the model for this version
121
+			$model = $controller->getModelVersionInfo()->loadModel($model_name);
122
+			$model_schema = new JsonModelSchema($model, LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields'));
123
+			return $model_schema->getModelSchemaForRelations(
124
+				$controller->getModelVersionInfo()->relationSettings($model),
125
+				$controller->customizeSchemaForRestResponse(
126
+					$model,
127
+					$model_schema->getModelSchemaForFields(
128
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
129
+						$model_schema->getInitialSchemaStructure()
130
+					)
131
+				)
132
+			);
133
+		} catch (Exception $e) {
134
+			return array();
135
+		}
136
+	}
137
+
138
+
139
+	/**
140
+	 * This loops through each field in the given schema for the model and does the following:
141
+	 * - add any extra fields that are REST API specific and related to existing fields.
142
+	 * - transform default values into the correct format for a REST API response.
143
+	 *
144
+	 * @param EEM_Base $model
145
+	 * @param array    $schema
146
+	 * @return array  The final schema.
147
+	 */
148
+	protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
149
+	{
150
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
151
+			$schema = $this->translateDefaultsForRestResponse(
152
+				$field_name,
153
+				$field,
154
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
155
+			);
156
+		}
157
+		return $schema;
158
+	}
159
+
160
+
161
+	/**
162
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
163
+	 * response.
164
+	 *
165
+	 * @param                      $field_name
166
+	 * @param EE_Model_Field_Base  $field
167
+	 * @param array                $schema
168
+	 * @return array
169
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
170
+	 * did, let's know about it ASAP, so let the exception bubble up)
171
+	 */
172
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
173
+	{
174
+		if (isset($schema['properties'][ $field_name ]['default'])) {
175
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
176
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
177
+					if ($default_key === 'raw') {
178
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
179
+							ModelDataTranslator::prepareFieldValueForJson(
180
+								$field,
181
+								$default_value,
182
+								$this->getModelVersionInfo()->requestedVersion()
183
+							);
184
+					}
185
+				}
186
+			} else {
187
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
188
+					$field,
189
+					$schema['properties'][ $field_name ]['default'],
190
+					$this->getModelVersionInfo()->requestedVersion()
191
+				);
192
+			}
193
+		}
194
+		return $schema;
195
+	}
196
+
197
+
198
+	/**
199
+	 * Adds additional fields to the schema
200
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
201
+	 * needs to be added to the schema.
202
+	 *
203
+	 * @param                      $field_name
204
+	 * @param EE_Model_Field_Base  $field
205
+	 * @param array                $schema
206
+	 * @return array
207
+	 */
208
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
209
+	{
210
+		if ($field instanceof EE_Datetime_Field) {
211
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
212
+			// modify the description
213
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
214
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
215
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
216
+			);
217
+		}
218
+		return $schema;
219
+	}
220
+
221
+
222
+	/**
223
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
224
+	 *
225
+	 * @return string
226
+	 */
227
+	protected function getRouteFromRequest()
228
+	{
229
+		if (isset($GLOBALS['wp'])
230
+			&& $GLOBALS['wp'] instanceof \WP
231
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
232
+		) {
233
+			return $GLOBALS['wp']->query_vars['rest_route'];
234
+		} else {
235
+			return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
236
+		}
237
+	}
238
+
239
+
240
+	/**
241
+	 * Gets a single entity related to the model indicated in the path and its id
242
+	 *
243
+	 * @param WP_REST_Request $request
244
+	 * @param string $version
245
+	 * @param string $model_name
246
+	 * @return WP_REST_Response|WP_Error
247
+	 * @throws InvalidDataTypeException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws InvalidArgumentException
250
+	 */
251
+	public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
252
+	{
253
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
254
+		try {
255
+			$controller->setRequestedVersion($version);
256
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
257
+				return $controller->sendResponse(
258
+					new WP_Error(
259
+						'endpoint_parsing_error',
260
+						sprintf(
261
+							__(
262
+								'There is no model for endpoint %s. Please contact event espresso support',
263
+								'event_espresso'
264
+							),
265
+							$model_name
266
+						)
267
+					)
268
+				);
269
+			}
270
+			return $controller->sendResponse(
271
+				$controller->getEntityFromModel(
272
+					$controller->getModelVersionInfo()->loadModel($model_name),
273
+					$request
274
+				)
275
+			);
276
+		} catch (Exception $e) {
277
+			return $controller->sendResponse($e);
278
+		}
279
+	}
280
+
281
+
282
+	/**
283
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
284
+	 * to the item with the given id
285
+	 *
286
+	 * @param WP_REST_Request $request
287
+	 * @param string $version
288
+	 * @param string $model_name
289
+	 * @param string $related_model_name
290
+	 * @return WP_REST_Response|WP_Error
291
+	 * @throws InvalidDataTypeException
292
+	 * @throws InvalidInterfaceException
293
+	 * @throws InvalidArgumentException
294
+	 */
295
+	public static function handleRequestGetRelated(
296
+		WP_REST_Request $request,
297
+		$version,
298
+		$model_name,
299
+		$related_model_name
300
+	) {
301
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
302
+		try {
303
+			$controller->setRequestedVersion($version);
304
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
305
+				return $controller->sendResponse(
306
+					new WP_Error(
307
+						'endpoint_parsing_error',
308
+						sprintf(
309
+							__(
310
+								'There is no model for endpoint %s. Please contact event espresso support',
311
+								'event_espresso'
312
+							),
313
+							$model_name
314
+						)
315
+					)
316
+				);
317
+			}
318
+			$main_model = $controller->getModelVersionInfo()->loadModel($model_name);
319
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
320
+				return $controller->sendResponse(
321
+					new WP_Error(
322
+						'endpoint_parsing_error',
323
+						sprintf(
324
+							__(
325
+								'There is no model for endpoint %s. Please contact event espresso support',
326
+								'event_espresso'
327
+							),
328
+							$related_model_name
329
+						)
330
+					)
331
+				);
332
+			}
333
+			return $controller->sendResponse(
334
+				$controller->getEntitiesFromRelation(
335
+					$request->get_param('id'),
336
+					$main_model->related_settings_for($related_model_name),
337
+					$request
338
+				)
339
+			);
340
+		} catch (Exception $e) {
341
+			return $controller->sendResponse($e);
342
+		}
343
+	}
344
+
345
+
346
+	/**
347
+	 * Gets a collection for the given model and filters
348
+	 *
349
+	 * @param EEM_Base        $model
350
+	 * @param WP_REST_Request $request
351
+	 * @return array|WP_Error
352
+	 */
353
+	public function getEntitiesFromModel($model, $request)
354
+	{
355
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
356
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
357
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
358
+			return new WP_Error(
359
+				sprintf('rest_%s_cannot_list', $model_name_plural),
360
+				sprintf(
361
+					__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
362
+					$model_name_plural,
363
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
364
+				),
365
+				array('status' => 403)
366
+			);
367
+		}
368
+		if (! $request->get_header('no_rest_headers')) {
369
+			$this->setHeadersFromQueryParams($model, $query_params);
370
+		}
371
+		/** @type array $results */
372
+		$results = $model->get_all_wpdb_results($query_params);
373
+		$nice_results = array();
374
+		foreach ($results as $result) {
375
+			$nice_results[] = $this->createEntityFromWpdbResult(
376
+				$model,
377
+				$result,
378
+				$request
379
+			);
380
+		}
381
+		return $nice_results;
382
+	}
383
+
384
+
385
+	/**
386
+	 * Gets the collection for given relation object
387
+	 * The same as Read::get_entities_from_model(), except if the relation
388
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
389
+	 * the join-model-object into the results
390
+	 *
391
+	 * @param array                   $primary_model_query_params query params for finding the item from which
392
+	 *                                                            relations will be based
393
+	 * @param \EE_Model_Relation_Base $relation
394
+	 * @param WP_REST_Request         $request
395
+	 * @return WP_Error|array
396
+	 * @throws RestException
397
+	 */
398
+	protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
399
+	{
400
+		$context = $this->validateContext($request->get_param('caps'));
401
+		$model = $relation->get_this_model();
402
+		$related_model = $relation->get_other_model();
403
+		if (! isset($primary_model_query_params[0])) {
404
+			$primary_model_query_params[0] = array();
405
+		}
406
+		// check if they can access the 1st model object
407
+		$primary_model_query_params = array(
408
+			0       => $primary_model_query_params[0],
409
+			'limit' => 1,
410
+		);
411
+		if ($model instanceof \EEM_Soft_Delete_Base) {
412
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
413
+				$primary_model_query_params
414
+			);
415
+		}
416
+		$restricted_query_params = $primary_model_query_params;
417
+		$restricted_query_params['caps'] = $context;
418
+		$this->setDebugInfo('main model query params', $restricted_query_params);
419
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
420
+		if (! (
421
+			Capabilities::currentUserHasPartialAccessTo($related_model, $context)
422
+			&& $model->exists($restricted_query_params)
423
+		)
424
+		) {
425
+			if ($relation instanceof EE_Belongs_To_Relation) {
426
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
427
+			} else {
428
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
429
+					$related_model->get_this_model_name()
430
+				);
431
+			}
432
+			return new WP_Error(
433
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
434
+				sprintf(
435
+					__(
436
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
437
+						'event_espresso'
438
+					),
439
+					$related_model_name_maybe_plural,
440
+					$relation->get_this_model()->get_this_model_name(),
441
+					implode(
442
+						',',
443
+						array_keys(
444
+							Capabilities::getMissingPermissions($related_model, $context)
445
+						)
446
+					)
447
+				),
448
+				array('status' => 403)
449
+			);
450
+		}
451
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
452
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
453
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
454
+							  . '.'
455
+							  . $where_condition_key ] = $where_condition_value;
456
+		}
457
+		$query_params['default_where_conditions'] = 'none';
458
+		$query_params['caps'] = $context;
459
+		if (! $request->get_header('no_rest_headers')) {
460
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
461
+		}
462
+		/** @type array $results */
463
+		$results = $relation->get_other_model()->get_all_wpdb_results($query_params);
464
+		$nice_results = array();
465
+		foreach ($results as $result) {
466
+			$nice_result = $this->createEntityFromWpdbResult(
467
+				$relation->get_other_model(),
468
+				$result,
469
+				$request
470
+			);
471
+			if ($relation instanceof \EE_HABTM_Relation) {
472
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
473
+				// if there are conflicts we prefer the properties from the main model
474
+				$join_model_result = $this->createEntityFromWpdbResult(
475
+					$relation->get_join_model(),
476
+					$result,
477
+					$request
478
+				);
479
+				$joined_result = array_merge($nice_result, $join_model_result);
480
+				// but keep the meta stuff from the main model
481
+				if (isset($nice_result['meta'])) {
482
+					$joined_result['meta'] = $nice_result['meta'];
483
+				}
484
+				$nice_result = $joined_result;
485
+			}
486
+			$nice_results[] = $nice_result;
487
+		}
488
+		if ($relation instanceof EE_Belongs_To_Relation) {
489
+			return array_shift($nice_results);
490
+		} else {
491
+			return $nice_results;
492
+		}
493
+	}
494
+
495
+
496
+	/**
497
+	 * Gets the collection for given relation object
498
+	 * The same as Read::get_entities_from_model(), except if the relation
499
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
500
+	 * the join-model-object into the results
501
+	 *
502
+	 * @param string                  $id the ID of the thing we are fetching related stuff from
503
+	 * @param \EE_Model_Relation_Base $relation
504
+	 * @param WP_REST_Request         $request
505
+	 * @return array|WP_Error
506
+	 * @throws EE_Error
507
+	 */
508
+	public function getEntitiesFromRelation($id, $relation, $request)
509
+	{
510
+		if (! $relation->get_this_model()->has_primary_key_field()) {
511
+			throw new EE_Error(
512
+				sprintf(
513
+					__(
514
+					// @codingStandardsIgnoreStart
515
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
516
+						// @codingStandardsIgnoreEnd
517
+						'event_espresso'
518
+					),
519
+					$relation->get_this_model()->get_this_model_name()
520
+				)
521
+			);
522
+		}
523
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
524
+			array(
525
+				array(
526
+					$relation->get_this_model()->primary_key_name() => $id,
527
+				),
528
+			),
529
+			$relation,
530
+			$request
531
+		);
532
+	}
533
+
534
+
535
+	/**
536
+	 * Sets the headers that are based on the model and query params,
537
+	 * like the total records. This should only be called on the original request
538
+	 * from the client, not on subsequent internal
539
+	 *
540
+	 * @param EEM_Base $model
541
+	 * @param array    $query_params
542
+	 * @return void
543
+	 */
544
+	protected function setHeadersFromQueryParams($model, $query_params)
545
+	{
546
+		$this->setDebugInfo('model query params', $query_params);
547
+		$this->setDebugInfo(
548
+			'missing caps',
549
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
550
+		);
551
+		// normally the limit to a 2-part array, where the 2nd item is the limit
552
+		if (! isset($query_params['limit'])) {
553
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
554
+		}
555
+		if (is_array($query_params['limit'])) {
556
+			$limit_parts = $query_params['limit'];
557
+		} else {
558
+			$limit_parts = explode(',', $query_params['limit']);
559
+			if (count($limit_parts) == 1) {
560
+				$limit_parts = array(0, $limit_parts[0]);
561
+			}
562
+		}
563
+		// remove the group by and having parts of the query, as those will
564
+		// make the sql query return an array of values, instead of just a single value
565
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
566
+		$count = $model->count($query_params, null, true);
567
+		$pages = $count / $limit_parts[1];
568
+		$this->setResponseHeader('Total', $count, false);
569
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
570
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
571
+	}
572
+
573
+
574
+	/**
575
+	 * Changes database results into REST API entities
576
+	 *
577
+	 * @param EEM_Base        $model
578
+	 * @param array           $db_row     like results from $wpdb->get_results()
579
+	 * @param WP_REST_Request $rest_request
580
+	 * @param string          $deprecated no longer used
581
+	 * @return array ready for being converted into json for sending to client
582
+	 */
583
+	public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
584
+	{
585
+		if (! $rest_request instanceof WP_REST_Request) {
586
+			// ok so this was called in the old style, where the 3rd arg was
587
+			// $include, and the 4th arg was $context
588
+			// now setup the request just to avoid fatal errors, although we won't be able
589
+			// to truly make use of it because it's kinda devoid of info
590
+			$rest_request = new WP_REST_Request();
591
+			$rest_request->set_param('include', $rest_request);
592
+			$rest_request->set_param('caps', $deprecated);
593
+		}
594
+		if ($rest_request->get_param('caps') == null) {
595
+			$rest_request->set_param('caps', EEM_Base::caps_read);
596
+		}
597
+		$entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
598
+		$entity_array = $this->addExtraFields($model, $db_row, $entity_array);
599
+		$entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
600
+		$entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request);
601
+		$entity_array = apply_filters(
602
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
603
+			$entity_array,
604
+			$model,
605
+			$rest_request->get_param('caps'),
606
+			$rest_request,
607
+			$this
608
+		);
609
+		$entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row);
610
+		$entity_array = apply_filters(
611
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
612
+			$entity_array,
613
+			$model,
614
+			$rest_request->get_param('caps'),
615
+			$rest_request,
616
+			$this
617
+		);
618
+		$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
619
+			$entity_array,
620
+			$model,
621
+			$rest_request->get_param('caps'),
622
+			$this->getModelVersionInfo(),
623
+			$model->get_index_primary_key_string(
624
+				$model->deduce_fields_n_values_from_cols_n_values($db_row)
625
+			)
626
+		);
627
+		$this->setDebugInfo(
628
+			'inaccessible fields',
629
+			array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
630
+		);
631
+		return apply_filters(
632
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
633
+			$result_without_inaccessible_fields,
634
+			$model,
635
+			$rest_request->get_param('caps')
636
+		);
637
+	}
638
+
639
+
640
+	/**
641
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
642
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
643
+	 * from $wpdb->get_row( $sql, ARRAY_A)
644
+	 *
645
+	 * @param EEM_Base $model
646
+	 * @param array    $db_row
647
+	 * @return array entity mostly ready for converting to JSON and sending in the response
648
+	 */
649
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
650
+	{
651
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
652
+		$result = array_intersect_key(
653
+			$result,
654
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
655
+		);
656
+		// if this is a CPT, we need to set the global $post to it,
657
+		// otherwise shortcodes etc won't work properly while rendering it
658
+		if ($model instanceof \EEM_CPT_Base) {
659
+			$do_chevy_shuffle = true;
660
+		} else {
661
+			$do_chevy_shuffle = false;
662
+		}
663
+		if ($do_chevy_shuffle) {
664
+			global $post;
665
+			$old_post = $post;
666
+			$post = get_post($result[ $model->primary_key_name() ]);
667
+			if (! $post instanceof \WP_Post) {
668
+				// well that's weird, because $result is what we JUST fetched from the database
669
+				throw new RestException(
670
+					'error_fetching_post_from_database_results',
671
+					esc_html__(
672
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
673
+						'event_espresso'
674
+					)
675
+				);
676
+			}
677
+			$model_object_classname = 'EE_' . $model->get_this_model_name();
678
+			$post->{$model_object_classname} = \EE_Registry::instance()->load_class(
679
+				$model_object_classname,
680
+				$result,
681
+				false,
682
+				false
683
+			);
684
+		}
685
+		foreach ($result as $field_name => $field_value) {
686
+			$field_obj = $model->field_settings_for($field_name);
687
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
688
+				unset($result[ $field_name ]);
689
+			} elseif ($this->isSubclassOfOne(
690
+				$field_obj,
691
+				$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
692
+			)
693
+			) {
694
+				$result[ $field_name ] = array(
695
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
696
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
697
+				);
698
+			} elseif ($this->isSubclassOfOne(
699
+				$field_obj,
700
+				$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
701
+			)
702
+			) {
703
+				$result[ $field_name ] = array(
704
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
705
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
706
+				);
707
+			} elseif ($field_obj instanceof \EE_Datetime_Field) {
708
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
709
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
710
+				if (is_null($field_value)) {
711
+					$field_value = $field_obj->getDefaultDateTimeObj();
712
+				}
713
+				if (is_null($field_value)) {
714
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
715
+						$field_obj,
716
+						$field_value,
717
+						$this->getModelVersionInfo()->requestedVersion()
718
+					);
719
+				} else {
720
+					$timezone = $field_value->getTimezone();
721
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
722
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
723
+						$field_obj,
724
+						$field_value,
725
+						$this->getModelVersionInfo()->requestedVersion()
726
+					);
727
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
728
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
729
+						$field_obj,
730
+						$field_value,
731
+						$this->getModelVersionInfo()->requestedVersion()
732
+					);
733
+				}
734
+				$result[ $field_name . '_gmt' ] = $gmt_date;
735
+				$result[ $field_name ] = $local_date;
736
+			} else {
737
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
738
+			}
739
+		}
740
+		if ($do_chevy_shuffle) {
741
+			$post = $old_post;
742
+		}
743
+		return $result;
744
+	}
745
+
746
+
747
+	/**
748
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
749
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
750
+	 * representation using $field_obj->prepare_for_set_from_db())
751
+	 *
752
+	 * @param EE_Model_Field_Base $field_obj
753
+	 * @param mixed               $value  as it's stored on a model object
754
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
755
+	 * @return mixed
756
+	 * @throws ObjectDetectedException if $value contains a PHP object
757
+	 */
758
+	protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
759
+	{
760
+		$value = $field_obj->prepare_for_set_from_db($value);
761
+		switch ($format) {
762
+			case 'pretty':
763
+				$value = $field_obj->prepare_for_pretty_echoing($value);
764
+				break;
765
+			case 'normal':
766
+			default:
767
+				$value = $field_obj->prepare_for_get($value);
768
+				break;
769
+		}
770
+		return ModelDataTranslator::prepareFieldValuesForJson(
771
+			$field_obj,
772
+			$value,
773
+			$this->getModelVersionInfo()->requestedVersion()
774
+		);
775
+	}
776
+
777
+
778
+	/**
779
+	 * Adds a few extra fields to the entity response
780
+	 *
781
+	 * @param EEM_Base $model
782
+	 * @param array    $db_row
783
+	 * @param array    $entity_array
784
+	 * @return array modified entity
785
+	 */
786
+	protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
787
+	{
788
+		if ($model instanceof EEM_CPT_Base) {
789
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
790
+		}
791
+		return $entity_array;
792
+	}
793
+
794
+
795
+	/**
796
+	 * Gets links we want to add to the response
797
+	 *
798
+	 * @global \WP_REST_Server $wp_rest_server
799
+	 * @param EEM_Base         $model
800
+	 * @param array            $db_row
801
+	 * @param array            $entity_array
802
+	 * @return array the _links item in the entity
803
+	 */
804
+	protected function getEntityLinks($model, $db_row, $entity_array)
805
+	{
806
+		// add basic links
807
+		$links = array();
808
+		if ($model->has_primary_key_field()) {
809
+			$links['self'] = array(
810
+				array(
811
+					'href' => $this->getVersionedLinkTo(
812
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
813
+						. '/'
814
+						. $entity_array[ $model->primary_key_name() ]
815
+					),
816
+				),
817
+			);
818
+		}
819
+		$links['collection'] = array(
820
+			array(
821
+				'href' => $this->getVersionedLinkTo(
822
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
823
+				),
824
+			),
825
+		);
826
+		// add links to related models
827
+		if ($model->has_primary_key_field()) {
828
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
829
+				$related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
830
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
831
+					array(
832
+						'href'   => $this->getVersionedLinkTo(
833
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
834
+							. '/'
835
+							. $entity_array[ $model->primary_key_name() ]
836
+							. '/'
837
+							. $related_model_part
838
+						),
839
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
840
+					),
841
+				);
842
+			}
843
+		}
844
+		return $links;
845
+	}
846
+
847
+
848
+	/**
849
+	 * Adds the included models indicated in the request to the entity provided
850
+	 *
851
+	 * @param EEM_Base        $model
852
+	 * @param WP_REST_Request $rest_request
853
+	 * @param array           $entity_array
854
+	 * @param array           $db_row
855
+	 * @return array the modified entity
856
+	 */
857
+	protected function includeRequestedModels(
858
+		EEM_Base $model,
859
+		WP_REST_Request $rest_request,
860
+		$entity_array,
861
+		$db_row = array()
862
+	) {
863
+		// if $db_row not included, hope the entity array has what we need
864
+		if (! $db_row) {
865
+			$db_row = $entity_array;
866
+		}
867
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
868
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
869
+		// if they passed in * or didn't specify any includes, return everything
870
+		if (! in_array('*', $includes_for_this_model)
871
+			&& ! empty($includes_for_this_model)
872
+		) {
873
+			if ($model->has_primary_key_field()) {
874
+				// always include the primary key. ya just gotta know that at least
875
+				$includes_for_this_model[] = $model->primary_key_name();
876
+			}
877
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
878
+				$includes_for_this_model[] = '_calculated_fields';
879
+			}
880
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
881
+		}
882
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
883
+		foreach ($relation_settings as $relation_name => $relation_obj) {
884
+			$related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
885
+				$rest_request->get_param('include'),
886
+				$relation_name
887
+			);
888
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
889
+				$rest_request->get_param('calculate'),
890
+				$relation_name
891
+			);
892
+			// did they specify they wanted to include a related model, or
893
+			// specific fields from a related model?
894
+			// or did they specify to calculate a field from a related model?
895
+			if ($related_fields_to_include || $related_fields_to_calculate) {
896
+				// if so, we should include at least some part of the related model
897
+				$pretend_related_request = new WP_REST_Request();
898
+				$pretend_related_request->set_query_params(
899
+					array(
900
+						'caps'      => $rest_request->get_param('caps'),
901
+						'include'   => $related_fields_to_include,
902
+						'calculate' => $related_fields_to_calculate,
903
+					)
904
+				);
905
+				$pretend_related_request->add_header('no_rest_headers', true);
906
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
907
+					$model->get_index_primary_key_string(
908
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
909
+					)
910
+				);
911
+				$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
912
+					$primary_model_query_params,
913
+					$relation_obj,
914
+					$pretend_related_request
915
+				);
916
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
917
+																							 instanceof
918
+																							 WP_Error
919
+					? null
920
+					: $related_results;
921
+			}
922
+		}
923
+		return $entity_array;
924
+	}
925
+
926
+
927
+	/**
928
+	 * Returns a new array with all the names of models removed. Eg
929
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
930
+	 *
931
+	 * @param array $arr
932
+	 * @return array
933
+	 */
934
+	private function removeModelNamesFromArray($arr)
935
+	{
936
+		return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
937
+	}
938
+
939
+
940
+	/**
941
+	 * Gets the calculated fields for the response
942
+	 *
943
+	 * @param EEM_Base        $model
944
+	 * @param array           $wpdb_row
945
+	 * @param WP_REST_Request $rest_request
946
+	 * @return \stdClass the _calculations item in the entity
947
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
948
+	 * did, let's know about it ASAP, so let the exception bubble up)
949
+	 */
950
+	protected function getEntityCalculations($model, $wpdb_row, $rest_request)
951
+	{
952
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
953
+			$rest_request->get_param('calculate'),
954
+			''
955
+		);
956
+		// note: setting calculate=* doesn't do anything
957
+		$calculated_fields_to_return = new \stdClass();
958
+		foreach ($calculated_fields as $field_to_calculate) {
959
+			try {
960
+				$calculated_fields_to_return->$field_to_calculate = ModelDataTranslator::prepareFieldValueForJson(
961
+					null,
962
+					$this->fields_calculator->retrieveCalculatedFieldValue(
963
+						$model,
964
+						$field_to_calculate,
965
+						$wpdb_row,
966
+						$rest_request,
967
+						$this
968
+					),
969
+					$this->getModelVersionInfo()->requestedVersion()
970
+				);
971
+			} catch (RestException $e) {
972
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
973
+				$this->setResponseHeader(
974
+					'Notices-Field-Calculation-Errors['
975
+					. $e->getStringCode()
976
+					. ']['
977
+					. $model->get_this_model_name()
978
+					. ']['
979
+					. $field_to_calculate
980
+					. ']',
981
+					$e->getMessage(),
982
+					true
983
+				);
984
+			}
985
+		}
986
+		return $calculated_fields_to_return;
987
+	}
988
+
989
+
990
+	/**
991
+	 * Gets the full URL to the resource, taking the requested version into account
992
+	 *
993
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
994
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
995
+	 */
996
+	public function getVersionedLinkTo($link_part_after_version_and_slash)
997
+	{
998
+		return rest_url(
999
+			EED_Core_Rest_Api::get_versioned_route_to(
1000
+				$link_part_after_version_and_slash,
1001
+				$this->getModelVersionInfo()->requestedVersion()
1002
+			)
1003
+		);
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * Gets the correct lowercase name for the relation in the API according
1009
+	 * to the relation's type
1010
+	 *
1011
+	 * @param string                  $relation_name
1012
+	 * @param \EE_Model_Relation_Base $relation_obj
1013
+	 * @return string
1014
+	 */
1015
+	public static function getRelatedEntityName($relation_name, $relation_obj)
1016
+	{
1017
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1018
+			return strtolower($relation_name);
1019
+		} else {
1020
+			return EEH_Inflector::pluralize_and_lower($relation_name);
1021
+		}
1022
+	}
1023
+
1024
+
1025
+	/**
1026
+	 * Gets the one model object with the specified id for the specified model
1027
+	 *
1028
+	 * @param EEM_Base        $model
1029
+	 * @param WP_REST_Request $request
1030
+	 * @return array|WP_Error
1031
+	 */
1032
+	public function getEntityFromModel($model, $request)
1033
+	{
1034
+		$context = $this->validateContext($request->get_param('caps'));
1035
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1036
+	}
1037
+
1038
+
1039
+	/**
1040
+	 * If a context is provided which isn't valid, maybe it was added in a future
1041
+	 * version so just treat it as a default read
1042
+	 *
1043
+	 * @param string $context
1044
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1045
+	 */
1046
+	public function validateContext($context)
1047
+	{
1048
+		if (! $context) {
1049
+			$context = EEM_Base::caps_read;
1050
+		}
1051
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1052
+		if (in_array($context, $valid_contexts)) {
1053
+			return $context;
1054
+		} else {
1055
+			return EEM_Base::caps_read;
1056
+		}
1057
+	}
1058
+
1059
+
1060
+	/**
1061
+	 * Verifies the passed in value is an allowable default where conditions value.
1062
+	 *
1063
+	 * @param $default_query_params
1064
+	 * @return string
1065
+	 */
1066
+	public function validateDefaultQueryParams($default_query_params)
1067
+	{
1068
+		$valid_default_where_conditions_for_api_calls = array(
1069
+			EEM_Base::default_where_conditions_all,
1070
+			EEM_Base::default_where_conditions_minimum_all,
1071
+			EEM_Base::default_where_conditions_minimum_others,
1072
+		);
1073
+		if (! $default_query_params) {
1074
+			$default_query_params = EEM_Base::default_where_conditions_all;
1075
+		}
1076
+		if (in_array(
1077
+			$default_query_params,
1078
+			$valid_default_where_conditions_for_api_calls,
1079
+			true
1080
+		)) {
1081
+			return $default_query_params;
1082
+		} else {
1083
+			return EEM_Base::default_where_conditions_all;
1084
+		}
1085
+	}
1086
+
1087
+
1088
+	/**
1089
+	 * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1090
+	 * Note: right now the query parameter keys for fields (and related fields)
1091
+	 * can be left as-is, but it's quite possible this will change someday.
1092
+	 * Also, this method's contents might be candidate for moving to Model_Data_Translator
1093
+	 *
1094
+	 * @param EEM_Base $model
1095
+	 * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1096
+	 * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1097
+	 *                                    that absolutely no results should be returned
1098
+	 * @throws EE_Error
1099
+	 * @throws RestException
1100
+	 */
1101
+	public function createModelQueryParams($model, $query_parameters)
1102
+	{
1103
+		$model_query_params = array();
1104
+		if (isset($query_parameters['where'])) {
1105
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1106
+				$query_parameters['where'],
1107
+				$model,
1108
+				$this->getModelVersionInfo()->requestedVersion()
1109
+			);
1110
+		}
1111
+		if (isset($query_parameters['order_by'])) {
1112
+			$order_by = $query_parameters['order_by'];
1113
+		} elseif (isset($query_parameters['orderby'])) {
1114
+			$order_by = $query_parameters['orderby'];
1115
+		} else {
1116
+			$order_by = null;
1117
+		}
1118
+		if ($order_by !== null) {
1119
+			if (is_array($order_by)) {
1120
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1121
+			} else {
1122
+				// it's a single item
1123
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1124
+			}
1125
+			$model_query_params['order_by'] = $order_by;
1126
+		}
1127
+		if (isset($query_parameters['group_by'])) {
1128
+			$group_by = $query_parameters['group_by'];
1129
+		} elseif (isset($query_parameters['groupby'])) {
1130
+			$group_by = $query_parameters['groupby'];
1131
+		} else {
1132
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1133
+		}
1134
+		// make sure they're all real names
1135
+		if (is_array($group_by)) {
1136
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1137
+		}
1138
+		if ($group_by !== null) {
1139
+			$model_query_params['group_by'] = $group_by;
1140
+		}
1141
+		if (isset($query_parameters['having'])) {
1142
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1143
+				$query_parameters['having'],
1144
+				$model,
1145
+				$this->getModelVersionInfo()->requestedVersion()
1146
+			);
1147
+		}
1148
+		if (isset($query_parameters['order'])) {
1149
+			$model_query_params['order'] = $query_parameters['order'];
1150
+		}
1151
+		if (isset($query_parameters['mine'])) {
1152
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1153
+		}
1154
+		if (isset($query_parameters['limit'])) {
1155
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1156
+			if (! is_array($query_parameters['limit'])) {
1157
+				$limit_array = explode(',', (string) $query_parameters['limit']);
1158
+			} else {
1159
+				$limit_array = $query_parameters['limit'];
1160
+			}
1161
+			$sanitized_limit = array();
1162
+			foreach ($limit_array as $key => $limit_part) {
1163
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1164
+					throw new EE_Error(
1165
+						sprintf(
1166
+							__(
1167
+							// @codingStandardsIgnoreStart
1168
+								'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1169
+								// @codingStandardsIgnoreEnd
1170
+								'event_espresso'
1171
+							),
1172
+							wp_json_encode($query_parameters['limit'])
1173
+						)
1174
+					);
1175
+				}
1176
+				$sanitized_limit[] = (int) $limit_part;
1177
+			}
1178
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1179
+		} else {
1180
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1181
+		}
1182
+		if (isset($query_parameters['caps'])) {
1183
+			$model_query_params['caps'] = $this->validateContext($query_parameters['caps']);
1184
+		} else {
1185
+			$model_query_params['caps'] = EEM_Base::caps_read;
1186
+		}
1187
+		if (isset($query_parameters['default_where_conditions'])) {
1188
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1189
+				$query_parameters['default_where_conditions']
1190
+			);
1191
+		}
1192
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1193
+	}
1194
+
1195
+
1196
+	/**
1197
+	 * Changes the REST-style query params for use in the models
1198
+	 *
1199
+	 * @deprecated
1200
+	 * @param EEM_Base $model
1201
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1202
+	 * @return array
1203
+	 */
1204
+	public function prepareRestQueryParamsKeyForModels($model, $query_params)
1205
+	{
1206
+		$model_ready_query_params = array();
1207
+		foreach ($query_params as $key => $value) {
1208
+			if (is_array($value)) {
1209
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1210
+			} else {
1211
+				$model_ready_query_params[ $key ] = $value;
1212
+			}
1213
+		}
1214
+		return $model_ready_query_params;
1215
+	}
1216
+
1217
+
1218
+	/**
1219
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1220
+	 * @param $model
1221
+	 * @param $query_params
1222
+	 * @return array
1223
+	 */
1224
+	public function prepareRestQueryParamsValuesForModels($model, $query_params)
1225
+	{
1226
+		$model_ready_query_params = array();
1227
+		foreach ($query_params as $key => $value) {
1228
+			if (is_array($value)) {
1229
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1230
+			} else {
1231
+				$model_ready_query_params[ $key ] = $value;
1232
+			}
1233
+		}
1234
+		return $model_ready_query_params;
1235
+	}
1236
+
1237
+
1238
+	/**
1239
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1240
+	 * If no prefix is specified, returns items with no period.
1241
+	 *
1242
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1243
+	 * @param string       $prefix            "Event" or "foobar"
1244
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1245
+	 *                                        we only return strings starting with that and a period; if no prefix was
1246
+	 *                                        specified we return all items containing NO periods
1247
+	 */
1248
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1249
+	{
1250
+		if (is_string($string_to_explode)) {
1251
+			$exploded_contents = explode(',', $string_to_explode);
1252
+		} elseif (is_array($string_to_explode)) {
1253
+			$exploded_contents = $string_to_explode;
1254
+		} else {
1255
+			$exploded_contents = array();
1256
+		}
1257
+		// if the string was empty, we want an empty array
1258
+		$exploded_contents = array_filter($exploded_contents);
1259
+		$contents_with_prefix = array();
1260
+		foreach ($exploded_contents as $item) {
1261
+			$item = trim($item);
1262
+			// if no prefix was provided, so we look for items with no "." in them
1263
+			if (! $prefix) {
1264
+				// does this item have a period?
1265
+				if (strpos($item, '.') === false) {
1266
+					// if not, then its what we're looking for
1267
+					$contents_with_prefix[] = $item;
1268
+				}
1269
+			} elseif (strpos($item, $prefix . '.') === 0) {
1270
+				// this item has the prefix and a period, grab it
1271
+				$contents_with_prefix[] = substr(
1272
+					$item,
1273
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1274
+				);
1275
+			} elseif ($item === $prefix) {
1276
+				// this item is JUST the prefix
1277
+				// so let's grab everything after, which is a blank string
1278
+				$contents_with_prefix[] = '';
1279
+			}
1280
+		}
1281
+		return $contents_with_prefix;
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1287
+	 * Deprecated because its return values were really quite confusing- sometimes it returned
1288
+	 * an empty array (when the include string was blank or '*') or sometimes it returned
1289
+	 * array('*') (when you provided a model and a model of that kind was found).
1290
+	 * Parses the $include_string so we fetch all the field names relating to THIS model
1291
+	 * (ie have NO period in them), or for the provided model (ie start with the model
1292
+	 * name and then a period).
1293
+	 * @param string $include_string @see Read:handle_request_get_all
1294
+	 * @param string $model_name
1295
+	 * @return array of fields for this model. If $model_name is provided, then
1296
+	 *                               the fields for that model, with the model's name removed from each.
1297
+	 *                               If $include_string was blank or '*' returns an empty array
1298
+	 */
1299
+	public function extractIncludesForThisModel($include_string, $model_name = null)
1300
+	{
1301
+		if (is_array($include_string)) {
1302
+			$include_string = implode(',', $include_string);
1303
+		}
1304
+		if ($include_string === '*' || $include_string === '') {
1305
+			return array();
1306
+		}
1307
+		$includes = explode(',', $include_string);
1308
+		$extracted_fields_to_include = array();
1309
+		if ($model_name) {
1310
+			foreach ($includes as $field_to_include) {
1311
+				$field_to_include = trim($field_to_include);
1312
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1313
+					// found the model name at the exact start
1314
+					$field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1315
+					$extracted_fields_to_include[] = $field_sans_model_name;
1316
+				} elseif ($field_to_include == $model_name) {
1317
+					$extracted_fields_to_include[] = '*';
1318
+				}
1319
+			}
1320
+		} else {
1321
+			// look for ones with no period
1322
+			foreach ($includes as $field_to_include) {
1323
+				$field_to_include = trim($field_to_include);
1324
+				if (strpos($field_to_include, '.') === false
1325
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1326
+				) {
1327
+					$extracted_fields_to_include[] = $field_to_include;
1328
+				}
1329
+			}
1330
+		}
1331
+		return $extracted_fields_to_include;
1332
+	}
1333
+
1334
+
1335
+	/**
1336
+	 * Gets the single item using the model according to the request in the context given, otherwise
1337
+	 * returns that it's inaccessible to the current user
1338
+	 *
1339
+	 * @param EEM_Base        $model
1340
+	 * @param WP_REST_Request $request
1341
+	 * @param null            $context
1342
+	 * @return array|WP_Error
1343
+	 */
1344
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1345
+	{
1346
+		$query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1347
+		if ($model instanceof \EEM_Soft_Delete_Base) {
1348
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1349
+		}
1350
+		$restricted_query_params = $query_params;
1351
+		$restricted_query_params['caps'] = $context;
1352
+		$this->setDebugInfo('model query params', $restricted_query_params);
1353
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1354
+		if (! empty($model_rows)) {
1355
+			return $this->createEntityFromWpdbResult(
1356
+				$model,
1357
+				array_shift($model_rows),
1358
+				$request
1359
+			);
1360
+		} else {
1361
+			// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1362
+			$lowercase_model_name = strtolower($model->get_this_model_name());
1363
+			$model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1364
+			if (! empty($model_rows_found_sans_restrictions)) {
1365
+				// you got shafted- it existed but we didn't want to tell you!
1366
+				return new WP_Error(
1367
+					'rest_user_cannot_' . $context,
1368
+					sprintf(
1369
+						__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1370
+						$context,
1371
+						strtolower($model->get_this_model_name()),
1372
+						Capabilities::getMissingPermissionsString(
1373
+							$model,
1374
+							$context
1375
+						)
1376
+					),
1377
+					array('status' => 403)
1378
+				);
1379
+			} else {
1380
+				// it's not you. It just doesn't exist
1381
+				return new WP_Error(
1382
+					sprintf('rest_%s_invalid_id', $lowercase_model_name),
1383
+					sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1384
+					array('status' => 404)
1385
+				);
1386
+			}
1387
+		}
1388
+	}
1389 1389
 }
Please login to merge, or discard this patch.
Spacing   +55 added lines, -55 removed lines patch added patch discarded remove patch
@@ -73,7 +73,7 @@  discard block
 block discarded – undo
73 73
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
74 74
         try {
75 75
             $controller->setRequestedVersion($version);
76
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
76
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
77 77
                 return $controller->sendResponse(
78 78
                     new WP_Error(
79 79
                         'endpoint_parsing_error',
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
115 115
         try {
116 116
             $controller->setRequestedVersion($version);
117
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
117
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
118 118
                 return array();
119 119
             }
120 120
             // get the model for this version
@@ -171,11 +171,11 @@  discard block
 block discarded – undo
171 171
      */
172 172
     protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
173 173
     {
174
-        if (isset($schema['properties'][ $field_name ]['default'])) {
175
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
176
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
174
+        if (isset($schema['properties'][$field_name]['default'])) {
175
+            if (is_array($schema['properties'][$field_name]['default'])) {
176
+                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
177 177
                     if ($default_key === 'raw') {
178
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
178
+                        $schema['properties'][$field_name]['default'][$default_key] =
179 179
                             ModelDataTranslator::prepareFieldValueForJson(
180 180
                                 $field,
181 181
                                 $default_value,
@@ -184,9 +184,9 @@  discard block
 block discarded – undo
184 184
                     }
185 185
                 }
186 186
             } else {
187
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
187
+                $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson(
188 188
                     $field,
189
-                    $schema['properties'][ $field_name ]['default'],
189
+                    $schema['properties'][$field_name]['default'],
190 190
                     $this->getModelVersionInfo()->requestedVersion()
191 191
                 );
192 192
             }
@@ -208,9 +208,9 @@  discard block
 block discarded – undo
208 208
     protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
209 209
     {
210 210
         if ($field instanceof EE_Datetime_Field) {
211
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
211
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
212 212
             // modify the description
213
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
213
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
214 214
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
215 215
                 wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
216 216
             );
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
254 254
         try {
255 255
             $controller->setRequestedVersion($version);
256
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
256
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
257 257
                 return $controller->sendResponse(
258 258
                     new WP_Error(
259 259
                         'endpoint_parsing_error',
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
302 302
         try {
303 303
             $controller->setRequestedVersion($version);
304
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
304
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
305 305
                 return $controller->sendResponse(
306 306
                     new WP_Error(
307 307
                         'endpoint_parsing_error',
@@ -316,7 +316,7 @@  discard block
 block discarded – undo
316 316
                 );
317 317
             }
318 318
             $main_model = $controller->getModelVersionInfo()->loadModel($model_name);
319
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
319
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
320 320
                 return $controller->sendResponse(
321 321
                     new WP_Error(
322 322
                         'endpoint_parsing_error',
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
     public function getEntitiesFromModel($model, $request)
354 354
     {
355 355
         $query_params = $this->createModelQueryParams($model, $request->get_params());
356
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
356
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
357 357
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
358 358
             return new WP_Error(
359 359
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -365,7 +365,7 @@  discard block
 block discarded – undo
365 365
                 array('status' => 403)
366 366
             );
367 367
         }
368
-        if (! $request->get_header('no_rest_headers')) {
368
+        if ( ! $request->get_header('no_rest_headers')) {
369 369
             $this->setHeadersFromQueryParams($model, $query_params);
370 370
         }
371 371
         /** @type array $results */
@@ -400,7 +400,7 @@  discard block
 block discarded – undo
400 400
         $context = $this->validateContext($request->get_param('caps'));
401 401
         $model = $relation->get_this_model();
402 402
         $related_model = $relation->get_other_model();
403
-        if (! isset($primary_model_query_params[0])) {
403
+        if ( ! isset($primary_model_query_params[0])) {
404 404
             $primary_model_query_params[0] = array();
405 405
         }
406 406
         // check if they can access the 1st model object
@@ -417,7 +417,7 @@  discard block
 block discarded – undo
417 417
         $restricted_query_params['caps'] = $context;
418 418
         $this->setDebugInfo('main model query params', $restricted_query_params);
419 419
         $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
420
-        if (! (
420
+        if ( ! (
421 421
             Capabilities::currentUserHasPartialAccessTo($related_model, $context)
422 422
             && $model->exists($restricted_query_params)
423 423
         )
@@ -450,13 +450,13 @@  discard block
 block discarded – undo
450 450
         }
451 451
         $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
452 452
         foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
453
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
453
+            $query_params[0][$relation->get_this_model()->get_this_model_name()
454 454
                               . '.'
455
-                              . $where_condition_key ] = $where_condition_value;
455
+                              . $where_condition_key] = $where_condition_value;
456 456
         }
457 457
         $query_params['default_where_conditions'] = 'none';
458 458
         $query_params['caps'] = $context;
459
-        if (! $request->get_header('no_rest_headers')) {
459
+        if ( ! $request->get_header('no_rest_headers')) {
460 460
             $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
461 461
         }
462 462
         /** @type array $results */
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
      */
508 508
     public function getEntitiesFromRelation($id, $relation, $request)
509 509
     {
510
-        if (! $relation->get_this_model()->has_primary_key_field()) {
510
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
511 511
             throw new EE_Error(
512 512
                 sprintf(
513 513
                     __(
@@ -549,7 +549,7 @@  discard block
 block discarded – undo
549 549
             Capabilities::getMissingPermissionsString($model, $query_params['caps'])
550 550
         );
551 551
         // normally the limit to a 2-part array, where the 2nd item is the limit
552
-        if (! isset($query_params['limit'])) {
552
+        if ( ! isset($query_params['limit'])) {
553 553
             $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
554 554
         }
555 555
         if (is_array($query_params['limit'])) {
@@ -582,7 +582,7 @@  discard block
 block discarded – undo
582 582
      */
583 583
     public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
584 584
     {
585
-        if (! $rest_request instanceof WP_REST_Request) {
585
+        if ( ! $rest_request instanceof WP_REST_Request) {
586 586
             // ok so this was called in the old style, where the 3rd arg was
587 587
             // $include, and the 4th arg was $context
588 588
             // now setup the request just to avoid fatal errors, although we won't be able
@@ -663,8 +663,8 @@  discard block
 block discarded – undo
663 663
         if ($do_chevy_shuffle) {
664 664
             global $post;
665 665
             $old_post = $post;
666
-            $post = get_post($result[ $model->primary_key_name() ]);
667
-            if (! $post instanceof \WP_Post) {
666
+            $post = get_post($result[$model->primary_key_name()]);
667
+            if ( ! $post instanceof \WP_Post) {
668 668
                 // well that's weird, because $result is what we JUST fetched from the database
669 669
                 throw new RestException(
670 670
                     'error_fetching_post_from_database_results',
@@ -674,7 +674,7 @@  discard block
 block discarded – undo
674 674
                     )
675 675
                 );
676 676
             }
677
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
677
+            $model_object_classname = 'EE_'.$model->get_this_model_name();
678 678
             $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
679 679
                 $model_object_classname,
680 680
                 $result,
@@ -685,13 +685,13 @@  discard block
 block discarded – undo
685 685
         foreach ($result as $field_name => $field_value) {
686 686
             $field_obj = $model->field_settings_for($field_name);
687 687
             if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
688
-                unset($result[ $field_name ]);
688
+                unset($result[$field_name]);
689 689
             } elseif ($this->isSubclassOfOne(
690 690
                 $field_obj,
691 691
                 $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
692 692
             )
693 693
             ) {
694
-                $result[ $field_name ] = array(
694
+                $result[$field_name] = array(
695 695
                     'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
696 696
                     'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
697 697
                 );
@@ -700,7 +700,7 @@  discard block
 block discarded – undo
700 700
                 $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
701 701
             )
702 702
             ) {
703
-                $result[ $field_name ] = array(
703
+                $result[$field_name] = array(
704 704
                     'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
705 705
                     'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
706 706
                 );
@@ -731,10 +731,10 @@  discard block
 block discarded – undo
731 731
                         $this->getModelVersionInfo()->requestedVersion()
732 732
                     );
733 733
                 }
734
-                $result[ $field_name . '_gmt' ] = $gmt_date;
735
-                $result[ $field_name ] = $local_date;
734
+                $result[$field_name.'_gmt'] = $gmt_date;
735
+                $result[$field_name] = $local_date;
736 736
             } else {
737
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
737
+                $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
738 738
             }
739 739
         }
740 740
         if ($do_chevy_shuffle) {
@@ -786,7 +786,7 @@  discard block
 block discarded – undo
786 786
     protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
787 787
     {
788 788
         if ($model instanceof EEM_CPT_Base) {
789
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
789
+            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
790 790
         }
791 791
         return $entity_array;
792 792
     }
@@ -811,7 +811,7 @@  discard block
 block discarded – undo
811 811
                     'href' => $this->getVersionedLinkTo(
812 812
                         EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
813 813
                         . '/'
814
-                        . $entity_array[ $model->primary_key_name() ]
814
+                        . $entity_array[$model->primary_key_name()]
815 815
                     ),
816 816
                 ),
817 817
             );
@@ -827,12 +827,12 @@  discard block
 block discarded – undo
827 827
         if ($model->has_primary_key_field()) {
828 828
             foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
829 829
                 $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
830
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
830
+                $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = array(
831 831
                     array(
832 832
                         'href'   => $this->getVersionedLinkTo(
833 833
                             EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
834 834
                             . '/'
835
-                            . $entity_array[ $model->primary_key_name() ]
835
+                            . $entity_array[$model->primary_key_name()]
836 836
                             . '/'
837 837
                             . $related_model_part
838 838
                         ),
@@ -861,13 +861,13 @@  discard block
 block discarded – undo
861 861
         $db_row = array()
862 862
     ) {
863 863
         // if $db_row not included, hope the entity array has what we need
864
-        if (! $db_row) {
864
+        if ( ! $db_row) {
865 865
             $db_row = $entity_array;
866 866
         }
867 867
         $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
868 868
         $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
869 869
         // if they passed in * or didn't specify any includes, return everything
870
-        if (! in_array('*', $includes_for_this_model)
870
+        if ( ! in_array('*', $includes_for_this_model)
871 871
             && ! empty($includes_for_this_model)
872 872
         ) {
873 873
             if ($model->has_primary_key_field()) {
@@ -913,7 +913,7 @@  discard block
 block discarded – undo
913 913
                     $relation_obj,
914 914
                     $pretend_related_request
915 915
                 );
916
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
916
+                $entity_array[Read::getRelatedEntityName($relation_name, $relation_obj)] = $related_results
917 917
                                                                                              instanceof
918 918
                                                                                              WP_Error
919 919
                     ? null
@@ -1045,7 +1045,7 @@  discard block
 block discarded – undo
1045 1045
      */
1046 1046
     public function validateContext($context)
1047 1047
     {
1048
-        if (! $context) {
1048
+        if ( ! $context) {
1049 1049
             $context = EEM_Base::caps_read;
1050 1050
         }
1051 1051
         $valid_contexts = EEM_Base::valid_cap_contexts();
@@ -1070,7 +1070,7 @@  discard block
 block discarded – undo
1070 1070
             EEM_Base::default_where_conditions_minimum_all,
1071 1071
             EEM_Base::default_where_conditions_minimum_others,
1072 1072
         );
1073
-        if (! $default_query_params) {
1073
+        if ( ! $default_query_params) {
1074 1074
             $default_query_params = EEM_Base::default_where_conditions_all;
1075 1075
         }
1076 1076
         if (in_array(
@@ -1153,14 +1153,14 @@  discard block
 block discarded – undo
1153 1153
         }
1154 1154
         if (isset($query_parameters['limit'])) {
1155 1155
             // limit should be either a string like '23' or '23,43', or an array with two items in it
1156
-            if (! is_array($query_parameters['limit'])) {
1156
+            if ( ! is_array($query_parameters['limit'])) {
1157 1157
                 $limit_array = explode(',', (string) $query_parameters['limit']);
1158 1158
             } else {
1159 1159
                 $limit_array = $query_parameters['limit'];
1160 1160
             }
1161 1161
             $sanitized_limit = array();
1162 1162
             foreach ($limit_array as $key => $limit_part) {
1163
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1163
+                if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1164 1164
                     throw new EE_Error(
1165 1165
                         sprintf(
1166 1166
                             __(
@@ -1206,9 +1206,9 @@  discard block
 block discarded – undo
1206 1206
         $model_ready_query_params = array();
1207 1207
         foreach ($query_params as $key => $value) {
1208 1208
             if (is_array($value)) {
1209
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1209
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1210 1210
             } else {
1211
-                $model_ready_query_params[ $key ] = $value;
1211
+                $model_ready_query_params[$key] = $value;
1212 1212
             }
1213 1213
         }
1214 1214
         return $model_ready_query_params;
@@ -1226,9 +1226,9 @@  discard block
 block discarded – undo
1226 1226
         $model_ready_query_params = array();
1227 1227
         foreach ($query_params as $key => $value) {
1228 1228
             if (is_array($value)) {
1229
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1229
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1230 1230
             } else {
1231
-                $model_ready_query_params[ $key ] = $value;
1231
+                $model_ready_query_params[$key] = $value;
1232 1232
             }
1233 1233
         }
1234 1234
         return $model_ready_query_params;
@@ -1260,17 +1260,17 @@  discard block
 block discarded – undo
1260 1260
         foreach ($exploded_contents as $item) {
1261 1261
             $item = trim($item);
1262 1262
             // if no prefix was provided, so we look for items with no "." in them
1263
-            if (! $prefix) {
1263
+            if ( ! $prefix) {
1264 1264
                 // does this item have a period?
1265 1265
                 if (strpos($item, '.') === false) {
1266 1266
                     // if not, then its what we're looking for
1267 1267
                     $contents_with_prefix[] = $item;
1268 1268
                 }
1269
-            } elseif (strpos($item, $prefix . '.') === 0) {
1269
+            } elseif (strpos($item, $prefix.'.') === 0) {
1270 1270
                 // this item has the prefix and a period, grab it
1271 1271
                 $contents_with_prefix[] = substr(
1272 1272
                     $item,
1273
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1273
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1274 1274
                 );
1275 1275
             } elseif ($item === $prefix) {
1276 1276
                 // this item is JUST the prefix
@@ -1309,9 +1309,9 @@  discard block
 block discarded – undo
1309 1309
         if ($model_name) {
1310 1310
             foreach ($includes as $field_to_include) {
1311 1311
                 $field_to_include = trim($field_to_include);
1312
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1312
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1313 1313
                     // found the model name at the exact start
1314
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1314
+                    $field_sans_model_name = str_replace($model_name.'.', '', $field_to_include);
1315 1315
                     $extracted_fields_to_include[] = $field_sans_model_name;
1316 1316
                 } elseif ($field_to_include == $model_name) {
1317 1317
                     $extracted_fields_to_include[] = '*';
@@ -1351,7 +1351,7 @@  discard block
 block discarded – undo
1351 1351
         $restricted_query_params['caps'] = $context;
1352 1352
         $this->setDebugInfo('model query params', $restricted_query_params);
1353 1353
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1354
-        if (! empty($model_rows)) {
1354
+        if ( ! empty($model_rows)) {
1355 1355
             return $this->createEntityFromWpdbResult(
1356 1356
                 $model,
1357 1357
                 array_shift($model_rows),
@@ -1361,10 +1361,10 @@  discard block
 block discarded – undo
1361 1361
             // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1362 1362
             $lowercase_model_name = strtolower($model->get_this_model_name());
1363 1363
             $model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1364
-            if (! empty($model_rows_found_sans_restrictions)) {
1364
+            if ( ! empty($model_rows_found_sans_restrictions)) {
1365 1365
                 // you got shafted- it existed but we didn't want to tell you!
1366 1366
                 return new WP_Error(
1367
-                    'rest_user_cannot_' . $context,
1367
+                    'rest_user_cannot_'.$context,
1368 1368
                     sprintf(
1369 1369
                         __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1370 1370
                         $context,
Please login to merge, or discard this patch.
core/domain/entities/shortcodes/EspressoTicketSelector.php 2 patches
Indentation   +82 added lines, -82 removed lines patch added patch discarded remove patch
@@ -24,92 +24,92 @@
 block discarded – undo
24 24
 {
25 25
 
26 26
 
27
-    /**
28
-     * the actual shortcode tag that gets registered with WordPress
29
-     *
30
-     * @return string
31
-     */
32
-    public function getTag()
33
-    {
34
-        return 'ESPRESSO_TICKET_SELECTOR';
35
-    }
27
+	/**
28
+	 * the actual shortcode tag that gets registered with WordPress
29
+	 *
30
+	 * @return string
31
+	 */
32
+	public function getTag()
33
+	{
34
+		return 'ESPRESSO_TICKET_SELECTOR';
35
+	}
36 36
 
37 37
 
38
-    /**
39
-     * the time in seconds to cache the results of the processShortcode() method
40
-     * 0 means the processShortcode() results will NOT be cached at all
41
-     *
42
-     * @return int
43
-     */
44
-    public function cacheExpiration()
45
-    {
46
-        return 0;
47
-    }
38
+	/**
39
+	 * the time in seconds to cache the results of the processShortcode() method
40
+	 * 0 means the processShortcode() results will NOT be cached at all
41
+	 *
42
+	 * @return int
43
+	 */
44
+	public function cacheExpiration()
45
+	{
46
+		return 0;
47
+	}
48 48
 
49 49
 
50
-    /**
51
-     * a place for adding any initialization code that needs to run prior to wp_header().
52
-     * this may be required for shortcodes that utilize a corresponding module,
53
-     * and need to enqueue assets for that module
54
-     *
55
-     * @return void
56
-     */
57
-    public function initializeShortcode()
58
-    {
59
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
60
-        $this->shortcodeHasBeenInitialized();
61
-    }
50
+	/**
51
+	 * a place for adding any initialization code that needs to run prior to wp_header().
52
+	 * this may be required for shortcodes that utilize a corresponding module,
53
+	 * and need to enqueue assets for that module
54
+	 *
55
+	 * @return void
56
+	 */
57
+	public function initializeShortcode()
58
+	{
59
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
60
+		$this->shortcodeHasBeenInitialized();
61
+	}
62 62
 
63 63
 
64
-    /**
65
-     * callback that runs when the shortcode is encountered in post content.
66
-     * IMPORTANT !!!
67
-     * remember that shortcode content should be RETURNED and NOT echoed out
68
-     *
69
-     * @param array $attributes
70
-     * @return string
71
-     * @throws InvalidArgumentException
72
-     * @throws EE_Error
73
-     * @throws InvalidDataTypeException
74
-     * @throws InvalidInterfaceException
75
-     * @throws ReflectionException
76
-     * @throws Exception
77
-     */
78
-    public function processShortcode($attributes = array())
79
-    {
80
-        extract($attributes, EXTR_OVERWRITE);
81
-        $event_id = isset($event_id) ? $event_id : 0;
82
-        $event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($event_id);
83
-        if (! $event instanceof EE_Event) {
84
-            if (WP_DEBUG === true && current_user_can('edit_pages')) {
85
-                new ExceptionStackTraceDisplay(
86
-                    new InvalidArgumentException(
87
-                        sprintf(
88
-                            esc_html__(
89
-                                'A valid Event ID is required to use the "%1$s" shortcode.%4$sAn Event with an ID of "%2$s" could not be found.%4$sPlease verify that the shortcode added to this post\'s content includes an "%3$s" argument and that its value corresponds to a valid Event ID.',
90
-                                'event_espresso'
91
-                            ),
92
-                            $this->getTag(),
93
-                            $event_id,
94
-                            'event_id',
95
-                            '<br />'
96
-                        )
97
-                    )
98
-                );
99
-                return '';
100
-            }
101
-            return sprintf(
102
-                esc_html__(
103
-                    'An Event with an ID of "%s" could not be found. Please contact the event administrator for assistance.',
104
-                    'event_espresso'
105
-                ),
106
-                $event_id
107
-            );
108
-        }
109
-        ob_start();
110
-        do_action('AHEE_event_details_before_post', $event_id);
111
-        espresso_ticket_selector($event);
112
-        do_action('AHEE_event_details_after_post');
113
-        return ob_get_clean();
114
-    }
64
+	/**
65
+	 * callback that runs when the shortcode is encountered in post content.
66
+	 * IMPORTANT !!!
67
+	 * remember that shortcode content should be RETURNED and NOT echoed out
68
+	 *
69
+	 * @param array $attributes
70
+	 * @return string
71
+	 * @throws InvalidArgumentException
72
+	 * @throws EE_Error
73
+	 * @throws InvalidDataTypeException
74
+	 * @throws InvalidInterfaceException
75
+	 * @throws ReflectionException
76
+	 * @throws Exception
77
+	 */
78
+	public function processShortcode($attributes = array())
79
+	{
80
+		extract($attributes, EXTR_OVERWRITE);
81
+		$event_id = isset($event_id) ? $event_id : 0;
82
+		$event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($event_id);
83
+		if (! $event instanceof EE_Event) {
84
+			if (WP_DEBUG === true && current_user_can('edit_pages')) {
85
+				new ExceptionStackTraceDisplay(
86
+					new InvalidArgumentException(
87
+						sprintf(
88
+							esc_html__(
89
+								'A valid Event ID is required to use the "%1$s" shortcode.%4$sAn Event with an ID of "%2$s" could not be found.%4$sPlease verify that the shortcode added to this post\'s content includes an "%3$s" argument and that its value corresponds to a valid Event ID.',
90
+								'event_espresso'
91
+							),
92
+							$this->getTag(),
93
+							$event_id,
94
+							'event_id',
95
+							'<br />'
96
+						)
97
+					)
98
+				);
99
+				return '';
100
+			}
101
+			return sprintf(
102
+				esc_html__(
103
+					'An Event with an ID of "%s" could not be found. Please contact the event administrator for assistance.',
104
+					'event_espresso'
105
+				),
106
+				$event_id
107
+			);
108
+		}
109
+		ob_start();
110
+		do_action('AHEE_event_details_before_post', $event_id);
111
+		espresso_ticket_selector($event);
112
+		do_action('AHEE_event_details_after_post');
113
+		return ob_get_clean();
114
+	}
115 115
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -80,7 +80,7 @@
 block discarded – undo
80 80
         extract($attributes, EXTR_OVERWRITE);
81 81
         $event_id = isset($event_id) ? $event_id : 0;
82 82
         $event = EE_Registry::instance()->load_model('Event')->get_one_by_ID($event_id);
83
-        if (! $event instanceof EE_Event) {
83
+        if ( ! $event instanceof EE_Event) {
84 84
             if (WP_DEBUG === true && current_user_can('edit_pages')) {
85 85
                 new ExceptionStackTraceDisplay(
86 86
                     new InvalidArgumentException(
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Admin_File_Uploader_Input.input.php 1 patch
Indentation   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -14,27 +14,27 @@
 block discarded – undo
14 14
 class EE_Admin_File_Uploader_Input extends EE_Form_Input_Base
15 15
 {
16 16
 
17
-    /**
18
-     * @param array $input_settings
19
-     * @throws InvalidArgumentException
20
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
21
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
22
-     */
23
-    public function __construct($input_settings = array())
24
-    {
25
-        $this->_set_display_strategy(new EE_Admin_File_Uploader_Display_Strategy());
26
-        $this->_set_normalization_strategy(new EE_Text_Normalization());
27
-        $this->_add_validation_strategy(
28
-            LoaderFactory::getLoader()->getNew(
29
-                'EE_URL_Validation_Strategy',
30
-                array(
31
-                    isset($input_settings['validation_error_message'])
32
-                        ? $input_settings['validation_error_message']
33
-                        : null,
34
-                    true
35
-                )
36
-            )
37
-        );
38
-        parent::__construct($input_settings);
39
-    }
17
+	/**
18
+	 * @param array $input_settings
19
+	 * @throws InvalidArgumentException
20
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
21
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
22
+	 */
23
+	public function __construct($input_settings = array())
24
+	{
25
+		$this->_set_display_strategy(new EE_Admin_File_Uploader_Display_Strategy());
26
+		$this->_set_normalization_strategy(new EE_Text_Normalization());
27
+		$this->_add_validation_strategy(
28
+			LoaderFactory::getLoader()->getNew(
29
+				'EE_URL_Validation_Strategy',
30
+				array(
31
+					isset($input_settings['validation_error_message'])
32
+						? $input_settings['validation_error_message']
33
+						: null,
34
+					true
35
+				)
36
+			)
37
+		);
38
+		parent::__construct($input_settings);
39
+	}
40 40
 }
Please login to merge, or discard this patch.