Completed
Pull Request — master (#680)
by Darren
12:43
created
core/libraries/rest_api/calculations/HasCalculationSchemaInterface.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -10,18 +10,18 @@
 block discarded – undo
10 10
  */
11 11
 interface HasCalculationSchemaInterface
12 12
 {
13
-    /**
14
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
15
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
16
-     * @return array
17
-     */
18
-    public static function schemaForCalculations();
13
+	/**
14
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
15
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
16
+	 * @return array
17
+	 */
18
+	public static function schemaForCalculations();
19 19
 
20 20
 
21
-    /**
22
-     * Returns the json schema for the given calculation index.
23
-     * @param $calculation_index
24
-     * @return array
25
-     */
26
-    public static function schemaForCalculation($calculation_index);
21
+	/**
22
+	 * Returns the json schema for the given calculation index.
23
+	 * @param $calculation_index
24
+	 * @return array
25
+	 */
26
+	public static function schemaForCalculation($calculation_index);
27 27
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 1 patch
Indentation   +1333 added lines, -1333 removed lines patch added patch discarded remove patch
@@ -35,1337 +35,1337 @@
 block discarded – undo
35 35
 {
36 36
 
37 37
 
38
-    /**
39
-     * @var CalculatedModelFields
40
-     */
41
-    protected $fields_calculator;
42
-
43
-
44
-    /**
45
-     * Read constructor.
46
-     */
47
-    public function __construct()
48
-    {
49
-        parent::__construct();
50
-        $this->fields_calculator = new CalculatedModelFields();
51
-    }
52
-
53
-
54
-    /**
55
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
56
-     *
57
-     * @param WP_REST_Request $request
58
-     * @param string          $version
59
-     * @param string          $model_name
60
-     * @return \WP_REST_Response|WP_Error
61
-     */
62
-    public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
63
-    {
64
-        $controller = new Read();
65
-        try {
66
-            $controller->setRequestedVersion($version);
67
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
68
-                return $controller->sendResponse(
69
-                    new WP_Error(
70
-                        'endpoint_parsing_error',
71
-                        sprintf(
72
-                            __(
73
-                                'There is no model for endpoint %s. Please contact event espresso support',
74
-                                'event_espresso'
75
-                            ),
76
-                            $model_name
77
-                        )
78
-                    )
79
-                );
80
-            }
81
-            return $controller->sendResponse(
82
-                $controller->getEntitiesFromModel(
83
-                    $controller->getModelVersionInfo()->loadModel($model_name),
84
-                    $request
85
-                )
86
-            );
87
-        } catch (Exception $e) {
88
-            return $controller->sendResponse($e);
89
-        }
90
-    }
91
-
92
-
93
-    /**
94
-     * Prepares and returns schema for any OPTIONS request.
95
-     *
96
-     * @param string $version    The API endpoint version being used.
97
-     * @param string $model_name Something like `Event` or `Registration`
98
-     * @return array
99
-     */
100
-    public static function handleSchemaRequest($version, $model_name)
101
-    {
102
-        $controller = new Read();
103
-        try {
104
-            $controller->setRequestedVersion($version);
105
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
106
-                return array();
107
-            }
108
-            // get the model for this version
109
-            $model = $controller->getModelVersionInfo()->loadModel($model_name);
110
-            $model_schema = new JsonModelSchema($model, new CalculatedModelFields());
111
-            return $model_schema->getModelSchemaForRelations(
112
-                $controller->getModelVersionInfo()->relationSettings($model),
113
-                $controller->customizeSchemaForRestResponse(
114
-                    $model,
115
-                    $model_schema->getModelSchemaForFields(
116
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
117
-                        $model_schema->getInitialSchemaStructure()
118
-                    )
119
-                )
120
-            );
121
-        } catch (Exception $e) {
122
-            return array();
123
-        }
124
-    }
125
-
126
-
127
-    /**
128
-     * This loops through each field in the given schema for the model and does the following:
129
-     * - add any extra fields that are REST API specific and related to existing fields.
130
-     * - transform default values into the correct format for a REST API response.
131
-     *
132
-     * @param EEM_Base $model
133
-     * @param array    $schema
134
-     * @return array  The final schema.
135
-     */
136
-    protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
137
-    {
138
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
139
-            $schema = $this->translateDefaultsForRestResponse(
140
-                $field_name,
141
-                $field,
142
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
143
-            );
144
-        }
145
-        return $schema;
146
-    }
147
-
148
-
149
-    /**
150
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
151
-     * response.
152
-     *
153
-     * @param                      $field_name
154
-     * @param EE_Model_Field_Base  $field
155
-     * @param array                $schema
156
-     * @return array
157
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
158
-     * did, let's know about it ASAP, so let the exception bubble up)
159
-     */
160
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
161
-    {
162
-        if (isset($schema['properties'][ $field_name ]['default'])) {
163
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
164
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
165
-                    if ($default_key === 'raw') {
166
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
167
-                            ModelDataTranslator::prepareFieldValueForJson(
168
-                                $field,
169
-                                $default_value,
170
-                                $this->getModelVersionInfo()->requestedVersion()
171
-                            );
172
-                    }
173
-                }
174
-            } else {
175
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
176
-                    $field,
177
-                    $schema['properties'][ $field_name ]['default'],
178
-                    $this->getModelVersionInfo()->requestedVersion()
179
-                );
180
-            }
181
-        }
182
-        return $schema;
183
-    }
184
-
185
-
186
-    /**
187
-     * Adds additional fields to the schema
188
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
189
-     * needs to be added to the schema.
190
-     *
191
-     * @param                      $field_name
192
-     * @param EE_Model_Field_Base  $field
193
-     * @param array                $schema
194
-     * @return array
195
-     */
196
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
197
-    {
198
-        if ($field instanceof EE_Datetime_Field) {
199
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
200
-            // modify the description
201
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
202
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
203
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
204
-            );
205
-        }
206
-        return $schema;
207
-    }
208
-
209
-
210
-    /**
211
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
212
-     *
213
-     * @return string
214
-     */
215
-    protected function getRouteFromRequest()
216
-    {
217
-        if (isset($GLOBALS['wp'])
218
-            && $GLOBALS['wp'] instanceof \WP
219
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
220
-        ) {
221
-            return $GLOBALS['wp']->query_vars['rest_route'];
222
-        } else {
223
-            return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
224
-        }
225
-    }
226
-
227
-
228
-    /**
229
-     * Gets a single entity related to the model indicated in the path and its id
230
-     *
231
-     * @param WP_REST_Request $request
232
-     * @param string          $version
233
-     * @param string          $model_name
234
-     * @return \WP_REST_Response|WP_Error
235
-     */
236
-    public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
237
-    {
238
-        $controller = new Read();
239
-        try {
240
-            $controller->setRequestedVersion($version);
241
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
242
-                return $controller->sendResponse(
243
-                    new WP_Error(
244
-                        'endpoint_parsing_error',
245
-                        sprintf(
246
-                            __(
247
-                                'There is no model for endpoint %s. Please contact event espresso support',
248
-                                'event_espresso'
249
-                            ),
250
-                            $model_name
251
-                        )
252
-                    )
253
-                );
254
-            }
255
-            return $controller->sendResponse(
256
-                $controller->getEntityFromModel(
257
-                    $controller->getModelVersionInfo()->loadModel($model_name),
258
-                    $request
259
-                )
260
-            );
261
-        } catch (Exception $e) {
262
-            return $controller->sendResponse($e);
263
-        }
264
-    }
265
-
266
-
267
-    /**
268
-     * Gets all the related entities (or if its a belongs-to relation just the one)
269
-     * to the item with the given id
270
-     *
271
-     * @param WP_REST_Request $request
272
-     * @param string          $version
273
-     * @param string          $model_name
274
-     * @param string          $related_model_name
275
-     * @return \WP_REST_Response|WP_Error
276
-     */
277
-    public static function handleRequestGetRelated(
278
-        WP_REST_Request $request,
279
-        $version,
280
-        $model_name,
281
-        $related_model_name
282
-    ) {
283
-        $controller = new Read();
284
-        try {
285
-            $controller->setRequestedVersion($version);
286
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
287
-                return $controller->sendResponse(
288
-                    new WP_Error(
289
-                        'endpoint_parsing_error',
290
-                        sprintf(
291
-                            __(
292
-                                'There is no model for endpoint %s. Please contact event espresso support',
293
-                                'event_espresso'
294
-                            ),
295
-                            $model_name
296
-                        )
297
-                    )
298
-                );
299
-            }
300
-            $main_model = $controller->getModelVersionInfo()->loadModel($model_name);
301
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
302
-                return $controller->sendResponse(
303
-                    new WP_Error(
304
-                        'endpoint_parsing_error',
305
-                        sprintf(
306
-                            __(
307
-                                'There is no model for endpoint %s. Please contact event espresso support',
308
-                                'event_espresso'
309
-                            ),
310
-                            $related_model_name
311
-                        )
312
-                    )
313
-                );
314
-            }
315
-            return $controller->sendResponse(
316
-                $controller->getEntitiesFromRelation(
317
-                    $request->get_param('id'),
318
-                    $main_model->related_settings_for($related_model_name),
319
-                    $request
320
-                )
321
-            );
322
-        } catch (Exception $e) {
323
-            return $controller->sendResponse($e);
324
-        }
325
-    }
326
-
327
-
328
-    /**
329
-     * Gets a collection for the given model and filters
330
-     *
331
-     * @param EEM_Base        $model
332
-     * @param WP_REST_Request $request
333
-     * @return array|WP_Error
334
-     */
335
-    public function getEntitiesFromModel($model, $request)
336
-    {
337
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
338
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
339
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
340
-            return new WP_Error(
341
-                sprintf('rest_%s_cannot_list', $model_name_plural),
342
-                sprintf(
343
-                    __('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
344
-                    $model_name_plural,
345
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
346
-                ),
347
-                array('status' => 403)
348
-            );
349
-        }
350
-        if (! $request->get_header('no_rest_headers')) {
351
-            $this->setHeadersFromQueryParams($model, $query_params);
352
-        }
353
-        /** @type array $results */
354
-        $results = $model->get_all_wpdb_results($query_params);
355
-        $nice_results = array();
356
-        foreach ($results as $result) {
357
-            $nice_results[] = $this->createEntityFromWpdbResult(
358
-                $model,
359
-                $result,
360
-                $request
361
-            );
362
-        }
363
-        return $nice_results;
364
-    }
365
-
366
-
367
-    /**
368
-     * Gets the collection for given relation object
369
-     * The same as Read::get_entities_from_model(), except if the relation
370
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
371
-     * the join-model-object into the results
372
-     *
373
-     * @param array                   $primary_model_query_params query params for finding the item from which
374
-     *                                                            relations will be based
375
-     * @param \EE_Model_Relation_Base $relation
376
-     * @param WP_REST_Request         $request
377
-     * @return WP_Error|array
378
-     * @throws RestException
379
-     */
380
-    protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
381
-    {
382
-        $context = $this->validateContext($request->get_param('caps'));
383
-        $model = $relation->get_this_model();
384
-        $related_model = $relation->get_other_model();
385
-        if (! isset($primary_model_query_params[0])) {
386
-            $primary_model_query_params[0] = array();
387
-        }
388
-        // check if they can access the 1st model object
389
-        $primary_model_query_params = array(
390
-            0       => $primary_model_query_params[0],
391
-            'limit' => 1,
392
-        );
393
-        if ($model instanceof \EEM_Soft_Delete_Base) {
394
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
395
-                $primary_model_query_params
396
-            );
397
-        }
398
-        $restricted_query_params = $primary_model_query_params;
399
-        $restricted_query_params['caps'] = $context;
400
-        $this->setDebugInfo('main model query params', $restricted_query_params);
401
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
402
-        if (! (
403
-            Capabilities::currentUserHasPartialAccessTo($related_model, $context)
404
-            && $model->exists($restricted_query_params)
405
-        )
406
-        ) {
407
-            if ($relation instanceof EE_Belongs_To_Relation) {
408
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
409
-            } else {
410
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
411
-                    $related_model->get_this_model_name()
412
-                );
413
-            }
414
-            return new WP_Error(
415
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
416
-                sprintf(
417
-                    __(
418
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
419
-                        'event_espresso'
420
-                    ),
421
-                    $related_model_name_maybe_plural,
422
-                    $relation->get_this_model()->get_this_model_name(),
423
-                    implode(
424
-                        ',',
425
-                        array_keys(
426
-                            Capabilities::getMissingPermissions($related_model, $context)
427
-                        )
428
-                    )
429
-                ),
430
-                array('status' => 403)
431
-            );
432
-        }
433
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
434
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
435
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
436
-                              . '.'
437
-                              . $where_condition_key ] = $where_condition_value;
438
-        }
439
-        $query_params['default_where_conditions'] = 'none';
440
-        $query_params['caps'] = $context;
441
-        if (! $request->get_header('no_rest_headers')) {
442
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
443
-        }
444
-        /** @type array $results */
445
-        $results = $relation->get_other_model()->get_all_wpdb_results($query_params);
446
-        $nice_results = array();
447
-        foreach ($results as $result) {
448
-            $nice_result = $this->createEntityFromWpdbResult(
449
-                $relation->get_other_model(),
450
-                $result,
451
-                $request
452
-            );
453
-            if ($relation instanceof \EE_HABTM_Relation) {
454
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
455
-                // if there are conflicts we prefer the properties from the main model
456
-                $join_model_result = $this->createEntityFromWpdbResult(
457
-                    $relation->get_join_model(),
458
-                    $result,
459
-                    $request
460
-                );
461
-                $joined_result = array_merge($nice_result, $join_model_result);
462
-                // but keep the meta stuff from the main model
463
-                if (isset($nice_result['meta'])) {
464
-                    $joined_result['meta'] = $nice_result['meta'];
465
-                }
466
-                $nice_result = $joined_result;
467
-            }
468
-            $nice_results[] = $nice_result;
469
-        }
470
-        if ($relation instanceof EE_Belongs_To_Relation) {
471
-            return array_shift($nice_results);
472
-        } else {
473
-            return $nice_results;
474
-        }
475
-    }
476
-
477
-
478
-    /**
479
-     * Gets the collection for given relation object
480
-     * The same as Read::get_entities_from_model(), except if the relation
481
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
482
-     * the join-model-object into the results
483
-     *
484
-     * @param string                  $id the ID of the thing we are fetching related stuff from
485
-     * @param \EE_Model_Relation_Base $relation
486
-     * @param WP_REST_Request         $request
487
-     * @return array|WP_Error
488
-     * @throws EE_Error
489
-     */
490
-    public function getEntitiesFromRelation($id, $relation, $request)
491
-    {
492
-        if (! $relation->get_this_model()->has_primary_key_field()) {
493
-            throw new EE_Error(
494
-                sprintf(
495
-                    __(
496
-                    // @codingStandardsIgnoreStart
497
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
498
-                        // @codingStandardsIgnoreEnd
499
-                        'event_espresso'
500
-                    ),
501
-                    $relation->get_this_model()->get_this_model_name()
502
-                )
503
-            );
504
-        }
505
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
506
-            array(
507
-                array(
508
-                    $relation->get_this_model()->primary_key_name() => $id,
509
-                ),
510
-            ),
511
-            $relation,
512
-            $request
513
-        );
514
-    }
515
-
516
-
517
-    /**
518
-     * Sets the headers that are based on the model and query params,
519
-     * like the total records. This should only be called on the original request
520
-     * from the client, not on subsequent internal
521
-     *
522
-     * @param EEM_Base $model
523
-     * @param array    $query_params
524
-     * @return void
525
-     */
526
-    protected function setHeadersFromQueryParams($model, $query_params)
527
-    {
528
-        $this->setDebugInfo('model query params', $query_params);
529
-        $this->setDebugInfo(
530
-            'missing caps',
531
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
532
-        );
533
-        // normally the limit to a 2-part array, where the 2nd item is the limit
534
-        if (! isset($query_params['limit'])) {
535
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
536
-        }
537
-        if (is_array($query_params['limit'])) {
538
-            $limit_parts = $query_params['limit'];
539
-        } else {
540
-            $limit_parts = explode(',', $query_params['limit']);
541
-            if (count($limit_parts) == 1) {
542
-                $limit_parts = array(0, $limit_parts[0]);
543
-            }
544
-        }
545
-        // remove the group by and having parts of the query, as those will
546
-        // make the sql query return an array of values, instead of just a single value
547
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
548
-        $count = $model->count($query_params, null, true);
549
-        $pages = $count / $limit_parts[1];
550
-        $this->setResponseHeader('Total', $count, false);
551
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
552
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
553
-    }
554
-
555
-
556
-    /**
557
-     * Changes database results into REST API entities
558
-     *
559
-     * @param EEM_Base        $model
560
-     * @param array           $db_row     like results from $wpdb->get_results()
561
-     * @param WP_REST_Request $rest_request
562
-     * @param string          $deprecated no longer used
563
-     * @return array ready for being converted into json for sending to client
564
-     */
565
-    public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
566
-    {
567
-        if (! $rest_request instanceof WP_REST_Request) {
568
-            // ok so this was called in the old style, where the 3rd arg was
569
-            // $include, and the 4th arg was $context
570
-            // now setup the request just to avoid fatal errors, although we won't be able
571
-            // to truly make use of it because it's kinda devoid of info
572
-            $rest_request = new WP_REST_Request();
573
-            $rest_request->set_param('include', $rest_request);
574
-            $rest_request->set_param('caps', $deprecated);
575
-        }
576
-        if ($rest_request->get_param('caps') == null) {
577
-            $rest_request->set_param('caps', EEM_Base::caps_read);
578
-        }
579
-        $entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
580
-        $entity_array = $this->addExtraFields($model, $db_row, $entity_array);
581
-        $entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
582
-        $entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request);
583
-        $entity_array = apply_filters(
584
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
585
-            $entity_array,
586
-            $model,
587
-            $rest_request->get_param('caps'),
588
-            $rest_request,
589
-            $this
590
-        );
591
-        $entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row);
592
-        $entity_array = apply_filters(
593
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
594
-            $entity_array,
595
-            $model,
596
-            $rest_request->get_param('caps'),
597
-            $rest_request,
598
-            $this
599
-        );
600
-        $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
601
-            $entity_array,
602
-            $model,
603
-            $rest_request->get_param('caps'),
604
-            $this->getModelVersionInfo(),
605
-            $model->get_index_primary_key_string(
606
-                $model->deduce_fields_n_values_from_cols_n_values($db_row)
607
-            )
608
-        );
609
-        $this->setDebugInfo(
610
-            'inaccessible fields',
611
-            array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
612
-        );
613
-        return apply_filters(
614
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
615
-            $result_without_inaccessible_fields,
616
-            $model,
617
-            $rest_request->get_param('caps')
618
-        );
619
-    }
620
-
621
-
622
-    /**
623
-     * Creates a REST entity array (JSON object we're going to return in the response, but
624
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
625
-     * from $wpdb->get_row( $sql, ARRAY_A)
626
-     *
627
-     * @param EEM_Base $model
628
-     * @param array    $db_row
629
-     * @return array entity mostly ready for converting to JSON and sending in the response
630
-     */
631
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
632
-    {
633
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
634
-        $result = array_intersect_key(
635
-            $result,
636
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
637
-        );
638
-        // if this is a CPT, we need to set the global $post to it,
639
-        // otherwise shortcodes etc won't work properly while rendering it
640
-        if ($model instanceof \EEM_CPT_Base) {
641
-            $do_chevy_shuffle = true;
642
-        } else {
643
-            $do_chevy_shuffle = false;
644
-        }
645
-        if ($do_chevy_shuffle) {
646
-            global $post;
647
-            $old_post = $post;
648
-            $post = get_post($result[ $model->primary_key_name() ]);
649
-            if (! $post instanceof \WP_Post) {
650
-                // well that's weird, because $result is what we JUST fetched from the database
651
-                throw new RestException(
652
-                    'error_fetching_post_from_database_results',
653
-                    esc_html__(
654
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
655
-                        'event_espresso'
656
-                    )
657
-                );
658
-            }
659
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
660
-            $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
661
-                $model_object_classname,
662
-                $result,
663
-                false,
664
-                false
665
-            );
666
-        }
667
-        foreach ($result as $field_name => $field_value) {
668
-            $field_obj = $model->field_settings_for($field_name);
669
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
670
-                unset($result[ $field_name ]);
671
-            } elseif ($this->isSubclassOfOne(
672
-                $field_obj,
673
-                $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
674
-            )
675
-            ) {
676
-                $result[ $field_name ] = array(
677
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
678
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
679
-                );
680
-            } elseif ($this->isSubclassOfOne(
681
-                $field_obj,
682
-                $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
683
-            )
684
-            ) {
685
-                $result[ $field_name ] = array(
686
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
687
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
688
-                );
689
-            } elseif ($field_obj instanceof \EE_Datetime_Field) {
690
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
691
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
692
-                if (is_null($field_value)) {
693
-                    $field_value = $field_obj->getDefaultDateTimeObj();
694
-                }
695
-                if (is_null($field_value)) {
696
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
697
-                        $field_obj,
698
-                        $field_value,
699
-                        $this->getModelVersionInfo()->requestedVersion()
700
-                    );
701
-                } else {
702
-                    $timezone = $field_value->getTimezone();
703
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
704
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
705
-                        $field_obj,
706
-                        $field_value,
707
-                        $this->getModelVersionInfo()->requestedVersion()
708
-                    );
709
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
710
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
711
-                        $field_obj,
712
-                        $field_value,
713
-                        $this->getModelVersionInfo()->requestedVersion()
714
-                    );
715
-                }
716
-                $result[ $field_name . '_gmt' ] = $gmt_date;
717
-                $result[ $field_name ] = $local_date;
718
-            } else {
719
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
720
-            }
721
-        }
722
-        if ($do_chevy_shuffle) {
723
-            $post = $old_post;
724
-        }
725
-        return $result;
726
-    }
727
-
728
-
729
-    /**
730
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
731
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
732
-     * representation using $field_obj->prepare_for_set_from_db())
733
-     *
734
-     * @param EE_Model_Field_Base $field_obj
735
-     * @param mixed               $value  as it's stored on a model object
736
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
737
-     * @return mixed
738
-     * @throws ObjectDetectedException if $value contains a PHP object
739
-     */
740
-    protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
741
-    {
742
-        $value = $field_obj->prepare_for_set_from_db($value);
743
-        switch ($format) {
744
-            case 'pretty':
745
-                $value = $field_obj->prepare_for_pretty_echoing($value);
746
-                break;
747
-            case 'normal':
748
-            default:
749
-                $value = $field_obj->prepare_for_get($value);
750
-                break;
751
-        }
752
-        return ModelDataTranslator::prepareFieldValuesForJson(
753
-            $field_obj,
754
-            $value,
755
-            $this->getModelVersionInfo()->requestedVersion()
756
-        );
757
-    }
758
-
759
-
760
-    /**
761
-     * Adds a few extra fields to the entity response
762
-     *
763
-     * @param EEM_Base $model
764
-     * @param array    $db_row
765
-     * @param array    $entity_array
766
-     * @return array modified entity
767
-     */
768
-    protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
769
-    {
770
-        if ($model instanceof EEM_CPT_Base) {
771
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
772
-        }
773
-        return $entity_array;
774
-    }
775
-
776
-
777
-    /**
778
-     * Gets links we want to add to the response
779
-     *
780
-     * @global \WP_REST_Server $wp_rest_server
781
-     * @param EEM_Base         $model
782
-     * @param array            $db_row
783
-     * @param array            $entity_array
784
-     * @return array the _links item in the entity
785
-     */
786
-    protected function getEntityLinks($model, $db_row, $entity_array)
787
-    {
788
-        // add basic links
789
-        $links = array();
790
-        if ($model->has_primary_key_field()) {
791
-            $links['self'] = array(
792
-                array(
793
-                    'href' => $this->getVersionedLinkTo(
794
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
795
-                        . '/'
796
-                        . $entity_array[ $model->primary_key_name() ]
797
-                    ),
798
-                ),
799
-            );
800
-        }
801
-        $links['collection'] = array(
802
-            array(
803
-                'href' => $this->getVersionedLinkTo(
804
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
805
-                ),
806
-            ),
807
-        );
808
-        // add links to related models
809
-        if ($model->has_primary_key_field()) {
810
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
811
-                $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
812
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
813
-                    array(
814
-                        'href'   => $this->getVersionedLinkTo(
815
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
816
-                            . '/'
817
-                            . $entity_array[ $model->primary_key_name() ]
818
-                            . '/'
819
-                            . $related_model_part
820
-                        ),
821
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
822
-                    ),
823
-                );
824
-            }
825
-        }
826
-        return $links;
827
-    }
828
-
829
-
830
-    /**
831
-     * Adds the included models indicated in the request to the entity provided
832
-     *
833
-     * @param EEM_Base        $model
834
-     * @param WP_REST_Request $rest_request
835
-     * @param array           $entity_array
836
-     * @param array           $db_row
837
-     * @return array the modified entity
838
-     */
839
-    protected function includeRequestedModels(
840
-        EEM_Base $model,
841
-        WP_REST_Request $rest_request,
842
-        $entity_array,
843
-        $db_row = array()
844
-    ) {
845
-        // if $db_row not included, hope the entity array has what we need
846
-        if (! $db_row) {
847
-            $db_row = $entity_array;
848
-        }
849
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
850
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
851
-        // if they passed in * or didn't specify any includes, return everything
852
-        if (! in_array('*', $includes_for_this_model)
853
-            && ! empty($includes_for_this_model)
854
-        ) {
855
-            if ($model->has_primary_key_field()) {
856
-                // always include the primary key. ya just gotta know that at least
857
-                $includes_for_this_model[] = $model->primary_key_name();
858
-            }
859
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
860
-                $includes_for_this_model[] = '_calculated_fields';
861
-            }
862
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
863
-        }
864
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
865
-        foreach ($relation_settings as $relation_name => $relation_obj) {
866
-            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
867
-                $rest_request->get_param('include'),
868
-                $relation_name
869
-            );
870
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
871
-                $rest_request->get_param('calculate'),
872
-                $relation_name
873
-            );
874
-            // did they specify they wanted to include a related model, or
875
-            // specific fields from a related model?
876
-            // or did they specify to calculate a field from a related model?
877
-            if ($related_fields_to_include || $related_fields_to_calculate) {
878
-                // if so, we should include at least some part of the related model
879
-                $pretend_related_request = new WP_REST_Request();
880
-                $pretend_related_request->set_query_params(
881
-                    array(
882
-                        'caps'      => $rest_request->get_param('caps'),
883
-                        'include'   => $related_fields_to_include,
884
-                        'calculate' => $related_fields_to_calculate,
885
-                    )
886
-                );
887
-                $pretend_related_request->add_header('no_rest_headers', true);
888
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
889
-                    $model->get_index_primary_key_string(
890
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
891
-                    )
892
-                );
893
-                $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
894
-                    $primary_model_query_params,
895
-                    $relation_obj,
896
-                    $pretend_related_request
897
-                );
898
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
899
-                                                                                             instanceof
900
-                                                                                             WP_Error
901
-                    ? null
902
-                    : $related_results;
903
-            }
904
-        }
905
-        return $entity_array;
906
-    }
907
-
908
-
909
-    /**
910
-     * Returns a new array with all the names of models removed. Eg
911
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
912
-     *
913
-     * @param array $arr
914
-     * @return array
915
-     */
916
-    private function removeModelNamesFromArray($arr)
917
-    {
918
-        return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
919
-    }
920
-
921
-
922
-    /**
923
-     * Gets the calculated fields for the response
924
-     *
925
-     * @param EEM_Base        $model
926
-     * @param array           $wpdb_row
927
-     * @param WP_REST_Request $rest_request
928
-     * @return \stdClass the _calculations item in the entity
929
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
930
-     * did, let's know about it ASAP, so let the exception bubble up)
931
-     */
932
-    protected function getEntityCalculations($model, $wpdb_row, $rest_request)
933
-    {
934
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
935
-            $rest_request->get_param('calculate'),
936
-            ''
937
-        );
938
-        // note: setting calculate=* doesn't do anything
939
-        $calculated_fields_to_return = new \stdClass();
940
-        foreach ($calculated_fields as $field_to_calculate) {
941
-            try {
942
-                $calculated_fields_to_return->$field_to_calculate = ModelDataTranslator::prepareFieldValueForJson(
943
-                    null,
944
-                    $this->fields_calculator->retrieveCalculatedFieldValue(
945
-                        $model,
946
-                        $field_to_calculate,
947
-                        $wpdb_row,
948
-                        $rest_request,
949
-                        $this
950
-                    ),
951
-                    $this->getModelVersionInfo()->requestedVersion()
952
-                );
953
-            } catch (RestException $e) {
954
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
955
-                $this->setResponseHeader(
956
-                    'Notices-Field-Calculation-Errors['
957
-                    . $e->getStringCode()
958
-                    . ']['
959
-                    . $model->get_this_model_name()
960
-                    . ']['
961
-                    . $field_to_calculate
962
-                    . ']',
963
-                    $e->getMessage(),
964
-                    true
965
-                );
966
-            }
967
-        }
968
-        return $calculated_fields_to_return;
969
-    }
970
-
971
-
972
-    /**
973
-     * Gets the full URL to the resource, taking the requested version into account
974
-     *
975
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
976
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
977
-     */
978
-    public function getVersionedLinkTo($link_part_after_version_and_slash)
979
-    {
980
-        return rest_url(
981
-            EED_Core_Rest_Api::get_versioned_route_to(
982
-                $link_part_after_version_and_slash,
983
-                $this->getModelVersionInfo()->requestedVersion()
984
-            )
985
-        );
986
-    }
987
-
988
-
989
-    /**
990
-     * Gets the correct lowercase name for the relation in the API according
991
-     * to the relation's type
992
-     *
993
-     * @param string                  $relation_name
994
-     * @param \EE_Model_Relation_Base $relation_obj
995
-     * @return string
996
-     */
997
-    public static function getRelatedEntityName($relation_name, $relation_obj)
998
-    {
999
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1000
-            return strtolower($relation_name);
1001
-        } else {
1002
-            return EEH_Inflector::pluralize_and_lower($relation_name);
1003
-        }
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * Gets the one model object with the specified id for the specified model
1009
-     *
1010
-     * @param EEM_Base        $model
1011
-     * @param WP_REST_Request $request
1012
-     * @return array|WP_Error
1013
-     */
1014
-    public function getEntityFromModel($model, $request)
1015
-    {
1016
-        $context = $this->validateContext($request->get_param('caps'));
1017
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1018
-    }
1019
-
1020
-
1021
-    /**
1022
-     * If a context is provided which isn't valid, maybe it was added in a future
1023
-     * version so just treat it as a default read
1024
-     *
1025
-     * @param string $context
1026
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1027
-     */
1028
-    public function validateContext($context)
1029
-    {
1030
-        if (! $context) {
1031
-            $context = EEM_Base::caps_read;
1032
-        }
1033
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1034
-        if (in_array($context, $valid_contexts)) {
1035
-            return $context;
1036
-        } else {
1037
-            return EEM_Base::caps_read;
1038
-        }
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * Verifies the passed in value is an allowable default where conditions value.
1044
-     *
1045
-     * @param $default_query_params
1046
-     * @return string
1047
-     */
1048
-    public function validateDefaultQueryParams($default_query_params)
1049
-    {
1050
-        $valid_default_where_conditions_for_api_calls = array(
1051
-            EEM_Base::default_where_conditions_all,
1052
-            EEM_Base::default_where_conditions_minimum_all,
1053
-            EEM_Base::default_where_conditions_minimum_others,
1054
-        );
1055
-        if (! $default_query_params) {
1056
-            $default_query_params = EEM_Base::default_where_conditions_all;
1057
-        }
1058
-        if (in_array(
1059
-            $default_query_params,
1060
-            $valid_default_where_conditions_for_api_calls,
1061
-            true
1062
-        )) {
1063
-            return $default_query_params;
1064
-        } else {
1065
-            return EEM_Base::default_where_conditions_all;
1066
-        }
1067
-    }
1068
-
1069
-
1070
-    /**
1071
-     * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1072
-     * Note: right now the query parameter keys for fields (and related fields)
1073
-     * can be left as-is, but it's quite possible this will change someday.
1074
-     * Also, this method's contents might be candidate for moving to Model_Data_Translator
1075
-     *
1076
-     * @param EEM_Base $model
1077
-     * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1078
-     * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1079
-     *                                    that absolutely no results should be returned
1080
-     * @throws EE_Error
1081
-     * @throws RestException
1082
-     */
1083
-    public function createModelQueryParams($model, $query_parameters)
1084
-    {
1085
-        $model_query_params = array();
1086
-        if (isset($query_parameters['where'])) {
1087
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1088
-                $query_parameters['where'],
1089
-                $model,
1090
-                $this->getModelVersionInfo()->requestedVersion()
1091
-            );
1092
-        }
1093
-        if (isset($query_parameters['order_by'])) {
1094
-            $order_by = $query_parameters['order_by'];
1095
-        } elseif (isset($query_parameters['orderby'])) {
1096
-            $order_by = $query_parameters['orderby'];
1097
-        } else {
1098
-            $order_by = null;
1099
-        }
1100
-        if ($order_by !== null) {
1101
-            if (is_array($order_by)) {
1102
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1103
-            } else {
1104
-                // it's a single item
1105
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1106
-            }
1107
-            $model_query_params['order_by'] = $order_by;
1108
-        }
1109
-        if (isset($query_parameters['group_by'])) {
1110
-            $group_by = $query_parameters['group_by'];
1111
-        } elseif (isset($query_parameters['groupby'])) {
1112
-            $group_by = $query_parameters['groupby'];
1113
-        } else {
1114
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1115
-        }
1116
-        // make sure they're all real names
1117
-        if (is_array($group_by)) {
1118
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1119
-        }
1120
-        if ($group_by !== null) {
1121
-            $model_query_params['group_by'] = $group_by;
1122
-        }
1123
-        if (isset($query_parameters['having'])) {
1124
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1125
-                $query_parameters['having'],
1126
-                $model,
1127
-                $this->getModelVersionInfo()->requestedVersion()
1128
-            );
1129
-        }
1130
-        if (isset($query_parameters['order'])) {
1131
-            $model_query_params['order'] = $query_parameters['order'];
1132
-        }
1133
-        if (isset($query_parameters['mine'])) {
1134
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1135
-        }
1136
-        if (isset($query_parameters['limit'])) {
1137
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1138
-            if (! is_array($query_parameters['limit'])) {
1139
-                $limit_array = explode(',', (string) $query_parameters['limit']);
1140
-            } else {
1141
-                $limit_array = $query_parameters['limit'];
1142
-            }
1143
-            $sanitized_limit = array();
1144
-            foreach ($limit_array as $key => $limit_part) {
1145
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1146
-                    throw new EE_Error(
1147
-                        sprintf(
1148
-                            __(
1149
-                            // @codingStandardsIgnoreStart
1150
-                                '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.',
1151
-                                // @codingStandardsIgnoreEnd
1152
-                                'event_espresso'
1153
-                            ),
1154
-                            wp_json_encode($query_parameters['limit'])
1155
-                        )
1156
-                    );
1157
-                }
1158
-                $sanitized_limit[] = (int) $limit_part;
1159
-            }
1160
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1161
-        } else {
1162
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1163
-        }
1164
-        if (isset($query_parameters['caps'])) {
1165
-            $model_query_params['caps'] = $this->validateContext($query_parameters['caps']);
1166
-        } else {
1167
-            $model_query_params['caps'] = EEM_Base::caps_read;
1168
-        }
1169
-        if (isset($query_parameters['default_where_conditions'])) {
1170
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1171
-                $query_parameters['default_where_conditions']
1172
-            );
1173
-        }
1174
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1175
-    }
1176
-
1177
-
1178
-    /**
1179
-     * Changes the REST-style query params for use in the models
1180
-     *
1181
-     * @deprecated
1182
-     * @param EEM_Base $model
1183
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1184
-     * @return array
1185
-     */
1186
-    public function prepareRestQueryParamsKeyForModels($model, $query_params)
1187
-    {
1188
-        $model_ready_query_params = array();
1189
-        foreach ($query_params as $key => $value) {
1190
-            if (is_array($value)) {
1191
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1192
-            } else {
1193
-                $model_ready_query_params[ $key ] = $value;
1194
-            }
1195
-        }
1196
-        return $model_ready_query_params;
1197
-    }
1198
-
1199
-
1200
-    /**
1201
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1202
-     * @param $model
1203
-     * @param $query_params
1204
-     * @return array
1205
-     */
1206
-    public function prepareRestQueryParamsValuesForModels($model, $query_params)
1207
-    {
1208
-        $model_ready_query_params = array();
1209
-        foreach ($query_params as $key => $value) {
1210
-            if (is_array($value)) {
1211
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1212
-            } else {
1213
-                $model_ready_query_params[ $key ] = $value;
1214
-            }
1215
-        }
1216
-        return $model_ready_query_params;
1217
-    }
1218
-
1219
-
1220
-    /**
1221
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1222
-     * If no prefix is specified, returns items with no period.
1223
-     *
1224
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1225
-     * @param string       $prefix            "Event" or "foobar"
1226
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1227
-     *                                        we only return strings starting with that and a period; if no prefix was
1228
-     *                                        specified we return all items containing NO periods
1229
-     */
1230
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1231
-    {
1232
-        if (is_string($string_to_explode)) {
1233
-            $exploded_contents = explode(',', $string_to_explode);
1234
-        } elseif (is_array($string_to_explode)) {
1235
-            $exploded_contents = $string_to_explode;
1236
-        } else {
1237
-            $exploded_contents = array();
1238
-        }
1239
-        // if the string was empty, we want an empty array
1240
-        $exploded_contents = array_filter($exploded_contents);
1241
-        $contents_with_prefix = array();
1242
-        foreach ($exploded_contents as $item) {
1243
-            $item = trim($item);
1244
-            // if no prefix was provided, so we look for items with no "." in them
1245
-            if (! $prefix) {
1246
-                // does this item have a period?
1247
-                if (strpos($item, '.') === false) {
1248
-                    // if not, then its what we're looking for
1249
-                    $contents_with_prefix[] = $item;
1250
-                }
1251
-            } elseif (strpos($item, $prefix . '.') === 0) {
1252
-                // this item has the prefix and a period, grab it
1253
-                $contents_with_prefix[] = substr(
1254
-                    $item,
1255
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1256
-                );
1257
-            } elseif ($item === $prefix) {
1258
-                // this item is JUST the prefix
1259
-                // so let's grab everything after, which is a blank string
1260
-                $contents_with_prefix[] = '';
1261
-            }
1262
-        }
1263
-        return $contents_with_prefix;
1264
-    }
1265
-
1266
-
1267
-    /**
1268
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1269
-     * Deprecated because its return values were really quite confusing- sometimes it returned
1270
-     * an empty array (when the include string was blank or '*') or sometimes it returned
1271
-     * array('*') (when you provided a model and a model of that kind was found).
1272
-     * Parses the $include_string so we fetch all the field names relating to THIS model
1273
-     * (ie have NO period in them), or for the provided model (ie start with the model
1274
-     * name and then a period).
1275
-     * @param string $include_string @see Read:handle_request_get_all
1276
-     * @param string $model_name
1277
-     * @return array of fields for this model. If $model_name is provided, then
1278
-     *                               the fields for that model, with the model's name removed from each.
1279
-     *                               If $include_string was blank or '*' returns an empty array
1280
-     */
1281
-    public function extractIncludesForThisModel($include_string, $model_name = null)
1282
-    {
1283
-        if (is_array($include_string)) {
1284
-            $include_string = implode(',', $include_string);
1285
-        }
1286
-        if ($include_string === '*' || $include_string === '') {
1287
-            return array();
1288
-        }
1289
-        $includes = explode(',', $include_string);
1290
-        $extracted_fields_to_include = array();
1291
-        if ($model_name) {
1292
-            foreach ($includes as $field_to_include) {
1293
-                $field_to_include = trim($field_to_include);
1294
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1295
-                    // found the model name at the exact start
1296
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1297
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1298
-                } elseif ($field_to_include == $model_name) {
1299
-                    $extracted_fields_to_include[] = '*';
1300
-                }
1301
-            }
1302
-        } else {
1303
-            // look for ones with no period
1304
-            foreach ($includes as $field_to_include) {
1305
-                $field_to_include = trim($field_to_include);
1306
-                if (strpos($field_to_include, '.') === false
1307
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1308
-                ) {
1309
-                    $extracted_fields_to_include[] = $field_to_include;
1310
-                }
1311
-            }
1312
-        }
1313
-        return $extracted_fields_to_include;
1314
-    }
1315
-
1316
-
1317
-    /**
1318
-     * Gets the single item using the model according to the request in the context given, otherwise
1319
-     * returns that it's inaccessible to the current user
1320
-     *
1321
-     * @param EEM_Base        $model
1322
-     * @param WP_REST_Request $request
1323
-     * @param null            $context
1324
-     * @return array|WP_Error
1325
-     */
1326
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1327
-    {
1328
-        $query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1329
-        if ($model instanceof \EEM_Soft_Delete_Base) {
1330
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1331
-        }
1332
-        $restricted_query_params = $query_params;
1333
-        $restricted_query_params['caps'] = $context;
1334
-        $this->setDebugInfo('model query params', $restricted_query_params);
1335
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1336
-        if (! empty($model_rows)) {
1337
-            return $this->createEntityFromWpdbResult(
1338
-                $model,
1339
-                array_shift($model_rows),
1340
-                $request
1341
-            );
1342
-        } else {
1343
-            // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1344
-            $lowercase_model_name = strtolower($model->get_this_model_name());
1345
-            $model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1346
-            if (! empty($model_rows_found_sans_restrictions)) {
1347
-                // you got shafted- it existed but we didn't want to tell you!
1348
-                return new WP_Error(
1349
-                    'rest_user_cannot_' . $context,
1350
-                    sprintf(
1351
-                        __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1352
-                        $context,
1353
-                        strtolower($model->get_this_model_name()),
1354
-                        Capabilities::getMissingPermissionsString(
1355
-                            $model,
1356
-                            $context
1357
-                        )
1358
-                    ),
1359
-                    array('status' => 403)
1360
-                );
1361
-            } else {
1362
-                // it's not you. It just doesn't exist
1363
-                return new WP_Error(
1364
-                    sprintf('rest_%s_invalid_id', $lowercase_model_name),
1365
-                    sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1366
-                    array('status' => 404)
1367
-                );
1368
-            }
1369
-        }
1370
-    }
38
+	/**
39
+	 * @var CalculatedModelFields
40
+	 */
41
+	protected $fields_calculator;
42
+
43
+
44
+	/**
45
+	 * Read constructor.
46
+	 */
47
+	public function __construct()
48
+	{
49
+		parent::__construct();
50
+		$this->fields_calculator = new CalculatedModelFields();
51
+	}
52
+
53
+
54
+	/**
55
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
56
+	 *
57
+	 * @param WP_REST_Request $request
58
+	 * @param string          $version
59
+	 * @param string          $model_name
60
+	 * @return \WP_REST_Response|WP_Error
61
+	 */
62
+	public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
63
+	{
64
+		$controller = new Read();
65
+		try {
66
+			$controller->setRequestedVersion($version);
67
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
68
+				return $controller->sendResponse(
69
+					new WP_Error(
70
+						'endpoint_parsing_error',
71
+						sprintf(
72
+							__(
73
+								'There is no model for endpoint %s. Please contact event espresso support',
74
+								'event_espresso'
75
+							),
76
+							$model_name
77
+						)
78
+					)
79
+				);
80
+			}
81
+			return $controller->sendResponse(
82
+				$controller->getEntitiesFromModel(
83
+					$controller->getModelVersionInfo()->loadModel($model_name),
84
+					$request
85
+				)
86
+			);
87
+		} catch (Exception $e) {
88
+			return $controller->sendResponse($e);
89
+		}
90
+	}
91
+
92
+
93
+	/**
94
+	 * Prepares and returns schema for any OPTIONS request.
95
+	 *
96
+	 * @param string $version    The API endpoint version being used.
97
+	 * @param string $model_name Something like `Event` or `Registration`
98
+	 * @return array
99
+	 */
100
+	public static function handleSchemaRequest($version, $model_name)
101
+	{
102
+		$controller = new Read();
103
+		try {
104
+			$controller->setRequestedVersion($version);
105
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
106
+				return array();
107
+			}
108
+			// get the model for this version
109
+			$model = $controller->getModelVersionInfo()->loadModel($model_name);
110
+			$model_schema = new JsonModelSchema($model, new CalculatedModelFields());
111
+			return $model_schema->getModelSchemaForRelations(
112
+				$controller->getModelVersionInfo()->relationSettings($model),
113
+				$controller->customizeSchemaForRestResponse(
114
+					$model,
115
+					$model_schema->getModelSchemaForFields(
116
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
117
+						$model_schema->getInitialSchemaStructure()
118
+					)
119
+				)
120
+			);
121
+		} catch (Exception $e) {
122
+			return array();
123
+		}
124
+	}
125
+
126
+
127
+	/**
128
+	 * This loops through each field in the given schema for the model and does the following:
129
+	 * - add any extra fields that are REST API specific and related to existing fields.
130
+	 * - transform default values into the correct format for a REST API response.
131
+	 *
132
+	 * @param EEM_Base $model
133
+	 * @param array    $schema
134
+	 * @return array  The final schema.
135
+	 */
136
+	protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
137
+	{
138
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
139
+			$schema = $this->translateDefaultsForRestResponse(
140
+				$field_name,
141
+				$field,
142
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
143
+			);
144
+		}
145
+		return $schema;
146
+	}
147
+
148
+
149
+	/**
150
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
151
+	 * response.
152
+	 *
153
+	 * @param                      $field_name
154
+	 * @param EE_Model_Field_Base  $field
155
+	 * @param array                $schema
156
+	 * @return array
157
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
158
+	 * did, let's know about it ASAP, so let the exception bubble up)
159
+	 */
160
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
161
+	{
162
+		if (isset($schema['properties'][ $field_name ]['default'])) {
163
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
164
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
165
+					if ($default_key === 'raw') {
166
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
167
+							ModelDataTranslator::prepareFieldValueForJson(
168
+								$field,
169
+								$default_value,
170
+								$this->getModelVersionInfo()->requestedVersion()
171
+							);
172
+					}
173
+				}
174
+			} else {
175
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
176
+					$field,
177
+					$schema['properties'][ $field_name ]['default'],
178
+					$this->getModelVersionInfo()->requestedVersion()
179
+				);
180
+			}
181
+		}
182
+		return $schema;
183
+	}
184
+
185
+
186
+	/**
187
+	 * Adds additional fields to the schema
188
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
189
+	 * needs to be added to the schema.
190
+	 *
191
+	 * @param                      $field_name
192
+	 * @param EE_Model_Field_Base  $field
193
+	 * @param array                $schema
194
+	 * @return array
195
+	 */
196
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
197
+	{
198
+		if ($field instanceof EE_Datetime_Field) {
199
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
200
+			// modify the description
201
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
202
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
203
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
204
+			);
205
+		}
206
+		return $schema;
207
+	}
208
+
209
+
210
+	/**
211
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
212
+	 *
213
+	 * @return string
214
+	 */
215
+	protected function getRouteFromRequest()
216
+	{
217
+		if (isset($GLOBALS['wp'])
218
+			&& $GLOBALS['wp'] instanceof \WP
219
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
220
+		) {
221
+			return $GLOBALS['wp']->query_vars['rest_route'];
222
+		} else {
223
+			return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
224
+		}
225
+	}
226
+
227
+
228
+	/**
229
+	 * Gets a single entity related to the model indicated in the path and its id
230
+	 *
231
+	 * @param WP_REST_Request $request
232
+	 * @param string          $version
233
+	 * @param string          $model_name
234
+	 * @return \WP_REST_Response|WP_Error
235
+	 */
236
+	public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
237
+	{
238
+		$controller = new Read();
239
+		try {
240
+			$controller->setRequestedVersion($version);
241
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
242
+				return $controller->sendResponse(
243
+					new WP_Error(
244
+						'endpoint_parsing_error',
245
+						sprintf(
246
+							__(
247
+								'There is no model for endpoint %s. Please contact event espresso support',
248
+								'event_espresso'
249
+							),
250
+							$model_name
251
+						)
252
+					)
253
+				);
254
+			}
255
+			return $controller->sendResponse(
256
+				$controller->getEntityFromModel(
257
+					$controller->getModelVersionInfo()->loadModel($model_name),
258
+					$request
259
+				)
260
+			);
261
+		} catch (Exception $e) {
262
+			return $controller->sendResponse($e);
263
+		}
264
+	}
265
+
266
+
267
+	/**
268
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
269
+	 * to the item with the given id
270
+	 *
271
+	 * @param WP_REST_Request $request
272
+	 * @param string          $version
273
+	 * @param string          $model_name
274
+	 * @param string          $related_model_name
275
+	 * @return \WP_REST_Response|WP_Error
276
+	 */
277
+	public static function handleRequestGetRelated(
278
+		WP_REST_Request $request,
279
+		$version,
280
+		$model_name,
281
+		$related_model_name
282
+	) {
283
+		$controller = new Read();
284
+		try {
285
+			$controller->setRequestedVersion($version);
286
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
287
+				return $controller->sendResponse(
288
+					new WP_Error(
289
+						'endpoint_parsing_error',
290
+						sprintf(
291
+							__(
292
+								'There is no model for endpoint %s. Please contact event espresso support',
293
+								'event_espresso'
294
+							),
295
+							$model_name
296
+						)
297
+					)
298
+				);
299
+			}
300
+			$main_model = $controller->getModelVersionInfo()->loadModel($model_name);
301
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
302
+				return $controller->sendResponse(
303
+					new WP_Error(
304
+						'endpoint_parsing_error',
305
+						sprintf(
306
+							__(
307
+								'There is no model for endpoint %s. Please contact event espresso support',
308
+								'event_espresso'
309
+							),
310
+							$related_model_name
311
+						)
312
+					)
313
+				);
314
+			}
315
+			return $controller->sendResponse(
316
+				$controller->getEntitiesFromRelation(
317
+					$request->get_param('id'),
318
+					$main_model->related_settings_for($related_model_name),
319
+					$request
320
+				)
321
+			);
322
+		} catch (Exception $e) {
323
+			return $controller->sendResponse($e);
324
+		}
325
+	}
326
+
327
+
328
+	/**
329
+	 * Gets a collection for the given model and filters
330
+	 *
331
+	 * @param EEM_Base        $model
332
+	 * @param WP_REST_Request $request
333
+	 * @return array|WP_Error
334
+	 */
335
+	public function getEntitiesFromModel($model, $request)
336
+	{
337
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
338
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
339
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
340
+			return new WP_Error(
341
+				sprintf('rest_%s_cannot_list', $model_name_plural),
342
+				sprintf(
343
+					__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
344
+					$model_name_plural,
345
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
346
+				),
347
+				array('status' => 403)
348
+			);
349
+		}
350
+		if (! $request->get_header('no_rest_headers')) {
351
+			$this->setHeadersFromQueryParams($model, $query_params);
352
+		}
353
+		/** @type array $results */
354
+		$results = $model->get_all_wpdb_results($query_params);
355
+		$nice_results = array();
356
+		foreach ($results as $result) {
357
+			$nice_results[] = $this->createEntityFromWpdbResult(
358
+				$model,
359
+				$result,
360
+				$request
361
+			);
362
+		}
363
+		return $nice_results;
364
+	}
365
+
366
+
367
+	/**
368
+	 * Gets the collection for given relation object
369
+	 * The same as Read::get_entities_from_model(), except if the relation
370
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
371
+	 * the join-model-object into the results
372
+	 *
373
+	 * @param array                   $primary_model_query_params query params for finding the item from which
374
+	 *                                                            relations will be based
375
+	 * @param \EE_Model_Relation_Base $relation
376
+	 * @param WP_REST_Request         $request
377
+	 * @return WP_Error|array
378
+	 * @throws RestException
379
+	 */
380
+	protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
381
+	{
382
+		$context = $this->validateContext($request->get_param('caps'));
383
+		$model = $relation->get_this_model();
384
+		$related_model = $relation->get_other_model();
385
+		if (! isset($primary_model_query_params[0])) {
386
+			$primary_model_query_params[0] = array();
387
+		}
388
+		// check if they can access the 1st model object
389
+		$primary_model_query_params = array(
390
+			0       => $primary_model_query_params[0],
391
+			'limit' => 1,
392
+		);
393
+		if ($model instanceof \EEM_Soft_Delete_Base) {
394
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
395
+				$primary_model_query_params
396
+			);
397
+		}
398
+		$restricted_query_params = $primary_model_query_params;
399
+		$restricted_query_params['caps'] = $context;
400
+		$this->setDebugInfo('main model query params', $restricted_query_params);
401
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
402
+		if (! (
403
+			Capabilities::currentUserHasPartialAccessTo($related_model, $context)
404
+			&& $model->exists($restricted_query_params)
405
+		)
406
+		) {
407
+			if ($relation instanceof EE_Belongs_To_Relation) {
408
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
409
+			} else {
410
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
411
+					$related_model->get_this_model_name()
412
+				);
413
+			}
414
+			return new WP_Error(
415
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
416
+				sprintf(
417
+					__(
418
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
419
+						'event_espresso'
420
+					),
421
+					$related_model_name_maybe_plural,
422
+					$relation->get_this_model()->get_this_model_name(),
423
+					implode(
424
+						',',
425
+						array_keys(
426
+							Capabilities::getMissingPermissions($related_model, $context)
427
+						)
428
+					)
429
+				),
430
+				array('status' => 403)
431
+			);
432
+		}
433
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
434
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
435
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
436
+							  . '.'
437
+							  . $where_condition_key ] = $where_condition_value;
438
+		}
439
+		$query_params['default_where_conditions'] = 'none';
440
+		$query_params['caps'] = $context;
441
+		if (! $request->get_header('no_rest_headers')) {
442
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
443
+		}
444
+		/** @type array $results */
445
+		$results = $relation->get_other_model()->get_all_wpdb_results($query_params);
446
+		$nice_results = array();
447
+		foreach ($results as $result) {
448
+			$nice_result = $this->createEntityFromWpdbResult(
449
+				$relation->get_other_model(),
450
+				$result,
451
+				$request
452
+			);
453
+			if ($relation instanceof \EE_HABTM_Relation) {
454
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
455
+				// if there are conflicts we prefer the properties from the main model
456
+				$join_model_result = $this->createEntityFromWpdbResult(
457
+					$relation->get_join_model(),
458
+					$result,
459
+					$request
460
+				);
461
+				$joined_result = array_merge($nice_result, $join_model_result);
462
+				// but keep the meta stuff from the main model
463
+				if (isset($nice_result['meta'])) {
464
+					$joined_result['meta'] = $nice_result['meta'];
465
+				}
466
+				$nice_result = $joined_result;
467
+			}
468
+			$nice_results[] = $nice_result;
469
+		}
470
+		if ($relation instanceof EE_Belongs_To_Relation) {
471
+			return array_shift($nice_results);
472
+		} else {
473
+			return $nice_results;
474
+		}
475
+	}
476
+
477
+
478
+	/**
479
+	 * Gets the collection for given relation object
480
+	 * The same as Read::get_entities_from_model(), except if the relation
481
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
482
+	 * the join-model-object into the results
483
+	 *
484
+	 * @param string                  $id the ID of the thing we are fetching related stuff from
485
+	 * @param \EE_Model_Relation_Base $relation
486
+	 * @param WP_REST_Request         $request
487
+	 * @return array|WP_Error
488
+	 * @throws EE_Error
489
+	 */
490
+	public function getEntitiesFromRelation($id, $relation, $request)
491
+	{
492
+		if (! $relation->get_this_model()->has_primary_key_field()) {
493
+			throw new EE_Error(
494
+				sprintf(
495
+					__(
496
+					// @codingStandardsIgnoreStart
497
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
498
+						// @codingStandardsIgnoreEnd
499
+						'event_espresso'
500
+					),
501
+					$relation->get_this_model()->get_this_model_name()
502
+				)
503
+			);
504
+		}
505
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
506
+			array(
507
+				array(
508
+					$relation->get_this_model()->primary_key_name() => $id,
509
+				),
510
+			),
511
+			$relation,
512
+			$request
513
+		);
514
+	}
515
+
516
+
517
+	/**
518
+	 * Sets the headers that are based on the model and query params,
519
+	 * like the total records. This should only be called on the original request
520
+	 * from the client, not on subsequent internal
521
+	 *
522
+	 * @param EEM_Base $model
523
+	 * @param array    $query_params
524
+	 * @return void
525
+	 */
526
+	protected function setHeadersFromQueryParams($model, $query_params)
527
+	{
528
+		$this->setDebugInfo('model query params', $query_params);
529
+		$this->setDebugInfo(
530
+			'missing caps',
531
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
532
+		);
533
+		// normally the limit to a 2-part array, where the 2nd item is the limit
534
+		if (! isset($query_params['limit'])) {
535
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
536
+		}
537
+		if (is_array($query_params['limit'])) {
538
+			$limit_parts = $query_params['limit'];
539
+		} else {
540
+			$limit_parts = explode(',', $query_params['limit']);
541
+			if (count($limit_parts) == 1) {
542
+				$limit_parts = array(0, $limit_parts[0]);
543
+			}
544
+		}
545
+		// remove the group by and having parts of the query, as those will
546
+		// make the sql query return an array of values, instead of just a single value
547
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
548
+		$count = $model->count($query_params, null, true);
549
+		$pages = $count / $limit_parts[1];
550
+		$this->setResponseHeader('Total', $count, false);
551
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
552
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
553
+	}
554
+
555
+
556
+	/**
557
+	 * Changes database results into REST API entities
558
+	 *
559
+	 * @param EEM_Base        $model
560
+	 * @param array           $db_row     like results from $wpdb->get_results()
561
+	 * @param WP_REST_Request $rest_request
562
+	 * @param string          $deprecated no longer used
563
+	 * @return array ready for being converted into json for sending to client
564
+	 */
565
+	public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
566
+	{
567
+		if (! $rest_request instanceof WP_REST_Request) {
568
+			// ok so this was called in the old style, where the 3rd arg was
569
+			// $include, and the 4th arg was $context
570
+			// now setup the request just to avoid fatal errors, although we won't be able
571
+			// to truly make use of it because it's kinda devoid of info
572
+			$rest_request = new WP_REST_Request();
573
+			$rest_request->set_param('include', $rest_request);
574
+			$rest_request->set_param('caps', $deprecated);
575
+		}
576
+		if ($rest_request->get_param('caps') == null) {
577
+			$rest_request->set_param('caps', EEM_Base::caps_read);
578
+		}
579
+		$entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
580
+		$entity_array = $this->addExtraFields($model, $db_row, $entity_array);
581
+		$entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
582
+		$entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request);
583
+		$entity_array = apply_filters(
584
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
585
+			$entity_array,
586
+			$model,
587
+			$rest_request->get_param('caps'),
588
+			$rest_request,
589
+			$this
590
+		);
591
+		$entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row);
592
+		$entity_array = apply_filters(
593
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
594
+			$entity_array,
595
+			$model,
596
+			$rest_request->get_param('caps'),
597
+			$rest_request,
598
+			$this
599
+		);
600
+		$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
601
+			$entity_array,
602
+			$model,
603
+			$rest_request->get_param('caps'),
604
+			$this->getModelVersionInfo(),
605
+			$model->get_index_primary_key_string(
606
+				$model->deduce_fields_n_values_from_cols_n_values($db_row)
607
+			)
608
+		);
609
+		$this->setDebugInfo(
610
+			'inaccessible fields',
611
+			array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
612
+		);
613
+		return apply_filters(
614
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
615
+			$result_without_inaccessible_fields,
616
+			$model,
617
+			$rest_request->get_param('caps')
618
+		);
619
+	}
620
+
621
+
622
+	/**
623
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
624
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
625
+	 * from $wpdb->get_row( $sql, ARRAY_A)
626
+	 *
627
+	 * @param EEM_Base $model
628
+	 * @param array    $db_row
629
+	 * @return array entity mostly ready for converting to JSON and sending in the response
630
+	 */
631
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
632
+	{
633
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
634
+		$result = array_intersect_key(
635
+			$result,
636
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
637
+		);
638
+		// if this is a CPT, we need to set the global $post to it,
639
+		// otherwise shortcodes etc won't work properly while rendering it
640
+		if ($model instanceof \EEM_CPT_Base) {
641
+			$do_chevy_shuffle = true;
642
+		} else {
643
+			$do_chevy_shuffle = false;
644
+		}
645
+		if ($do_chevy_shuffle) {
646
+			global $post;
647
+			$old_post = $post;
648
+			$post = get_post($result[ $model->primary_key_name() ]);
649
+			if (! $post instanceof \WP_Post) {
650
+				// well that's weird, because $result is what we JUST fetched from the database
651
+				throw new RestException(
652
+					'error_fetching_post_from_database_results',
653
+					esc_html__(
654
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
655
+						'event_espresso'
656
+					)
657
+				);
658
+			}
659
+			$model_object_classname = 'EE_' . $model->get_this_model_name();
660
+			$post->{$model_object_classname} = \EE_Registry::instance()->load_class(
661
+				$model_object_classname,
662
+				$result,
663
+				false,
664
+				false
665
+			);
666
+		}
667
+		foreach ($result as $field_name => $field_value) {
668
+			$field_obj = $model->field_settings_for($field_name);
669
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
670
+				unset($result[ $field_name ]);
671
+			} elseif ($this->isSubclassOfOne(
672
+				$field_obj,
673
+				$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
674
+			)
675
+			) {
676
+				$result[ $field_name ] = array(
677
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
678
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
679
+				);
680
+			} elseif ($this->isSubclassOfOne(
681
+				$field_obj,
682
+				$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
683
+			)
684
+			) {
685
+				$result[ $field_name ] = array(
686
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
687
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
688
+				);
689
+			} elseif ($field_obj instanceof \EE_Datetime_Field) {
690
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
691
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
692
+				if (is_null($field_value)) {
693
+					$field_value = $field_obj->getDefaultDateTimeObj();
694
+				}
695
+				if (is_null($field_value)) {
696
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
697
+						$field_obj,
698
+						$field_value,
699
+						$this->getModelVersionInfo()->requestedVersion()
700
+					);
701
+				} else {
702
+					$timezone = $field_value->getTimezone();
703
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
704
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
705
+						$field_obj,
706
+						$field_value,
707
+						$this->getModelVersionInfo()->requestedVersion()
708
+					);
709
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
710
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
711
+						$field_obj,
712
+						$field_value,
713
+						$this->getModelVersionInfo()->requestedVersion()
714
+					);
715
+				}
716
+				$result[ $field_name . '_gmt' ] = $gmt_date;
717
+				$result[ $field_name ] = $local_date;
718
+			} else {
719
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
720
+			}
721
+		}
722
+		if ($do_chevy_shuffle) {
723
+			$post = $old_post;
724
+		}
725
+		return $result;
726
+	}
727
+
728
+
729
+	/**
730
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
731
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
732
+	 * representation using $field_obj->prepare_for_set_from_db())
733
+	 *
734
+	 * @param EE_Model_Field_Base $field_obj
735
+	 * @param mixed               $value  as it's stored on a model object
736
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
737
+	 * @return mixed
738
+	 * @throws ObjectDetectedException if $value contains a PHP object
739
+	 */
740
+	protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
741
+	{
742
+		$value = $field_obj->prepare_for_set_from_db($value);
743
+		switch ($format) {
744
+			case 'pretty':
745
+				$value = $field_obj->prepare_for_pretty_echoing($value);
746
+				break;
747
+			case 'normal':
748
+			default:
749
+				$value = $field_obj->prepare_for_get($value);
750
+				break;
751
+		}
752
+		return ModelDataTranslator::prepareFieldValuesForJson(
753
+			$field_obj,
754
+			$value,
755
+			$this->getModelVersionInfo()->requestedVersion()
756
+		);
757
+	}
758
+
759
+
760
+	/**
761
+	 * Adds a few extra fields to the entity response
762
+	 *
763
+	 * @param EEM_Base $model
764
+	 * @param array    $db_row
765
+	 * @param array    $entity_array
766
+	 * @return array modified entity
767
+	 */
768
+	protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
769
+	{
770
+		if ($model instanceof EEM_CPT_Base) {
771
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
772
+		}
773
+		return $entity_array;
774
+	}
775
+
776
+
777
+	/**
778
+	 * Gets links we want to add to the response
779
+	 *
780
+	 * @global \WP_REST_Server $wp_rest_server
781
+	 * @param EEM_Base         $model
782
+	 * @param array            $db_row
783
+	 * @param array            $entity_array
784
+	 * @return array the _links item in the entity
785
+	 */
786
+	protected function getEntityLinks($model, $db_row, $entity_array)
787
+	{
788
+		// add basic links
789
+		$links = array();
790
+		if ($model->has_primary_key_field()) {
791
+			$links['self'] = array(
792
+				array(
793
+					'href' => $this->getVersionedLinkTo(
794
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
795
+						. '/'
796
+						. $entity_array[ $model->primary_key_name() ]
797
+					),
798
+				),
799
+			);
800
+		}
801
+		$links['collection'] = array(
802
+			array(
803
+				'href' => $this->getVersionedLinkTo(
804
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
805
+				),
806
+			),
807
+		);
808
+		// add links to related models
809
+		if ($model->has_primary_key_field()) {
810
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
811
+				$related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
812
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
813
+					array(
814
+						'href'   => $this->getVersionedLinkTo(
815
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
816
+							. '/'
817
+							. $entity_array[ $model->primary_key_name() ]
818
+							. '/'
819
+							. $related_model_part
820
+						),
821
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
822
+					),
823
+				);
824
+			}
825
+		}
826
+		return $links;
827
+	}
828
+
829
+
830
+	/**
831
+	 * Adds the included models indicated in the request to the entity provided
832
+	 *
833
+	 * @param EEM_Base        $model
834
+	 * @param WP_REST_Request $rest_request
835
+	 * @param array           $entity_array
836
+	 * @param array           $db_row
837
+	 * @return array the modified entity
838
+	 */
839
+	protected function includeRequestedModels(
840
+		EEM_Base $model,
841
+		WP_REST_Request $rest_request,
842
+		$entity_array,
843
+		$db_row = array()
844
+	) {
845
+		// if $db_row not included, hope the entity array has what we need
846
+		if (! $db_row) {
847
+			$db_row = $entity_array;
848
+		}
849
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
850
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
851
+		// if they passed in * or didn't specify any includes, return everything
852
+		if (! in_array('*', $includes_for_this_model)
853
+			&& ! empty($includes_for_this_model)
854
+		) {
855
+			if ($model->has_primary_key_field()) {
856
+				// always include the primary key. ya just gotta know that at least
857
+				$includes_for_this_model[] = $model->primary_key_name();
858
+			}
859
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
860
+				$includes_for_this_model[] = '_calculated_fields';
861
+			}
862
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
863
+		}
864
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
865
+		foreach ($relation_settings as $relation_name => $relation_obj) {
866
+			$related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
867
+				$rest_request->get_param('include'),
868
+				$relation_name
869
+			);
870
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
871
+				$rest_request->get_param('calculate'),
872
+				$relation_name
873
+			);
874
+			// did they specify they wanted to include a related model, or
875
+			// specific fields from a related model?
876
+			// or did they specify to calculate a field from a related model?
877
+			if ($related_fields_to_include || $related_fields_to_calculate) {
878
+				// if so, we should include at least some part of the related model
879
+				$pretend_related_request = new WP_REST_Request();
880
+				$pretend_related_request->set_query_params(
881
+					array(
882
+						'caps'      => $rest_request->get_param('caps'),
883
+						'include'   => $related_fields_to_include,
884
+						'calculate' => $related_fields_to_calculate,
885
+					)
886
+				);
887
+				$pretend_related_request->add_header('no_rest_headers', true);
888
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
889
+					$model->get_index_primary_key_string(
890
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
891
+					)
892
+				);
893
+				$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
894
+					$primary_model_query_params,
895
+					$relation_obj,
896
+					$pretend_related_request
897
+				);
898
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
899
+																							 instanceof
900
+																							 WP_Error
901
+					? null
902
+					: $related_results;
903
+			}
904
+		}
905
+		return $entity_array;
906
+	}
907
+
908
+
909
+	/**
910
+	 * Returns a new array with all the names of models removed. Eg
911
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
912
+	 *
913
+	 * @param array $arr
914
+	 * @return array
915
+	 */
916
+	private function removeModelNamesFromArray($arr)
917
+	{
918
+		return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
919
+	}
920
+
921
+
922
+	/**
923
+	 * Gets the calculated fields for the response
924
+	 *
925
+	 * @param EEM_Base        $model
926
+	 * @param array           $wpdb_row
927
+	 * @param WP_REST_Request $rest_request
928
+	 * @return \stdClass the _calculations item in the entity
929
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
930
+	 * did, let's know about it ASAP, so let the exception bubble up)
931
+	 */
932
+	protected function getEntityCalculations($model, $wpdb_row, $rest_request)
933
+	{
934
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
935
+			$rest_request->get_param('calculate'),
936
+			''
937
+		);
938
+		// note: setting calculate=* doesn't do anything
939
+		$calculated_fields_to_return = new \stdClass();
940
+		foreach ($calculated_fields as $field_to_calculate) {
941
+			try {
942
+				$calculated_fields_to_return->$field_to_calculate = ModelDataTranslator::prepareFieldValueForJson(
943
+					null,
944
+					$this->fields_calculator->retrieveCalculatedFieldValue(
945
+						$model,
946
+						$field_to_calculate,
947
+						$wpdb_row,
948
+						$rest_request,
949
+						$this
950
+					),
951
+					$this->getModelVersionInfo()->requestedVersion()
952
+				);
953
+			} catch (RestException $e) {
954
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
955
+				$this->setResponseHeader(
956
+					'Notices-Field-Calculation-Errors['
957
+					. $e->getStringCode()
958
+					. ']['
959
+					. $model->get_this_model_name()
960
+					. ']['
961
+					. $field_to_calculate
962
+					. ']',
963
+					$e->getMessage(),
964
+					true
965
+				);
966
+			}
967
+		}
968
+		return $calculated_fields_to_return;
969
+	}
970
+
971
+
972
+	/**
973
+	 * Gets the full URL to the resource, taking the requested version into account
974
+	 *
975
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
976
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
977
+	 */
978
+	public function getVersionedLinkTo($link_part_after_version_and_slash)
979
+	{
980
+		return rest_url(
981
+			EED_Core_Rest_Api::get_versioned_route_to(
982
+				$link_part_after_version_and_slash,
983
+				$this->getModelVersionInfo()->requestedVersion()
984
+			)
985
+		);
986
+	}
987
+
988
+
989
+	/**
990
+	 * Gets the correct lowercase name for the relation in the API according
991
+	 * to the relation's type
992
+	 *
993
+	 * @param string                  $relation_name
994
+	 * @param \EE_Model_Relation_Base $relation_obj
995
+	 * @return string
996
+	 */
997
+	public static function getRelatedEntityName($relation_name, $relation_obj)
998
+	{
999
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1000
+			return strtolower($relation_name);
1001
+		} else {
1002
+			return EEH_Inflector::pluralize_and_lower($relation_name);
1003
+		}
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * Gets the one model object with the specified id for the specified model
1009
+	 *
1010
+	 * @param EEM_Base        $model
1011
+	 * @param WP_REST_Request $request
1012
+	 * @return array|WP_Error
1013
+	 */
1014
+	public function getEntityFromModel($model, $request)
1015
+	{
1016
+		$context = $this->validateContext($request->get_param('caps'));
1017
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1018
+	}
1019
+
1020
+
1021
+	/**
1022
+	 * If a context is provided which isn't valid, maybe it was added in a future
1023
+	 * version so just treat it as a default read
1024
+	 *
1025
+	 * @param string $context
1026
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1027
+	 */
1028
+	public function validateContext($context)
1029
+	{
1030
+		if (! $context) {
1031
+			$context = EEM_Base::caps_read;
1032
+		}
1033
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1034
+		if (in_array($context, $valid_contexts)) {
1035
+			return $context;
1036
+		} else {
1037
+			return EEM_Base::caps_read;
1038
+		}
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * Verifies the passed in value is an allowable default where conditions value.
1044
+	 *
1045
+	 * @param $default_query_params
1046
+	 * @return string
1047
+	 */
1048
+	public function validateDefaultQueryParams($default_query_params)
1049
+	{
1050
+		$valid_default_where_conditions_for_api_calls = array(
1051
+			EEM_Base::default_where_conditions_all,
1052
+			EEM_Base::default_where_conditions_minimum_all,
1053
+			EEM_Base::default_where_conditions_minimum_others,
1054
+		);
1055
+		if (! $default_query_params) {
1056
+			$default_query_params = EEM_Base::default_where_conditions_all;
1057
+		}
1058
+		if (in_array(
1059
+			$default_query_params,
1060
+			$valid_default_where_conditions_for_api_calls,
1061
+			true
1062
+		)) {
1063
+			return $default_query_params;
1064
+		} else {
1065
+			return EEM_Base::default_where_conditions_all;
1066
+		}
1067
+	}
1068
+
1069
+
1070
+	/**
1071
+	 * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1072
+	 * Note: right now the query parameter keys for fields (and related fields)
1073
+	 * can be left as-is, but it's quite possible this will change someday.
1074
+	 * Also, this method's contents might be candidate for moving to Model_Data_Translator
1075
+	 *
1076
+	 * @param EEM_Base $model
1077
+	 * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1078
+	 * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1079
+	 *                                    that absolutely no results should be returned
1080
+	 * @throws EE_Error
1081
+	 * @throws RestException
1082
+	 */
1083
+	public function createModelQueryParams($model, $query_parameters)
1084
+	{
1085
+		$model_query_params = array();
1086
+		if (isset($query_parameters['where'])) {
1087
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1088
+				$query_parameters['where'],
1089
+				$model,
1090
+				$this->getModelVersionInfo()->requestedVersion()
1091
+			);
1092
+		}
1093
+		if (isset($query_parameters['order_by'])) {
1094
+			$order_by = $query_parameters['order_by'];
1095
+		} elseif (isset($query_parameters['orderby'])) {
1096
+			$order_by = $query_parameters['orderby'];
1097
+		} else {
1098
+			$order_by = null;
1099
+		}
1100
+		if ($order_by !== null) {
1101
+			if (is_array($order_by)) {
1102
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1103
+			} else {
1104
+				// it's a single item
1105
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1106
+			}
1107
+			$model_query_params['order_by'] = $order_by;
1108
+		}
1109
+		if (isset($query_parameters['group_by'])) {
1110
+			$group_by = $query_parameters['group_by'];
1111
+		} elseif (isset($query_parameters['groupby'])) {
1112
+			$group_by = $query_parameters['groupby'];
1113
+		} else {
1114
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1115
+		}
1116
+		// make sure they're all real names
1117
+		if (is_array($group_by)) {
1118
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1119
+		}
1120
+		if ($group_by !== null) {
1121
+			$model_query_params['group_by'] = $group_by;
1122
+		}
1123
+		if (isset($query_parameters['having'])) {
1124
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1125
+				$query_parameters['having'],
1126
+				$model,
1127
+				$this->getModelVersionInfo()->requestedVersion()
1128
+			);
1129
+		}
1130
+		if (isset($query_parameters['order'])) {
1131
+			$model_query_params['order'] = $query_parameters['order'];
1132
+		}
1133
+		if (isset($query_parameters['mine'])) {
1134
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1135
+		}
1136
+		if (isset($query_parameters['limit'])) {
1137
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1138
+			if (! is_array($query_parameters['limit'])) {
1139
+				$limit_array = explode(',', (string) $query_parameters['limit']);
1140
+			} else {
1141
+				$limit_array = $query_parameters['limit'];
1142
+			}
1143
+			$sanitized_limit = array();
1144
+			foreach ($limit_array as $key => $limit_part) {
1145
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1146
+					throw new EE_Error(
1147
+						sprintf(
1148
+							__(
1149
+							// @codingStandardsIgnoreStart
1150
+								'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.',
1151
+								// @codingStandardsIgnoreEnd
1152
+								'event_espresso'
1153
+							),
1154
+							wp_json_encode($query_parameters['limit'])
1155
+						)
1156
+					);
1157
+				}
1158
+				$sanitized_limit[] = (int) $limit_part;
1159
+			}
1160
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1161
+		} else {
1162
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1163
+		}
1164
+		if (isset($query_parameters['caps'])) {
1165
+			$model_query_params['caps'] = $this->validateContext($query_parameters['caps']);
1166
+		} else {
1167
+			$model_query_params['caps'] = EEM_Base::caps_read;
1168
+		}
1169
+		if (isset($query_parameters['default_where_conditions'])) {
1170
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1171
+				$query_parameters['default_where_conditions']
1172
+			);
1173
+		}
1174
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * Changes the REST-style query params for use in the models
1180
+	 *
1181
+	 * @deprecated
1182
+	 * @param EEM_Base $model
1183
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1184
+	 * @return array
1185
+	 */
1186
+	public function prepareRestQueryParamsKeyForModels($model, $query_params)
1187
+	{
1188
+		$model_ready_query_params = array();
1189
+		foreach ($query_params as $key => $value) {
1190
+			if (is_array($value)) {
1191
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1192
+			} else {
1193
+				$model_ready_query_params[ $key ] = $value;
1194
+			}
1195
+		}
1196
+		return $model_ready_query_params;
1197
+	}
1198
+
1199
+
1200
+	/**
1201
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1202
+	 * @param $model
1203
+	 * @param $query_params
1204
+	 * @return array
1205
+	 */
1206
+	public function prepareRestQueryParamsValuesForModels($model, $query_params)
1207
+	{
1208
+		$model_ready_query_params = array();
1209
+		foreach ($query_params as $key => $value) {
1210
+			if (is_array($value)) {
1211
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1212
+			} else {
1213
+				$model_ready_query_params[ $key ] = $value;
1214
+			}
1215
+		}
1216
+		return $model_ready_query_params;
1217
+	}
1218
+
1219
+
1220
+	/**
1221
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1222
+	 * If no prefix is specified, returns items with no period.
1223
+	 *
1224
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1225
+	 * @param string       $prefix            "Event" or "foobar"
1226
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1227
+	 *                                        we only return strings starting with that and a period; if no prefix was
1228
+	 *                                        specified we return all items containing NO periods
1229
+	 */
1230
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1231
+	{
1232
+		if (is_string($string_to_explode)) {
1233
+			$exploded_contents = explode(',', $string_to_explode);
1234
+		} elseif (is_array($string_to_explode)) {
1235
+			$exploded_contents = $string_to_explode;
1236
+		} else {
1237
+			$exploded_contents = array();
1238
+		}
1239
+		// if the string was empty, we want an empty array
1240
+		$exploded_contents = array_filter($exploded_contents);
1241
+		$contents_with_prefix = array();
1242
+		foreach ($exploded_contents as $item) {
1243
+			$item = trim($item);
1244
+			// if no prefix was provided, so we look for items with no "." in them
1245
+			if (! $prefix) {
1246
+				// does this item have a period?
1247
+				if (strpos($item, '.') === false) {
1248
+					// if not, then its what we're looking for
1249
+					$contents_with_prefix[] = $item;
1250
+				}
1251
+			} elseif (strpos($item, $prefix . '.') === 0) {
1252
+				// this item has the prefix and a period, grab it
1253
+				$contents_with_prefix[] = substr(
1254
+					$item,
1255
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1256
+				);
1257
+			} elseif ($item === $prefix) {
1258
+				// this item is JUST the prefix
1259
+				// so let's grab everything after, which is a blank string
1260
+				$contents_with_prefix[] = '';
1261
+			}
1262
+		}
1263
+		return $contents_with_prefix;
1264
+	}
1265
+
1266
+
1267
+	/**
1268
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1269
+	 * Deprecated because its return values were really quite confusing- sometimes it returned
1270
+	 * an empty array (when the include string was blank or '*') or sometimes it returned
1271
+	 * array('*') (when you provided a model and a model of that kind was found).
1272
+	 * Parses the $include_string so we fetch all the field names relating to THIS model
1273
+	 * (ie have NO period in them), or for the provided model (ie start with the model
1274
+	 * name and then a period).
1275
+	 * @param string $include_string @see Read:handle_request_get_all
1276
+	 * @param string $model_name
1277
+	 * @return array of fields for this model. If $model_name is provided, then
1278
+	 *                               the fields for that model, with the model's name removed from each.
1279
+	 *                               If $include_string was blank or '*' returns an empty array
1280
+	 */
1281
+	public function extractIncludesForThisModel($include_string, $model_name = null)
1282
+	{
1283
+		if (is_array($include_string)) {
1284
+			$include_string = implode(',', $include_string);
1285
+		}
1286
+		if ($include_string === '*' || $include_string === '') {
1287
+			return array();
1288
+		}
1289
+		$includes = explode(',', $include_string);
1290
+		$extracted_fields_to_include = array();
1291
+		if ($model_name) {
1292
+			foreach ($includes as $field_to_include) {
1293
+				$field_to_include = trim($field_to_include);
1294
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1295
+					// found the model name at the exact start
1296
+					$field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1297
+					$extracted_fields_to_include[] = $field_sans_model_name;
1298
+				} elseif ($field_to_include == $model_name) {
1299
+					$extracted_fields_to_include[] = '*';
1300
+				}
1301
+			}
1302
+		} else {
1303
+			// look for ones with no period
1304
+			foreach ($includes as $field_to_include) {
1305
+				$field_to_include = trim($field_to_include);
1306
+				if (strpos($field_to_include, '.') === false
1307
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1308
+				) {
1309
+					$extracted_fields_to_include[] = $field_to_include;
1310
+				}
1311
+			}
1312
+		}
1313
+		return $extracted_fields_to_include;
1314
+	}
1315
+
1316
+
1317
+	/**
1318
+	 * Gets the single item using the model according to the request in the context given, otherwise
1319
+	 * returns that it's inaccessible to the current user
1320
+	 *
1321
+	 * @param EEM_Base        $model
1322
+	 * @param WP_REST_Request $request
1323
+	 * @param null            $context
1324
+	 * @return array|WP_Error
1325
+	 */
1326
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1327
+	{
1328
+		$query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1329
+		if ($model instanceof \EEM_Soft_Delete_Base) {
1330
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1331
+		}
1332
+		$restricted_query_params = $query_params;
1333
+		$restricted_query_params['caps'] = $context;
1334
+		$this->setDebugInfo('model query params', $restricted_query_params);
1335
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1336
+		if (! empty($model_rows)) {
1337
+			return $this->createEntityFromWpdbResult(
1338
+				$model,
1339
+				array_shift($model_rows),
1340
+				$request
1341
+			);
1342
+		} else {
1343
+			// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1344
+			$lowercase_model_name = strtolower($model->get_this_model_name());
1345
+			$model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1346
+			if (! empty($model_rows_found_sans_restrictions)) {
1347
+				// you got shafted- it existed but we didn't want to tell you!
1348
+				return new WP_Error(
1349
+					'rest_user_cannot_' . $context,
1350
+					sprintf(
1351
+						__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1352
+						$context,
1353
+						strtolower($model->get_this_model_name()),
1354
+						Capabilities::getMissingPermissionsString(
1355
+							$model,
1356
+							$context
1357
+						)
1358
+					),
1359
+					array('status' => 403)
1360
+				);
1361
+			} else {
1362
+				// it's not you. It just doesn't exist
1363
+				return new WP_Error(
1364
+					sprintf('rest_%s_invalid_id', $lowercase_model_name),
1365
+					sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1366
+					array('status' => 404)
1367
+				);
1368
+			}
1369
+		}
1370
+	}
1371 1371
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/CalculatedModelFields.php 2 patches
Indentation   +164 added lines, -164 removed lines patch added patch discarded remove patch
@@ -20,168 +20,168 @@
 block discarded – undo
20 20
 class CalculatedModelFields
21 21
 {
22 22
 
23
-    /**
24
-     * @var array
25
-     */
26
-    protected $mapping;
27
-
28
-    /**
29
-     * @var array
30
-     */
31
-    protected $mapping_schema;
32
-
33
-
34
-    /**
35
-     * @param bool $refresh
36
-     * @return array top-level-keys are model names (eg "Event")
37
-     * next-level are the calculated field names AND method names on classes
38
-     * which perform calculations, values are the fully qualified classnames which do the calculations
39
-     * These callbacks should accept as arguments:
40
-     * the wpdb row results,
41
-     * the WP_Request object,
42
-     * the controller object
43
-     */
44
-    public function mapping($refresh = false)
45
-    {
46
-        if (! $this->mapping || $refresh) {
47
-            $this->mapping = $this->generateNewMapping();
48
-        }
49
-        return $this->mapping;
50
-    }
51
-
52
-
53
-    /**
54
-     * Generates a new mapping between model calculated fields and their callbacks
55
-     *
56
-     * @return array
57
-     */
58
-    protected function generateNewMapping()
59
-    {
60
-        $namespace = 'EventEspresso\core\libraries\rest_api\calculations\\';
61
-        $mapping = array();
62
-        $models_with_calculated_fields = array(
63
-            'Attendee',
64
-            'Datetime',
65
-            'Event',
66
-            'Registration'
67
-        );
68
-        foreach ($models_with_calculated_fields as $model_name) {
69
-            $calculated_fields_classname = $namespace . $model_name;
70
-            foreach (array_keys(call_user_func(array($calculated_fields_classname, 'schemaForCalculations'))) as $field_name) {
71
-                $mapping[ $model_name ][ $field_name ] = $calculated_fields_classname;
72
-            }
73
-        }
74
-        return apply_filters(
75
-            'FHEE__EventEspresso\core\libraries\rest_api\Calculated_Model_Fields__mapping',
76
-            $mapping
77
-        );
78
-    }
79
-
80
-
81
-    /**
82
-     * Generates the schema for each calculation index in the calculation map.
83
-     *
84
-     * @return array
85
-     */
86
-    protected function generateNewMappingSchema()
87
-    {
88
-        $schema_map = array();
89
-        foreach ($this->mapping() as $map_model => $map_for_model) {
90
-            /**
91
-             * @var string $calculation_index
92
-             * @var HasCalculationSchemaInterface $calculations_class
93
-             */
94
-            foreach ($map_for_model as $calculation_index => $calculations_class) {
95
-                if (in_array(
96
-                    'EventEspresso\core\libraries\rest_api\calculations\HasCalculationSchemaInterface',
97
-                    class_implements($calculations_class),
98
-                    true
99
-                )) {
100
-                    $schema = $calculations_class::schemaForCalculation($calculation_index);
101
-                    if (! empty($schema)) {
102
-                        $schema_map[ $map_model ][ $calculation_index ] = $schema;
103
-                    }
104
-                }
105
-            }
106
-        }
107
-        return $schema_map;
108
-    }
109
-
110
-
111
-    /**
112
-     * Gets the known calculated fields for model
113
-     *
114
-     * @param EEM_Base $model
115
-     * @return array allowable values for this field
116
-     */
117
-    public function retrieveCalculatedFieldsForModel(EEM_Base $model)
118
-    {
119
-        $mapping = $this->mapping();
120
-        if (isset($mapping[ $model->get_this_model_name() ])) {
121
-            return array_keys($mapping[ $model->get_this_model_name() ]);
122
-        }
123
-        return array();
124
-    }
125
-
126
-
127
-    /**
128
-     * Returns the JsonSchema for the calculated fields on the given model.
129
-     * @param EEM_Base $model
130
-     * @return array
131
-     */
132
-    public function getJsonSchemaForModel(EEM_Base $model)
133
-    {
134
-        if (! $this->mapping_schema) {
135
-            $this->mapping_schema = $this->generateNewMappingSchema();
136
-        }
137
-        return array(
138
-            'description' => esc_html__(
139
-                'Available calculated fields for this model.  Fields are only present in the response if explicitly requested',
140
-                'event_espresso'
141
-            ),
142
-            'type' => 'object',
143
-            'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ])
144
-                ? $this->mapping_schema[ $model->get_this_model_name() ]
145
-                : array(),
146
-            'additionalProperties' => false,
147
-            'readonly' => true,
148
-        );
149
-    }
150
-
151
-
152
-    /**
153
-     * Retrieves the value for this calculation
154
-     *
155
-     * @param EEM_Base                                                $model
156
-     * @param string                                                  $field_name
157
-     * @param array                                                   $wpdb_row
158
-     * @param \WP_REST_Request
159
-     * @param \EventEspresso\core\libraries\rest_api\controllers\Base $controller
160
-     * @return mixed|null
161
-     * @throws \EE_Error
162
-     */
163
-    public function retrieveCalculatedFieldValue(
164
-        EEM_Base $model,
165
-        $field_name,
166
-        $wpdb_row,
167
-        $rest_request,
168
-        Base $controller
169
-    ) {
170
-        $mapping = $this->mapping();
171
-        if (isset($mapping[ $model->get_this_model_name() ])
172
-            && isset($mapping[ $model->get_this_model_name() ][ $field_name ])
173
-        ) {
174
-            $classname = $mapping[ $model->get_this_model_name() ][ $field_name ];
175
-            $class_method_name = EEH_Inflector::camelize_all_but_first($field_name);
176
-            return call_user_func(array($classname, $class_method_name), $wpdb_row, $rest_request, $controller);
177
-        }
178
-        throw new RestException(
179
-            'calculated_field_does_not_exist',
180
-            sprintf(
181
-                __('There is no calculated field %1$s on resource %2$s', 'event_espresso'),
182
-                $field_name,
183
-                $model->get_this_model_name()
184
-            )
185
-        );
186
-    }
23
+	/**
24
+	 * @var array
25
+	 */
26
+	protected $mapping;
27
+
28
+	/**
29
+	 * @var array
30
+	 */
31
+	protected $mapping_schema;
32
+
33
+
34
+	/**
35
+	 * @param bool $refresh
36
+	 * @return array top-level-keys are model names (eg "Event")
37
+	 * next-level are the calculated field names AND method names on classes
38
+	 * which perform calculations, values are the fully qualified classnames which do the calculations
39
+	 * These callbacks should accept as arguments:
40
+	 * the wpdb row results,
41
+	 * the WP_Request object,
42
+	 * the controller object
43
+	 */
44
+	public function mapping($refresh = false)
45
+	{
46
+		if (! $this->mapping || $refresh) {
47
+			$this->mapping = $this->generateNewMapping();
48
+		}
49
+		return $this->mapping;
50
+	}
51
+
52
+
53
+	/**
54
+	 * Generates a new mapping between model calculated fields and their callbacks
55
+	 *
56
+	 * @return array
57
+	 */
58
+	protected function generateNewMapping()
59
+	{
60
+		$namespace = 'EventEspresso\core\libraries\rest_api\calculations\\';
61
+		$mapping = array();
62
+		$models_with_calculated_fields = array(
63
+			'Attendee',
64
+			'Datetime',
65
+			'Event',
66
+			'Registration'
67
+		);
68
+		foreach ($models_with_calculated_fields as $model_name) {
69
+			$calculated_fields_classname = $namespace . $model_name;
70
+			foreach (array_keys(call_user_func(array($calculated_fields_classname, 'schemaForCalculations'))) as $field_name) {
71
+				$mapping[ $model_name ][ $field_name ] = $calculated_fields_classname;
72
+			}
73
+		}
74
+		return apply_filters(
75
+			'FHEE__EventEspresso\core\libraries\rest_api\Calculated_Model_Fields__mapping',
76
+			$mapping
77
+		);
78
+	}
79
+
80
+
81
+	/**
82
+	 * Generates the schema for each calculation index in the calculation map.
83
+	 *
84
+	 * @return array
85
+	 */
86
+	protected function generateNewMappingSchema()
87
+	{
88
+		$schema_map = array();
89
+		foreach ($this->mapping() as $map_model => $map_for_model) {
90
+			/**
91
+			 * @var string $calculation_index
92
+			 * @var HasCalculationSchemaInterface $calculations_class
93
+			 */
94
+			foreach ($map_for_model as $calculation_index => $calculations_class) {
95
+				if (in_array(
96
+					'EventEspresso\core\libraries\rest_api\calculations\HasCalculationSchemaInterface',
97
+					class_implements($calculations_class),
98
+					true
99
+				)) {
100
+					$schema = $calculations_class::schemaForCalculation($calculation_index);
101
+					if (! empty($schema)) {
102
+						$schema_map[ $map_model ][ $calculation_index ] = $schema;
103
+					}
104
+				}
105
+			}
106
+		}
107
+		return $schema_map;
108
+	}
109
+
110
+
111
+	/**
112
+	 * Gets the known calculated fields for model
113
+	 *
114
+	 * @param EEM_Base $model
115
+	 * @return array allowable values for this field
116
+	 */
117
+	public function retrieveCalculatedFieldsForModel(EEM_Base $model)
118
+	{
119
+		$mapping = $this->mapping();
120
+		if (isset($mapping[ $model->get_this_model_name() ])) {
121
+			return array_keys($mapping[ $model->get_this_model_name() ]);
122
+		}
123
+		return array();
124
+	}
125
+
126
+
127
+	/**
128
+	 * Returns the JsonSchema for the calculated fields on the given model.
129
+	 * @param EEM_Base $model
130
+	 * @return array
131
+	 */
132
+	public function getJsonSchemaForModel(EEM_Base $model)
133
+	{
134
+		if (! $this->mapping_schema) {
135
+			$this->mapping_schema = $this->generateNewMappingSchema();
136
+		}
137
+		return array(
138
+			'description' => esc_html__(
139
+				'Available calculated fields for this model.  Fields are only present in the response if explicitly requested',
140
+				'event_espresso'
141
+			),
142
+			'type' => 'object',
143
+			'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ])
144
+				? $this->mapping_schema[ $model->get_this_model_name() ]
145
+				: array(),
146
+			'additionalProperties' => false,
147
+			'readonly' => true,
148
+		);
149
+	}
150
+
151
+
152
+	/**
153
+	 * Retrieves the value for this calculation
154
+	 *
155
+	 * @param EEM_Base                                                $model
156
+	 * @param string                                                  $field_name
157
+	 * @param array                                                   $wpdb_row
158
+	 * @param \WP_REST_Request
159
+	 * @param \EventEspresso\core\libraries\rest_api\controllers\Base $controller
160
+	 * @return mixed|null
161
+	 * @throws \EE_Error
162
+	 */
163
+	public function retrieveCalculatedFieldValue(
164
+		EEM_Base $model,
165
+		$field_name,
166
+		$wpdb_row,
167
+		$rest_request,
168
+		Base $controller
169
+	) {
170
+		$mapping = $this->mapping();
171
+		if (isset($mapping[ $model->get_this_model_name() ])
172
+			&& isset($mapping[ $model->get_this_model_name() ][ $field_name ])
173
+		) {
174
+			$classname = $mapping[ $model->get_this_model_name() ][ $field_name ];
175
+			$class_method_name = EEH_Inflector::camelize_all_but_first($field_name);
176
+			return call_user_func(array($classname, $class_method_name), $wpdb_row, $rest_request, $controller);
177
+		}
178
+		throw new RestException(
179
+			'calculated_field_does_not_exist',
180
+			sprintf(
181
+				__('There is no calculated field %1$s on resource %2$s', 'event_espresso'),
182
+				$field_name,
183
+				$model->get_this_model_name()
184
+			)
185
+		);
186
+	}
187 187
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -43,7 +43,7 @@  discard block
 block discarded – undo
43 43
      */
44 44
     public function mapping($refresh = false)
45 45
     {
46
-        if (! $this->mapping || $refresh) {
46
+        if ( ! $this->mapping || $refresh) {
47 47
             $this->mapping = $this->generateNewMapping();
48 48
         }
49 49
         return $this->mapping;
@@ -66,9 +66,9 @@  discard block
 block discarded – undo
66 66
             'Registration'
67 67
         );
68 68
         foreach ($models_with_calculated_fields as $model_name) {
69
-            $calculated_fields_classname = $namespace . $model_name;
69
+            $calculated_fields_classname = $namespace.$model_name;
70 70
             foreach (array_keys(call_user_func(array($calculated_fields_classname, 'schemaForCalculations'))) as $field_name) {
71
-                $mapping[ $model_name ][ $field_name ] = $calculated_fields_classname;
71
+                $mapping[$model_name][$field_name] = $calculated_fields_classname;
72 72
             }
73 73
         }
74 74
         return apply_filters(
@@ -98,8 +98,8 @@  discard block
 block discarded – undo
98 98
                     true
99 99
                 )) {
100 100
                     $schema = $calculations_class::schemaForCalculation($calculation_index);
101
-                    if (! empty($schema)) {
102
-                        $schema_map[ $map_model ][ $calculation_index ] = $schema;
101
+                    if ( ! empty($schema)) {
102
+                        $schema_map[$map_model][$calculation_index] = $schema;
103 103
                     }
104 104
                 }
105 105
             }
@@ -117,8 +117,8 @@  discard block
 block discarded – undo
117 117
     public function retrieveCalculatedFieldsForModel(EEM_Base $model)
118 118
     {
119 119
         $mapping = $this->mapping();
120
-        if (isset($mapping[ $model->get_this_model_name() ])) {
121
-            return array_keys($mapping[ $model->get_this_model_name() ]);
120
+        if (isset($mapping[$model->get_this_model_name()])) {
121
+            return array_keys($mapping[$model->get_this_model_name()]);
122 122
         }
123 123
         return array();
124 124
     }
@@ -131,7 +131,7 @@  discard block
 block discarded – undo
131 131
      */
132 132
     public function getJsonSchemaForModel(EEM_Base $model)
133 133
     {
134
-        if (! $this->mapping_schema) {
134
+        if ( ! $this->mapping_schema) {
135 135
             $this->mapping_schema = $this->generateNewMappingSchema();
136 136
         }
137 137
         return array(
@@ -140,8 +140,8 @@  discard block
 block discarded – undo
140 140
                 'event_espresso'
141 141
             ),
142 142
             'type' => 'object',
143
-            'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ])
144
-                ? $this->mapping_schema[ $model->get_this_model_name() ]
143
+            'properties' => isset($this->mapping_schema[$model->get_this_model_name()])
144
+                ? $this->mapping_schema[$model->get_this_model_name()]
145 145
                 : array(),
146 146
             'additionalProperties' => false,
147 147
             'readonly' => true,
@@ -168,10 +168,10 @@  discard block
 block discarded – undo
168 168
         Base $controller
169 169
     ) {
170 170
         $mapping = $this->mapping();
171
-        if (isset($mapping[ $model->get_this_model_name() ])
172
-            && isset($mapping[ $model->get_this_model_name() ][ $field_name ])
171
+        if (isset($mapping[$model->get_this_model_name()])
172
+            && isset($mapping[$model->get_this_model_name()][$field_name])
173 173
         ) {
174
-            $classname = $mapping[ $model->get_this_model_name() ][ $field_name ];
174
+            $classname = $mapping[$model->get_this_model_name()][$field_name];
175 175
             $class_method_name = EEH_Inflector::camelize_all_but_first($field_name);
176 176
             return call_user_func(array($classname, $class_method_name), $wpdb_row, $rest_request, $controller);
177 177
         }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Datetime.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -73,7 +73,7 @@  discard block
 block discarded – undo
73 73
      */
74 74
     public static function registrationsCheckedInCount($wpdb_row, $request, $controller)
75 75
     {
76
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
76
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
77 77
             throw new EE_Error(
78 78
                 sprintf(
79 79
                     __(
@@ -107,7 +107,7 @@  discard block
 block discarded – undo
107 107
      */
108 108
     public static function registrationsCheckedOutCount($wpdb_row, $request, $controller)
109 109
     {
110
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
110
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
111 111
             throw new EE_Error(
112 112
                 sprintf(
113 113
                     __(
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
      */
143 143
     public static function spotsTakenPendingPayment($wpdb_row, $request, $controller)
144 144
     {
145
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
145
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
146 146
             throw new EE_Error(
147 147
                 sprintf(
148 148
                     __(
@@ -221,6 +221,6 @@  discard block
 block discarded – undo
221 221
     public static function schemaForCalculation($calculation_index)
222 222
     {
223 223
         $schema_map = Datetime::schemaForCalculations();
224
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
224
+        return isset($schema_map[$calculation_index]) ? $schema_map[$calculation_index] : array();
225 225
     }
226 226
 }
Please login to merge, or discard this patch.
Indentation   +195 added lines, -195 removed lines patch added patch discarded remove patch
@@ -18,209 +18,209 @@
 block discarded – undo
18 18
 class Datetime extends DatetimeCalculationBase implements HasCalculationSchemaInterface
19 19
 {
20 20
 
21
-    /**
22
-     * Calculates the total spaces available on the datetime, taking into account
23
-     * ticket limits too.
24
-     *
25
-     * @see EE_Datetime::spaces_remaining( true )
26
-     * @param array            $wpdb_row
27
-     * @param WP_REST_Request $request
28
-     * @param DatetimeControllerBase  $controller
29
-     * @return int
30
-     * @throws EE_Error
31
-     * @throws InvalidDataTypeException
32
-     * @throws InvalidInterfaceException
33
-     * @throws InvalidArgumentException
34
-     * @throws ReflectionException
35
-     */
36
-    public static function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
37
-    {
38
-        if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
39
-            $dtt_obj = EEM_Datetime::instance()->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
40
-        } else {
41
-            $dtt_obj = null;
42
-        }
43
-        if ($dtt_obj instanceof EE_Datetime) {
44
-            return $dtt_obj->spaces_remaining(true);
45
-        }
46
-        throw new EE_Error(
47
-            sprintf(
48
-                __(
49
-                // @codingStandardsIgnoreStart
50
-                    'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
51
-                    // @codingStandardsIgnoreEnd
52
-                    'event_espresso'
53
-                ),
54
-                $wpdb_row['Datetime.DTT_ID'],
55
-                print_r($wpdb_row, true)
56
-            )
57
-        );
58
-    }
21
+	/**
22
+	 * Calculates the total spaces available on the datetime, taking into account
23
+	 * ticket limits too.
24
+	 *
25
+	 * @see EE_Datetime::spaces_remaining( true )
26
+	 * @param array            $wpdb_row
27
+	 * @param WP_REST_Request $request
28
+	 * @param DatetimeControllerBase  $controller
29
+	 * @return int
30
+	 * @throws EE_Error
31
+	 * @throws InvalidDataTypeException
32
+	 * @throws InvalidInterfaceException
33
+	 * @throws InvalidArgumentException
34
+	 * @throws ReflectionException
35
+	 */
36
+	public static function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
37
+	{
38
+		if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
39
+			$dtt_obj = EEM_Datetime::instance()->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
40
+		} else {
41
+			$dtt_obj = null;
42
+		}
43
+		if ($dtt_obj instanceof EE_Datetime) {
44
+			return $dtt_obj->spaces_remaining(true);
45
+		}
46
+		throw new EE_Error(
47
+			sprintf(
48
+				__(
49
+				// @codingStandardsIgnoreStart
50
+					'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
51
+					// @codingStandardsIgnoreEnd
52
+					'event_espresso'
53
+				),
54
+				$wpdb_row['Datetime.DTT_ID'],
55
+				print_r($wpdb_row, true)
56
+			)
57
+		);
58
+	}
59 59
 
60 60
 
61
-    /**
62
-     * Counts registrations who have checked into this datetime
63
-     *
64
-     * @param array           $wpdb_row
65
-     * @param WP_REST_Request $request
66
-     * @param DatetimeControllerBase $controller
67
-     * @return int
68
-     * @throws EE_Error
69
-     * @throws InvalidArgumentException
70
-     * @throws InvalidDataTypeException
71
-     * @throws InvalidInterfaceException
72
-     * @throws RestException
73
-     */
74
-    public static function registrationsCheckedInCount($wpdb_row, $request, $controller)
75
-    {
76
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
77
-            throw new EE_Error(
78
-                sprintf(
79
-                    __(
80
-                    // @codingStandardsIgnoreStart
81
-                        'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
82
-                        // @codingStandardsIgnoreEnd
83
-                        'event_espresso'
84
-                    ),
85
-                    print_r($wpdb_row, true)
86
-                )
87
-            );
88
-        }
89
-        self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
90
-        return EEM_Registration::instance()
91
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
92
-    }
61
+	/**
62
+	 * Counts registrations who have checked into this datetime
63
+	 *
64
+	 * @param array           $wpdb_row
65
+	 * @param WP_REST_Request $request
66
+	 * @param DatetimeControllerBase $controller
67
+	 * @return int
68
+	 * @throws EE_Error
69
+	 * @throws InvalidArgumentException
70
+	 * @throws InvalidDataTypeException
71
+	 * @throws InvalidInterfaceException
72
+	 * @throws RestException
73
+	 */
74
+	public static function registrationsCheckedInCount($wpdb_row, $request, $controller)
75
+	{
76
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
77
+			throw new EE_Error(
78
+				sprintf(
79
+					__(
80
+					// @codingStandardsIgnoreStart
81
+						'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
82
+						// @codingStandardsIgnoreEnd
83
+						'event_espresso'
84
+					),
85
+					print_r($wpdb_row, true)
86
+				)
87
+			);
88
+		}
89
+		self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
90
+		return EEM_Registration::instance()
91
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
92
+	}
93 93
 
94 94
 
95
-    /**
96
-     * Counts registrations who have checked out of this datetime
97
-     *
98
-     * @param array           $wpdb_row
99
-     * @param WP_REST_Request $request
100
-     * @param DatetimeControllerBase $controller
101
-     * @return int
102
-     * @throws EE_Error
103
-     * @throws InvalidArgumentException
104
-     * @throws InvalidDataTypeException
105
-     * @throws InvalidInterfaceException
106
-     * @throws RestException
107
-     */
108
-    public static function registrationsCheckedOutCount($wpdb_row, $request, $controller)
109
-    {
110
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
111
-            throw new EE_Error(
112
-                sprintf(
113
-                    __(
114
-                    // @codingStandardsIgnoreStart
115
-                        'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
116
-                        // @codingStandardsIgnoreEnd
117
-                        'event_espresso'
118
-                    ),
119
-                    print_r($wpdb_row, true)
120
-                )
121
-            );
122
-        }
123
-        self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
124
-        return EEM_Registration::instance()
125
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
126
-    }
95
+	/**
96
+	 * Counts registrations who have checked out of this datetime
97
+	 *
98
+	 * @param array           $wpdb_row
99
+	 * @param WP_REST_Request $request
100
+	 * @param DatetimeControllerBase $controller
101
+	 * @return int
102
+	 * @throws EE_Error
103
+	 * @throws InvalidArgumentException
104
+	 * @throws InvalidDataTypeException
105
+	 * @throws InvalidInterfaceException
106
+	 * @throws RestException
107
+	 */
108
+	public static function registrationsCheckedOutCount($wpdb_row, $request, $controller)
109
+	{
110
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
111
+			throw new EE_Error(
112
+				sprintf(
113
+					__(
114
+					// @codingStandardsIgnoreStart
115
+						'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
116
+						// @codingStandardsIgnoreEnd
117
+						'event_espresso'
118
+					),
119
+					print_r($wpdb_row, true)
120
+				)
121
+			);
122
+		}
123
+		self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
124
+		return EEM_Registration::instance()
125
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
126
+	}
127 127
 
128 128
 
129
-    /**
130
-     * Counts the number of pending-payment registrations for this event (regardless
131
-     * of how many datetimes each registrations' ticket purchase is for)
132
-     *
133
-     * @param array           $wpdb_row
134
-     * @param WP_REST_Request $request
135
-     * @param DatetimeControllerBase $controller
136
-     * @return int
137
-     * @throws EE_Error
138
-     * @throws InvalidArgumentException
139
-     * @throws InvalidDataTypeException
140
-     * @throws InvalidInterfaceException
141
-     * @throws RestException
142
-     */
143
-    public static function spotsTakenPendingPayment($wpdb_row, $request, $controller)
144
-    {
145
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
146
-            throw new EE_Error(
147
-                sprintf(
148
-                    __(
149
-                    // @codingStandardsIgnoreStart
150
-                        'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
151
-                        // @codingStandardsIgnoreEnd
152
-                        'event_espresso'
153
-                    ),
154
-                    print_r($wpdb_row, true)
155
-                )
156
-            );
157
-        }
158
-        self::verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
159
-        return EEM_Registration::instance()->count(
160
-            array(
161
-                array(
162
-                    'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
163
-                    'STS_ID'                 => EEM_Registration::status_id_pending_payment,
164
-                ),
165
-            ),
166
-            'REG_ID',
167
-            true
168
-        );
169
-    }
129
+	/**
130
+	 * Counts the number of pending-payment registrations for this event (regardless
131
+	 * of how many datetimes each registrations' ticket purchase is for)
132
+	 *
133
+	 * @param array           $wpdb_row
134
+	 * @param WP_REST_Request $request
135
+	 * @param DatetimeControllerBase $controller
136
+	 * @return int
137
+	 * @throws EE_Error
138
+	 * @throws InvalidArgumentException
139
+	 * @throws InvalidDataTypeException
140
+	 * @throws InvalidInterfaceException
141
+	 * @throws RestException
142
+	 */
143
+	public static function spotsTakenPendingPayment($wpdb_row, $request, $controller)
144
+	{
145
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
146
+			throw new EE_Error(
147
+				sprintf(
148
+					__(
149
+					// @codingStandardsIgnoreStart
150
+						'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
151
+						// @codingStandardsIgnoreEnd
152
+						'event_espresso'
153
+					),
154
+					print_r($wpdb_row, true)
155
+				)
156
+			);
157
+		}
158
+		self::verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
159
+		return EEM_Registration::instance()->count(
160
+			array(
161
+				array(
162
+					'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
163
+					'STS_ID'                 => EEM_Registration::status_id_pending_payment,
164
+				),
165
+			),
166
+			'REG_ID',
167
+			true
168
+		);
169
+	}
170 170
 
171 171
 
172
-    /**
173
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
174
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
175
-     *
176
-     * @since $VID:$
177
-     * @return array
178
-     */
179
-    public static function schemaForCalculations()
180
-    {
181
-        return array(
182
-            'spaces_remaining_considering_tickets' => array(
183
-                'description' => esc_html__(
184
-                    'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
185
-                    'event_espresso'
186
-                ),
187
-                'type' => 'number'
188
-            ),
189
-            'registrations_checked_in_count' => array(
190
-                'description' => esc_html__(
191
-                    'Counts registrations who have checked into this datetime.',
192
-                    'event_espresso'
193
-                ),
194
-                'type' => 'number'
195
-            ),
196
-            'registrations_checked_out_count' => array(
197
-                'description' => esc_html__(
198
-                    'Counts registrations who have checked out of this datetime.',
199
-                    'event_espresso'
200
-                ),
201
-                'type' => 'number'
202
-            ),
203
-            'spots_taken_pending_payment' => array(
204
-                'description' => esc_html__(
205
-                    'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
206
-                    'event_espresso'
207
-                ),
208
-                'type' => 'number'
209
-            ),
210
-        );
211
-    }
172
+	/**
173
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
174
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
175
+	 *
176
+	 * @since $VID:$
177
+	 * @return array
178
+	 */
179
+	public static function schemaForCalculations()
180
+	{
181
+		return array(
182
+			'spaces_remaining_considering_tickets' => array(
183
+				'description' => esc_html__(
184
+					'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
185
+					'event_espresso'
186
+				),
187
+				'type' => 'number'
188
+			),
189
+			'registrations_checked_in_count' => array(
190
+				'description' => esc_html__(
191
+					'Counts registrations who have checked into this datetime.',
192
+					'event_espresso'
193
+				),
194
+				'type' => 'number'
195
+			),
196
+			'registrations_checked_out_count' => array(
197
+				'description' => esc_html__(
198
+					'Counts registrations who have checked out of this datetime.',
199
+					'event_espresso'
200
+				),
201
+				'type' => 'number'
202
+			),
203
+			'spots_taken_pending_payment' => array(
204
+				'description' => esc_html__(
205
+					'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
206
+					'event_espresso'
207
+				),
208
+				'type' => 'number'
209
+			),
210
+		);
211
+	}
212 212
 
213 213
 
214
-    /**
215
-     * Returns the json schema for the given calculation index.
216
-     *
217
-     * @param string $calculation_index
218
-     * @since $VID:$
219
-     * @return array
220
-     */
221
-    public static function schemaForCalculation($calculation_index)
222
-    {
223
-        $schema_map = Datetime::schemaForCalculations();
224
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
225
-    }
214
+	/**
215
+	 * Returns the json schema for the given calculation index.
216
+	 *
217
+	 * @param string $calculation_index
218
+	 * @since $VID:$
219
+	 * @return array
220
+	 */
221
+	public static function schemaForCalculation($calculation_index)
222
+	{
223
+		$schema_map = Datetime::schemaForCalculations();
224
+		return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
225
+	}
226 226
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Event.php 2 patches
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
      */
162 162
     public static function spotsTaken($wpdb_row, $request, $controller)
163 163
     {
164
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
164
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
165 165
             throw new EE_Error(
166 166
                 sprintf(
167 167
                     __(
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
      */
204 204
     public static function spotsTakenPendingPayment($wpdb_row, $request, $controller)
205 205
     {
206
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
206
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
207 207
             throw new EE_Error(
208 208
                 sprintf(
209 209
                     __(
@@ -246,7 +246,7 @@  discard block
 block discarded – undo
246 246
      */
247 247
     public static function registrationsCheckedInCount($wpdb_row, $request, $controller)
248 248
     {
249
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
249
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
250 250
             throw new EE_Error(
251 251
                 sprintf(
252 252
                     __(
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
      */
281 281
     public static function registrationsCheckedOutCount($wpdb_row, $request, $controller)
282 282
     {
283
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
283
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
284 284
             throw new EE_Error(
285 285
                 sprintf(
286 286
                     __(
@@ -399,7 +399,7 @@  discard block
 block discarded – undo
399 399
      */
400 400
     protected static function calculateImageData($wpdb_row, $image_size)
401 401
     {
402
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
402
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
403 403
             throw new EE_Error(
404 404
                 sprintf(
405 405
                     __(
@@ -415,7 +415,7 @@  discard block
 block discarded – undo
415 415
         $EVT_ID = $wpdb_row['Event_CPT.ID'];
416 416
         $attachment_id = get_post_thumbnail_id($EVT_ID);
417 417
         $data = wp_get_attachment_image_src($attachment_id, $image_size);
418
-        if (! $data) {
418
+        if ( ! $data) {
419 419
             return null;
420 420
         }
421 421
         $generated = true;
@@ -584,6 +584,6 @@  discard block
 block discarded – undo
584 584
     public static function schemaForCalculation($calculation_index)
585 585
     {
586 586
         $schema_map = Event::schemaForCalculations();
587
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
587
+        return isset($schema_map[$calculation_index]) ? $schema_map[$calculation_index] : array();
588 588
     }
589 589
 }
Please login to merge, or discard this patch.
Indentation   +559 added lines, -559 removed lines patch added patch discarded remove patch
@@ -27,563 +27,563 @@
 block discarded – undo
27 27
 class Event extends EventCalculationBase implements HasCalculationSchemaInterface
28 28
 {
29 29
 
30
-    /**
31
-     * Calculates the total spaces on the event (not subtracting sales, but taking
32
-     * sales into account; so this is the optimum sales that CAN still be achieved)
33
-     * See EE_Event::total_available_spaces( true );
34
-     *
35
-     * @param array               $wpdb_row
36
-     * @param WP_REST_Request     $request
37
-     * @param EventControllerBase $controller
38
-     * @return int
39
-     * @throws EE_Error
40
-     * @throws DomainException
41
-     * @throws InvalidDataTypeException
42
-     * @throws InvalidInterfaceException
43
-     * @throws UnexpectedEntityException
44
-     * @throws InvalidArgumentException
45
-     */
46
-    public static function optimumSalesAtStart($wpdb_row, $request, $controller)
47
-    {
48
-        $event_obj = null;
49
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
50
-            $event_obj = EEM_Event::instance()->get_one_by_ID($wpdb_row['Event_CPT.ID']);
51
-        }
52
-        if ($event_obj instanceof EE_Event) {
53
-            return $event_obj->total_available_spaces();
54
-        }
55
-        throw new EE_Error(
56
-            sprintf(
57
-                __(
58
-                // @codingStandardsIgnoreStart
59
-                    'Cannot calculate optimum_sales_at_start because the event with ID %1$s (from database row %2$s) was not found',
60
-                    // @codingStandardsIgnoreEnd
61
-                    'event_espresso'
62
-                ),
63
-                $wpdb_row['Event_CPT.ID'],
64
-                print_r($wpdb_row, true)
65
-            )
66
-        );
67
-    }
68
-
69
-
70
-    /**
71
-     * Calculates the total spaces on the event (ignoring all sales; so this is the optimum
72
-     * sales that COULD have been achieved)
73
-     * See EE_Event::total_available_spaces( true );
74
-     *
75
-     * @param array               $wpdb_row
76
-     * @param WP_REST_Request     $request
77
-     * @param EventControllerBase $controller
78
-     * @return int
79
-     * @throws DomainException
80
-     * @throws EE_Error
81
-     * @throws InvalidArgumentException
82
-     * @throws InvalidDataTypeException
83
-     * @throws InvalidInterfaceException
84
-     * @throws UnexpectedEntityException
85
-     */
86
-    public static function optimumSalesNow($wpdb_row, $request, $controller)
87
-    {
88
-        $event_obj = null;
89
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
90
-            $event_obj = EEM_Event::instance()->get_one_by_ID($wpdb_row['Event_CPT.ID']);
91
-        }
92
-        if ($event_obj instanceof EE_Event) {
93
-            return $event_obj->total_available_spaces(true);
94
-        }
95
-        throw new EE_Error(
96
-            sprintf(
97
-                __(
98
-                // @codingStandardsIgnoreStart
99
-                    'Cannot calculate optimum_sales_now because the event with ID %1$s (from database row %2$s) was not found',
100
-                    // @codingStandardsIgnoreEnd
101
-                    'event_espresso'
102
-                ),
103
-                $wpdb_row['Event_CPT.ID'],
104
-                print_r($wpdb_row, true)
105
-            )
106
-        );
107
-    }
108
-
109
-
110
-    /**
111
-     * Like optimum_sales_now, but minus total sales so far.
112
-     * See EE_Event::spaces_remaining_for_sale( true );
113
-     *
114
-     * @param array               $wpdb_row
115
-     * @param WP_REST_Request     $request
116
-     * @param EventControllerBase $controller
117
-     * @return int
118
-     * @throws DomainException
119
-     * @throws EE_Error
120
-     * @throws InvalidArgumentException
121
-     * @throws InvalidDataTypeException
122
-     * @throws InvalidInterfaceException
123
-     * @throws UnexpectedEntityException
124
-     */
125
-    public static function spacesRemaining($wpdb_row, $request, $controller)
126
-    {
127
-        $event_obj = null;
128
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
129
-            $event_obj = EEM_Event::instance()->get_one_by_ID($wpdb_row['Event_CPT.ID']);
130
-        }
131
-        if ($event_obj instanceof EE_Event) {
132
-            return $event_obj->spaces_remaining_for_sale();
133
-        }
134
-        throw new EE_Error(
135
-            sprintf(
136
-                __(
137
-                // @codingStandardsIgnoreStart
138
-                    'Cannot calculate spaces_remaining because the event with ID %1$s (from database row %2$s) was not found',
139
-                    // @codingStandardsIgnoreEnd
140
-                    'event_espresso'
141
-                ),
142
-                $wpdb_row['Event_CPT.ID'],
143
-                print_r($wpdb_row, true)
144
-            )
145
-        );
146
-    }
147
-
148
-
149
-    /**
150
-     * Counts the number of approved registrations for this event (regardless
151
-     * of how many datetimes each registrations' ticket purchase is for)
152
-     *
153
-     * @param array               $wpdb_row
154
-     * @param WP_REST_Request     $request
155
-     * @param EventControllerBase $controller
156
-     * @return int
157
-     * @throws EE_Error
158
-     * @throws InvalidArgumentException
159
-     * @throws InvalidDataTypeException
160
-     * @throws InvalidInterfaceException
161
-     */
162
-    public static function spotsTaken($wpdb_row, $request, $controller)
163
-    {
164
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
165
-            throw new EE_Error(
166
-                sprintf(
167
-                    __(
168
-                    // @codingStandardsIgnoreStart
169
-                        'Cannot calculate spots_taken because the database row %1$s does not have a valid entry for "Event_CPT.ID"',
170
-                        // @codingStandardsIgnoreEnd
171
-                        'event_espresso'
172
-                    ),
173
-                    print_r($wpdb_row, true)
174
-                )
175
-            );
176
-        }
177
-        return EEM_Registration::instance()->count(
178
-            array(
179
-                array(
180
-                    'EVT_ID' => $wpdb_row['Event_CPT.ID'],
181
-                    'STS_ID' => EEM_Registration::status_id_approved,
182
-                ),
183
-            ),
184
-            'REG_ID',
185
-            true
186
-        );
187
-    }
188
-
189
-
190
-    /**
191
-     * Counts the number of pending-payment registrations for this event (regardless
192
-     * of how many datetimes each registrations' ticket purchase is for)
193
-     *
194
-     * @param array               $wpdb_row
195
-     * @param WP_REST_Request     $request
196
-     * @param EventControllerBase $controller
197
-     * @return int
198
-     * @throws EE_Error
199
-     * @throws InvalidArgumentException
200
-     * @throws InvalidDataTypeException
201
-     * @throws InvalidInterfaceException
202
-     * @throws RestException
203
-     */
204
-    public static function spotsTakenPendingPayment($wpdb_row, $request, $controller)
205
-    {
206
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
207
-            throw new EE_Error(
208
-                sprintf(
209
-                    __(
210
-                    // @codingStandardsIgnoreStart
211
-                        'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Event_CPT.ID"',
212
-                        // @codingStandardsIgnoreEnd
213
-                        'event_espresso'
214
-                    ),
215
-                    print_r($wpdb_row, true)
216
-                )
217
-            );
218
-        }
219
-        self::verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
220
-        return EEM_Registration::instance()->count(
221
-            array(
222
-                array(
223
-                    'EVT_ID' => $wpdb_row['Event_CPT.ID'],
224
-                    'STS_ID' => EEM_Registration::status_id_pending_payment,
225
-                ),
226
-            ),
227
-            'REG_ID',
228
-            true
229
-        );
230
-    }
231
-
232
-
233
-    /**
234
-     * Counts all the registrations who have checked into one of this events' datetimes
235
-     * See EE_Event::total_available_spaces( false );
236
-     *
237
-     * @param array               $wpdb_row
238
-     * @param WP_REST_Request     $request
239
-     * @param EventControllerBase $controller
240
-     * @return int|null if permission denied
241
-     * @throws EE_Error
242
-     * @throws InvalidArgumentException
243
-     * @throws InvalidDataTypeException
244
-     * @throws InvalidInterfaceException
245
-     * @throws RestException
246
-     */
247
-    public static function registrationsCheckedInCount($wpdb_row, $request, $controller)
248
-    {
249
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
250
-            throw new EE_Error(
251
-                sprintf(
252
-                    __(
253
-                    // @codingStandardsIgnoreStart
254
-                        'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
255
-                        // @codingStandardsIgnoreEnd
256
-                        'event_espresso'
257
-                    ),
258
-                    print_r($wpdb_row, true)
259
-                )
260
-            );
261
-        }
262
-        self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
263
-        return EEM_Registration::instance()->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], true);
264
-    }
265
-
266
-
267
-    /**
268
-     * Counts all the registrations who have checked out of one of this events' datetimes
269
-     * See EE_Event::total_available_spaces( false );
270
-     *
271
-     * @param array               $wpdb_row
272
-     * @param WP_REST_Request     $request
273
-     * @param EventControllerBase $controller
274
-     * @return int
275
-     * @throws EE_Error
276
-     * @throws InvalidArgumentException
277
-     * @throws InvalidDataTypeException
278
-     * @throws InvalidInterfaceException
279
-     * @throws RestException
280
-     */
281
-    public static function registrationsCheckedOutCount($wpdb_row, $request, $controller)
282
-    {
283
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
284
-            throw new EE_Error(
285
-                sprintf(
286
-                    __(
287
-                    // @codingStandardsIgnoreStart
288
-                        'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
289
-                        // @codingStandardsIgnoreEnd
290
-                        'event_espresso'
291
-                    ),
292
-                    print_r($wpdb_row, true)
293
-                )
294
-            );
295
-        }
296
-        self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
297
-        return EEM_Registration::instance()->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], false);
298
-    }
299
-
300
-
301
-    /**
302
-     * Gets the thumbnail image
303
-     *
304
-     * @param array               $wpdb_row
305
-     * @param WP_REST_Request     $request
306
-     * @param EventControllerBase $controller
307
-     * @return array
308
-     * @throws EE_Error
309
-     */
310
-    public static function imageThumbnail($wpdb_row, $request, $controller)
311
-    {
312
-        return self::calculateImageData($wpdb_row, 'thumbnail');
313
-    }
314
-
315
-
316
-    /**
317
-     * Gets the medium image
318
-     *
319
-     * @param array               $wpdb_row
320
-     * @param WP_REST_Request     $request
321
-     * @param EventControllerBase $controller
322
-     * @return array
323
-     * @throws EE_Error
324
-     */
325
-    public static function imageMedium($wpdb_row, $request, $controller)
326
-    {
327
-        return self::calculateImageData($wpdb_row, 'medium');
328
-    }
329
-
330
-
331
-    /**
332
-     * Gets the medium-large image
333
-     *
334
-     * @param array               $wpdb_row
335
-     * @param WP_REST_Request     $request
336
-     * @param EventControllerBase $controller
337
-     * @return array
338
-     * @throws EE_Error
339
-     */
340
-    public static function imageMediumLarge($wpdb_row, $request, $controller)
341
-    {
342
-        return self::calculateImageData($wpdb_row, 'medium_large');
343
-    }
344
-
345
-
346
-    /**
347
-     * Gets the large image
348
-     *
349
-     * @param array               $wpdb_row
350
-     * @param WP_REST_Request     $request
351
-     * @param EventControllerBase $controller
352
-     * @return array
353
-     * @throws EE_Error
354
-     */
355
-    public static function imageLarge($wpdb_row, $request, $controller)
356
-    {
357
-        return self::calculateImageData($wpdb_row, 'large');
358
-    }
359
-
360
-
361
-    /**
362
-     * Gets the post-thumbnail image
363
-     *
364
-     * @param array               $wpdb_row
365
-     * @param WP_REST_Request     $request
366
-     * @param EventControllerBase $controller
367
-     * @return array
368
-     * @throws EE_Error
369
-     */
370
-    public static function imagePostThumbnail($wpdb_row, $request, $controller)
371
-    {
372
-        return self::calculateImageData($wpdb_row, 'post-thumbnail');
373
-    }
374
-
375
-
376
-    /**
377
-     * Gets the full size image
378
-     *
379
-     * @param array               $wpdb_row
380
-     * @param WP_REST_Request     $request
381
-     * @param EventControllerBase $controller
382
-     * @return array
383
-     * @throws EE_Error
384
-     */
385
-    public static function imageFull($wpdb_row, $request, $controller)
386
-    {
387
-        return self::calculateImageData($wpdb_row, 'full');
388
-    }
389
-
390
-
391
-    /**
392
-     * Gets image specs and formats them for the display in the API,
393
-     * according to the image size requested
394
-     *
395
-     * @param array  $wpdb_row
396
-     * @param string $image_size one of these: thumbnail, medium, medium_large, large, post-thumbnail, full
397
-     * @return array|false if no such image exists. If array it will have keys 'url', 'width', 'height' and 'original'
398
-     * @throws EE_Error
399
-     */
400
-    protected static function calculateImageData($wpdb_row, $image_size)
401
-    {
402
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
403
-            throw new EE_Error(
404
-                sprintf(
405
-                    __(
406
-                    // @codingStandardsIgnoreStart
407
-                        'Cannot calculate image because the database row %1$s does not have an entry for "Event_CPT.ID"',
408
-                        // @codingStandardsIgnoreEnd
409
-                        'event_espresso'
410
-                    ),
411
-                    print_r($wpdb_row, true)
412
-                )
413
-            );
414
-        }
415
-        $EVT_ID = $wpdb_row['Event_CPT.ID'];
416
-        $attachment_id = get_post_thumbnail_id($EVT_ID);
417
-        $data = wp_get_attachment_image_src($attachment_id, $image_size);
418
-        if (! $data) {
419
-            return null;
420
-        }
421
-        $generated = true;
422
-        if (isset($data[3])) {
423
-            $generated = $data[3];
424
-        }
425
-        return array(
426
-            'url'       => $data[0],
427
-            'width'     => $data[1],
428
-            'height'    => $data[2],
429
-            'generated' => $generated,
430
-        );
431
-    }
432
-
433
-
434
-    /**
435
-     * Returns true if the array of data contains 'Event_CPT.ID'. False otherwise
436
-     *
437
-     * @param array $wpdb_row
438
-     * @return bool
439
-     */
440
-    protected static function wpdbRowHasEventId($wpdb_row)
441
-    {
442
-        return (is_array($wpdb_row) && isset($wpdb_row['Event_CPT.ID']) && absint($wpdb_row['Event_CPT.ID']));
443
-    }
444
-
445
-
446
-    /**
447
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
448
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
449
-     *
450
-     * @since $VID:$
451
-     * @return array
452
-     */
453
-    public static function schemaForCalculations()
454
-    {
455
-        $image_object_properties = array(
456
-            'url'       => array(
457
-                'type' => 'string',
458
-            ),
459
-            'width'     => array(
460
-                'type' => 'number',
461
-            ),
462
-            'height'    => array(
463
-                'type' => 'number',
464
-            ),
465
-            'generated' => array(
466
-                'type' => 'boolean',
467
-            ),
468
-        );
469
-        return array(
470
-            'optimum_sales_at_start'          => array(
471
-                'description' => esc_html__(
472
-                    '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.',
473
-                    'event_espresso'
474
-                ),
475
-                'type'        => 'number',
476
-            ),
477
-            'optimum_sales_now'               => array(
478
-                'description' => esc_html__(
479
-                    'The total spaces on the event (ignoring all sales; so this is the optimum sales that could have been achieved.',
480
-                    'event_espresso'
481
-                ),
482
-                'type'        => 'number',
483
-            ),
484
-            'spaces_remaining'                => array(
485
-                'description' => esc_html__(
486
-                    'The optimum_sales_number result, minus total sales so far.',
487
-                    'event_espresso'
488
-                ),
489
-                'type'        => 'number',
490
-            ),
491
-            'spots_taken'                     => array(
492
-                'description' => esc_html__(
493
-                    'The number of approved registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
494
-                    'event_espresso'
495
-                ),
496
-                'type'        => 'number',
497
-            ),
498
-            'spots_taken_pending_payment'     => array(
499
-                'description' => esc_html__(
500
-                    'The number of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
501
-                    'event_espresso'
502
-                ),
503
-                'type'        => 'number',
504
-            ),
505
-            'registrations_checked_in_count'  => array(
506
-                'description' => esc_html__(
507
-                    'The count of all the registrations who have checked into one of this event\'s datetimes.',
508
-                    'event_espresso'
509
-                ),
510
-                'type'        => 'number',
511
-            ),
512
-            'registrations_checked_out_count' => array(
513
-                'description' => esc_html__(
514
-                    'The count of all registrations who have checked out of one of this event\'s datetimes.',
515
-                    'event_espresso'
516
-                ),
517
-                'type'        => 'number',
518
-            ),
519
-            'image_thumbnail'                 => array(
520
-                'description'          => esc_html__(
521
-                    'The thumbnail image data.',
522
-                    'event_espresso'
523
-                ),
524
-                'type'                 => 'object',
525
-                'properties'           => $image_object_properties,
526
-                'additionalProperties' => false,
527
-            ),
528
-            'image_medium'                    => array(
529
-                'description'          => esc_html__(
530
-                    'The medium image data.',
531
-                    'event_espresso'
532
-                ),
533
-                'type'                 => 'object',
534
-                'properties'           => $image_object_properties,
535
-                'additionalProperties' => false,
536
-            ),
537
-            'image_medium_large'              => array(
538
-                'description'          => esc_html__(
539
-                    'The medium-large image data.',
540
-                    'event_espresso'
541
-                ),
542
-                'type'                 => 'object',
543
-                'properties'           => $image_object_properties,
544
-                'additionalProperties' => false,
545
-            ),
546
-            'image_large'                     => array(
547
-                'description'          => esc_html__(
548
-                    'The large image data.',
549
-                    'event_espresso'
550
-                ),
551
-                'type'                 => 'object',
552
-                'properties'           => $image_object_properties,
553
-                'additionalProperties' => false,
554
-            ),
555
-            'image_post_thumbnail'            => array(
556
-                'description'          => esc_html__(
557
-                    'The post-thumbnail image data.',
558
-                    'event_espresso'
559
-                ),
560
-                'type'                 => 'object',
561
-                'properties'           => $image_object_properties,
562
-                'additionalProperties' => false,
563
-            ),
564
-            'image_full'                      => array(
565
-                'description'          => esc_html__(
566
-                    'The full size image data',
567
-                    'event_espresso'
568
-                ),
569
-                'type'                 => 'object',
570
-                'properties'           => $image_object_properties,
571
-                'additionalProperties' => false,
572
-            ),
573
-        );
574
-    }
575
-
576
-
577
-    /**
578
-     * Returns the json schema for the given calculation index.
579
-     *
580
-     * @param $calculation_index
581
-     * @since $VID:$
582
-     * @return array
583
-     */
584
-    public static function schemaForCalculation($calculation_index)
585
-    {
586
-        $schema_map = Event::schemaForCalculations();
587
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
588
-    }
30
+	/**
31
+	 * Calculates the total spaces on the event (not subtracting sales, but taking
32
+	 * sales into account; so this is the optimum sales that CAN still be achieved)
33
+	 * See EE_Event::total_available_spaces( true );
34
+	 *
35
+	 * @param array               $wpdb_row
36
+	 * @param WP_REST_Request     $request
37
+	 * @param EventControllerBase $controller
38
+	 * @return int
39
+	 * @throws EE_Error
40
+	 * @throws DomainException
41
+	 * @throws InvalidDataTypeException
42
+	 * @throws InvalidInterfaceException
43
+	 * @throws UnexpectedEntityException
44
+	 * @throws InvalidArgumentException
45
+	 */
46
+	public static function optimumSalesAtStart($wpdb_row, $request, $controller)
47
+	{
48
+		$event_obj = null;
49
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
50
+			$event_obj = EEM_Event::instance()->get_one_by_ID($wpdb_row['Event_CPT.ID']);
51
+		}
52
+		if ($event_obj instanceof EE_Event) {
53
+			return $event_obj->total_available_spaces();
54
+		}
55
+		throw new EE_Error(
56
+			sprintf(
57
+				__(
58
+				// @codingStandardsIgnoreStart
59
+					'Cannot calculate optimum_sales_at_start because the event with ID %1$s (from database row %2$s) was not found',
60
+					// @codingStandardsIgnoreEnd
61
+					'event_espresso'
62
+				),
63
+				$wpdb_row['Event_CPT.ID'],
64
+				print_r($wpdb_row, true)
65
+			)
66
+		);
67
+	}
68
+
69
+
70
+	/**
71
+	 * Calculates the total spaces on the event (ignoring all sales; so this is the optimum
72
+	 * sales that COULD have been achieved)
73
+	 * See EE_Event::total_available_spaces( true );
74
+	 *
75
+	 * @param array               $wpdb_row
76
+	 * @param WP_REST_Request     $request
77
+	 * @param EventControllerBase $controller
78
+	 * @return int
79
+	 * @throws DomainException
80
+	 * @throws EE_Error
81
+	 * @throws InvalidArgumentException
82
+	 * @throws InvalidDataTypeException
83
+	 * @throws InvalidInterfaceException
84
+	 * @throws UnexpectedEntityException
85
+	 */
86
+	public static function optimumSalesNow($wpdb_row, $request, $controller)
87
+	{
88
+		$event_obj = null;
89
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
90
+			$event_obj = EEM_Event::instance()->get_one_by_ID($wpdb_row['Event_CPT.ID']);
91
+		}
92
+		if ($event_obj instanceof EE_Event) {
93
+			return $event_obj->total_available_spaces(true);
94
+		}
95
+		throw new EE_Error(
96
+			sprintf(
97
+				__(
98
+				// @codingStandardsIgnoreStart
99
+					'Cannot calculate optimum_sales_now because the event with ID %1$s (from database row %2$s) was not found',
100
+					// @codingStandardsIgnoreEnd
101
+					'event_espresso'
102
+				),
103
+				$wpdb_row['Event_CPT.ID'],
104
+				print_r($wpdb_row, true)
105
+			)
106
+		);
107
+	}
108
+
109
+
110
+	/**
111
+	 * Like optimum_sales_now, but minus total sales so far.
112
+	 * See EE_Event::spaces_remaining_for_sale( true );
113
+	 *
114
+	 * @param array               $wpdb_row
115
+	 * @param WP_REST_Request     $request
116
+	 * @param EventControllerBase $controller
117
+	 * @return int
118
+	 * @throws DomainException
119
+	 * @throws EE_Error
120
+	 * @throws InvalidArgumentException
121
+	 * @throws InvalidDataTypeException
122
+	 * @throws InvalidInterfaceException
123
+	 * @throws UnexpectedEntityException
124
+	 */
125
+	public static function spacesRemaining($wpdb_row, $request, $controller)
126
+	{
127
+		$event_obj = null;
128
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
129
+			$event_obj = EEM_Event::instance()->get_one_by_ID($wpdb_row['Event_CPT.ID']);
130
+		}
131
+		if ($event_obj instanceof EE_Event) {
132
+			return $event_obj->spaces_remaining_for_sale();
133
+		}
134
+		throw new EE_Error(
135
+			sprintf(
136
+				__(
137
+				// @codingStandardsIgnoreStart
138
+					'Cannot calculate spaces_remaining because the event with ID %1$s (from database row %2$s) was not found',
139
+					// @codingStandardsIgnoreEnd
140
+					'event_espresso'
141
+				),
142
+				$wpdb_row['Event_CPT.ID'],
143
+				print_r($wpdb_row, true)
144
+			)
145
+		);
146
+	}
147
+
148
+
149
+	/**
150
+	 * Counts the number of approved registrations for this event (regardless
151
+	 * of how many datetimes each registrations' ticket purchase is for)
152
+	 *
153
+	 * @param array               $wpdb_row
154
+	 * @param WP_REST_Request     $request
155
+	 * @param EventControllerBase $controller
156
+	 * @return int
157
+	 * @throws EE_Error
158
+	 * @throws InvalidArgumentException
159
+	 * @throws InvalidDataTypeException
160
+	 * @throws InvalidInterfaceException
161
+	 */
162
+	public static function spotsTaken($wpdb_row, $request, $controller)
163
+	{
164
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
165
+			throw new EE_Error(
166
+				sprintf(
167
+					__(
168
+					// @codingStandardsIgnoreStart
169
+						'Cannot calculate spots_taken because the database row %1$s does not have a valid entry for "Event_CPT.ID"',
170
+						// @codingStandardsIgnoreEnd
171
+						'event_espresso'
172
+					),
173
+					print_r($wpdb_row, true)
174
+				)
175
+			);
176
+		}
177
+		return EEM_Registration::instance()->count(
178
+			array(
179
+				array(
180
+					'EVT_ID' => $wpdb_row['Event_CPT.ID'],
181
+					'STS_ID' => EEM_Registration::status_id_approved,
182
+				),
183
+			),
184
+			'REG_ID',
185
+			true
186
+		);
187
+	}
188
+
189
+
190
+	/**
191
+	 * Counts the number of pending-payment registrations for this event (regardless
192
+	 * of how many datetimes each registrations' ticket purchase is for)
193
+	 *
194
+	 * @param array               $wpdb_row
195
+	 * @param WP_REST_Request     $request
196
+	 * @param EventControllerBase $controller
197
+	 * @return int
198
+	 * @throws EE_Error
199
+	 * @throws InvalidArgumentException
200
+	 * @throws InvalidDataTypeException
201
+	 * @throws InvalidInterfaceException
202
+	 * @throws RestException
203
+	 */
204
+	public static function spotsTakenPendingPayment($wpdb_row, $request, $controller)
205
+	{
206
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
207
+			throw new EE_Error(
208
+				sprintf(
209
+					__(
210
+					// @codingStandardsIgnoreStart
211
+						'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Event_CPT.ID"',
212
+						// @codingStandardsIgnoreEnd
213
+						'event_espresso'
214
+					),
215
+					print_r($wpdb_row, true)
216
+				)
217
+			);
218
+		}
219
+		self::verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
220
+		return EEM_Registration::instance()->count(
221
+			array(
222
+				array(
223
+					'EVT_ID' => $wpdb_row['Event_CPT.ID'],
224
+					'STS_ID' => EEM_Registration::status_id_pending_payment,
225
+				),
226
+			),
227
+			'REG_ID',
228
+			true
229
+		);
230
+	}
231
+
232
+
233
+	/**
234
+	 * Counts all the registrations who have checked into one of this events' datetimes
235
+	 * See EE_Event::total_available_spaces( false );
236
+	 *
237
+	 * @param array               $wpdb_row
238
+	 * @param WP_REST_Request     $request
239
+	 * @param EventControllerBase $controller
240
+	 * @return int|null if permission denied
241
+	 * @throws EE_Error
242
+	 * @throws InvalidArgumentException
243
+	 * @throws InvalidDataTypeException
244
+	 * @throws InvalidInterfaceException
245
+	 * @throws RestException
246
+	 */
247
+	public static function registrationsCheckedInCount($wpdb_row, $request, $controller)
248
+	{
249
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
250
+			throw new EE_Error(
251
+				sprintf(
252
+					__(
253
+					// @codingStandardsIgnoreStart
254
+						'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
255
+						// @codingStandardsIgnoreEnd
256
+						'event_espresso'
257
+					),
258
+					print_r($wpdb_row, true)
259
+				)
260
+			);
261
+		}
262
+		self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
263
+		return EEM_Registration::instance()->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], true);
264
+	}
265
+
266
+
267
+	/**
268
+	 * Counts all the registrations who have checked out of one of this events' datetimes
269
+	 * See EE_Event::total_available_spaces( false );
270
+	 *
271
+	 * @param array               $wpdb_row
272
+	 * @param WP_REST_Request     $request
273
+	 * @param EventControllerBase $controller
274
+	 * @return int
275
+	 * @throws EE_Error
276
+	 * @throws InvalidArgumentException
277
+	 * @throws InvalidDataTypeException
278
+	 * @throws InvalidInterfaceException
279
+	 * @throws RestException
280
+	 */
281
+	public static function registrationsCheckedOutCount($wpdb_row, $request, $controller)
282
+	{
283
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
284
+			throw new EE_Error(
285
+				sprintf(
286
+					__(
287
+					// @codingStandardsIgnoreStart
288
+						'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
289
+						// @codingStandardsIgnoreEnd
290
+						'event_espresso'
291
+					),
292
+					print_r($wpdb_row, true)
293
+				)
294
+			);
295
+		}
296
+		self::verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
297
+		return EEM_Registration::instance()->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], false);
298
+	}
299
+
300
+
301
+	/**
302
+	 * Gets the thumbnail image
303
+	 *
304
+	 * @param array               $wpdb_row
305
+	 * @param WP_REST_Request     $request
306
+	 * @param EventControllerBase $controller
307
+	 * @return array
308
+	 * @throws EE_Error
309
+	 */
310
+	public static function imageThumbnail($wpdb_row, $request, $controller)
311
+	{
312
+		return self::calculateImageData($wpdb_row, 'thumbnail');
313
+	}
314
+
315
+
316
+	/**
317
+	 * Gets the medium image
318
+	 *
319
+	 * @param array               $wpdb_row
320
+	 * @param WP_REST_Request     $request
321
+	 * @param EventControllerBase $controller
322
+	 * @return array
323
+	 * @throws EE_Error
324
+	 */
325
+	public static function imageMedium($wpdb_row, $request, $controller)
326
+	{
327
+		return self::calculateImageData($wpdb_row, 'medium');
328
+	}
329
+
330
+
331
+	/**
332
+	 * Gets the medium-large image
333
+	 *
334
+	 * @param array               $wpdb_row
335
+	 * @param WP_REST_Request     $request
336
+	 * @param EventControllerBase $controller
337
+	 * @return array
338
+	 * @throws EE_Error
339
+	 */
340
+	public static function imageMediumLarge($wpdb_row, $request, $controller)
341
+	{
342
+		return self::calculateImageData($wpdb_row, 'medium_large');
343
+	}
344
+
345
+
346
+	/**
347
+	 * Gets the large image
348
+	 *
349
+	 * @param array               $wpdb_row
350
+	 * @param WP_REST_Request     $request
351
+	 * @param EventControllerBase $controller
352
+	 * @return array
353
+	 * @throws EE_Error
354
+	 */
355
+	public static function imageLarge($wpdb_row, $request, $controller)
356
+	{
357
+		return self::calculateImageData($wpdb_row, 'large');
358
+	}
359
+
360
+
361
+	/**
362
+	 * Gets the post-thumbnail image
363
+	 *
364
+	 * @param array               $wpdb_row
365
+	 * @param WP_REST_Request     $request
366
+	 * @param EventControllerBase $controller
367
+	 * @return array
368
+	 * @throws EE_Error
369
+	 */
370
+	public static function imagePostThumbnail($wpdb_row, $request, $controller)
371
+	{
372
+		return self::calculateImageData($wpdb_row, 'post-thumbnail');
373
+	}
374
+
375
+
376
+	/**
377
+	 * Gets the full size image
378
+	 *
379
+	 * @param array               $wpdb_row
380
+	 * @param WP_REST_Request     $request
381
+	 * @param EventControllerBase $controller
382
+	 * @return array
383
+	 * @throws EE_Error
384
+	 */
385
+	public static function imageFull($wpdb_row, $request, $controller)
386
+	{
387
+		return self::calculateImageData($wpdb_row, 'full');
388
+	}
389
+
390
+
391
+	/**
392
+	 * Gets image specs and formats them for the display in the API,
393
+	 * according to the image size requested
394
+	 *
395
+	 * @param array  $wpdb_row
396
+	 * @param string $image_size one of these: thumbnail, medium, medium_large, large, post-thumbnail, full
397
+	 * @return array|false if no such image exists. If array it will have keys 'url', 'width', 'height' and 'original'
398
+	 * @throws EE_Error
399
+	 */
400
+	protected static function calculateImageData($wpdb_row, $image_size)
401
+	{
402
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
403
+			throw new EE_Error(
404
+				sprintf(
405
+					__(
406
+					// @codingStandardsIgnoreStart
407
+						'Cannot calculate image because the database row %1$s does not have an entry for "Event_CPT.ID"',
408
+						// @codingStandardsIgnoreEnd
409
+						'event_espresso'
410
+					),
411
+					print_r($wpdb_row, true)
412
+				)
413
+			);
414
+		}
415
+		$EVT_ID = $wpdb_row['Event_CPT.ID'];
416
+		$attachment_id = get_post_thumbnail_id($EVT_ID);
417
+		$data = wp_get_attachment_image_src($attachment_id, $image_size);
418
+		if (! $data) {
419
+			return null;
420
+		}
421
+		$generated = true;
422
+		if (isset($data[3])) {
423
+			$generated = $data[3];
424
+		}
425
+		return array(
426
+			'url'       => $data[0],
427
+			'width'     => $data[1],
428
+			'height'    => $data[2],
429
+			'generated' => $generated,
430
+		);
431
+	}
432
+
433
+
434
+	/**
435
+	 * Returns true if the array of data contains 'Event_CPT.ID'. False otherwise
436
+	 *
437
+	 * @param array $wpdb_row
438
+	 * @return bool
439
+	 */
440
+	protected static function wpdbRowHasEventId($wpdb_row)
441
+	{
442
+		return (is_array($wpdb_row) && isset($wpdb_row['Event_CPT.ID']) && absint($wpdb_row['Event_CPT.ID']));
443
+	}
444
+
445
+
446
+	/**
447
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
448
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
449
+	 *
450
+	 * @since $VID:$
451
+	 * @return array
452
+	 */
453
+	public static function schemaForCalculations()
454
+	{
455
+		$image_object_properties = array(
456
+			'url'       => array(
457
+				'type' => 'string',
458
+			),
459
+			'width'     => array(
460
+				'type' => 'number',
461
+			),
462
+			'height'    => array(
463
+				'type' => 'number',
464
+			),
465
+			'generated' => array(
466
+				'type' => 'boolean',
467
+			),
468
+		);
469
+		return array(
470
+			'optimum_sales_at_start'          => array(
471
+				'description' => esc_html__(
472
+					'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.',
473
+					'event_espresso'
474
+				),
475
+				'type'        => 'number',
476
+			),
477
+			'optimum_sales_now'               => array(
478
+				'description' => esc_html__(
479
+					'The total spaces on the event (ignoring all sales; so this is the optimum sales that could have been achieved.',
480
+					'event_espresso'
481
+				),
482
+				'type'        => 'number',
483
+			),
484
+			'spaces_remaining'                => array(
485
+				'description' => esc_html__(
486
+					'The optimum_sales_number result, minus total sales so far.',
487
+					'event_espresso'
488
+				),
489
+				'type'        => 'number',
490
+			),
491
+			'spots_taken'                     => array(
492
+				'description' => esc_html__(
493
+					'The number of approved registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
494
+					'event_espresso'
495
+				),
496
+				'type'        => 'number',
497
+			),
498
+			'spots_taken_pending_payment'     => array(
499
+				'description' => esc_html__(
500
+					'The number of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
501
+					'event_espresso'
502
+				),
503
+				'type'        => 'number',
504
+			),
505
+			'registrations_checked_in_count'  => array(
506
+				'description' => esc_html__(
507
+					'The count of all the registrations who have checked into one of this event\'s datetimes.',
508
+					'event_espresso'
509
+				),
510
+				'type'        => 'number',
511
+			),
512
+			'registrations_checked_out_count' => array(
513
+				'description' => esc_html__(
514
+					'The count of all registrations who have checked out of one of this event\'s datetimes.',
515
+					'event_espresso'
516
+				),
517
+				'type'        => 'number',
518
+			),
519
+			'image_thumbnail'                 => array(
520
+				'description'          => esc_html__(
521
+					'The thumbnail image data.',
522
+					'event_espresso'
523
+				),
524
+				'type'                 => 'object',
525
+				'properties'           => $image_object_properties,
526
+				'additionalProperties' => false,
527
+			),
528
+			'image_medium'                    => array(
529
+				'description'          => esc_html__(
530
+					'The medium image data.',
531
+					'event_espresso'
532
+				),
533
+				'type'                 => 'object',
534
+				'properties'           => $image_object_properties,
535
+				'additionalProperties' => false,
536
+			),
537
+			'image_medium_large'              => array(
538
+				'description'          => esc_html__(
539
+					'The medium-large image data.',
540
+					'event_espresso'
541
+				),
542
+				'type'                 => 'object',
543
+				'properties'           => $image_object_properties,
544
+				'additionalProperties' => false,
545
+			),
546
+			'image_large'                     => array(
547
+				'description'          => esc_html__(
548
+					'The large image data.',
549
+					'event_espresso'
550
+				),
551
+				'type'                 => 'object',
552
+				'properties'           => $image_object_properties,
553
+				'additionalProperties' => false,
554
+			),
555
+			'image_post_thumbnail'            => array(
556
+				'description'          => esc_html__(
557
+					'The post-thumbnail image data.',
558
+					'event_espresso'
559
+				),
560
+				'type'                 => 'object',
561
+				'properties'           => $image_object_properties,
562
+				'additionalProperties' => false,
563
+			),
564
+			'image_full'                      => array(
565
+				'description'          => esc_html__(
566
+					'The full size image data',
567
+					'event_espresso'
568
+				),
569
+				'type'                 => 'object',
570
+				'properties'           => $image_object_properties,
571
+				'additionalProperties' => false,
572
+			),
573
+		);
574
+	}
575
+
576
+
577
+	/**
578
+	 * Returns the json schema for the given calculation index.
579
+	 *
580
+	 * @param $calculation_index
581
+	 * @since $VID:$
582
+	 * @return array
583
+	 */
584
+	public static function schemaForCalculation($calculation_index)
585
+	{
586
+		$schema_map = Event::schemaForCalculations();
587
+		return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
588
+	}
589 589
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Attendee.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -74,6 +74,6 @@
 block discarded – undo
74 74
     public static function schemaForCalculation($calculation_index)
75 75
     {
76 76
         $schema_map = Attendee::schemaForCalculations();
77
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
77
+        return isset($schema_map[$calculation_index]) ? $schema_map[$calculation_index] : array();
78 78
     }
79 79
 }
Please login to merge, or discard this patch.
Indentation   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -17,57 +17,57 @@
 block discarded – undo
17 17
 class Attendee extends AttendeeCalculationsBase implements HasCalculationSchemaInterface
18 18
 {
19 19
 
20
-    /**
21
-     * @param array                  $wpdb_row
22
-     * @param WP_REST_Request        $request
23
-     * @param AttendeeControllerBase $controller
24
-     * @since 4.9.66.p
25
-     * @return string
26
-     */
27
-    public static function userAvatar(array $wpdb_row, WP_REST_Request $request, AttendeeControllerBase $controller)
28
-    {
29
-        if (is_array($wpdb_row) && isset($wpdb_row['Attendee_Meta.ATT_email'])) {
30
-            $email_address = $wpdb_row['Attendee_Meta.ATT_email'];
31
-        }
32
-        if (empty($email_address)) {
33
-            return '';
34
-        }
35
-        $avatar = get_avatar_url($email_address);
36
-        return $avatar ? $avatar : '';
37
-    }
20
+	/**
21
+	 * @param array                  $wpdb_row
22
+	 * @param WP_REST_Request        $request
23
+	 * @param AttendeeControllerBase $controller
24
+	 * @since 4.9.66.p
25
+	 * @return string
26
+	 */
27
+	public static function userAvatar(array $wpdb_row, WP_REST_Request $request, AttendeeControllerBase $controller)
28
+	{
29
+		if (is_array($wpdb_row) && isset($wpdb_row['Attendee_Meta.ATT_email'])) {
30
+			$email_address = $wpdb_row['Attendee_Meta.ATT_email'];
31
+		}
32
+		if (empty($email_address)) {
33
+			return '';
34
+		}
35
+		$avatar = get_avatar_url($email_address);
36
+		return $avatar ? $avatar : '';
37
+	}
38 38
 
39 39
 
40
-    /**
41
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
42
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
43
-     *
44
-     * @since $VID:$
45
-     * @return array
46
-     */
47
-    public static function schemaForCalculations()
48
-    {
49
-        return array(
50
-            'user_avatar' => array(
51
-                'description' => esc_html__(
52
-                    'The avatar url for the attendee (if available).',
53
-                    'event_espresso'
54
-                ),
55
-                'type'        => 'string',
56
-            ),
57
-        );
58
-    }
40
+	/**
41
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
42
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
43
+	 *
44
+	 * @since $VID:$
45
+	 * @return array
46
+	 */
47
+	public static function schemaForCalculations()
48
+	{
49
+		return array(
50
+			'user_avatar' => array(
51
+				'description' => esc_html__(
52
+					'The avatar url for the attendee (if available).',
53
+					'event_espresso'
54
+				),
55
+				'type'        => 'string',
56
+			),
57
+		);
58
+	}
59 59
 
60 60
 
61
-    /**
62
-     * Returns the json schema for the given calculation index.
63
-     *
64
-     * @since $VID:$
65
-     * @param $calculation_index
66
-     * @return array
67
-     */
68
-    public static function schemaForCalculation($calculation_index)
69
-    {
70
-        $schema_map = Attendee::schemaForCalculations();
71
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
72
-    }
61
+	/**
62
+	 * Returns the json schema for the given calculation index.
63
+	 *
64
+	 * @since $VID:$
65
+	 * @param $calculation_index
66
+	 * @return array
67
+	 */
68
+	public static function schemaForCalculation($calculation_index)
69
+	{
70
+		$schema_map = Attendee::schemaForCalculations();
71
+		return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
72
+	}
73 73
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Registration.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -43,7 +43,7 @@  discard block
 block discarded – undo
43 43
         } else {
44 44
             $reg = null;
45 45
         }
46
-        if (! $reg instanceof EE_Registration
46
+        if ( ! $reg instanceof EE_Registration
47 47
         ) {
48 48
             throw new EE_Error(
49 49
                 sprintf(
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
                     $status_pretty = 'NEVER';
82 82
                     break;
83 83
             }
84
-            $checkin_stati[ $datetime_id ] = $status_pretty;
84
+            $checkin_stati[$datetime_id] = $status_pretty;
85 85
         }
86 86
         return $checkin_stati;
87 87
     }
@@ -126,6 +126,6 @@  discard block
 block discarded – undo
126 126
     public static function schemaForCalculation($calculation_index)
127 127
     {
128 128
         $schema_map = Registration::schemaForCalculations();
129
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
129
+        return isset($schema_map[$calculation_index]) ? $schema_map[$calculation_index] : array();
130 130
     }
131 131
 }
Please login to merge, or discard this patch.
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -24,108 +24,108 @@
 block discarded – undo
24 24
 class Registration extends RegistrationCalculationBase implements HasCalculationSchemaInterface
25 25
 {
26 26
 
27
-    /**
28
-     * Calculates the checkin status for each datetime this registration has access to
29
-     *
30
-     * @param array            $wpdb_row
31
-     * @param WP_REST_Request $request
32
-     * @param RegistrationControllerBase $controller
33
-     * @return array
34
-     * @throws EE_Error
35
-     * @throws InvalidDataTypeException
36
-     * @throws InvalidInterfaceException
37
-     * @throws InvalidArgumentException
38
-     */
39
-    public static function datetimeCheckinStati($wpdb_row, $request, $controller)
40
-    {
41
-        if (is_array($wpdb_row) && isset($wpdb_row['Registration.REG_ID'])) {
42
-            $reg = EEM_Registration::instance()->get_one_by_ID($wpdb_row['Registration.REG_ID']);
43
-        } else {
44
-            $reg = null;
45
-        }
46
-        if (! $reg instanceof EE_Registration
47
-        ) {
48
-            throw new EE_Error(
49
-                sprintf(
50
-                    __(
51
-                    // @codingStandardsIgnoreStart
52
-                        'Cannot calculate datetime_checkin_stati because the registration with ID %1$s (from database row %2$s) was not found',
53
-                        // @codingStandardsIgnoreEnd
54
-                        'event_espresso'
55
-                    ),
56
-                    $wpdb_row['Registration.REG_ID'],
57
-                    print_r($wpdb_row, true)
58
-                )
59
-            );
60
-        }
61
-        $datetime_ids = EEM_Datetime::instance()->get_col(
62
-            array(
63
-                array(
64
-                    'Ticket.TKT_ID' => $reg->ticket_ID(),
65
-                ),
66
-                'default_where_conditions' => \EEM_Base::default_where_conditions_minimum_all,
67
-            )
68
-        );
69
-        $checkin_stati = array();
70
-        foreach ($datetime_ids as $datetime_id) {
71
-            $status = $reg->check_in_status_for_datetime($datetime_id);
72
-            switch ($status) {
73
-                case EE_Checkin::status_checked_out:
74
-                    $status_pretty = 'OUT';
75
-                    break;
76
-                case EE_Checkin::status_checked_in:
77
-                    $status_pretty = 'IN';
78
-                    break;
79
-                case EE_Checkin::status_checked_never:
80
-                default:
81
-                    $status_pretty = 'NEVER';
82
-                    break;
83
-            }
84
-            $checkin_stati[ $datetime_id ] = $status_pretty;
85
-        }
86
-        return $checkin_stati;
87
-    }
27
+	/**
28
+	 * Calculates the checkin status for each datetime this registration has access to
29
+	 *
30
+	 * @param array            $wpdb_row
31
+	 * @param WP_REST_Request $request
32
+	 * @param RegistrationControllerBase $controller
33
+	 * @return array
34
+	 * @throws EE_Error
35
+	 * @throws InvalidDataTypeException
36
+	 * @throws InvalidInterfaceException
37
+	 * @throws InvalidArgumentException
38
+	 */
39
+	public static function datetimeCheckinStati($wpdb_row, $request, $controller)
40
+	{
41
+		if (is_array($wpdb_row) && isset($wpdb_row['Registration.REG_ID'])) {
42
+			$reg = EEM_Registration::instance()->get_one_by_ID($wpdb_row['Registration.REG_ID']);
43
+		} else {
44
+			$reg = null;
45
+		}
46
+		if (! $reg instanceof EE_Registration
47
+		) {
48
+			throw new EE_Error(
49
+				sprintf(
50
+					__(
51
+					// @codingStandardsIgnoreStart
52
+						'Cannot calculate datetime_checkin_stati because the registration with ID %1$s (from database row %2$s) was not found',
53
+						// @codingStandardsIgnoreEnd
54
+						'event_espresso'
55
+					),
56
+					$wpdb_row['Registration.REG_ID'],
57
+					print_r($wpdb_row, true)
58
+				)
59
+			);
60
+		}
61
+		$datetime_ids = EEM_Datetime::instance()->get_col(
62
+			array(
63
+				array(
64
+					'Ticket.TKT_ID' => $reg->ticket_ID(),
65
+				),
66
+				'default_where_conditions' => \EEM_Base::default_where_conditions_minimum_all,
67
+			)
68
+		);
69
+		$checkin_stati = array();
70
+		foreach ($datetime_ids as $datetime_id) {
71
+			$status = $reg->check_in_status_for_datetime($datetime_id);
72
+			switch ($status) {
73
+				case EE_Checkin::status_checked_out:
74
+					$status_pretty = 'OUT';
75
+					break;
76
+				case EE_Checkin::status_checked_in:
77
+					$status_pretty = 'IN';
78
+					break;
79
+				case EE_Checkin::status_checked_never:
80
+				default:
81
+					$status_pretty = 'NEVER';
82
+					break;
83
+			}
84
+			$checkin_stati[ $datetime_id ] = $status_pretty;
85
+		}
86
+		return $checkin_stati;
87
+	}
88 88
 
89 89
 
90
-    /**
91
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
92
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
93
-     *
94
-     * @since $VID:$
95
-     * @return array
96
-     */
97
-    public static function schemaForCalculations()
98
-    {
99
-        return array(
100
-            'datetime_checkin_stati' => array(
101
-                'description' => esc_html__(
102
-                    'Returns the checkin status for each datetime this registration has access to.',
103
-                    'event_espresso'
104
-                ),
105
-                'type' => 'object',
106
-                'properties' => array(),
107
-                'additionalProperties' => array(
108
-                    'description' => esc_html(
109
-                        'Keys are date-time ids and values are the check-in status',
110
-                        'event_espresso'
111
-                    ),
112
-                    'type' => 'string'
113
-                ),
114
-            ),
115
-        );
116
-    }
90
+	/**
91
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
92
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
93
+	 *
94
+	 * @since $VID:$
95
+	 * @return array
96
+	 */
97
+	public static function schemaForCalculations()
98
+	{
99
+		return array(
100
+			'datetime_checkin_stati' => array(
101
+				'description' => esc_html__(
102
+					'Returns the checkin status for each datetime this registration has access to.',
103
+					'event_espresso'
104
+				),
105
+				'type' => 'object',
106
+				'properties' => array(),
107
+				'additionalProperties' => array(
108
+					'description' => esc_html(
109
+						'Keys are date-time ids and values are the check-in status',
110
+						'event_espresso'
111
+					),
112
+					'type' => 'string'
113
+				),
114
+			),
115
+		);
116
+	}
117 117
 
118 118
 
119
-    /**
120
-     * Returns the json schema for the given calculation index.
121
-     *
122
-     * @param $calculation_index
123
-     * @since $VID:$
124
-     * @return array
125
-     */
126
-    public static function schemaForCalculation($calculation_index)
127
-    {
128
-        $schema_map = Registration::schemaForCalculations();
129
-        return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
130
-    }
119
+	/**
120
+	 * Returns the json schema for the given calculation index.
121
+	 *
122
+	 * @param $calculation_index
123
+	 * @since $VID:$
124
+	 * @return array
125
+	 */
126
+	public static function schemaForCalculation($calculation_index)
127
+	{
128
+		$schema_map = Registration::schemaForCalculations();
129
+		return isset($schema_map[ $calculation_index ]) ? $schema_map[ $calculation_index ] : array();
130
+	}
131 131
 }
Please login to merge, or discard this patch.
core/entities/models/JsonModelSchema.php 2 patches
Indentation   +226 added lines, -226 removed lines patch added patch discarded remove patch
@@ -25,230 +25,230 @@
 block discarded – undo
25 25
 class JsonModelSchema
26 26
 {
27 27
 
28
-    /**
29
-     * @var EEM_Base
30
-     */
31
-    protected $model;
32
-
33
-    /**
34
-     * @var CalculatedModelFields
35
-     */
36
-    protected $fields_calculator;
37
-
38
-
39
-    /**
40
-     * JsonModelSchema constructor.
41
-     *
42
-     * @param EEM_Base              $model
43
-     * @param CalculatedModelFields $fields_calculator
44
-     */
45
-    public function __construct(EEM_Base $model, CalculatedModelFields $fields_calculator)
46
-    {
47
-        $this->model = $model;
48
-        $this->fields_calculator = $fields_calculator;
49
-    }
50
-
51
-
52
-    /**
53
-     * Return the schema for a given model from a given model.
54
-     *
55
-     * @return array
56
-     */
57
-    public function getModelSchema()
58
-    {
59
-        return $this->getModelSchemaForRelations(
60
-            $this->model->relation_settings(),
61
-            $this->getModelSchemaForFields(
62
-                $this->model->field_settings(),
63
-                $this->getInitialSchemaStructure()
64
-            )
65
-        );
66
-    }
67
-
68
-
69
-    /**
70
-     * Get the schema for a given set of model fields.
71
-     *
72
-     * @param EE_Model_Field_Base[] $model_fields
73
-     * @param array                  $schema
74
-     * @return array
75
-     */
76
-    public function getModelSchemaForFields(array $model_fields, array $schema)
77
-    {
78
-        foreach ($model_fields as $field => $model_field) {
79
-            if (! $model_field instanceof EE_Model_Field_Base) {
80
-                continue;
81
-            }
82
-            $schema['properties'][ $field ] = $model_field->getSchema();
83
-
84
-            // if this is a primary key field add the primary key item
85
-            if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
-                $schema['properties'][ $field ]['primary_key'] = true;
87
-                if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
-                    $schema['properties'][ $field ]['readonly'] = true;
89
-                }
90
-            }
91
-
92
-            // if this is a foreign key field add the foreign key item
93
-            if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
-                $schema['properties'][ $field ]['foreign_key'] = array(
95
-                    'description' => esc_html__(
96
-                        'This is a foreign key the points to the given models.',
97
-                        'event_espresso'
98
-                    ),
99
-                    'type'        => 'array',
100
-                    'enum'        => $model_field->get_model_class_names_pointed_to(),
101
-                );
102
-            }
103
-        }
104
-        return $schema;
105
-    }
106
-
107
-
108
-    /**
109
-     * Get the schema for a given set of model relations
110
-     *
111
-     * @param EE_Model_Relation_Base[] $relations_on_model
112
-     * @param array                    $schema
113
-     * @return array
114
-     */
115
-    public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116
-    {
117
-        foreach ($relations_on_model as $model_name => $relation) {
118
-            if (! $relation instanceof EE_Model_Relation_Base) {
119
-                continue;
120
-            }
121
-            $model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122
-                ? strtolower($model_name)
123
-                : EEH_Inflector::pluralize_and_lower($model_name);
124
-            $schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
-            $schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
126
-
127
-            // links schema
128
-            $links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
-            $schema['properties']['_links']['properties'][ $links_key ] = array(
130
-                'description' => esc_html__(
131
-                    'Array of objects describing the link(s) for this relation resource.',
132
-                    'event_espresso'
133
-                ),
134
-                'type' => 'array',
135
-                'readonly' => true,
136
-                'items' => array(
137
-                    'type' => 'object',
138
-                    'properties' => array(
139
-                        'href' => array(
140
-                            'type' => 'string',
141
-                            'description' => sprintf(
142
-                                // translators: placeholder is the model name for the relation.
143
-                                esc_html__(
144
-                                    'The link to the resource for the %s relation(s) to this entity',
145
-                                    'event_espresso'
146
-                                ),
147
-                                $model_name
148
-                            ),
149
-                        ),
150
-                        'single' => array(
151
-                            'type' => 'boolean',
152
-                            'description' => sprintf(
153
-                                // translators: placeholder is the model name for the relation.
154
-                                esc_html__(
155
-                                    'Whether or not there is only a single %s relation to this entity',
156
-                                    'event_espresso'
157
-                                ),
158
-                                $model_name
159
-                            ),
160
-                        ),
161
-                    ),
162
-                    'additionalProperties' => false
163
-                ),
164
-            );
165
-        }
166
-        return $schema;
167
-    }
168
-
169
-
170
-    /**
171
-     * Outputs the schema header for a model.
172
-     *
173
-     * @return array
174
-     */
175
-    public function getInitialSchemaStructure()
176
-    {
177
-        return array(
178
-            '$schema'    => 'http://json-schema.org/draft-04/schema#',
179
-            'title'      => $this->model->get_this_model_name(),
180
-            'type'       => 'object',
181
-            'properties' => array(
182
-                'link' => array(
183
-                    'description' => esc_html__(
184
-                        'Link to event on WordPress site hosting events.',
185
-                        'event_espresso'
186
-                    ),
187
-                    'type' => 'string',
188
-                    'readonly' => true,
189
-                ),
190
-                '_links' => array(
191
-                    'description' => esc_html__(
192
-                        'Various links for resources related to the entity.',
193
-                        'event_espresso'
194
-                    ),
195
-                    'type' => 'object',
196
-                    'readonly' => true,
197
-                    'properties' => array(
198
-                        'self' => array(
199
-                            'description' => esc_html__(
200
-                                'Link to this entities resource.',
201
-                                'event_espresso'
202
-                            ),
203
-                            'type' => 'array',
204
-                            'items' => array(
205
-                                'type' => 'object',
206
-                                'properties' => array(
207
-                                    'href' => array(
208
-                                        'type' => 'string',
209
-                                    ),
210
-                                ),
211
-                                'additionalProperties' => false
212
-                            ),
213
-                            'readonly' => true
214
-                        ),
215
-                        'collection' => array(
216
-                            'description' => esc_html__(
217
-                                'Link to this entities collection resource.',
218
-                                'event_espresso'
219
-                            ),
220
-                            'type' => 'array',
221
-                            'items' => array(
222
-                                'type' => 'object',
223
-                                'properties' => array(
224
-                                    'href' => array(
225
-                                        'type' => 'string'
226
-                                    ),
227
-                                ),
228
-                                'additionalProperties' => false
229
-                            ),
230
-                            'readonly' => true
231
-                        ),
232
-                    ),
233
-                    'additionalProperties' => false,
234
-                ),
235
-                '_calculated_fields' => $this->fields_calculator->getJsonSchemaForModel($this->model)
236
-            ),
237
-            'additionalProperties' => false,
238
-        );
239
-    }
240
-
241
-
242
-    /**
243
-     * Allows one to just use the object as a string to get the json.
244
-     * eg.
245
-     * $json_schema = new JsonModelSchema(EEM_Event::instance(), new CalculatedModelFields);
246
-     * echo $json_schema; //outputs the schema as a json formatted string.
247
-     *
248
-     * @return bool|false|mixed|string
249
-     */
250
-    public function __toString()
251
-    {
252
-        return wp_json_encode($this->getModelSchema());
253
-    }
28
+	/**
29
+	 * @var EEM_Base
30
+	 */
31
+	protected $model;
32
+
33
+	/**
34
+	 * @var CalculatedModelFields
35
+	 */
36
+	protected $fields_calculator;
37
+
38
+
39
+	/**
40
+	 * JsonModelSchema constructor.
41
+	 *
42
+	 * @param EEM_Base              $model
43
+	 * @param CalculatedModelFields $fields_calculator
44
+	 */
45
+	public function __construct(EEM_Base $model, CalculatedModelFields $fields_calculator)
46
+	{
47
+		$this->model = $model;
48
+		$this->fields_calculator = $fields_calculator;
49
+	}
50
+
51
+
52
+	/**
53
+	 * Return the schema for a given model from a given model.
54
+	 *
55
+	 * @return array
56
+	 */
57
+	public function getModelSchema()
58
+	{
59
+		return $this->getModelSchemaForRelations(
60
+			$this->model->relation_settings(),
61
+			$this->getModelSchemaForFields(
62
+				$this->model->field_settings(),
63
+				$this->getInitialSchemaStructure()
64
+			)
65
+		);
66
+	}
67
+
68
+
69
+	/**
70
+	 * Get the schema for a given set of model fields.
71
+	 *
72
+	 * @param EE_Model_Field_Base[] $model_fields
73
+	 * @param array                  $schema
74
+	 * @return array
75
+	 */
76
+	public function getModelSchemaForFields(array $model_fields, array $schema)
77
+	{
78
+		foreach ($model_fields as $field => $model_field) {
79
+			if (! $model_field instanceof EE_Model_Field_Base) {
80
+				continue;
81
+			}
82
+			$schema['properties'][ $field ] = $model_field->getSchema();
83
+
84
+			// if this is a primary key field add the primary key item
85
+			if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
+				$schema['properties'][ $field ]['primary_key'] = true;
87
+				if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
+					$schema['properties'][ $field ]['readonly'] = true;
89
+				}
90
+			}
91
+
92
+			// if this is a foreign key field add the foreign key item
93
+			if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
+				$schema['properties'][ $field ]['foreign_key'] = array(
95
+					'description' => esc_html__(
96
+						'This is a foreign key the points to the given models.',
97
+						'event_espresso'
98
+					),
99
+					'type'        => 'array',
100
+					'enum'        => $model_field->get_model_class_names_pointed_to(),
101
+				);
102
+			}
103
+		}
104
+		return $schema;
105
+	}
106
+
107
+
108
+	/**
109
+	 * Get the schema for a given set of model relations
110
+	 *
111
+	 * @param EE_Model_Relation_Base[] $relations_on_model
112
+	 * @param array                    $schema
113
+	 * @return array
114
+	 */
115
+	public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116
+	{
117
+		foreach ($relations_on_model as $model_name => $relation) {
118
+			if (! $relation instanceof EE_Model_Relation_Base) {
119
+				continue;
120
+			}
121
+			$model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122
+				? strtolower($model_name)
123
+				: EEH_Inflector::pluralize_and_lower($model_name);
124
+			$schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
+			$schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
126
+
127
+			// links schema
128
+			$links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
+			$schema['properties']['_links']['properties'][ $links_key ] = array(
130
+				'description' => esc_html__(
131
+					'Array of objects describing the link(s) for this relation resource.',
132
+					'event_espresso'
133
+				),
134
+				'type' => 'array',
135
+				'readonly' => true,
136
+				'items' => array(
137
+					'type' => 'object',
138
+					'properties' => array(
139
+						'href' => array(
140
+							'type' => 'string',
141
+							'description' => sprintf(
142
+								// translators: placeholder is the model name for the relation.
143
+								esc_html__(
144
+									'The link to the resource for the %s relation(s) to this entity',
145
+									'event_espresso'
146
+								),
147
+								$model_name
148
+							),
149
+						),
150
+						'single' => array(
151
+							'type' => 'boolean',
152
+							'description' => sprintf(
153
+								// translators: placeholder is the model name for the relation.
154
+								esc_html__(
155
+									'Whether or not there is only a single %s relation to this entity',
156
+									'event_espresso'
157
+								),
158
+								$model_name
159
+							),
160
+						),
161
+					),
162
+					'additionalProperties' => false
163
+				),
164
+			);
165
+		}
166
+		return $schema;
167
+	}
168
+
169
+
170
+	/**
171
+	 * Outputs the schema header for a model.
172
+	 *
173
+	 * @return array
174
+	 */
175
+	public function getInitialSchemaStructure()
176
+	{
177
+		return array(
178
+			'$schema'    => 'http://json-schema.org/draft-04/schema#',
179
+			'title'      => $this->model->get_this_model_name(),
180
+			'type'       => 'object',
181
+			'properties' => array(
182
+				'link' => array(
183
+					'description' => esc_html__(
184
+						'Link to event on WordPress site hosting events.',
185
+						'event_espresso'
186
+					),
187
+					'type' => 'string',
188
+					'readonly' => true,
189
+				),
190
+				'_links' => array(
191
+					'description' => esc_html__(
192
+						'Various links for resources related to the entity.',
193
+						'event_espresso'
194
+					),
195
+					'type' => 'object',
196
+					'readonly' => true,
197
+					'properties' => array(
198
+						'self' => array(
199
+							'description' => esc_html__(
200
+								'Link to this entities resource.',
201
+								'event_espresso'
202
+							),
203
+							'type' => 'array',
204
+							'items' => array(
205
+								'type' => 'object',
206
+								'properties' => array(
207
+									'href' => array(
208
+										'type' => 'string',
209
+									),
210
+								),
211
+								'additionalProperties' => false
212
+							),
213
+							'readonly' => true
214
+						),
215
+						'collection' => array(
216
+							'description' => esc_html__(
217
+								'Link to this entities collection resource.',
218
+								'event_espresso'
219
+							),
220
+							'type' => 'array',
221
+							'items' => array(
222
+								'type' => 'object',
223
+								'properties' => array(
224
+									'href' => array(
225
+										'type' => 'string'
226
+									),
227
+								),
228
+								'additionalProperties' => false
229
+							),
230
+							'readonly' => true
231
+						),
232
+					),
233
+					'additionalProperties' => false,
234
+				),
235
+				'_calculated_fields' => $this->fields_calculator->getJsonSchemaForModel($this->model)
236
+			),
237
+			'additionalProperties' => false,
238
+		);
239
+	}
240
+
241
+
242
+	/**
243
+	 * Allows one to just use the object as a string to get the json.
244
+	 * eg.
245
+	 * $json_schema = new JsonModelSchema(EEM_Event::instance(), new CalculatedModelFields);
246
+	 * echo $json_schema; //outputs the schema as a json formatted string.
247
+	 *
248
+	 * @return bool|false|mixed|string
249
+	 */
250
+	public function __toString()
251
+	{
252
+		return wp_json_encode($this->getModelSchema());
253
+	}
254 254
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -76,22 +76,22 @@  discard block
 block discarded – undo
76 76
     public function getModelSchemaForFields(array $model_fields, array $schema)
77 77
     {
78 78
         foreach ($model_fields as $field => $model_field) {
79
-            if (! $model_field instanceof EE_Model_Field_Base) {
79
+            if ( ! $model_field instanceof EE_Model_Field_Base) {
80 80
                 continue;
81 81
             }
82
-            $schema['properties'][ $field ] = $model_field->getSchema();
82
+            $schema['properties'][$field] = $model_field->getSchema();
83 83
 
84 84
             // if this is a primary key field add the primary key item
85 85
             if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
-                $schema['properties'][ $field ]['primary_key'] = true;
86
+                $schema['properties'][$field]['primary_key'] = true;
87 87
                 if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
-                    $schema['properties'][ $field ]['readonly'] = true;
88
+                    $schema['properties'][$field]['readonly'] = true;
89 89
                 }
90 90
             }
91 91
 
92 92
             // if this is a foreign key field add the foreign key item
93 93
             if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
-                $schema['properties'][ $field ]['foreign_key'] = array(
94
+                $schema['properties'][$field]['foreign_key'] = array(
95 95
                     'description' => esc_html__(
96 96
                         'This is a foreign key the points to the given models.',
97 97
                         'event_espresso'
@@ -115,18 +115,18 @@  discard block
 block discarded – undo
115 115
     public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116 116
     {
117 117
         foreach ($relations_on_model as $model_name => $relation) {
118
-            if (! $relation instanceof EE_Model_Relation_Base) {
118
+            if ( ! $relation instanceof EE_Model_Relation_Base) {
119 119
                 continue;
120 120
             }
121 121
             $model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122 122
                 ? strtolower($model_name)
123 123
                 : EEH_Inflector::pluralize_and_lower($model_name);
124
-            $schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
-            $schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
124
+            $schema['properties'][$model_name_for_schema] = $relation->getSchema();
125
+            $schema['properties'][$model_name_for_schema]['relation_model'] = $model_name;
126 126
 
127 127
             // links schema
128
-            $links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
-            $schema['properties']['_links']['properties'][ $links_key ] = array(
128
+            $links_key = 'https://api.eventespresso.com/'.strtolower($model_name);
129
+            $schema['properties']['_links']['properties'][$links_key] = array(
130 130
                 'description' => esc_html__(
131 131
                     'Array of objects describing the link(s) for this relation resource.',
132 132
                     'event_espresso'
Please login to merge, or discard this patch.