Completed
Branch BUG/fix-ee-rest-debug-headers (1355bc)
by
unknown
03:29 queued 18s
created
core/libraries/payment_methods/EE_PMT_Base.lib.php 2 patches
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -118,7 +118,7 @@  discard block
 block discarded – undo
118 118
             $this->_gateway->set_unsupported_character_remover(new AsciiOnly());
119 119
             do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
120 120
         }
121
-        if (! isset($this->_has_billing_form)) {
121
+        if ( ! isset($this->_has_billing_form)) {
122 122
             // by default, On Site gateways have a billing form
123 123
             if ($this->payment_occurs() == EE_PMT_Base::onsite) {
124 124
                 $this->set_has_billing_form(true);
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
             }
128 128
         }
129 129
 
130
-        if (! $this->_pretty_name) {
130
+        if ( ! $this->_pretty_name) {
131 131
             throw new EE_Error(
132 132
                 sprintf(
133 133
                     esc_html__(
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
         }
140 140
         // if the child didn't specify a default button, use the credit card one
141 141
         if ($this->_default_button_url === null) {
142
-            $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods/pay-by-credit-card.png';
142
+            $this->_default_button_url = EE_PLUGIN_DIR_URL.'payment_methods/pay-by-credit-card.png';
143 143
         }
144 144
     }
145 145
 
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
     {
161 161
         $reflector = new ReflectionClass(get_class($this));
162 162
         $fn = $reflector->getFileName();
163
-        $this->_file_folder = dirname($fn) . '/';
163
+        $this->_file_folder = dirname($fn).'/';
164 164
     }
165 165
 
166 166
 
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
      */
194 194
     public function file_folder()
195 195
     {
196
-        if (! $this->_file_folder) {
196
+        if ( ! $this->_file_folder) {
197 197
             $this->_set_file_folder();
198 198
         }
199 199
         return $this->_file_folder;
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
      */
206 206
     public function file_url()
207 207
     {
208
-        if (! $this->_file_url) {
208
+        if ( ! $this->_file_url) {
209 209
             $this->_set_file_url();
210 210
         }
211 211
         return $this->_file_url;
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
      */
240 240
     public function settings_form()
241 241
     {
242
-        if (! $this->_settings_form) {
242
+        if ( ! $this->_settings_form) {
243 243
             $this->_settings_form = $this->generate_new_settings_form();
244 244
             $this->_settings_form->set_payment_method_type($this);
245 245
             // if we have already assigned a model object to this pmt, make
@@ -293,7 +293,7 @@  discard block
 block discarded – undo
293 293
     public function billing_form(EE_Transaction $transaction = null, $extra_args = array())
294 294
     {
295 295
         // has billing form already been regenerated ? or overwrite cache?
296
-        if (! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) {
296
+        if ( ! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) {
297 297
             $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
298 298
         }
299 299
         // if we know who the attendee is, and this is a billing form
@@ -397,7 +397,7 @@  discard block
 block discarded – undo
397 397
             $payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
398 398
             // if we didn't already have a payment in progress for the same thing,
399 399
             // then we actually want to make a new payment
400
-            if (! $payment instanceof EE_Payment) {
400
+            if ( ! $payment instanceof EE_Payment) {
401 401
                 $payment = EE_Payment::new_instance(
402 402
                     array_merge(
403 403
                         $duplicate_properties,
@@ -498,7 +498,7 @@  discard block
 block discarded – undo
498 498
     public function handle_ipn($req_data, $transaction)
499 499
     {
500 500
         $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
501
-        if (! $this->_gateway instanceof EE_Offsite_Gateway) {
501
+        if ( ! $this->_gateway instanceof EE_Offsite_Gateway) {
502 502
             throw new EE_Error(
503 503
                 sprintf(
504 504
                     esc_html__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"),
@@ -521,7 +521,7 @@  discard block
 block discarded – undo
521 521
      */
522 522
     protected function _save_billing_info_to_attendee($billing_form, $transaction)
523 523
     {
524
-        if (! $transaction || ! $transaction instanceof EE_Transaction) {
524
+        if ( ! $transaction || ! $transaction instanceof EE_Transaction) {
525 525
             EE_Error::add_error(
526 526
                 esc_html__("Cannot save billing info because no transaction was specified", "event_espresso"),
527 527
                 __FILE__,
@@ -531,7 +531,7 @@  discard block
 block discarded – undo
531 531
             return false;
532 532
         }
533 533
         $primary_reg = $transaction->primary_registration();
534
-        if (! $primary_reg) {
534
+        if ( ! $primary_reg) {
535 535
             EE_Error::add_error(
536 536
                 esc_html__("Cannot save billing info because the transaction has no primary registration", "event_espresso"),
537 537
                 __FILE__,
@@ -541,7 +541,7 @@  discard block
 block discarded – undo
541 541
             return false;
542 542
         }
543 543
         $attendee = $primary_reg->attendee();
544
-        if (! $attendee) {
544
+        if ( ! $attendee) {
545 545
             EE_Error::add_error(
546 546
                 esc_html__(
547 547
                     "Cannot save billing info because the transaction's primary registration has no attendee!",
@@ -654,7 +654,7 @@  discard block
 block discarded – undo
654 654
      */
655 655
     public function payment_occurs()
656 656
     {
657
-        if (! $this->_gateway) {
657
+        if ( ! $this->_gateway) {
658 658
             return EE_PMT_Base::offline;
659 659
         } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
660 660
             return EE_PMT_Base::onsite;
@@ -685,7 +685,7 @@  discard block
 block discarded – undo
685 685
     public function payment_overview_content(EE_Payment $payment)
686 686
     {
687 687
         return EEH_Template::display_template(
688
-            EE_LIBRARIES . 'payment_methods/templates/payment_details_content.template.php',
688
+            EE_LIBRARIES.'payment_methods/templates/payment_details_content.template.php',
689 689
             array('payment_method' => $this->_pm_instance, 'payment' => $payment),
690 690
             true
691 691
         );
@@ -783,7 +783,7 @@  discard block
 block discarded – undo
783 783
      */
784 784
     public function get_help_tab_name()
785 785
     {
786
-        return 'ee_' . strtolower($this->system_name()) . '_help_tab';
786
+        return 'ee_'.strtolower($this->system_name()).'_help_tab';
787 787
     }
788 788
 
789 789
     /**
@@ -794,7 +794,7 @@  discard block
 block discarded – undo
794 794
      */
795 795
     public function cap_name()
796 796
     {
797
-        return 'ee_payment_method_' . strtolower($this->system_name());
797
+        return 'ee_payment_method_'.strtolower($this->system_name());
798 798
     }
799 799
 
800 800
     /**
@@ -828,7 +828,7 @@  discard block
 block discarded – undo
828 828
     public function introductory_html()
829 829
     {
830 830
         return EEH_Template::locate_template(
831
-            $this->file_folder() . 'templates/' . strtolower($this->system_name()) . '_intro.template.php',
831
+            $this->file_folder().'templates/'.strtolower($this->system_name()).'_intro.template.php',
832 832
             array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance)
833 833
         );
834 834
     }
Please login to merge, or discard this patch.
Indentation   +810 added lines, -810 removed lines patch added patch discarded remove patch
@@ -21,814 +21,814 @@
 block discarded – undo
21 21
  */
22 22
 abstract class EE_PMT_Base
23 23
 {
24
-    const onsite = 'on-site';
25
-    const offsite = 'off-site';
26
-    const offline = 'off-line';
27
-
28
-    /**
29
-     * @var EE_Payment_Method
30
-     */
31
-    protected $_pm_instance = null;
32
-
33
-    /**
34
-     * @var boolean
35
-     */
36
-    protected $_requires_https = false;
37
-
38
-    /**
39
-     * @var boolean
40
-     */
41
-    protected $_has_billing_form;
42
-
43
-    /**
44
-     * @var EE_Gateway
45
-     */
46
-    protected $_gateway = null;
47
-
48
-    /**
49
-     * @var EE_Payment_Method_Form
50
-     */
51
-    protected $_settings_form = null;
52
-
53
-    /**
54
-     * @var EE_Form_Section_Proper
55
-     */
56
-    protected $_billing_form = null;
57
-
58
-    /**
59
-     * @var boolean
60
-     */
61
-    protected $_cache_billing_form = true;
62
-
63
-    /**
64
-     * String of the absolute path to the folder containing this file, with a trailing slash.
65
-     * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/'
66
-     *
67
-     * @var string
68
-     */
69
-    protected $_file_folder = null;
70
-
71
-    /**
72
-     * String to the absolute URL to this file (useful for getting its web-accessible resources
73
-     * like images, js, or css)
74
-     *
75
-     * @var string
76
-     */
77
-    protected $_file_url = null;
78
-
79
-    /**
80
-     * Pretty name for the payment method
81
-     *
82
-     * @var string
83
-     */
84
-    protected $_pretty_name = null;
85
-
86
-    /**
87
-     *
88
-     * @var string
89
-     */
90
-    protected $_default_button_url = null;
91
-
92
-    /**
93
-     *
94
-     * @var string
95
-     */
96
-    protected $_default_description = null;
97
-
98
-
99
-    /**
100
-     *
101
-     * @param EE_Payment_Method $pm_instance
102
-     * @throws EE_Error
103
-     * @return EE_PMT_Base
104
-     */
105
-    public function __construct($pm_instance = null)
106
-    {
107
-        if ($pm_instance instanceof EE_Payment_Method) {
108
-            $this->set_instance($pm_instance);
109
-        }
110
-        if ($this->_gateway) {
111
-            $this->_gateway->set_payment_model(EEM_Payment::instance());
112
-            $this->_gateway->set_payment_log(EEM_Change_Log::instance());
113
-            $this->_gateway->set_template_helper(new EEH_Template());
114
-            $this->_gateway->set_line_item_helper(new EEH_Line_Item());
115
-            $this->_gateway->set_money_helper(new EEH_Money());
116
-            $this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter());
117
-            $this->_gateway->set_unsupported_character_remover(new AsciiOnly());
118
-            do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
119
-        }
120
-        if (! isset($this->_has_billing_form)) {
121
-            // by default, On Site gateways have a billing form
122
-            if ($this->payment_occurs() == EE_PMT_Base::onsite) {
123
-                $this->set_has_billing_form(true);
124
-            } else {
125
-                $this->set_has_billing_form(false);
126
-            }
127
-        }
128
-
129
-        if (! $this->_pretty_name) {
130
-            throw new EE_Error(
131
-                sprintf(
132
-                    esc_html__(
133
-                        "You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized",
134
-                        "event_espresso"
135
-                    )
136
-                )
137
-            );
138
-        }
139
-        // if the child didn't specify a default button, use the credit card one
140
-        if ($this->_default_button_url === null) {
141
-            $this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods/pay-by-credit-card.png';
142
-        }
143
-    }
144
-
145
-
146
-    /**
147
-     * @param boolean $has_billing_form
148
-     */
149
-    public function set_has_billing_form($has_billing_form)
150
-    {
151
-        $this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN);
152
-    }
153
-
154
-
155
-    /**
156
-     * sets the file_folder property
157
-     */
158
-    protected function _set_file_folder()
159
-    {
160
-        $reflector = new ReflectionClass(get_class($this));
161
-        $fn = $reflector->getFileName();
162
-        $this->_file_folder = dirname($fn) . '/';
163
-    }
164
-
165
-
166
-    /**
167
-     * sets the file URL with a trailing slash for this PMT
168
-     */
169
-    protected function _set_file_url()
170
-    {
171
-        $plugins_dir_fixed = str_replace('\\', '/', WP_PLUGIN_DIR);
172
-        $file_folder_fixed = str_replace('\\', '/', $this->file_folder());
173
-        $file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed);
174
-        $this->_file_url = set_url_scheme($file_path);
175
-    }
176
-
177
-    /**
178
-     * Gets the default description on all payment methods of this type
179
-     *
180
-     * @return string
181
-     */
182
-    public function default_description()
183
-    {
184
-        return $this->_default_description;
185
-    }
186
-
187
-
188
-    /**
189
-     * Returns the folder containing the PMT child class, with a trailing slash
190
-     *
191
-     * @return string
192
-     */
193
-    public function file_folder()
194
-    {
195
-        if (! $this->_file_folder) {
196
-            $this->_set_file_folder();
197
-        }
198
-        return $this->_file_folder;
199
-    }
200
-
201
-
202
-    /**
203
-     * @return string
204
-     */
205
-    public function file_url()
206
-    {
207
-        if (! $this->_file_url) {
208
-            $this->_set_file_url();
209
-        }
210
-        return $this->_file_url;
211
-    }
212
-
213
-
214
-    /**
215
-     * Sets the payment method instance this payment method type is for.
216
-     * Its important teh payment method instance is set before
217
-     *
218
-     * @param EE_Payment_Method $payment_method_instance
219
-     */
220
-    public function set_instance($payment_method_instance)
221
-    {
222
-        $this->_pm_instance = $payment_method_instance;
223
-        // if they have already requested the settings form, make sure its
224
-        // data matches this model object
225
-        if ($this->_settings_form) {
226
-            $this->settings_form()->populate_model_obj($payment_method_instance);
227
-        }
228
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
229
-            $this->_gateway->set_settings($payment_method_instance->settings_array());
230
-        }
231
-    }
232
-
233
-
234
-    /**
235
-     * Gets teh form for displaying to admins where they setup the payment method
236
-     *
237
-     * @return EE_Payment_Method_Form
238
-     */
239
-    public function settings_form()
240
-    {
241
-        if (! $this->_settings_form) {
242
-            $this->_settings_form = $this->generate_new_settings_form();
243
-            $this->_settings_form->set_payment_method_type($this);
244
-            // if we have already assigned a model object to this pmt, make
245
-            // sure its reflected in teh form we just generated
246
-            if ($this->_pm_instance) {
247
-                $this->_settings_form->populate_model_obj($this->_pm_instance);
248
-            }
249
-        }
250
-        return $this->_settings_form;
251
-    }
252
-
253
-
254
-    /**
255
-     * Gets the form for all the settings related to this payment method type
256
-     *
257
-     * @return EE_Payment_Method_Form
258
-     */
259
-    abstract public function generate_new_settings_form();
260
-
261
-
262
-    /**
263
-     * Sets the form for settings. This may be useful if we have already received
264
-     * a form submission and have form data it in, and want to use it anytime we're showing
265
-     * this payment method type's settings form later in the request
266
-     *
267
-     * @param EE_Payment_Method_Form $form
268
-     */
269
-    public function set_settings_form($form)
270
-    {
271
-        $this->_settings_form = $form;
272
-    }
273
-
274
-
275
-    /**
276
-     * @return boolean
277
-     */
278
-    public function has_billing_form()
279
-    {
280
-        return $this->_has_billing_form;
281
-    }
282
-
283
-
284
-    /**
285
-     * Gets the form for displaying to attendees where they can enter their billing info
286
-     * which will be sent to teh gateway (can be null)
287
-     *
288
-     * @param \EE_Transaction $transaction
289
-     * @param array           $extra_args
290
-     * @return \EE_Billing_Attendee_Info_Form|\EE_Billing_Info_Form|null
291
-     */
292
-    public function billing_form(EE_Transaction $transaction = null, $extra_args = array())
293
-    {
294
-        // has billing form already been regenerated ? or overwrite cache?
295
-        if (! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) {
296
-            $this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
297
-        }
298
-        // if we know who the attendee is, and this is a billing form
299
-        // that uses attendee info, populate it
300
-        if (
301
-            apply_filters(
302
-                'FHEE__populate_billing_form_fields_from_attendee',
303
-                ($this->_billing_form instanceof EE_Billing_Attendee_Info_Form
304
-                && $transaction instanceof EE_Transaction
305
-                && $transaction->primary_registration() instanceof EE_Registration
306
-                && $transaction->primary_registration()->attendee() instanceof EE_Attendee
307
-                ),
308
-                $this->_billing_form,
309
-                $transaction
310
-            )
311
-        ) {
312
-            $this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee());
313
-        }
314
-        return $this->_billing_form;
315
-    }
316
-
317
-
318
-    /**
319
-     * Creates the billing form for this payment method type
320
-     *
321
-     * @param \EE_Transaction $transaction
322
-     * @return \EE_Billing_Info_Form
323
-     */
324
-    abstract public function generate_new_billing_form(EE_Transaction $transaction = null);
325
-
326
-
327
-    /**
328
-     * apply_billing_form_debug_settings
329
-     * applies debug data to the form
330
-     *
331
-     * @param \EE_Billing_Info_Form $billing_form
332
-     * @return \EE_Billing_Info_Form
333
-     */
334
-    public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
335
-    {
336
-        return $billing_form;
337
-    }
338
-
339
-
340
-    /**
341
-     * Sets the billing form for this payment method type. You may want to use this
342
-     * if you have form
343
-     *
344
-     * @param EE_Payment_Method $form
345
-     */
346
-    public function set_billing_form($form)
347
-    {
348
-        $this->_billing_form = $form;
349
-    }
350
-
351
-
352
-    /**
353
-     * Returns whether or not this payment method requires HTTPS to be used
354
-     *
355
-     * @return boolean
356
-     */
357
-    public function requires_https()
358
-    {
359
-        return $this->_requires_https;
360
-    }
361
-
362
-
363
-    /**
364
-     *
365
-     * @param EE_Transaction       $transaction
366
-     * @param float                $amount
367
-     * @param EE_Billing_Info_Form $billing_info
368
-     * @param string               $return_url
369
-     * @param string               $fail_url
370
-     * @param string               $method
371
-     * @param bool                 $by_admin
372
-     * @return EE_Payment
373
-     * @throws EE_Error
374
-     */
375
-    public function process_payment(
376
-        EE_Transaction $transaction,
377
-        $amount = null,
378
-        $billing_info = null,
379
-        $return_url = null,
380
-        $fail_url = '',
381
-        $method = 'CART',
382
-        $by_admin = false
383
-    ) {
384
-        // @todo: add surcharge for the payment method, if any
385
-        if ($this->_gateway) {
386
-            // there is a gateway, so we're going to make a payment object
387
-            // but wait! do they already have a payment in progress that we thought was failed?
388
-            $duplicate_properties = array(
389
-                'STS_ID'               => EEM_Payment::status_id_failed,
390
-                'TXN_ID'               => $transaction->ID(),
391
-                'PMD_ID'               => $this->_pm_instance->ID(),
392
-                'PAY_source'           => $method,
393
-                'PAY_amount'           => $amount !== null ? $amount : $transaction->remaining(),
394
-                'PAY_gateway_response' => null,
395
-            );
396
-            $payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
397
-            // if we didn't already have a payment in progress for the same thing,
398
-            // then we actually want to make a new payment
399
-            if (! $payment instanceof EE_Payment) {
400
-                $payment = EE_Payment::new_instance(
401
-                    array_merge(
402
-                        $duplicate_properties,
403
-                        array(
404
-                            'PAY_timestamp'       => time(),
405
-                            'PAY_txn_id_chq_nmbr' => null,
406
-                            'PAY_po_number'       => null,
407
-                            'PAY_extra_accntng'   => null,
408
-                            'PAY_details'         => null,
409
-                        )
410
-                    )
411
-                );
412
-            }
413
-            // make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
414
-            $payment->save();
415
-            $billing_values = $this->_get_billing_values_from_form($billing_info);
416
-
417
-            //  Offsite Gateway
418
-            if ($this->_gateway instanceof EE_Offsite_Gateway) {
419
-                $payment = $this->_gateway->set_redirection_info(
420
-                    $payment,
421
-                    $billing_values,
422
-                    $return_url,
423
-                    EE_Config::instance()->core->txn_page_url(
424
-                        array(
425
-                            'e_reg_url_link'    => $transaction->primary_registration()->reg_url_link(),
426
-                            'ee_payment_method' => $this->_pm_instance->slug(),
427
-                        )
428
-                    ),
429
-                    $fail_url
430
-                );
431
-                $payment->save();
432
-                //  Onsite Gateway
433
-            } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
434
-                $payment = $this->_gateway->do_direct_payment($payment, $billing_values);
435
-                $payment->save();
436
-            } else {
437
-                throw new EE_Error(
438
-                    sprintf(
439
-                        esc_html__(
440
-                            'Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)',
441
-                            'event_espresso'
442
-                        ),
443
-                        get_class($this),
444
-                        gettype($this->_gateway)
445
-                    )
446
-                );
447
-            }
448
-        } else {
449
-            // no gateway provided
450
-            // there is no payment. Must be an offline gateway
451
-            // create a payment object anyways, but dont save it
452
-            $payment = EE_Payment::new_instance(
453
-                array(
454
-                    'STS_ID'        => EEM_Payment::status_id_pending,
455
-                    'TXN_ID'        => $transaction->ID(),
456
-                    'PMD_ID'        => $transaction->payment_method_ID(),
457
-                    'PAY_amount'    => 0.00,
458
-                    'PAY_timestamp' => time(),
459
-                )
460
-            );
461
-        }
462
-
463
-        // if there is billing info, clean it and save it now
464
-        if ($billing_info instanceof EE_Billing_Attendee_Info_Form) {
465
-            $this->_save_billing_info_to_attendee($billing_info, $transaction);
466
-        }
467
-
468
-        return $payment;
469
-    }
470
-
471
-    /**
472
-     * Gets the values we want to pass onto the gateway. Normally these
473
-     * are just the 'pretty' values, but there may be times the data may need
474
-     * a  little massaging. Proper subsections will become arrays of inputs
475
-     *
476
-     * @param EE_Billing_Info_Form $billing_form
477
-     * @return array
478
-     */
479
-    protected function _get_billing_values_from_form($billing_form)
480
-    {
481
-        if ($billing_form instanceof EE_Form_Section_Proper) {
482
-            return $billing_form->input_pretty_values(true);
483
-        } else {
484
-            return null;
485
-        }
486
-    }
487
-
488
-
489
-    /**
490
-     * Handles an instant payment notification when the transaction is known (by default).
491
-     *
492
-     * @param array          $req_data
493
-     * @param EE_Transaction $transaction
494
-     * @return EE_Payment
495
-     * @throws EE_Error
496
-     */
497
-    public function handle_ipn($req_data, $transaction)
498
-    {
499
-        $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
500
-        if (! $this->_gateway instanceof EE_Offsite_Gateway) {
501
-            throw new EE_Error(
502
-                sprintf(
503
-                    esc_html__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"),
504
-                    print_r($this->_gateway, true)
505
-                )
506
-            );
507
-        }
508
-        $payment = $this->_gateway->handle_payment_update($req_data, $transaction);
509
-        return $payment;
510
-    }
511
-
512
-
513
-    /**
514
-     * Saves the billing info onto the attendee of the primary registrant on this transaction, and
515
-     * cleans it first.
516
-     *
517
-     * @param EE_Billing_Attendee_Info_Form $billing_form
518
-     * @param EE_Transaction                $transaction
519
-     * @return boolean success
520
-     */
521
-    protected function _save_billing_info_to_attendee($billing_form, $transaction)
522
-    {
523
-        if (! $transaction || ! $transaction instanceof EE_Transaction) {
524
-            EE_Error::add_error(
525
-                esc_html__("Cannot save billing info because no transaction was specified", "event_espresso"),
526
-                __FILE__,
527
-                __FUNCTION__,
528
-                __LINE__
529
-            );
530
-            return false;
531
-        }
532
-        $primary_reg = $transaction->primary_registration();
533
-        if (! $primary_reg) {
534
-            EE_Error::add_error(
535
-                esc_html__("Cannot save billing info because the transaction has no primary registration", "event_espresso"),
536
-                __FILE__,
537
-                __FUNCTION__,
538
-                __LINE__
539
-            );
540
-            return false;
541
-        }
542
-        $attendee = $primary_reg->attendee();
543
-        if (! $attendee) {
544
-            EE_Error::add_error(
545
-                esc_html__(
546
-                    "Cannot save billing info because the transaction's primary registration has no attendee!",
547
-                    "event_espresso"
548
-                ),
549
-                __FILE__,
550
-                __FUNCTION__,
551
-                __LINE__
552
-            );
553
-            return false;
554
-        }
555
-        return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method());
556
-    }
557
-
558
-
559
-    /**
560
-     * Gets the payment this IPN is for. Children may often want to
561
-     * override this to inspect the request
562
-     *
563
-     * @param EE_Transaction $transaction
564
-     * @param array          $req_data
565
-     * @return EE_Payment
566
-     */
567
-    protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array())
568
-    {
569
-        return $transaction->last_payment();
570
-    }
571
-
572
-
573
-    /**
574
-     * In case generic code cannot provide the payment processor with a specific payment method
575
-     * and transaction, it will try calling this method on each activate payment method.
576
-     * If the payment method is able to identify the request as being for it, it should fetch
577
-     * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot
578
-     * handle the IPN
579
-     *
580
-     * @param array $req_data
581
-     * @return EE_Payment only if this payment method can find the info its needs from $req_data
582
-     * and identifies the IPN as being for this payment method (not just fo ra payment method of this type)
583
-     * @throws EE_Error
584
-     */
585
-    public function handle_unclaimed_ipn($req_data = array())
586
-    {
587
-        throw new EE_Error(
588
-            sprintf(esc_html__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this))
589
-        );
590
-    }
591
-
592
-
593
-    /**
594
-     * Logic to be accomplished when the payment attempt is complete.
595
-     * Most payment methods don't need to do anything at this point; but some, like Mijireh, do.
596
-     * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from
597
-     * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status
598
-     * of the payment). Fed a transaction because it's always assumed to be the last payment that
599
-     * we're dealing with. Returns that last payment (if there is one)
600
-     *
601
-     * @param EE_Transaction $transaction
602
-     * @return EE_Payment
603
-     */
604
-    public function finalize_payment_for($transaction)
605
-    {
606
-        return $transaction->last_payment();
607
-    }
608
-
609
-
610
-    /**
611
-     * Whether or not this payment method's gateway supports sending refund requests
612
-     *
613
-     * @return boolean
614
-     */
615
-    public function supports_sending_refunds()
616
-    {
617
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
618
-            return $this->_gateway->supports_sending_refunds();
619
-        } else {
620
-            return false;
621
-        }
622
-    }
623
-
624
-
625
-    /**
626
-     *
627
-     * @param EE_Payment $payment
628
-     * @param array      $refund_info
629
-     * @throws EE_Error
630
-     * @return EE_Payment
631
-     */
632
-    public function process_refund(EE_Payment $payment, $refund_info = array())
633
-    {
634
-        if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
635
-            return $this->_gateway->do_direct_refund($payment, $refund_info);
636
-        } else {
637
-            throw new EE_Error(
638
-                sprintf(
639
-                    esc_html__('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'),
640
-                    get_class($this)
641
-                )
642
-            );
643
-        }
644
-    }
645
-
646
-
647
-    /**
648
-     * Returns one the class's constants onsite,offsite, or offline, depending on this
649
-     * payment method's gateway.
650
-     *
651
-     * @return string
652
-     * @throws EE_Error
653
-     */
654
-    public function payment_occurs()
655
-    {
656
-        if (! $this->_gateway) {
657
-            return EE_PMT_Base::offline;
658
-        } elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
659
-            return EE_PMT_Base::onsite;
660
-        } elseif ($this->_gateway instanceof EE_Offsite_Gateway) {
661
-            return EE_PMT_Base::offsite;
662
-        } else {
663
-            throw new EE_Error(
664
-                sprintf(
665
-                    esc_html__(
666
-                        "Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those",
667
-                        "event_espresso"
668
-                    ),
669
-                    get_class($this)
670
-                )
671
-            );
672
-        }
673
-    }
674
-
675
-
676
-    /**
677
-     * For adding any html output ab ove the payment overview.
678
-     * Many gateways won't want ot display anything, so this function just returns an empty string.
679
-     * Other gateways may want to override this, such as offline gateways.
680
-     *
681
-     * @param EE_Payment $payment
682
-     * @return string
683
-     */
684
-    public function payment_overview_content(EE_Payment $payment)
685
-    {
686
-        return EEH_Template::display_template(
687
-            EE_LIBRARIES . 'payment_methods/templates/payment_details_content.template.php',
688
-            array('payment_method' => $this->_pm_instance, 'payment' => $payment),
689
-            true
690
-        );
691
-    }
692
-
693
-
694
-    /**
695
-     * @return array where keys are the help tab name,
696
-     * values are: array {
697
-     * @type string $title         i18n name for the help tab
698
-     * @type string $filename      name of the file located in ./help_tabs/ (ie, in a folder next to this file)
699
-     * @type array  $template_args any arguments you want passed to the template file while rendering.
700
-     *                Keys will be variable names and values with be their values.
701
-     */
702
-    public function help_tabs_config()
703
-    {
704
-        return array();
705
-    }
706
-
707
-
708
-    /**
709
-     * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into
710
-     * the payment method's table's PMT_type column)
711
-     *
712
-     * @return string
713
-     */
714
-    public function system_name()
715
-    {
716
-        $classname = get_class($this);
717
-        return str_replace("EE_PMT_", '', $classname);
718
-    }
719
-
720
-
721
-    /**
722
-     * A pretty i18n version of the PMT name. Often the same as the "pretty_name", but you can change it by overriding
723
-     * this method.
724
-     * @return string
725
-     */
726
-    public function defaultFrontendName()
727
-    {
728
-        return $this->pretty_name();
729
-    }
730
-
731
-
732
-    /**
733
-     * A pretty i18n version of the PMT name
734
-     *
735
-     * @return string
736
-     */
737
-    public function pretty_name()
738
-    {
739
-        return $this->_pretty_name;
740
-    }
741
-
742
-
743
-    /**
744
-     * Gets the default absolute URL to the payment method type's button
745
-     *
746
-     * @return string
747
-     */
748
-    public function default_button_url()
749
-    {
750
-        return $this->_default_button_url;
751
-    }
752
-
753
-
754
-    /**
755
-     * Gets the gateway used by this payment method (if any)
756
-     *
757
-     * @return EE_Gateway
758
-     */
759
-    public function get_gateway()
760
-    {
761
-        return $this->_gateway;
762
-    }
763
-
764
-
765
-    /**
766
-     * @return string html for the link to a help tab
767
-     */
768
-    public function get_help_tab_link()
769
-    {
770
-        return EEH_Template::get_help_tab_link(
771
-            $this->get_help_tab_name(),
772
-            'espresso_payment_settings',
773
-            'default'
774
-        );
775
-    }
776
-
777
-
778
-    /**
779
-     * Returns the name of the help tab for this PMT
780
-     *
781
-     * @return string
782
-     */
783
-    public function get_help_tab_name()
784
-    {
785
-        return 'ee_' . strtolower($this->system_name()) . '_help_tab';
786
-    }
787
-
788
-    /**
789
-     * The name of the wp capability that should be associated with the usage of
790
-     * this PMT by an admin
791
-     *
792
-     * @return string
793
-     */
794
-    public function cap_name()
795
-    {
796
-        return 'ee_payment_method_' . strtolower($this->system_name());
797
-    }
798
-
799
-    /**
800
-     * Called by client code to tell the gateway that if it wants to change
801
-     * the transaction or line items or registrations related to teh payment it already
802
-     * processed (we think, but possibly not) that now's the time to do it.
803
-     * It is expected that gateways will store any info they need for this on the PAY_details,
804
-     * or maybe an extra meta value
805
-     *
806
-     * @param EE_Payment $payment
807
-     * @return void
808
-     */
809
-    public function update_txn_based_on_payment($payment)
810
-    {
811
-        if ($this->_gateway instanceof EE_Gateway) {
812
-            $this->_gateway->update_txn_based_on_payment($payment);
813
-        }
814
-    }
815
-
816
-    /**
817
-     * Returns a string of HTML describing this payment method type for an admin,
818
-     * primarily intended for them to read before activating it.
819
-     * The easiest way to set this is to create a folder 'templates' alongside
820
-     * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php".
821
-     * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php",
822
-     * then you'd create a file named "templates" in the same folder as it, and name the file
823
-     * "foo_bar_intro.template.php", and its content will be returned by this method
824
-     *
825
-     * @return string
826
-     */
827
-    public function introductory_html()
828
-    {
829
-        return EEH_Template::locate_template(
830
-            $this->file_folder() . 'templates/' . strtolower($this->system_name()) . '_intro.template.php',
831
-            array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance)
832
-        );
833
-    }
24
+	const onsite = 'on-site';
25
+	const offsite = 'off-site';
26
+	const offline = 'off-line';
27
+
28
+	/**
29
+	 * @var EE_Payment_Method
30
+	 */
31
+	protected $_pm_instance = null;
32
+
33
+	/**
34
+	 * @var boolean
35
+	 */
36
+	protected $_requires_https = false;
37
+
38
+	/**
39
+	 * @var boolean
40
+	 */
41
+	protected $_has_billing_form;
42
+
43
+	/**
44
+	 * @var EE_Gateway
45
+	 */
46
+	protected $_gateway = null;
47
+
48
+	/**
49
+	 * @var EE_Payment_Method_Form
50
+	 */
51
+	protected $_settings_form = null;
52
+
53
+	/**
54
+	 * @var EE_Form_Section_Proper
55
+	 */
56
+	protected $_billing_form = null;
57
+
58
+	/**
59
+	 * @var boolean
60
+	 */
61
+	protected $_cache_billing_form = true;
62
+
63
+	/**
64
+	 * String of the absolute path to the folder containing this file, with a trailing slash.
65
+	 * eg '/public_html/wp-site/wp-content/plugins/event-espresso/payment_methods/Invoice/'
66
+	 *
67
+	 * @var string
68
+	 */
69
+	protected $_file_folder = null;
70
+
71
+	/**
72
+	 * String to the absolute URL to this file (useful for getting its web-accessible resources
73
+	 * like images, js, or css)
74
+	 *
75
+	 * @var string
76
+	 */
77
+	protected $_file_url = null;
78
+
79
+	/**
80
+	 * Pretty name for the payment method
81
+	 *
82
+	 * @var string
83
+	 */
84
+	protected $_pretty_name = null;
85
+
86
+	/**
87
+	 *
88
+	 * @var string
89
+	 */
90
+	protected $_default_button_url = null;
91
+
92
+	/**
93
+	 *
94
+	 * @var string
95
+	 */
96
+	protected $_default_description = null;
97
+
98
+
99
+	/**
100
+	 *
101
+	 * @param EE_Payment_Method $pm_instance
102
+	 * @throws EE_Error
103
+	 * @return EE_PMT_Base
104
+	 */
105
+	public function __construct($pm_instance = null)
106
+	{
107
+		if ($pm_instance instanceof EE_Payment_Method) {
108
+			$this->set_instance($pm_instance);
109
+		}
110
+		if ($this->_gateway) {
111
+			$this->_gateway->set_payment_model(EEM_Payment::instance());
112
+			$this->_gateway->set_payment_log(EEM_Change_Log::instance());
113
+			$this->_gateway->set_template_helper(new EEH_Template());
114
+			$this->_gateway->set_line_item_helper(new EEH_Line_Item());
115
+			$this->_gateway->set_money_helper(new EEH_Money());
116
+			$this->_gateway->set_gateway_data_formatter(new GatewayDataFormatter());
117
+			$this->_gateway->set_unsupported_character_remover(new AsciiOnly());
118
+			do_action('AHEE__EE_PMT_Base___construct__done_initializing_gateway_class', $this, $this->_gateway);
119
+		}
120
+		if (! isset($this->_has_billing_form)) {
121
+			// by default, On Site gateways have a billing form
122
+			if ($this->payment_occurs() == EE_PMT_Base::onsite) {
123
+				$this->set_has_billing_form(true);
124
+			} else {
125
+				$this->set_has_billing_form(false);
126
+			}
127
+		}
128
+
129
+		if (! $this->_pretty_name) {
130
+			throw new EE_Error(
131
+				sprintf(
132
+					esc_html__(
133
+						"You must set the pretty name for the Payment Method Type in the constructor (_pretty_name), and please make it internationalized",
134
+						"event_espresso"
135
+					)
136
+				)
137
+			);
138
+		}
139
+		// if the child didn't specify a default button, use the credit card one
140
+		if ($this->_default_button_url === null) {
141
+			$this->_default_button_url = EE_PLUGIN_DIR_URL . 'payment_methods/pay-by-credit-card.png';
142
+		}
143
+	}
144
+
145
+
146
+	/**
147
+	 * @param boolean $has_billing_form
148
+	 */
149
+	public function set_has_billing_form($has_billing_form)
150
+	{
151
+		$this->_has_billing_form = filter_var($has_billing_form, FILTER_VALIDATE_BOOLEAN);
152
+	}
153
+
154
+
155
+	/**
156
+	 * sets the file_folder property
157
+	 */
158
+	protected function _set_file_folder()
159
+	{
160
+		$reflector = new ReflectionClass(get_class($this));
161
+		$fn = $reflector->getFileName();
162
+		$this->_file_folder = dirname($fn) . '/';
163
+	}
164
+
165
+
166
+	/**
167
+	 * sets the file URL with a trailing slash for this PMT
168
+	 */
169
+	protected function _set_file_url()
170
+	{
171
+		$plugins_dir_fixed = str_replace('\\', '/', WP_PLUGIN_DIR);
172
+		$file_folder_fixed = str_replace('\\', '/', $this->file_folder());
173
+		$file_path = str_replace($plugins_dir_fixed, WP_PLUGIN_URL, $file_folder_fixed);
174
+		$this->_file_url = set_url_scheme($file_path);
175
+	}
176
+
177
+	/**
178
+	 * Gets the default description on all payment methods of this type
179
+	 *
180
+	 * @return string
181
+	 */
182
+	public function default_description()
183
+	{
184
+		return $this->_default_description;
185
+	}
186
+
187
+
188
+	/**
189
+	 * Returns the folder containing the PMT child class, with a trailing slash
190
+	 *
191
+	 * @return string
192
+	 */
193
+	public function file_folder()
194
+	{
195
+		if (! $this->_file_folder) {
196
+			$this->_set_file_folder();
197
+		}
198
+		return $this->_file_folder;
199
+	}
200
+
201
+
202
+	/**
203
+	 * @return string
204
+	 */
205
+	public function file_url()
206
+	{
207
+		if (! $this->_file_url) {
208
+			$this->_set_file_url();
209
+		}
210
+		return $this->_file_url;
211
+	}
212
+
213
+
214
+	/**
215
+	 * Sets the payment method instance this payment method type is for.
216
+	 * Its important teh payment method instance is set before
217
+	 *
218
+	 * @param EE_Payment_Method $payment_method_instance
219
+	 */
220
+	public function set_instance($payment_method_instance)
221
+	{
222
+		$this->_pm_instance = $payment_method_instance;
223
+		// if they have already requested the settings form, make sure its
224
+		// data matches this model object
225
+		if ($this->_settings_form) {
226
+			$this->settings_form()->populate_model_obj($payment_method_instance);
227
+		}
228
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
229
+			$this->_gateway->set_settings($payment_method_instance->settings_array());
230
+		}
231
+	}
232
+
233
+
234
+	/**
235
+	 * Gets teh form for displaying to admins where they setup the payment method
236
+	 *
237
+	 * @return EE_Payment_Method_Form
238
+	 */
239
+	public function settings_form()
240
+	{
241
+		if (! $this->_settings_form) {
242
+			$this->_settings_form = $this->generate_new_settings_form();
243
+			$this->_settings_form->set_payment_method_type($this);
244
+			// if we have already assigned a model object to this pmt, make
245
+			// sure its reflected in teh form we just generated
246
+			if ($this->_pm_instance) {
247
+				$this->_settings_form->populate_model_obj($this->_pm_instance);
248
+			}
249
+		}
250
+		return $this->_settings_form;
251
+	}
252
+
253
+
254
+	/**
255
+	 * Gets the form for all the settings related to this payment method type
256
+	 *
257
+	 * @return EE_Payment_Method_Form
258
+	 */
259
+	abstract public function generate_new_settings_form();
260
+
261
+
262
+	/**
263
+	 * Sets the form for settings. This may be useful if we have already received
264
+	 * a form submission and have form data it in, and want to use it anytime we're showing
265
+	 * this payment method type's settings form later in the request
266
+	 *
267
+	 * @param EE_Payment_Method_Form $form
268
+	 */
269
+	public function set_settings_form($form)
270
+	{
271
+		$this->_settings_form = $form;
272
+	}
273
+
274
+
275
+	/**
276
+	 * @return boolean
277
+	 */
278
+	public function has_billing_form()
279
+	{
280
+		return $this->_has_billing_form;
281
+	}
282
+
283
+
284
+	/**
285
+	 * Gets the form for displaying to attendees where they can enter their billing info
286
+	 * which will be sent to teh gateway (can be null)
287
+	 *
288
+	 * @param \EE_Transaction $transaction
289
+	 * @param array           $extra_args
290
+	 * @return \EE_Billing_Attendee_Info_Form|\EE_Billing_Info_Form|null
291
+	 */
292
+	public function billing_form(EE_Transaction $transaction = null, $extra_args = array())
293
+	{
294
+		// has billing form already been regenerated ? or overwrite cache?
295
+		if (! $this->_billing_form instanceof EE_Billing_Info_Form || ! $this->_cache_billing_form) {
296
+			$this->_billing_form = $this->generate_new_billing_form($transaction, $extra_args);
297
+		}
298
+		// if we know who the attendee is, and this is a billing form
299
+		// that uses attendee info, populate it
300
+		if (
301
+			apply_filters(
302
+				'FHEE__populate_billing_form_fields_from_attendee',
303
+				($this->_billing_form instanceof EE_Billing_Attendee_Info_Form
304
+				&& $transaction instanceof EE_Transaction
305
+				&& $transaction->primary_registration() instanceof EE_Registration
306
+				&& $transaction->primary_registration()->attendee() instanceof EE_Attendee
307
+				),
308
+				$this->_billing_form,
309
+				$transaction
310
+			)
311
+		) {
312
+			$this->_billing_form->populate_from_attendee($transaction->primary_registration()->attendee());
313
+		}
314
+		return $this->_billing_form;
315
+	}
316
+
317
+
318
+	/**
319
+	 * Creates the billing form for this payment method type
320
+	 *
321
+	 * @param \EE_Transaction $transaction
322
+	 * @return \EE_Billing_Info_Form
323
+	 */
324
+	abstract public function generate_new_billing_form(EE_Transaction $transaction = null);
325
+
326
+
327
+	/**
328
+	 * apply_billing_form_debug_settings
329
+	 * applies debug data to the form
330
+	 *
331
+	 * @param \EE_Billing_Info_Form $billing_form
332
+	 * @return \EE_Billing_Info_Form
333
+	 */
334
+	public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
335
+	{
336
+		return $billing_form;
337
+	}
338
+
339
+
340
+	/**
341
+	 * Sets the billing form for this payment method type. You may want to use this
342
+	 * if you have form
343
+	 *
344
+	 * @param EE_Payment_Method $form
345
+	 */
346
+	public function set_billing_form($form)
347
+	{
348
+		$this->_billing_form = $form;
349
+	}
350
+
351
+
352
+	/**
353
+	 * Returns whether or not this payment method requires HTTPS to be used
354
+	 *
355
+	 * @return boolean
356
+	 */
357
+	public function requires_https()
358
+	{
359
+		return $this->_requires_https;
360
+	}
361
+
362
+
363
+	/**
364
+	 *
365
+	 * @param EE_Transaction       $transaction
366
+	 * @param float                $amount
367
+	 * @param EE_Billing_Info_Form $billing_info
368
+	 * @param string               $return_url
369
+	 * @param string               $fail_url
370
+	 * @param string               $method
371
+	 * @param bool                 $by_admin
372
+	 * @return EE_Payment
373
+	 * @throws EE_Error
374
+	 */
375
+	public function process_payment(
376
+		EE_Transaction $transaction,
377
+		$amount = null,
378
+		$billing_info = null,
379
+		$return_url = null,
380
+		$fail_url = '',
381
+		$method = 'CART',
382
+		$by_admin = false
383
+	) {
384
+		// @todo: add surcharge for the payment method, if any
385
+		if ($this->_gateway) {
386
+			// there is a gateway, so we're going to make a payment object
387
+			// but wait! do they already have a payment in progress that we thought was failed?
388
+			$duplicate_properties = array(
389
+				'STS_ID'               => EEM_Payment::status_id_failed,
390
+				'TXN_ID'               => $transaction->ID(),
391
+				'PMD_ID'               => $this->_pm_instance->ID(),
392
+				'PAY_source'           => $method,
393
+				'PAY_amount'           => $amount !== null ? $amount : $transaction->remaining(),
394
+				'PAY_gateway_response' => null,
395
+			);
396
+			$payment = EEM_Payment::instance()->get_one(array($duplicate_properties));
397
+			// if we didn't already have a payment in progress for the same thing,
398
+			// then we actually want to make a new payment
399
+			if (! $payment instanceof EE_Payment) {
400
+				$payment = EE_Payment::new_instance(
401
+					array_merge(
402
+						$duplicate_properties,
403
+						array(
404
+							'PAY_timestamp'       => time(),
405
+							'PAY_txn_id_chq_nmbr' => null,
406
+							'PAY_po_number'       => null,
407
+							'PAY_extra_accntng'   => null,
408
+							'PAY_details'         => null,
409
+						)
410
+					)
411
+				);
412
+			}
413
+			// make sure the payment has been saved to show we started it, and so it has an ID should the gateway try to log it
414
+			$payment->save();
415
+			$billing_values = $this->_get_billing_values_from_form($billing_info);
416
+
417
+			//  Offsite Gateway
418
+			if ($this->_gateway instanceof EE_Offsite_Gateway) {
419
+				$payment = $this->_gateway->set_redirection_info(
420
+					$payment,
421
+					$billing_values,
422
+					$return_url,
423
+					EE_Config::instance()->core->txn_page_url(
424
+						array(
425
+							'e_reg_url_link'    => $transaction->primary_registration()->reg_url_link(),
426
+							'ee_payment_method' => $this->_pm_instance->slug(),
427
+						)
428
+					),
429
+					$fail_url
430
+				);
431
+				$payment->save();
432
+				//  Onsite Gateway
433
+			} elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
434
+				$payment = $this->_gateway->do_direct_payment($payment, $billing_values);
435
+				$payment->save();
436
+			} else {
437
+				throw new EE_Error(
438
+					sprintf(
439
+						esc_html__(
440
+							'Gateway for payment method type "%s" is "%s", not a subclass of either EE_Offsite_Gateway or EE_Onsite_Gateway, or null (to indicate NO gateway)',
441
+							'event_espresso'
442
+						),
443
+						get_class($this),
444
+						gettype($this->_gateway)
445
+					)
446
+				);
447
+			}
448
+		} else {
449
+			// no gateway provided
450
+			// there is no payment. Must be an offline gateway
451
+			// create a payment object anyways, but dont save it
452
+			$payment = EE_Payment::new_instance(
453
+				array(
454
+					'STS_ID'        => EEM_Payment::status_id_pending,
455
+					'TXN_ID'        => $transaction->ID(),
456
+					'PMD_ID'        => $transaction->payment_method_ID(),
457
+					'PAY_amount'    => 0.00,
458
+					'PAY_timestamp' => time(),
459
+				)
460
+			);
461
+		}
462
+
463
+		// if there is billing info, clean it and save it now
464
+		if ($billing_info instanceof EE_Billing_Attendee_Info_Form) {
465
+			$this->_save_billing_info_to_attendee($billing_info, $transaction);
466
+		}
467
+
468
+		return $payment;
469
+	}
470
+
471
+	/**
472
+	 * Gets the values we want to pass onto the gateway. Normally these
473
+	 * are just the 'pretty' values, but there may be times the data may need
474
+	 * a  little massaging. Proper subsections will become arrays of inputs
475
+	 *
476
+	 * @param EE_Billing_Info_Form $billing_form
477
+	 * @return array
478
+	 */
479
+	protected function _get_billing_values_from_form($billing_form)
480
+	{
481
+		if ($billing_form instanceof EE_Form_Section_Proper) {
482
+			return $billing_form->input_pretty_values(true);
483
+		} else {
484
+			return null;
485
+		}
486
+	}
487
+
488
+
489
+	/**
490
+	 * Handles an instant payment notification when the transaction is known (by default).
491
+	 *
492
+	 * @param array          $req_data
493
+	 * @param EE_Transaction $transaction
494
+	 * @return EE_Payment
495
+	 * @throws EE_Error
496
+	 */
497
+	public function handle_ipn($req_data, $transaction)
498
+	{
499
+		$transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
500
+		if (! $this->_gateway instanceof EE_Offsite_Gateway) {
501
+			throw new EE_Error(
502
+				sprintf(
503
+					esc_html__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"),
504
+					print_r($this->_gateway, true)
505
+				)
506
+			);
507
+		}
508
+		$payment = $this->_gateway->handle_payment_update($req_data, $transaction);
509
+		return $payment;
510
+	}
511
+
512
+
513
+	/**
514
+	 * Saves the billing info onto the attendee of the primary registrant on this transaction, and
515
+	 * cleans it first.
516
+	 *
517
+	 * @param EE_Billing_Attendee_Info_Form $billing_form
518
+	 * @param EE_Transaction                $transaction
519
+	 * @return boolean success
520
+	 */
521
+	protected function _save_billing_info_to_attendee($billing_form, $transaction)
522
+	{
523
+		if (! $transaction || ! $transaction instanceof EE_Transaction) {
524
+			EE_Error::add_error(
525
+				esc_html__("Cannot save billing info because no transaction was specified", "event_espresso"),
526
+				__FILE__,
527
+				__FUNCTION__,
528
+				__LINE__
529
+			);
530
+			return false;
531
+		}
532
+		$primary_reg = $transaction->primary_registration();
533
+		if (! $primary_reg) {
534
+			EE_Error::add_error(
535
+				esc_html__("Cannot save billing info because the transaction has no primary registration", "event_espresso"),
536
+				__FILE__,
537
+				__FUNCTION__,
538
+				__LINE__
539
+			);
540
+			return false;
541
+		}
542
+		$attendee = $primary_reg->attendee();
543
+		if (! $attendee) {
544
+			EE_Error::add_error(
545
+				esc_html__(
546
+					"Cannot save billing info because the transaction's primary registration has no attendee!",
547
+					"event_espresso"
548
+				),
549
+				__FILE__,
550
+				__FUNCTION__,
551
+				__LINE__
552
+			);
553
+			return false;
554
+		}
555
+		return $attendee->save_and_clean_billing_info_for_payment_method($billing_form, $transaction->payment_method());
556
+	}
557
+
558
+
559
+	/**
560
+	 * Gets the payment this IPN is for. Children may often want to
561
+	 * override this to inspect the request
562
+	 *
563
+	 * @param EE_Transaction $transaction
564
+	 * @param array          $req_data
565
+	 * @return EE_Payment
566
+	 */
567
+	protected function find_payment_for_ipn(EE_Transaction $transaction, $req_data = array())
568
+	{
569
+		return $transaction->last_payment();
570
+	}
571
+
572
+
573
+	/**
574
+	 * In case generic code cannot provide the payment processor with a specific payment method
575
+	 * and transaction, it will try calling this method on each activate payment method.
576
+	 * If the payment method is able to identify the request as being for it, it should fetch
577
+	 * the payment its for and return it. If not, it should throw an EE_Error to indicate it cannot
578
+	 * handle the IPN
579
+	 *
580
+	 * @param array $req_data
581
+	 * @return EE_Payment only if this payment method can find the info its needs from $req_data
582
+	 * and identifies the IPN as being for this payment method (not just fo ra payment method of this type)
583
+	 * @throws EE_Error
584
+	 */
585
+	public function handle_unclaimed_ipn($req_data = array())
586
+	{
587
+		throw new EE_Error(
588
+			sprintf(esc_html__("Payment Method '%s' cannot handle unclaimed IPNs", "event_espresso"), get_class($this))
589
+		);
590
+	}
591
+
592
+
593
+	/**
594
+	 * Logic to be accomplished when the payment attempt is complete.
595
+	 * Most payment methods don't need to do anything at this point; but some, like Mijireh, do.
596
+	 * (Mijireh is an offsite gateway which doesn't send an IPN. So when the user returns to EE from
597
+	 * mijireh, this method needs to be called so the Mijireh PM can ping Mijireh to know the status
598
+	 * of the payment). Fed a transaction because it's always assumed to be the last payment that
599
+	 * we're dealing with. Returns that last payment (if there is one)
600
+	 *
601
+	 * @param EE_Transaction $transaction
602
+	 * @return EE_Payment
603
+	 */
604
+	public function finalize_payment_for($transaction)
605
+	{
606
+		return $transaction->last_payment();
607
+	}
608
+
609
+
610
+	/**
611
+	 * Whether or not this payment method's gateway supports sending refund requests
612
+	 *
613
+	 * @return boolean
614
+	 */
615
+	public function supports_sending_refunds()
616
+	{
617
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
618
+			return $this->_gateway->supports_sending_refunds();
619
+		} else {
620
+			return false;
621
+		}
622
+	}
623
+
624
+
625
+	/**
626
+	 *
627
+	 * @param EE_Payment $payment
628
+	 * @param array      $refund_info
629
+	 * @throws EE_Error
630
+	 * @return EE_Payment
631
+	 */
632
+	public function process_refund(EE_Payment $payment, $refund_info = array())
633
+	{
634
+		if ($this->_gateway && $this->_gateway instanceof EE_Gateway) {
635
+			return $this->_gateway->do_direct_refund($payment, $refund_info);
636
+		} else {
637
+			throw new EE_Error(
638
+				sprintf(
639
+					esc_html__('Payment Method Type "%s" does not support sending refund requests', 'event_espresso'),
640
+					get_class($this)
641
+				)
642
+			);
643
+		}
644
+	}
645
+
646
+
647
+	/**
648
+	 * Returns one the class's constants onsite,offsite, or offline, depending on this
649
+	 * payment method's gateway.
650
+	 *
651
+	 * @return string
652
+	 * @throws EE_Error
653
+	 */
654
+	public function payment_occurs()
655
+	{
656
+		if (! $this->_gateway) {
657
+			return EE_PMT_Base::offline;
658
+		} elseif ($this->_gateway instanceof EE_Onsite_Gateway) {
659
+			return EE_PMT_Base::onsite;
660
+		} elseif ($this->_gateway instanceof EE_Offsite_Gateway) {
661
+			return EE_PMT_Base::offsite;
662
+		} else {
663
+			throw new EE_Error(
664
+				sprintf(
665
+					esc_html__(
666
+						"Payment method type '%s's gateway isn't an instance of EE_Onsite_Gateway, EE_Offsite_Gateway, or null. It must be one of those",
667
+						"event_espresso"
668
+					),
669
+					get_class($this)
670
+				)
671
+			);
672
+		}
673
+	}
674
+
675
+
676
+	/**
677
+	 * For adding any html output ab ove the payment overview.
678
+	 * Many gateways won't want ot display anything, so this function just returns an empty string.
679
+	 * Other gateways may want to override this, such as offline gateways.
680
+	 *
681
+	 * @param EE_Payment $payment
682
+	 * @return string
683
+	 */
684
+	public function payment_overview_content(EE_Payment $payment)
685
+	{
686
+		return EEH_Template::display_template(
687
+			EE_LIBRARIES . 'payment_methods/templates/payment_details_content.template.php',
688
+			array('payment_method' => $this->_pm_instance, 'payment' => $payment),
689
+			true
690
+		);
691
+	}
692
+
693
+
694
+	/**
695
+	 * @return array where keys are the help tab name,
696
+	 * values are: array {
697
+	 * @type string $title         i18n name for the help tab
698
+	 * @type string $filename      name of the file located in ./help_tabs/ (ie, in a folder next to this file)
699
+	 * @type array  $template_args any arguments you want passed to the template file while rendering.
700
+	 *                Keys will be variable names and values with be their values.
701
+	 */
702
+	public function help_tabs_config()
703
+	{
704
+		return array();
705
+	}
706
+
707
+
708
+	/**
709
+	 * The system name for this PMT (eg AIM, Paypal_Pro, Invoice... what gets put into
710
+	 * the payment method's table's PMT_type column)
711
+	 *
712
+	 * @return string
713
+	 */
714
+	public function system_name()
715
+	{
716
+		$classname = get_class($this);
717
+		return str_replace("EE_PMT_", '', $classname);
718
+	}
719
+
720
+
721
+	/**
722
+	 * A pretty i18n version of the PMT name. Often the same as the "pretty_name", but you can change it by overriding
723
+	 * this method.
724
+	 * @return string
725
+	 */
726
+	public function defaultFrontendName()
727
+	{
728
+		return $this->pretty_name();
729
+	}
730
+
731
+
732
+	/**
733
+	 * A pretty i18n version of the PMT name
734
+	 *
735
+	 * @return string
736
+	 */
737
+	public function pretty_name()
738
+	{
739
+		return $this->_pretty_name;
740
+	}
741
+
742
+
743
+	/**
744
+	 * Gets the default absolute URL to the payment method type's button
745
+	 *
746
+	 * @return string
747
+	 */
748
+	public function default_button_url()
749
+	{
750
+		return $this->_default_button_url;
751
+	}
752
+
753
+
754
+	/**
755
+	 * Gets the gateway used by this payment method (if any)
756
+	 *
757
+	 * @return EE_Gateway
758
+	 */
759
+	public function get_gateway()
760
+	{
761
+		return $this->_gateway;
762
+	}
763
+
764
+
765
+	/**
766
+	 * @return string html for the link to a help tab
767
+	 */
768
+	public function get_help_tab_link()
769
+	{
770
+		return EEH_Template::get_help_tab_link(
771
+			$this->get_help_tab_name(),
772
+			'espresso_payment_settings',
773
+			'default'
774
+		);
775
+	}
776
+
777
+
778
+	/**
779
+	 * Returns the name of the help tab for this PMT
780
+	 *
781
+	 * @return string
782
+	 */
783
+	public function get_help_tab_name()
784
+	{
785
+		return 'ee_' . strtolower($this->system_name()) . '_help_tab';
786
+	}
787
+
788
+	/**
789
+	 * The name of the wp capability that should be associated with the usage of
790
+	 * this PMT by an admin
791
+	 *
792
+	 * @return string
793
+	 */
794
+	public function cap_name()
795
+	{
796
+		return 'ee_payment_method_' . strtolower($this->system_name());
797
+	}
798
+
799
+	/**
800
+	 * Called by client code to tell the gateway that if it wants to change
801
+	 * the transaction or line items or registrations related to teh payment it already
802
+	 * processed (we think, but possibly not) that now's the time to do it.
803
+	 * It is expected that gateways will store any info they need for this on the PAY_details,
804
+	 * or maybe an extra meta value
805
+	 *
806
+	 * @param EE_Payment $payment
807
+	 * @return void
808
+	 */
809
+	public function update_txn_based_on_payment($payment)
810
+	{
811
+		if ($this->_gateway instanceof EE_Gateway) {
812
+			$this->_gateway->update_txn_based_on_payment($payment);
813
+		}
814
+	}
815
+
816
+	/**
817
+	 * Returns a string of HTML describing this payment method type for an admin,
818
+	 * primarily intended for them to read before activating it.
819
+	 * The easiest way to set this is to create a folder 'templates' alongside
820
+	 * your EE_PMT_{System_Name} file, and in it create a file named "{system_name}_intro.template.php".
821
+	 * Eg, if your payment method file is named "EE_PMT_Foo_Bar.pm.php",
822
+	 * then you'd create a file named "templates" in the same folder as it, and name the file
823
+	 * "foo_bar_intro.template.php", and its content will be returned by this method
824
+	 *
825
+	 * @return string
826
+	 */
827
+	public function introductory_html()
828
+	{
829
+		return EEH_Template::locate_template(
830
+			$this->file_folder() . 'templates/' . strtolower($this->system_name()) . '_intro.template.php',
831
+			array('pmt_obj' => $this, 'pm_instance' => $this->_pm_instance)
832
+		);
833
+	}
834 834
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Base.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
      */
51 51
     public function getModelVersionInfo()
52 52
     {
53
-        if (! $this->model_version_info) {
53
+        if ( ! $this->model_version_info) {
54 54
             throw new EE_Error(
55 55
                 sprintf(
56 56
                     esc_html__(
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
      */
96 96
     protected function validateModel($model_name)
97 97
     {
98
-        if (! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
98
+        if ( ! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
99 99
             throw new RestException(
100 100
                 'endpoint_parsing_error',
101 101
                 sprintf(
Please login to merge, or discard this patch.
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -18,95 +18,95 @@
 block discarded – undo
18 18
  */
19 19
 class Base extends Controller_Base
20 20
 {
21
-    /**
22
-     * Holds reference to the model version info, which knows the requested version
23
-     *
24
-     * @var ModelVersionInfo
25
-     */
26
-    protected $model_version_info;
21
+	/**
22
+	 * Holds reference to the model version info, which knows the requested version
23
+	 *
24
+	 * @var ModelVersionInfo
25
+	 */
26
+	protected $model_version_info;
27 27
 
28 28
 
29 29
 
30
-    /**
31
-     * Sets the version the user requested
32
-     *
33
-     * @param string $version eg '4.8'
34
-     */
35
-    public function setRequestedVersion($version)
36
-    {
37
-        parent::setRequestedVersion($version);
38
-        $this->model_version_info = new ModelVersionInfo($version);
39
-    }
30
+	/**
31
+	 * Sets the version the user requested
32
+	 *
33
+	 * @param string $version eg '4.8'
34
+	 */
35
+	public function setRequestedVersion($version)
36
+	{
37
+		parent::setRequestedVersion($version);
38
+		$this->model_version_info = new ModelVersionInfo($version);
39
+	}
40 40
 
41 41
 
42 42
 
43
-    /**
44
-     * Gets the object that should be used for getting any info from the models,
45
-     * because it's takes the requested and current core version into account
46
-     *
47
-     * @return \EventEspresso\core\libraries\rest_api\ModelVersionInfo
48
-     * @throws EE_Error
49
-     */
50
-    public function getModelVersionInfo()
51
-    {
52
-        if (! $this->model_version_info) {
53
-            throw new EE_Error(
54
-                sprintf(
55
-                    esc_html__(
56
-                        'Cannot use model version info before setting the requested version in the controller',
57
-                        'event_espresso'
58
-                    )
59
-                )
60
-            );
61
-        }
62
-        return $this->model_version_info;
63
-    }
43
+	/**
44
+	 * Gets the object that should be used for getting any info from the models,
45
+	 * because it's takes the requested and current core version into account
46
+	 *
47
+	 * @return \EventEspresso\core\libraries\rest_api\ModelVersionInfo
48
+	 * @throws EE_Error
49
+	 */
50
+	public function getModelVersionInfo()
51
+	{
52
+		if (! $this->model_version_info) {
53
+			throw new EE_Error(
54
+				sprintf(
55
+					esc_html__(
56
+						'Cannot use model version info before setting the requested version in the controller',
57
+						'event_espresso'
58
+					)
59
+				)
60
+			);
61
+		}
62
+		return $this->model_version_info;
63
+	}
64 64
 
65 65
 
66 66
 
67
-    /**
68
-     * Determines if $object is of one of the classes of $classes. Similar to
69
-     * in_array(), except this checks if $object is a subclass of the classnames provided
70
-     * in $classnames
71
-     *
72
-     * @param object $object
73
-     * @param array  $classnames
74
-     * @return boolean
75
-     */
76
-    public function isSubclassOfOne($object, $classnames)
77
-    {
78
-        foreach ($classnames as $classname) {
79
-            if (is_a($object, $classname)) {
80
-                return true;
81
-            }
82
-        }
83
-        return false;
84
-    }
67
+	/**
68
+	 * Determines if $object is of one of the classes of $classes. Similar to
69
+	 * in_array(), except this checks if $object is a subclass of the classnames provided
70
+	 * in $classnames
71
+	 *
72
+	 * @param object $object
73
+	 * @param array  $classnames
74
+	 * @return boolean
75
+	 */
76
+	public function isSubclassOfOne($object, $classnames)
77
+	{
78
+		foreach ($classnames as $classname) {
79
+			if (is_a($object, $classname)) {
80
+				return true;
81
+			}
82
+		}
83
+		return false;
84
+	}
85 85
 
86
-    /**
87
-     * Verifies the model name provided was valid. If so, returns the model (as an object). Otherwise, throws an
88
-     * exception. Must be called after `setRequestedVersion()`.
89
-     * @since 4.9.76.p
90
-     * @param $model_name
91
-     * @return EEM_Base
92
-     * @throws EE_Error
93
-     * @throws RestException
94
-     */
95
-    protected function validateModel($model_name)
96
-    {
97
-        if (! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
98
-            throw new RestException(
99
-                'endpoint_parsing_error',
100
-                sprintf(
101
-                    esc_html__(
102
-                        'There is no model for endpoint %s. Please contact event espresso support',
103
-                        'event_espresso'
104
-                    ),
105
-                    $model_name
106
-                )
107
-            );
108
-        }
109
-        return $this->getModelVersionInfo()->loadModel($model_name);
110
-    }
86
+	/**
87
+	 * Verifies the model name provided was valid. If so, returns the model (as an object). Otherwise, throws an
88
+	 * exception. Must be called after `setRequestedVersion()`.
89
+	 * @since 4.9.76.p
90
+	 * @param $model_name
91
+	 * @return EEM_Base
92
+	 * @throws EE_Error
93
+	 * @throws RestException
94
+	 */
95
+	protected function validateModel($model_name)
96
+	{
97
+		if (! $this->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
98
+			throw new RestException(
99
+				'endpoint_parsing_error',
100
+				sprintf(
101
+					esc_html__(
102
+						'There is no model for endpoint %s. Please contact event espresso support',
103
+						'event_espresso'
104
+					),
105
+					$model_name
106
+				)
107
+			);
108
+		}
109
+		return $this->getModelVersionInfo()->loadModel($model_name);
110
+	}
111 111
 }
112 112
 // End of file Base.php
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Spacing   +63 added lines, -63 removed lines patch added patch discarded remove patch
@@ -86,7 +86,7 @@  discard block
 block discarded – undo
86 86
             LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
87 87
         try {
88 88
             $controller->setRequestedVersion($version);
89
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
89
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
90 90
                 return $controller->sendResponse(
91 91
                     new WP_Error(
92 92
                         'endpoint_parsing_error',
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
             LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
129 129
         try {
130 130
             $controller->setRequestedVersion($version);
131
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
131
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
132 132
                 return [];
133 133
             }
134 134
             // get the model for this version
@@ -192,11 +192,11 @@  discard block
 block discarded – undo
192 192
      */
193 193
     protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
194 194
     {
195
-        if (isset($schema['properties'][ $field_name ]['default'])) {
196
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
197
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
195
+        if (isset($schema['properties'][$field_name]['default'])) {
196
+            if (is_array($schema['properties'][$field_name]['default'])) {
197
+                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
198 198
                     if ($default_key === 'raw') {
199
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
199
+                        $schema['properties'][$field_name]['default'][$default_key] =
200 200
                             ModelDataTranslator::prepareFieldValueForJson(
201 201
                                 $field,
202 202
                                 $default_value,
@@ -205,9 +205,9 @@  discard block
 block discarded – undo
205 205
                     }
206 206
                 }
207 207
             } else {
208
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
208
+                $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson(
209 209
                     $field,
210
-                    $schema['properties'][ $field_name ]['default'],
210
+                    $schema['properties'][$field_name]['default'],
211 211
                     $this->getModelVersionInfo()->requestedVersion()
212 212
                 );
213 213
             }
@@ -229,9 +229,9 @@  discard block
 block discarded – undo
229 229
     protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
230 230
     {
231 231
         if ($field instanceof EE_Datetime_Field) {
232
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
232
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
233 233
             // modify the description
234
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
234
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
235 235
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
236 236
                 wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
237 237
             );
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
             LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
281 281
         try {
282 282
             $controller->setRequestedVersion($version);
283
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
283
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
284 284
                 return $controller->sendResponse(
285 285
                     new WP_Error(
286 286
                         'endpoint_parsing_error',
@@ -360,7 +360,7 @@  discard block
 block discarded – undo
360 360
     public function getEntitiesFromModel($model, $request)
361 361
     {
362 362
         $query_params = $this->createModelQueryParams($model, $request->get_params());
363
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
363
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
364 364
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
365 365
             throw new RestException(
366 366
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -372,7 +372,7 @@  discard block
 block discarded – undo
372 372
                 ['status' => 403]
373 373
             );
374 374
         }
375
-        if (! $request->get_header('no_rest_headers')) {
375
+        if ( ! $request->get_header('no_rest_headers')) {
376 376
             $this->setHeadersFromQueryParams($model, $query_params);
377 377
         }
378 378
         /** @type array $results */
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
         $context       = $this->validateContext($request->get_param('caps'));
414 414
         $model         = $relation->get_this_model();
415 415
         $related_model = $relation->get_other_model();
416
-        if (! isset($primary_model_query_params[0])) {
416
+        if ( ! isset($primary_model_query_params[0])) {
417 417
             $primary_model_query_params[0] = [];
418 418
         }
419 419
         // check if they can access the 1st model object
@@ -477,13 +477,13 @@  discard block
 block discarded – undo
477 477
         );
478 478
         $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
479 479
         foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
480
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
480
+            $query_params[0][$relation->get_this_model()->get_this_model_name()
481 481
                               . '.'
482
-                              . $where_condition_key ] = $where_condition_value;
482
+                              . $where_condition_key] = $where_condition_value;
483 483
         }
484 484
         $query_params['default_where_conditions'] = 'none';
485 485
         $query_params['caps']                     = $context;
486
-        if (! $request->get_header('no_rest_headers')) {
486
+        if ( ! $request->get_header('no_rest_headers')) {
487 487
             $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
488 488
         }
489 489
         /** @type array $results */
@@ -503,7 +503,7 @@  discard block
 block discarded – undo
503 503
                     $result,
504 504
                     $request
505 505
                 );
506
-                $joined_result     = array_merge($join_model_result, $nice_result);
506
+                $joined_result = array_merge($join_model_result, $nice_result);
507 507
                 // but keep the meta stuff from the main model
508 508
                 if (isset($nice_result['meta'])) {
509 509
                     $joined_result['meta'] = $nice_result['meta'];
@@ -535,7 +535,7 @@  discard block
 block discarded – undo
535 535
      */
536 536
     public function getEntitiesFromRelation($id, $relation, $request)
537 537
     {
538
-        if (! $relation->get_this_model()->has_primary_key_field()) {
538
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
539 539
             throw new EE_Error(
540 540
                 sprintf(
541 541
                     esc_html__(
@@ -582,7 +582,7 @@  discard block
 block discarded – undo
582 582
             Capabilities::getMissingPermissionsString($model, $query_params['caps'])
583 583
         );
584 584
         // normally the limit to a 2-part array, where the 2nd item is the limit
585
-        if (! isset($query_params['limit'])) {
585
+        if ( ! isset($query_params['limit'])) {
586 586
             $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
587 587
         }
588 588
         if (is_array($query_params['limit'])) {
@@ -621,7 +621,7 @@  discard block
 block discarded – undo
621 621
      */
622 622
     public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
623 623
     {
624
-        if (! $rest_request instanceof WP_REST_Request) {
624
+        if ( ! $rest_request instanceof WP_REST_Request) {
625 625
             // ok so this was called in the old style, where the 3rd arg was
626 626
             // $include, and the 4th arg was $context
627 627
             // now setup the request just to avoid fatal errors, although we won't be able
@@ -698,7 +698,7 @@  discard block
 block discarded – undo
698 698
             $rest_request,
699 699
             $this
700 700
         );
701
-        if (! $current_user_full_access_to_entity) {
701
+        if ( ! $current_user_full_access_to_entity) {
702 702
             $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
703 703
                 $entity_array,
704 704
                 $model,
@@ -733,7 +733,7 @@  discard block
 block discarded – undo
733 733
      */
734 734
     protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
735 735
     {
736
-        if (! $model->hasPassword() || ! $protected) {
736
+        if ( ! $model->hasPassword() || ! $protected) {
737 737
             return $results_so_far;
738 738
         }
739 739
         $password_field  = $model->getPasswordField();
@@ -782,8 +782,8 @@  discard block
 block discarded – undo
782 782
         if ($do_chevy_shuffle) {
783 783
             global $post;
784 784
             $old_post = $post;
785
-            $post     = get_post($result[ $model->primary_key_name() ]);
786
-            if (! $post instanceof WP_Post) {
785
+            $post     = get_post($result[$model->primary_key_name()]);
786
+            if ( ! $post instanceof WP_Post) {
787 787
                 // well that's weird, because $result is what we JUST fetched from the database
788 788
                 throw new RestException(
789 789
                     'error_fetching_post_from_database_results',
@@ -793,7 +793,7 @@  discard block
 block discarded – undo
793 793
                     )
794 794
                 );
795 795
             }
796
-            $model_object_classname          = 'EE_' . $model->get_this_model_name();
796
+            $model_object_classname          = 'EE_'.$model->get_this_model_name();
797 797
             $post->{$model_object_classname} = EE_Registry::instance()->load_class(
798 798
                 $model_object_classname,
799 799
                 $result,
@@ -804,14 +804,14 @@  discard block
 block discarded – undo
804 804
         foreach ($result as $field_name => $field_value) {
805 805
             $field_obj = $model->field_settings_for($field_name);
806 806
             if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
807
-                unset($result[ $field_name ]);
807
+                unset($result[$field_name]);
808 808
             } elseif (
809 809
                 $this->isSubclassOfOne(
810 810
                     $field_obj,
811 811
                     $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
812 812
                 )
813 813
             ) {
814
-                $result[ $field_name ] = [
814
+                $result[$field_name] = [
815 815
                     'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
816 816
                     'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
817 817
                 ];
@@ -821,7 +821,7 @@  discard block
 block discarded – undo
821 821
                     $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
822 822
                 )
823 823
             ) {
824
-                $result[ $field_name ] = [
824
+                $result[$field_name] = [
825 825
                     'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
826 826
                     'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
827 827
                 ];
@@ -852,10 +852,10 @@  discard block
 block discarded – undo
852 852
                         $this->getModelVersionInfo()->requestedVersion()
853 853
                     );
854 854
                 }
855
-                $result[ $field_name . '_gmt' ] = $gmt_date;
856
-                $result[ $field_name ]          = $local_date;
855
+                $result[$field_name.'_gmt'] = $gmt_date;
856
+                $result[$field_name]          = $local_date;
857 857
             } else {
858
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
858
+                $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
859 859
             }
860 860
         }
861 861
         if ($do_chevy_shuffle) {
@@ -910,7 +910,7 @@  discard block
 block discarded – undo
910 910
     protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
911 911
     {
912 912
         if ($model instanceof EEM_CPT_Base) {
913
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
913
+            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
914 914
         }
915 915
         return $entity_array;
916 916
     }
@@ -937,7 +937,7 @@  discard block
 block discarded – undo
937 937
                     'href' => $this->getVersionedLinkTo(
938 938
                         EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
939 939
                         . '/'
940
-                        . $entity_array[ $model->primary_key_name() ]
940
+                        . $entity_array[$model->primary_key_name()]
941 941
                     ),
942 942
                 ],
943 943
             ];
@@ -954,12 +954,12 @@  discard block
 block discarded – undo
954 954
             foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
955 955
                 $related_model_part                                                      =
956 956
                     Read::getRelatedEntityName($relation_name, $relation_obj);
957
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
957
+                $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = [
958 958
                     [
959 959
                         'href'   => $this->getVersionedLinkTo(
960 960
                             EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
961 961
                             . '/'
962
-                            . $entity_array[ $model->primary_key_name() ]
962
+                            . $entity_array[$model->primary_key_name()]
963 963
                             . '/'
964 964
                             . $related_model_part
965 965
                         ),
@@ -993,12 +993,12 @@  discard block
 block discarded – undo
993 993
         $included_items_protected = false
994 994
     ) {
995 995
         // if $db_row not included, hope the entity array has what we need
996
-        if (! $db_row) {
996
+        if ( ! $db_row) {
997 997
             $db_row = $entity_array;
998 998
         }
999 999
         $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
1000 1000
         foreach ($relation_settings as $relation_name => $relation_obj) {
1001
-            $related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1001
+            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
1002 1002
                 $rest_request->get_param('include'),
1003 1003
                 $relation_name
1004 1004
             );
@@ -1026,7 +1026,7 @@  discard block
 block discarded – undo
1026 1026
                         $model->deduce_fields_n_values_from_cols_n_values($db_row)
1027 1027
                     )
1028 1028
                 );
1029
-                if (! $included_items_protected) {
1029
+                if ( ! $included_items_protected) {
1030 1030
                     try {
1031 1031
                         $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1032 1032
                             $primary_model_query_params,
@@ -1047,7 +1047,7 @@  discard block
 block discarded – undo
1047 1047
                             ? null
1048 1048
                             : [];
1049 1049
                 }
1050
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1050
+                $entity_array[Read::getRelatedEntityName($relation_name, $relation_obj)] = $related_results;
1051 1051
             }
1052 1052
         }
1053 1053
         return $entity_array;
@@ -1131,13 +1131,13 @@  discard block
 block discarded – undo
1131 1131
                 $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1132 1132
                 if (
1133 1133
                     $row_is_protected
1134
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1135
-                    && $schema['properties'][ $field_to_calculate ]['protected']
1134
+                    && isset($schema['properties'][$field_to_calculate]['protected'])
1135
+                    && $schema['properties'][$field_to_calculate]['protected']
1136 1136
                 ) {
1137 1137
                     $calculated_value   = null;
1138 1138
                     $protected_fields[] = $field_to_calculate;
1139
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1140
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1139
+                    if ($schema['properties'][$field_to_calculate]['type']) {
1140
+                        switch ($schema['properties'][$field_to_calculate]['type']) {
1141 1141
                             case 'boolean':
1142 1142
                                 $calculated_value = false;
1143 1143
                                 break;
@@ -1252,7 +1252,7 @@  discard block
 block discarded – undo
1252 1252
      */
1253 1253
     public function validateContext($context)
1254 1254
     {
1255
-        if (! $context) {
1255
+        if ( ! $context) {
1256 1256
             $context = EEM_Base::caps_read;
1257 1257
         }
1258 1258
         $valid_contexts = EEM_Base::valid_cap_contexts();
@@ -1277,7 +1277,7 @@  discard block
 block discarded – undo
1277 1277
             EEM_Base::default_where_conditions_minimum_all,
1278 1278
             EEM_Base::default_where_conditions_minimum_others,
1279 1279
         ];
1280
-        if (! $default_query_params) {
1280
+        if ( ! $default_query_params) {
1281 1281
             $default_query_params = EEM_Base::default_where_conditions_all;
1282 1282
         }
1283 1283
         if (
@@ -1363,14 +1363,14 @@  discard block
 block discarded – undo
1363 1363
         }
1364 1364
         if (isset($query_params['limit'])) {
1365 1365
             // limit should be either a string like '23' or '23,43', or an array with two items in it
1366
-            if (! is_array($query_params['limit'])) {
1366
+            if ( ! is_array($query_params['limit'])) {
1367 1367
                 $limit_array = explode(',', (string) $query_params['limit']);
1368 1368
             } else {
1369 1369
                 $limit_array = $query_params['limit'];
1370 1370
             }
1371 1371
             $sanitized_limit = [];
1372 1372
             foreach ($limit_array as $limit_part) {
1373
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1373
+                if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1374 1374
                     throw new EE_Error(
1375 1375
                         sprintf(
1376 1376
                             esc_html__(
@@ -1428,7 +1428,7 @@  discard block
 block discarded – undo
1428 1428
     {
1429 1429
         $model_ready_query_params = [];
1430 1430
         foreach ($query_params as $key => $value) {
1431
-            $model_ready_query_params[ $key ] = is_array($value)
1431
+            $model_ready_query_params[$key] = is_array($value)
1432 1432
                 ? $this->prepareRestQueryParamsKeyForModels($model, $value)
1433 1433
                 : $value;
1434 1434
         }
@@ -1447,9 +1447,9 @@  discard block
 block discarded – undo
1447 1447
         $model_ready_query_params = [];
1448 1448
         foreach ($query_params as $key => $value) {
1449 1449
             if (is_array($value)) {
1450
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1450
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1451 1451
             } else {
1452
-                $model_ready_query_params[ $key ] = $value;
1452
+                $model_ready_query_params[$key] = $value;
1453 1453
             }
1454 1454
         }
1455 1455
         return $model_ready_query_params;
@@ -1481,17 +1481,17 @@  discard block
 block discarded – undo
1481 1481
         foreach ($exploded_contents as $item) {
1482 1482
             $item = trim($item);
1483 1483
             // if no prefix was provided, so we look for items with no "." in them
1484
-            if (! $prefix) {
1484
+            if ( ! $prefix) {
1485 1485
                 // does this item have a period?
1486 1486
                 if (strpos($item, '.') === false) {
1487 1487
                     // if not, then its what we're looking for
1488 1488
                     $contents_with_prefix[] = $item;
1489 1489
                 }
1490
-            } elseif (strpos($item, $prefix . '.') === 0) {
1490
+            } elseif (strpos($item, $prefix.'.') === 0) {
1491 1491
                 // this item has the prefix and a period, grab it
1492 1492
                 $contents_with_prefix[] = substr(
1493 1493
                     $item,
1494
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1494
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1495 1495
                 );
1496 1496
             } elseif ($item === $prefix) {
1497 1497
                 // this item is JUST the prefix
@@ -1533,9 +1533,9 @@  discard block
 block discarded – undo
1533 1533
         if ($model_name) {
1534 1534
             foreach ($includes as $field_to_include) {
1535 1535
                 $field_to_include = trim($field_to_include);
1536
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1536
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1537 1537
                     // found the model name at the exact start
1538
-                    $field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1538
+                    $field_sans_model_name         = str_replace($model_name.'.', '', $field_to_include);
1539 1539
                     $extracted_fields_to_include[] = $field_sans_model_name;
1540 1540
                 } elseif ($field_to_include == $model_name) {
1541 1541
                     $extracted_fields_to_include[] = '*';
@@ -1578,7 +1578,7 @@  discard block
 block discarded – undo
1578 1578
         $restricted_query_params['caps'] = $context;
1579 1579
         $this->setDebugInfo('model query params', $restricted_query_params);
1580 1580
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1581
-        if (! empty($model_rows)) {
1581
+        if ( ! empty($model_rows)) {
1582 1582
             return $this->createEntityFromWpdbResult(
1583 1583
                 $model,
1584 1584
                 reset($model_rows),
@@ -1590,7 +1590,7 @@  discard block
 block discarded – undo
1590 1590
             if ($model->exists($query_params)) {
1591 1591
                 // you got shafted- it existed but we didn't want to tell you!
1592 1592
                 throw new RestException(
1593
-                    'rest_user_cannot_' . $context,
1593
+                    'rest_user_cannot_'.$context,
1594 1594
                     sprintf(
1595 1595
                         esc_html__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1596 1596
                         $context,
@@ -1644,14 +1644,14 @@  discard block
 block discarded – undo
1644 1644
         // if this entity requires a password, they better give it and it better be right!
1645 1645
         if (
1646 1646
             $model->hasPassword()
1647
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1647
+            && $model_row[$model->getPasswordField()->get_qualified_column()] !== ''
1648 1648
         ) {
1649 1649
             if (empty($request['password'])) {
1650 1650
                 throw new RestPasswordRequiredException();
1651 1651
             }
1652 1652
             if (
1653 1653
                 ! hash_equals(
1654
-                    $model_row[ $model->getPasswordField()->get_qualified_column() ],
1654
+                    $model_row[$model->getPasswordField()->get_qualified_column()],
1655 1655
                     $request['password']
1656 1656
                 )
1657 1657
             ) {
@@ -1665,12 +1665,12 @@  discard block
 block discarded – undo
1665 1665
             $password_supplied = $request->get_param('password');
1666 1666
             if (empty($password_supplied)) {
1667 1667
                 $query_params['exclude_protected'] = true;
1668
-                if (! $model->exists($query_params)) {
1668
+                if ( ! $model->exists($query_params)) {
1669 1669
                     throw new RestPasswordRequiredException();
1670 1670
                 }
1671 1671
             } else {
1672
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1673
-                if (! $model->exists($query_params)) {
1672
+                $query_params[0][$model->modelChainAndPassword()] = $password_supplied;
1673
+                if ( ! $model->exists($query_params)) {
1674 1674
                     throw new RestPasswordIncorrectException();
1675 1675
                 }
1676 1676
             }
Please login to merge, or discard this patch.
Indentation   +1625 added lines, -1625 removed lines patch added patch discarded remove patch
@@ -49,1629 +49,1629 @@
 block discarded – undo
49 49
  */
50 50
 class Read extends Base
51 51
 {
52
-    /**
53
-     * @var CalculatedModelFields
54
-     */
55
-    protected $fields_calculator;
56
-
57
-
58
-    /**
59
-     * Read constructor.
60
-     *
61
-     * @param CalculatedModelFields $fields_calculator
62
-     */
63
-    public function __construct(CalculatedModelFields $fields_calculator)
64
-    {
65
-        parent::__construct();
66
-        $this->fields_calculator = $fields_calculator;
67
-    }
68
-
69
-
70
-    /**
71
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
72
-     *
73
-     * @param WP_REST_Request $request
74
-     * @param string          $version
75
-     * @param string          $model_name
76
-     * @return WP_REST_Response|WP_Error
77
-     * @throws InvalidArgumentException
78
-     * @throws InvalidDataTypeException
79
-     * @throws InvalidInterfaceException
80
-     */
81
-    public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
82
-    {
83
-        $controller =
84
-            LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
85
-        try {
86
-            $controller->setRequestedVersion($version);
87
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
88
-                return $controller->sendResponse(
89
-                    new WP_Error(
90
-                        'endpoint_parsing_error',
91
-                        sprintf(
92
-                            esc_html__(
93
-                                'There is no model for endpoint %s. Please contact event espresso support',
94
-                                'event_espresso'
95
-                            ),
96
-                            $model_name
97
-                        )
98
-                    )
99
-                );
100
-            }
101
-            return $controller->sendResponse(
102
-                $controller->getEntitiesFromModel(
103
-                    $controller->getModelVersionInfo()->loadModel($model_name),
104
-                    $request
105
-                )
106
-            );
107
-        } catch (Exception $e) {
108
-            return $controller->sendResponse($e);
109
-        }
110
-    }
111
-
112
-
113
-    /**
114
-     * Prepares and returns schema for any OPTIONS request.
115
-     *
116
-     * @param string $version    The API endpoint version being used.
117
-     * @param string $model_name Something like `Event` or `Registration`
118
-     * @return array
119
-     * @throws InvalidArgumentException
120
-     * @throws InvalidDataTypeException
121
-     * @throws InvalidInterfaceException
122
-     */
123
-    public static function handleSchemaRequest($version, $model_name)
124
-    {
125
-        $controller =
126
-            LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
127
-        try {
128
-            $controller->setRequestedVersion($version);
129
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
130
-                return [];
131
-            }
132
-            // get the model for this version
133
-            $model        = $controller->getModelVersionInfo()->loadModel($model_name);
134
-            $model_schema = new JsonModelSchema(
135
-                $model,
136
-                LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields')
137
-            );
138
-            return $model_schema->getModelSchemaForRelations(
139
-                $controller->getModelVersionInfo()->relationSettings($model),
140
-                $controller->customizeSchemaForRestResponse(
141
-                    $model,
142
-                    $model_schema->getModelSchemaForFields(
143
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
144
-                        $model_schema->getInitialSchemaStructure()
145
-                    )
146
-                )
147
-            );
148
-        } catch (Exception $e) {
149
-            return [];
150
-        }
151
-    }
152
-
153
-
154
-    /**
155
-     * This loops through each field in the given schema for the model and does the following:
156
-     * - add any extra fields that are REST API specific and related to existing fields.
157
-     * - transform default values into the correct format for a REST API response.
158
-     *
159
-     * @param EEM_Base $model
160
-     * @param array    $schema
161
-     * @return array  The final schema.
162
-     * @throws EE_Error
163
-     * @throws EE_Error
164
-     */
165
-    protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
166
-    {
167
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
168
-            $schema = $this->translateDefaultsForRestResponse(
169
-                $field_name,
170
-                $field,
171
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
172
-            );
173
-        }
174
-        return $schema;
175
-    }
176
-
177
-
178
-    /**
179
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
180
-     * response.
181
-     *
182
-     * @param                      $field_name
183
-     * @param EE_Model_Field_Base  $field
184
-     * @param array                $schema
185
-     * @return array
186
-     * @throws RestException  if a default value has a PHP object, which we should never do
187
-     *                                  (but if we did, let's know about it ASAP, so let the exception bubble up)
188
-     * @throws EE_Error
189
-     *
190
-     */
191
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
192
-    {
193
-        if (isset($schema['properties'][ $field_name ]['default'])) {
194
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
195
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
196
-                    if ($default_key === 'raw') {
197
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
198
-                            ModelDataTranslator::prepareFieldValueForJson(
199
-                                $field,
200
-                                $default_value,
201
-                                $this->getModelVersionInfo()->requestedVersion()
202
-                            );
203
-                    }
204
-                }
205
-            } else {
206
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
207
-                    $field,
208
-                    $schema['properties'][ $field_name ]['default'],
209
-                    $this->getModelVersionInfo()->requestedVersion()
210
-                );
211
-            }
212
-        }
213
-        return $schema;
214
-    }
215
-
216
-
217
-    /**
218
-     * Adds additional fields to the schema
219
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
220
-     * needs to be added to the schema.
221
-     *
222
-     * @param                      $field_name
223
-     * @param EE_Model_Field_Base  $field
224
-     * @param array                $schema
225
-     * @return array
226
-     */
227
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
228
-    {
229
-        if ($field instanceof EE_Datetime_Field) {
230
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
231
-            // modify the description
232
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
233
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
234
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
235
-            );
236
-        }
237
-        return $schema;
238
-    }
239
-
240
-
241
-    /**
242
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
243
-     *
244
-     * @return string
245
-     */
246
-    protected function getRouteFromRequest()
247
-    {
248
-        if (
249
-            isset($GLOBALS['wp'])
250
-            && $GLOBALS['wp'] instanceof WP
251
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
252
-        ) {
253
-            return $GLOBALS['wp']->query_vars['rest_route'];
254
-        } else {
255
-            /** @var RequestInterface $request */
256
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
257
-            return $request->serverParamIsSet('PATH_INFO')
258
-                ? $request->getServerParam('PATH_INFO')
259
-                : '/';
260
-        }
261
-    }
262
-
263
-
264
-    /**
265
-     * Gets a single entity related to the model indicated in the path and its id
266
-     *
267
-     * @param WP_REST_Request $request
268
-     * @param string          $version
269
-     * @param string          $model_name
270
-     * @return WP_REST_Response|WP_Error
271
-     * @throws InvalidDataTypeException
272
-     * @throws InvalidInterfaceException
273
-     * @throws InvalidArgumentException
274
-     */
275
-    public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
276
-    {
277
-        $controller =
278
-            LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
279
-        try {
280
-            $controller->setRequestedVersion($version);
281
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
282
-                return $controller->sendResponse(
283
-                    new WP_Error(
284
-                        'endpoint_parsing_error',
285
-                        sprintf(
286
-                            esc_html__(
287
-                                'There is no model for endpoint %s. Please contact event espresso support',
288
-                                'event_espresso'
289
-                            ),
290
-                            $model_name
291
-                        )
292
-                    )
293
-                );
294
-            }
295
-            return $controller->sendResponse(
296
-                $controller->getEntityFromModel(
297
-                    $controller->getModelVersionInfo()->loadModel($model_name),
298
-                    $request
299
-                )
300
-            );
301
-        } catch (Exception $e) {
302
-            return $controller->sendResponse($e);
303
-        }
304
-    }
305
-
306
-
307
-    /**
308
-     * Gets all the related entities (or if its a belongs-to relation just the one)
309
-     * to the item with the given id
310
-     *
311
-     * @param WP_REST_Request $request
312
-     * @param string          $version
313
-     * @param string          $model_name
314
-     * @param string          $related_model_name
315
-     * @return WP_REST_Response|WP_Error
316
-     * @throws InvalidDataTypeException
317
-     * @throws InvalidInterfaceException
318
-     * @throws InvalidArgumentException
319
-     */
320
-    public static function handleRequestGetRelated(
321
-        WP_REST_Request $request,
322
-        $version,
323
-        $model_name,
324
-        $related_model_name
325
-    ) {
326
-        $controller =
327
-            LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
328
-        try {
329
-            $controller->setRequestedVersion($version);
330
-            $main_model = $controller->validateModel($model_name);
331
-            $controller->validateModel($related_model_name);
332
-            return $controller->sendResponse(
333
-                $controller->getEntitiesFromRelation(
334
-                    $request->get_param('id'),
335
-                    $main_model->related_settings_for($related_model_name),
336
-                    $request
337
-                )
338
-            );
339
-        } catch (Exception $e) {
340
-            return $controller->sendResponse($e);
341
-        }
342
-    }
343
-
344
-
345
-    /**
346
-     * Gets a collection for the given model and filters
347
-     *
348
-     * @param EEM_Base        $model
349
-     * @param WP_REST_Request $request
350
-     * @return array
351
-     * @throws EE_Error
352
-     * @throws InvalidArgumentException
353
-     * @throws InvalidDataTypeException
354
-     * @throws InvalidInterfaceException
355
-     * @throws ReflectionException
356
-     * @throws RestException
357
-     */
358
-    public function getEntitiesFromModel($model, $request)
359
-    {
360
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
361
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
362
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
363
-            throw new RestException(
364
-                sprintf('rest_%s_cannot_list', $model_name_plural),
365
-                sprintf(
366
-                    esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
367
-                    $model_name_plural,
368
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
369
-                ),
370
-                ['status' => 403]
371
-            );
372
-        }
373
-        if (! $request->get_header('no_rest_headers')) {
374
-            $this->setHeadersFromQueryParams($model, $query_params);
375
-        }
376
-        /** @type array $results */
377
-        $results      = $model->get_all_wpdb_results($query_params);
378
-        $nice_results = [];
379
-        foreach ($results as $result) {
380
-            $nice_results[] = $this->createEntityFromWpdbResult(
381
-                $model,
382
-                $result,
383
-                $request
384
-            );
385
-        }
386
-        return $nice_results;
387
-    }
388
-
389
-
390
-    /**
391
-     * Gets the collection for given relation object
392
-     * The same as Read::get_entities_from_model(), except if the relation
393
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
394
-     * the join-model-object into the results
395
-     *
396
-     * @param array                  $primary_model_query_params  query params for finding the item from which
397
-     *                                                            relations will be based
398
-     * @param EE_Model_Relation_Base $relation
399
-     * @param WP_REST_Request        $request
400
-     * @return array
401
-     * @throws EE_Error
402
-     * @throws InvalidArgumentException
403
-     * @throws InvalidDataTypeException
404
-     * @throws InvalidInterfaceException
405
-     * @throws ReflectionException
406
-     * @throws RestException
407
-     * @throws ModelConfigurationException
408
-     */
409
-    protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
410
-    {
411
-        $context       = $this->validateContext($request->get_param('caps'));
412
-        $model         = $relation->get_this_model();
413
-        $related_model = $relation->get_other_model();
414
-        if (! isset($primary_model_query_params[0])) {
415
-            $primary_model_query_params[0] = [];
416
-        }
417
-        // check if they can access the 1st model object
418
-        $primary_model_query_params = [
419
-            0       => $primary_model_query_params[0],
420
-            'limit' => 1,
421
-        ];
422
-        if ($model instanceof EEM_Soft_Delete_Base) {
423
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
424
-                $primary_model_query_params
425
-            );
426
-        }
427
-        $restricted_query_params          = $primary_model_query_params;
428
-        $restricted_query_params['caps']  = $context;
429
-        $restricted_query_params['limit'] = 1;
430
-        $this->setDebugInfo('main model query params', $restricted_query_params);
431
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
432
-        $primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
433
-        $primary_model_row  = null;
434
-        if (is_array($primary_model_rows)) {
435
-            $primary_model_row = reset($primary_model_rows);
436
-        }
437
-        if (
438
-            ! (
439
-                $primary_model_row
440
-                && Capabilities::currentUserHasPartialAccessTo($related_model, $context)
441
-            )
442
-        ) {
443
-            if ($relation instanceof EE_Belongs_To_Relation) {
444
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
445
-            } else {
446
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
447
-                    $related_model->get_this_model_name()
448
-                );
449
-            }
450
-            throw new RestException(
451
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
452
-                sprintf(
453
-                    esc_html__(
454
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
455
-                        'event_espresso'
456
-                    ),
457
-                    $related_model_name_maybe_plural,
458
-                    $relation->get_this_model()->get_this_model_name(),
459
-                    implode(
460
-                        ',',
461
-                        array_keys(
462
-                            Capabilities::getMissingPermissions($related_model, $context)
463
-                        )
464
-                    )
465
-                ),
466
-                ['status' => 403]
467
-            );
468
-        }
469
-
470
-        $this->checkPassword(
471
-            $model,
472
-            $primary_model_row,
473
-            $restricted_query_params,
474
-            $request
475
-        );
476
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
477
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
478
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
479
-                              . '.'
480
-                              . $where_condition_key ] = $where_condition_value;
481
-        }
482
-        $query_params['default_where_conditions'] = 'none';
483
-        $query_params['caps']                     = $context;
484
-        if (! $request->get_header('no_rest_headers')) {
485
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
486
-        }
487
-        /** @type array $results */
488
-        $results      = $relation->get_other_model()->get_all_wpdb_results($query_params);
489
-        $nice_results = [];
490
-        foreach ($results as $result) {
491
-            $nice_result = $this->createEntityFromWpdbResult(
492
-                $relation->get_other_model(),
493
-                $result,
494
-                $request
495
-            );
496
-            if ($relation instanceof EE_HABTM_Relation) {
497
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
498
-                // if there are conflicts we prefer the properties from the main model
499
-                $join_model_result = $this->createEntityFromWpdbResult(
500
-                    $relation->get_join_model(),
501
-                    $result,
502
-                    $request
503
-                );
504
-                $joined_result     = array_merge($join_model_result, $nice_result);
505
-                // but keep the meta stuff from the main model
506
-                if (isset($nice_result['meta'])) {
507
-                    $joined_result['meta'] = $nice_result['meta'];
508
-                }
509
-                $nice_result = $joined_result;
510
-            }
511
-            $nice_results[] = $nice_result;
512
-        }
513
-        if ($relation instanceof EE_Belongs_To_Relation) {
514
-            return array_shift($nice_results);
515
-        } else {
516
-            return $nice_results;
517
-        }
518
-    }
519
-
520
-
521
-    /**
522
-     * Gets the collection for given relation object
523
-     * The same as Read::get_entities_from_model(), except if the relation
524
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
525
-     * the join-model-object into the results
526
-     *
527
-     * @param string                 $id the ID of the thing we are fetching related stuff from
528
-     * @param EE_Model_Relation_Base $relation
529
-     * @param WP_REST_Request        $request
530
-     * @return array
531
-     * @throws EE_Error
532
-     * @throws ReflectionException
533
-     */
534
-    public function getEntitiesFromRelation($id, $relation, $request)
535
-    {
536
-        if (! $relation->get_this_model()->has_primary_key_field()) {
537
-            throw new EE_Error(
538
-                sprintf(
539
-                    esc_html__(
540
-                    // @codingStandardsIgnoreStart
541
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
542
-                        // @codingStandardsIgnoreEnd
543
-                        'event_espresso'
544
-                    ),
545
-                    $relation->get_this_model()->get_this_model_name()
546
-                )
547
-            );
548
-        }
549
-        // can we edit that main item?
550
-        // if not, show nothing but an error
551
-        // otherwise, please proceed
552
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
553
-            [
554
-                [
555
-                    $relation->get_this_model()->primary_key_name() => $id,
556
-                ],
557
-            ],
558
-            $relation,
559
-            $request
560
-        );
561
-    }
562
-
563
-
564
-    /**
565
-     * Sets the headers that are based on the model and query params,
566
-     * like the total records. This should only be called on the original request
567
-     * from the client, not on subsequent internal
568
-     *
569
-     * @param EEM_Base $model
570
-     * @param array    $query_params
571
-     * @return void
572
-     * @throws EE_Error
573
-     * @throws EE_Error
574
-     */
575
-    protected function setHeadersFromQueryParams($model, $query_params)
576
-    {
577
-        $this->setDebugInfo('model query params', $query_params);
578
-        $this->setDebugInfo(
579
-            'missing caps',
580
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
581
-        );
582
-        // normally the limit to a 2-part array, where the 2nd item is the limit
583
-        if (! isset($query_params['limit'])) {
584
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
585
-        }
586
-        if (is_array($query_params['limit'])) {
587
-            $limit_parts = $query_params['limit'];
588
-        } else {
589
-            $limit_parts = explode(',', $query_params['limit']);
590
-            if (count($limit_parts) == 1) {
591
-                $limit_parts = [0, $limit_parts[0]];
592
-            }
593
-        }
594
-        // remove the group by and having parts of the query, as those will
595
-        // make the sql query return an array of values, instead of just a single value
596
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
597
-        $count = $model->count($query_params, null, true);
598
-        $pages = $count / $limit_parts[1];
599
-        $this->setResponseHeader('Total', $count, false);
600
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
601
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
602
-    }
603
-
604
-
605
-    /**
606
-     * Changes database results into REST API entities
607
-     *
608
-     * @param EEM_Base        $model
609
-     * @param array           $db_row     like results from $wpdb->get_results()
610
-     * @param WP_REST_Request $rest_request
611
-     * @param string          $deprecated no longer used
612
-     * @return array ready for being converted into json for sending to client
613
-     * @throws EE_Error
614
-     * @throws RestException
615
-     * @throws InvalidDataTypeException
616
-     * @throws InvalidInterfaceException
617
-     * @throws InvalidArgumentException
618
-     * @throws ReflectionException
619
-     */
620
-    public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
621
-    {
622
-        if (! $rest_request instanceof WP_REST_Request) {
623
-            // ok so this was called in the old style, where the 3rd arg was
624
-            // $include, and the 4th arg was $context
625
-            // now setup the request just to avoid fatal errors, although we won't be able
626
-            // to truly make use of it because it's kinda devoid of info
627
-            $rest_request = new WP_REST_Request();
628
-            $rest_request->set_param('include', $rest_request);
629
-            $rest_request->set_param('caps', $deprecated);
630
-        }
631
-        if ($rest_request->get_param('caps') == null) {
632
-            $rest_request->set_param('caps', EEM_Base::caps_read);
633
-        }
634
-        $current_user_full_access_to_entity = $model->currentUserCan(
635
-            EEM_Base::caps_read_admin,
636
-            $model->deduce_fields_n_values_from_cols_n_values($db_row)
637
-        );
638
-        $entity_array                       = $this->createBareEntityFromWpdbResults($model, $db_row);
639
-        $entity_array                       = $this->addExtraFields($model, $db_row, $entity_array);
640
-        $entity_array['_links']             = $this->getEntityLinks($model, $db_row, $entity_array);
641
-        // when it's a regular read request for a model with a password and the password wasn't provided
642
-        // remove the password protected fields
643
-        $has_protected_fields = false;
644
-        try {
645
-            $this->checkPassword(
646
-                $model,
647
-                $db_row,
648
-                $model->alter_query_params_to_restrict_by_ID(
649
-                    $model->get_index_primary_key_string(
650
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
651
-                    )
652
-                ),
653
-                $rest_request
654
-            );
655
-        } catch (RestPasswordRequiredException $e) {
656
-            if ($model->hasPassword()) {
657
-                // just remove protected fields
658
-                $has_protected_fields = true;
659
-                $entity_array         = Capabilities::filterOutPasswordProtectedFields(
660
-                    $entity_array,
661
-                    $model,
662
-                    $this->getModelVersionInfo()
663
-                );
664
-            } else {
665
-                // that's a problem. None of this should be accessible if no password was provided
666
-                throw $e;
667
-            }
668
-        }
669
-
670
-        $entity_array['_calculated_fields'] =
671
-            $this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields);
672
-        $entity_array                       = apply_filters(
673
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
674
-            $entity_array,
675
-            $model,
676
-            $rest_request->get_param('caps'),
677
-            $rest_request,
678
-            $this
679
-        );
680
-        // add an empty protected property for now. If it's still around after we remove everything the request didn't
681
-        // want, we'll populate it then. k?
682
-        $entity_array['_protected'] = [];
683
-        // remove any properties the request didn't want. This way _protected won't bother mentioning them
684
-        $entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
685
-        $entity_array =
686
-            $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields);
687
-        // if they still wanted the _protected property, add it.
688
-        if (isset($entity_array['_protected'])) {
689
-            $entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
690
-        }
691
-        $entity_array = apply_filters(
692
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
693
-            $entity_array,
694
-            $model,
695
-            $rest_request->get_param('caps'),
696
-            $rest_request,
697
-            $this
698
-        );
699
-        if (! $current_user_full_access_to_entity) {
700
-            $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
701
-                $entity_array,
702
-                $model,
703
-                $rest_request->get_param('caps'),
704
-                $this->getModelVersionInfo()
705
-            );
706
-        } else {
707
-            $result_without_inaccessible_fields = $entity_array;
708
-        }
709
-        $this->setDebugInfo(
710
-            'inaccessible fields',
711
-            array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
712
-        );
713
-        return apply_filters(
714
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
715
-            $result_without_inaccessible_fields,
716
-            $model,
717
-            $rest_request->get_param('caps')
718
-        );
719
-    }
720
-
721
-
722
-    /**
723
-     * Returns an array describing which fields can be protected, and which actually were removed this request
724
-     *
725
-     * @param EEM_Base $model
726
-     * @param array    $results_so_far
727
-     * @param bool     $protected
728
-     * @return array results
729
-     * @throws EE_Error
730
-     * @since 4.9.74.p
731
-     */
732
-    protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
733
-    {
734
-        if (! $model->hasPassword() || ! $protected) {
735
-            return $results_so_far;
736
-        }
737
-        $password_field  = $model->getPasswordField();
738
-        $all_protected   = array_merge(
739
-            [$password_field->get_name()],
740
-            $password_field->protectedFields()
741
-        );
742
-        $fields_included = array_keys($results_so_far);
743
-        $fields_included = array_intersect(
744
-            $all_protected,
745
-            $fields_included
746
-        );
747
-        foreach ($fields_included as $field_name) {
748
-            $results_so_far['_protected'][] = $field_name;
749
-        }
750
-        return $results_so_far;
751
-    }
752
-
753
-
754
-    /**
755
-     * Creates a REST entity array (JSON object we're going to return in the response, but
756
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
757
-     * from $wpdb->get_row( $sql, ARRAY_A)
758
-     *
759
-     * @param EEM_Base $model
760
-     * @param array    $db_row
761
-     * @return array entity mostly ready for converting to JSON and sending in the response
762
-     * @throws EE_Error
763
-     * @throws ReflectionException
764
-     * @throws RestException
765
-     */
766
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
767
-    {
768
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
769
-        $result = array_intersect_key(
770
-            $result,
771
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
772
-        );
773
-        // if this is a CPT, we need to set the global $post to it,
774
-        // otherwise shortcodes etc won't work properly while rendering it
775
-        if ($model instanceof EEM_CPT_Base) {
776
-            $do_chevy_shuffle = true;
777
-        } else {
778
-            $do_chevy_shuffle = false;
779
-        }
780
-        if ($do_chevy_shuffle) {
781
-            global $post;
782
-            $old_post = $post;
783
-            $post     = get_post($result[ $model->primary_key_name() ]);
784
-            if (! $post instanceof WP_Post) {
785
-                // well that's weird, because $result is what we JUST fetched from the database
786
-                throw new RestException(
787
-                    'error_fetching_post_from_database_results',
788
-                    esc_html__(
789
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
790
-                        'event_espresso'
791
-                    )
792
-                );
793
-            }
794
-            $model_object_classname          = 'EE_' . $model->get_this_model_name();
795
-            $post->{$model_object_classname} = EE_Registry::instance()->load_class(
796
-                $model_object_classname,
797
-                $result,
798
-                false,
799
-                false
800
-            );
801
-        }
802
-        foreach ($result as $field_name => $field_value) {
803
-            $field_obj = $model->field_settings_for($field_name);
804
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
805
-                unset($result[ $field_name ]);
806
-            } elseif (
807
-                $this->isSubclassOfOne(
808
-                    $field_obj,
809
-                    $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
810
-                )
811
-            ) {
812
-                $result[ $field_name ] = [
813
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
814
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
815
-                ];
816
-            } elseif (
817
-                $this->isSubclassOfOne(
818
-                    $field_obj,
819
-                    $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
820
-                )
821
-            ) {
822
-                $result[ $field_name ] = [
823
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
824
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
825
-                ];
826
-            } elseif ($field_obj instanceof EE_Datetime_Field) {
827
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
828
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
829
-                if (is_null($field_value)) {
830
-                    $field_value = $field_obj->getDefaultDateTimeObj();
831
-                }
832
-                if (is_null($field_value)) {
833
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
834
-                        $field_obj,
835
-                        $field_value,
836
-                        $this->getModelVersionInfo()->requestedVersion()
837
-                    );
838
-                } else {
839
-                    $timezone = $field_value->getTimezone();
840
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
841
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
842
-                        $field_obj,
843
-                        $field_value,
844
-                        $this->getModelVersionInfo()->requestedVersion()
845
-                    );
846
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
847
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
848
-                        $field_obj,
849
-                        $field_value,
850
-                        $this->getModelVersionInfo()->requestedVersion()
851
-                    );
852
-                }
853
-                $result[ $field_name . '_gmt' ] = $gmt_date;
854
-                $result[ $field_name ]          = $local_date;
855
-            } else {
856
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
857
-            }
858
-        }
859
-        if ($do_chevy_shuffle) {
860
-            $post = $old_post;
861
-        }
862
-        return $result;
863
-    }
864
-
865
-
866
-    /**
867
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
868
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
869
-     * representation using $field_obj->prepare_for_set_from_db())
870
-     *
871
-     * @param EE_Model_Field_Base $field_obj
872
-     * @param mixed               $value  as it's stored on a model object
873
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
874
-     * @return array
875
-     * @throws RestException if $value contains a PHP object
876
-     * @throws EE_Error
877
-     */
878
-    protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
879
-    {
880
-        $value = $field_obj->prepare_for_set_from_db($value);
881
-        switch ($format) {
882
-            case 'pretty':
883
-                $value = $field_obj->prepare_for_pretty_echoing($value);
884
-                break;
885
-            case 'normal':
886
-            default:
887
-                $value = $field_obj->prepare_for_get($value);
888
-                break;
889
-        }
890
-        return ModelDataTranslator::prepareFieldValuesForJson(
891
-            $field_obj,
892
-            $value,
893
-            $this->getModelVersionInfo()->requestedVersion()
894
-        );
895
-    }
896
-
897
-
898
-    /**
899
-     * Adds a few extra fields to the entity response
900
-     *
901
-     * @param EEM_Base $model
902
-     * @param array    $db_row
903
-     * @param array    $entity_array
904
-     * @return array modified entity
905
-     * @throws EE_Error
906
-     * @throws EE_Error
907
-     */
908
-    protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
909
-    {
910
-        if ($model instanceof EEM_CPT_Base) {
911
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
912
-        }
913
-        return $entity_array;
914
-    }
915
-
916
-
917
-    /**
918
-     * Gets links we want to add to the response
919
-     *
920
-     * @param EEM_Base        $model
921
-     * @param array           $db_row
922
-     * @param array           $entity_array
923
-     * @return array the _links item in the entity
924
-     * @throws EE_Error
925
-     * @throws EE_Error
926
-     * @global WP_REST_Server $wp_rest_server
927
-     */
928
-    protected function getEntityLinks($model, $db_row, $entity_array)
929
-    {
930
-        // add basic links
931
-        $links = [];
932
-        if ($model->has_primary_key_field()) {
933
-            $links['self'] = [
934
-                [
935
-                    'href' => $this->getVersionedLinkTo(
936
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
937
-                        . '/'
938
-                        . $entity_array[ $model->primary_key_name() ]
939
-                    ),
940
-                ],
941
-            ];
942
-        }
943
-        $links['collection'] = [
944
-            [
945
-                'href' => $this->getVersionedLinkTo(
946
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
947
-                ),
948
-            ],
949
-        ];
950
-        // add links to related models
951
-        if ($model->has_primary_key_field()) {
952
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
953
-                $related_model_part                                                      =
954
-                    Read::getRelatedEntityName($relation_name, $relation_obj);
955
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
956
-                    [
957
-                        'href'   => $this->getVersionedLinkTo(
958
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
959
-                            . '/'
960
-                            . $entity_array[ $model->primary_key_name() ]
961
-                            . '/'
962
-                            . $related_model_part
963
-                        ),
964
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation,
965
-                    ],
966
-                ];
967
-            }
968
-        }
969
-        return $links;
970
-    }
971
-
972
-
973
-    /**
974
-     * Adds the included models indicated in the request to the entity provided
975
-     *
976
-     * @param EEM_Base        $model
977
-     * @param WP_REST_Request $rest_request
978
-     * @param array           $entity_array
979
-     * @param array           $db_row
980
-     * @param boolean         $included_items_protected if the original item is password protected, don't include any
981
-     *                                                  related models.
982
-     * @return array the modified entity
983
-     * @throws EE_Error
984
-     * @throws ReflectionException
985
-     */
986
-    protected function includeRequestedModels(
987
-        EEM_Base $model,
988
-        WP_REST_Request $rest_request,
989
-        $entity_array,
990
-        $db_row = [],
991
-        $included_items_protected = false
992
-    ) {
993
-        // if $db_row not included, hope the entity array has what we need
994
-        if (! $db_row) {
995
-            $db_row = $entity_array;
996
-        }
997
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
998
-        foreach ($relation_settings as $relation_name => $relation_obj) {
999
-            $related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1000
-                $rest_request->get_param('include'),
1001
-                $relation_name
1002
-            );
1003
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
1004
-                $rest_request->get_param('calculate'),
1005
-                $relation_name
1006
-            );
1007
-            // did they specify they wanted to include a related model, or
1008
-            // specific fields from a related model?
1009
-            // or did they specify to calculate a field from a related model?
1010
-            if ($related_fields_to_include || $related_fields_to_calculate) {
1011
-                // if so, we should include at least some part of the related model
1012
-                $pretend_related_request = new WP_REST_Request();
1013
-                $pretend_related_request->set_query_params(
1014
-                    [
1015
-                        'caps'      => $rest_request->get_param('caps'),
1016
-                        'include'   => $related_fields_to_include,
1017
-                        'calculate' => $related_fields_to_calculate,
1018
-                        'password'  => $rest_request->get_param('password'),
1019
-                    ]
1020
-                );
1021
-                $pretend_related_request->add_header('no_rest_headers', true);
1022
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
1023
-                    $model->get_index_primary_key_string(
1024
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
1025
-                    )
1026
-                );
1027
-                if (! $included_items_protected) {
1028
-                    try {
1029
-                        $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1030
-                            $primary_model_query_params,
1031
-                            $relation_obj,
1032
-                            $pretend_related_request
1033
-                        );
1034
-                    } catch (RestException $e) {
1035
-                        $related_results = null;
1036
-                    }
1037
-                } else {
1038
-                    // they're protected, hide them.
1039
-                    $related_results              = null;
1040
-                    $entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
1041
-                }
1042
-                if ($related_results instanceof WP_Error || $related_results === null) {
1043
-                    $related_results =
1044
-                        $relation_obj instanceof EE_Belongs_To_Relation
1045
-                            ? null
1046
-                            : [];
1047
-                }
1048
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1049
-            }
1050
-        }
1051
-        return $entity_array;
1052
-    }
1053
-
1054
-
1055
-    /**
1056
-     * If the user has requested only specific properties (including meta properties like _links or _protected)
1057
-     * remove everything else.
1058
-     *
1059
-     * @param EEM_Base        $model
1060
-     * @param WP_REST_Request $rest_request
1061
-     * @param                 $entity_array
1062
-     * @return array
1063
-     * @throws EE_Error
1064
-     * @since 4.9.74.p
1065
-     */
1066
-    protected function includeOnlyRequestedProperties(
1067
-        EEM_Base $model,
1068
-        WP_REST_Request $rest_request,
1069
-        $entity_array
1070
-    ) {
1071
-
1072
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1073
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1074
-        // if they passed in * or didn't specify any includes, return everything
1075
-        if (
1076
-            ! in_array('*', $includes_for_this_model)
1077
-            && ! empty($includes_for_this_model)
1078
-        ) {
1079
-            if ($model->has_primary_key_field()) {
1080
-                // always include the primary key. ya just gotta know that at least
1081
-                $includes_for_this_model[] = $model->primary_key_name();
1082
-            }
1083
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1084
-                $includes_for_this_model[] = '_calculated_fields';
1085
-            }
1086
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1087
-        }
1088
-        return $entity_array;
1089
-    }
1090
-
1091
-
1092
-    /**
1093
-     * Returns a new array with all the names of models removed. Eg
1094
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1095
-     *
1096
-     * @param array $arr
1097
-     * @return array
1098
-     */
1099
-    private function removeModelNamesFromArray($arr)
1100
-    {
1101
-        return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
1102
-    }
1103
-
1104
-
1105
-    /**
1106
-     * Gets the calculated fields for the response
1107
-     *
1108
-     * @param EEM_Base        $model
1109
-     * @param array           $wpdb_row
1110
-     * @param WP_REST_Request $rest_request
1111
-     * @param boolean         $row_is_protected whether this row is password protected or not
1112
-     * @return stdClass the _calculations item in the entity
1113
-     * @throws RestException if a default value has a PHP object, which should never do (and if we
1114
-     * @throws EE_Error
1115
-     *                                          did, let's know about it ASAP, so let the exception bubble up)
1116
-     */
1117
-    protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false)
1118
-    {
1119
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1120
-            $rest_request->get_param('calculate'),
1121
-            ''
1122
-        );
1123
-        // note: setting calculate=* doesn't do anything
1124
-        $calculated_fields_to_return = new stdClass();
1125
-        $protected_fields            = [];
1126
-        foreach ($calculated_fields as $field_to_calculate) {
1127
-            try {
1128
-                // it's password protected, so they shouldn't be able to read this. Remove the value
1129
-                $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1130
-                if (
1131
-                    $row_is_protected
1132
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1133
-                    && $schema['properties'][ $field_to_calculate ]['protected']
1134
-                ) {
1135
-                    $calculated_value   = null;
1136
-                    $protected_fields[] = $field_to_calculate;
1137
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1138
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1139
-                            case 'boolean':
1140
-                                $calculated_value = false;
1141
-                                break;
1142
-                            case 'integer':
1143
-                                $calculated_value = 0;
1144
-                                break;
1145
-                            case 'string':
1146
-                                $calculated_value = '';
1147
-                                break;
1148
-                            case 'array':
1149
-                                $calculated_value = [];
1150
-                                break;
1151
-                            case 'object':
1152
-                                $calculated_value = new stdClass();
1153
-                                break;
1154
-                        }
1155
-                    }
1156
-                } else {
1157
-                    $calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1158
-                        null,
1159
-                        $this->fields_calculator->retrieveCalculatedFieldValue(
1160
-                            $model,
1161
-                            $field_to_calculate,
1162
-                            $wpdb_row,
1163
-                            $rest_request,
1164
-                            $this
1165
-                        ),
1166
-                        $this->getModelVersionInfo()->requestedVersion()
1167
-                    );
1168
-                }
1169
-                $calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1170
-            } catch (RestException $e) {
1171
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
1172
-                $this->setResponseHeader(
1173
-                    'Notices-Field-Calculation-Errors['
1174
-                    . $e->getStringCode()
1175
-                    . ']['
1176
-                    . $model->get_this_model_name()
1177
-                    . ']['
1178
-                    . $field_to_calculate
1179
-                    . ']',
1180
-                    $e->getMessage(),
1181
-                    true
1182
-                );
1183
-            }
1184
-        }
1185
-        $calculated_fields_to_return->_protected = $protected_fields;
1186
-        return $calculated_fields_to_return;
1187
-    }
1188
-
1189
-
1190
-    /**
1191
-     * Gets the full URL to the resource, taking the requested version into account
1192
-     *
1193
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1194
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1195
-     * @throws EE_Error
1196
-     * @throws EE_Error
1197
-     */
1198
-    public function getVersionedLinkTo($link_part_after_version_and_slash)
1199
-    {
1200
-        return rest_url(
1201
-            EED_Core_Rest_Api::get_versioned_route_to(
1202
-                $link_part_after_version_and_slash,
1203
-                $this->getModelVersionInfo()->requestedVersion()
1204
-            )
1205
-        );
1206
-    }
1207
-
1208
-
1209
-    /**
1210
-     * Gets the correct lowercase name for the relation in the API according
1211
-     * to the relation's type
1212
-     *
1213
-     * @param string                 $relation_name
1214
-     * @param EE_Model_Relation_Base $relation_obj
1215
-     * @return string
1216
-     */
1217
-    public static function getRelatedEntityName($relation_name, $relation_obj)
1218
-    {
1219
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1220
-            return strtolower($relation_name);
1221
-        } else {
1222
-            return EEH_Inflector::pluralize_and_lower($relation_name);
1223
-        }
1224
-    }
1225
-
1226
-
1227
-    /**
1228
-     * Gets the one model object with the specified id for the specified model
1229
-     *
1230
-     * @param EEM_Base        $model
1231
-     * @param WP_REST_Request $request
1232
-     * @return array
1233
-     * @throws EE_Error
1234
-     * @throws EE_Error
1235
-     * @throws ReflectionException
1236
-     */
1237
-    public function getEntityFromModel($model, $request)
1238
-    {
1239
-        $context = $this->validateContext($request->get_param('caps'));
1240
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1241
-    }
1242
-
1243
-
1244
-    /**
1245
-     * If a context is provided which isn't valid, maybe it was added in a future
1246
-     * version so just treat it as a default read
1247
-     *
1248
-     * @param string $context
1249
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1250
-     */
1251
-    public function validateContext($context)
1252
-    {
1253
-        if (! $context) {
1254
-            $context = EEM_Base::caps_read;
1255
-        }
1256
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1257
-        if (in_array($context, $valid_contexts)) {
1258
-            return $context;
1259
-        } else {
1260
-            return EEM_Base::caps_read;
1261
-        }
1262
-    }
1263
-
1264
-
1265
-    /**
1266
-     * Verifies the passed in value is an allowable default where conditions value.
1267
-     *
1268
-     * @param $default_query_params
1269
-     * @return string
1270
-     */
1271
-    public function validateDefaultQueryParams($default_query_params)
1272
-    {
1273
-        $valid_default_where_conditions_for_api_calls = [
1274
-            EEM_Base::default_where_conditions_all,
1275
-            EEM_Base::default_where_conditions_minimum_all,
1276
-            EEM_Base::default_where_conditions_minimum_others,
1277
-        ];
1278
-        if (! $default_query_params) {
1279
-            $default_query_params = EEM_Base::default_where_conditions_all;
1280
-        }
1281
-        if (
1282
-            in_array(
1283
-                $default_query_params,
1284
-                $valid_default_where_conditions_for_api_calls,
1285
-                true
1286
-            )
1287
-        ) {
1288
-            return $default_query_params;
1289
-        }
1290
-        return EEM_Base::default_where_conditions_all;
1291
-    }
1292
-
1293
-
1294
-    /**
1295
-     * Translates API filter get parameter into model query params @see
1296
-     * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1297
-     * Note: right now the query parameter keys for fields (and related fields) can be left as-is, but it's quite
1298
-     * possible this will change someday. Also, this method's contents might be candidate for moving to
1299
-     * Model_Data_Translator
1300
-     *
1301
-     * @param EEM_Base $model
1302
-     * @param array    $query_params
1303
-     * @return array model query params (@see
1304
-     *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1305
-     *               or FALSE to indicate that absolutely no results should be returned
1306
-     * @throws EE_Error
1307
-     * @throws RestException
1308
-     */
1309
-    public function createModelQueryParams($model, $query_params)
1310
-    {
1311
-        $model_query_params = [];
1312
-        if (isset($query_params['where'])) {
1313
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1314
-                $query_params['where'],
1315
-                $model,
1316
-                $this->getModelVersionInfo()->requestedVersion()
1317
-            );
1318
-        }
1319
-        if (isset($query_params['order_by'])) {
1320
-            $order_by = $query_params['order_by'];
1321
-        } elseif (isset($query_params['orderby'])) {
1322
-            $order_by = $query_params['orderby'];
1323
-        } else {
1324
-            $order_by = null;
1325
-        }
1326
-        if ($order_by !== null) {
1327
-            if (is_array($order_by)) {
1328
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1329
-            } else {
1330
-                // it's a single item
1331
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1332
-            }
1333
-            $model_query_params['order_by'] = $order_by;
1334
-        }
1335
-        if (isset($query_params['group_by'])) {
1336
-            $group_by = $query_params['group_by'];
1337
-        } elseif (isset($query_params['groupby'])) {
1338
-            $group_by = $query_params['groupby'];
1339
-        } else {
1340
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1341
-        }
1342
-        // make sure they're all real names
1343
-        if (is_array($group_by)) {
1344
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1345
-        }
1346
-        if ($group_by !== null) {
1347
-            $model_query_params['group_by'] = $group_by;
1348
-        }
1349
-        if (isset($query_params['having'])) {
1350
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1351
-                $query_params['having'],
1352
-                $model,
1353
-                $this->getModelVersionInfo()->requestedVersion()
1354
-            );
1355
-        }
1356
-        if (isset($query_params['order'])) {
1357
-            $model_query_params['order'] = $query_params['order'];
1358
-        }
1359
-        if (isset($query_params['mine'])) {
1360
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1361
-        }
1362
-        if (isset($query_params['limit'])) {
1363
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1364
-            if (! is_array($query_params['limit'])) {
1365
-                $limit_array = explode(',', (string) $query_params['limit']);
1366
-            } else {
1367
-                $limit_array = $query_params['limit'];
1368
-            }
1369
-            $sanitized_limit = [];
1370
-            foreach ($limit_array as $limit_part) {
1371
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1372
-                    throw new EE_Error(
1373
-                        sprintf(
1374
-                            esc_html__(
1375
-                            // @codingStandardsIgnoreStart
1376
-                                '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.',
1377
-                                // @codingStandardsIgnoreEnd
1378
-                                'event_espresso'
1379
-                            ),
1380
-                            wp_json_encode($query_params['limit'])
1381
-                        )
1382
-                    );
1383
-                }
1384
-                $sanitized_limit[] = (int) $limit_part;
1385
-            }
1386
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1387
-        } else {
1388
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1389
-        }
1390
-        if (isset($query_params['caps'])) {
1391
-            $model_query_params['caps'] = $this->validateContext($query_params['caps']);
1392
-        } else {
1393
-            $model_query_params['caps'] = EEM_Base::caps_read;
1394
-        }
1395
-        if (isset($query_params['default_where_conditions'])) {
1396
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1397
-                $query_params['default_where_conditions']
1398
-            );
1399
-        }
1400
-        // if this is a model protected by a password on another model, exclude the password protected
1401
-        // entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1402
-        // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1403
-        if (
1404
-            ! $model->hasPassword()
1405
-            && $model->restrictedByRelatedModelPassword()
1406
-            && $model_query_params['caps'] === EEM_Base::caps_read
1407
-        ) {
1408
-            if (empty($query_params['password'])) {
1409
-                $model_query_params['exclude_protected'] = true;
1410
-            }
1411
-        }
1412
-
1413
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1414
-    }
1415
-
1416
-
1417
-    /**
1418
-     * Changes the REST-style query params for use in the models
1419
-     *
1420
-     * @param EEM_Base $model
1421
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1422
-     * @return array
1423
-     * @deprecated
1424
-     */
1425
-    public function prepareRestQueryParamsKeyForModels($model, $query_params)
1426
-    {
1427
-        $model_ready_query_params = [];
1428
-        foreach ($query_params as $key => $value) {
1429
-            $model_ready_query_params[ $key ] = is_array($value)
1430
-                ? $this->prepareRestQueryParamsKeyForModels($model, $value)
1431
-                : $value;
1432
-        }
1433
-        return $model_ready_query_params;
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * @param $model
1439
-     * @param $query_params
1440
-     * @return array
1441
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1442
-     */
1443
-    public function prepareRestQueryParamsValuesForModels($model, $query_params)
1444
-    {
1445
-        $model_ready_query_params = [];
1446
-        foreach ($query_params as $key => $value) {
1447
-            if (is_array($value)) {
1448
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1449
-            } else {
1450
-                $model_ready_query_params[ $key ] = $value;
1451
-            }
1452
-        }
1453
-        return $model_ready_query_params;
1454
-    }
1455
-
1456
-
1457
-    /**
1458
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1459
-     * If no prefix is specified, returns items with no period.
1460
-     *
1461
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1462
-     * @param string       $prefix            "Event" or "foobar"
1463
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1464
-     *                                        we only return strings starting with that and a period; if no prefix was
1465
-     *                                        specified we return all items containing NO periods
1466
-     */
1467
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1468
-    {
1469
-        if (is_string($string_to_explode)) {
1470
-            $exploded_contents = explode(',', $string_to_explode);
1471
-        } elseif (is_array($string_to_explode)) {
1472
-            $exploded_contents = $string_to_explode;
1473
-        } else {
1474
-            $exploded_contents = [];
1475
-        }
1476
-        // if the string was empty, we want an empty array
1477
-        $exploded_contents    = array_filter($exploded_contents);
1478
-        $contents_with_prefix = [];
1479
-        foreach ($exploded_contents as $item) {
1480
-            $item = trim($item);
1481
-            // if no prefix was provided, so we look for items with no "." in them
1482
-            if (! $prefix) {
1483
-                // does this item have a period?
1484
-                if (strpos($item, '.') === false) {
1485
-                    // if not, then its what we're looking for
1486
-                    $contents_with_prefix[] = $item;
1487
-                }
1488
-            } elseif (strpos($item, $prefix . '.') === 0) {
1489
-                // this item has the prefix and a period, grab it
1490
-                $contents_with_prefix[] = substr(
1491
-                    $item,
1492
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1493
-                );
1494
-            } elseif ($item === $prefix) {
1495
-                // this item is JUST the prefix
1496
-                // so let's grab everything after, which is a blank string
1497
-                $contents_with_prefix[] = '';
1498
-            }
1499
-        }
1500
-        return $contents_with_prefix;
1501
-    }
1502
-
1503
-
1504
-    /**
1505
-     * @param string $include_string @see Read:handle_request_get_all
1506
-     * @param string $model_name
1507
-     * @return array of fields for this model. If $model_name is provided, then
1508
-     *                               the fields for that model, with the model's name removed from each.
1509
-     *                               If $include_string was blank or '*' returns an empty array
1510
-     * @throws EE_Error
1511
-     * @throws EE_Error
1512
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1513
-     *                               Deprecated because its return values were really quite confusing- sometimes it
1514
-     *                               returned an empty array (when the include string was blank or '*') or sometimes it
1515
-     *                               returned array('*') (when you provided a model and a model of that kind was
1516
-     *                               found). Parses the $include_string so we fetch all the field names relating to
1517
-     *                               THIS model
1518
-     *                               (ie have NO period in them), or for the provided model (ie start with the model
1519
-     *                               name and then a period).
1520
-     */
1521
-    public function extractIncludesForThisModel($include_string, $model_name = null)
1522
-    {
1523
-        if (is_array($include_string)) {
1524
-            $include_string = implode(',', $include_string);
1525
-        }
1526
-        if ($include_string === '*' || $include_string === '') {
1527
-            return [];
1528
-        }
1529
-        $includes                    = explode(',', $include_string);
1530
-        $extracted_fields_to_include = [];
1531
-        if ($model_name) {
1532
-            foreach ($includes as $field_to_include) {
1533
-                $field_to_include = trim($field_to_include);
1534
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1535
-                    // found the model name at the exact start
1536
-                    $field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1537
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1538
-                } elseif ($field_to_include == $model_name) {
1539
-                    $extracted_fields_to_include[] = '*';
1540
-                }
1541
-            }
1542
-        } else {
1543
-            // look for ones with no period
1544
-            foreach ($includes as $field_to_include) {
1545
-                $field_to_include = trim($field_to_include);
1546
-                if (
1547
-                    strpos($field_to_include, '.') === false
1548
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1549
-                ) {
1550
-                    $extracted_fields_to_include[] = $field_to_include;
1551
-                }
1552
-            }
1553
-        }
1554
-        return $extracted_fields_to_include;
1555
-    }
1556
-
1557
-
1558
-    /**
1559
-     * Gets the single item using the model according to the request in the context given, otherwise
1560
-     * returns that it's inaccessible to the current user
1561
-     *
1562
-     * @param EEM_Base        $model
1563
-     * @param WP_REST_Request $request
1564
-     * @param null            $context
1565
-     * @return array
1566
-     * @throws EE_Error
1567
-     * @throws ReflectionException
1568
-     */
1569
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1570
-    {
1571
-        $query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1];
1572
-        if ($model instanceof EEM_Soft_Delete_Base) {
1573
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1574
-        }
1575
-        $restricted_query_params         = $query_params;
1576
-        $restricted_query_params['caps'] = $context;
1577
-        $this->setDebugInfo('model query params', $restricted_query_params);
1578
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1579
-        if (! empty($model_rows)) {
1580
-            return $this->createEntityFromWpdbResult(
1581
-                $model,
1582
-                reset($model_rows),
1583
-                $request
1584
-            );
1585
-        } else {
1586
-            // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1587
-            $lowercase_model_name = strtolower($model->get_this_model_name());
1588
-            if ($model->exists($query_params)) {
1589
-                // you got shafted- it existed but we didn't want to tell you!
1590
-                throw new RestException(
1591
-                    'rest_user_cannot_' . $context,
1592
-                    sprintf(
1593
-                        esc_html__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1594
-                        $context,
1595
-                        $lowercase_model_name,
1596
-                        Capabilities::getMissingPermissionsString(
1597
-                            $model,
1598
-                            $context
1599
-                        )
1600
-                    ),
1601
-                    ['status' => 403]
1602
-                );
1603
-            } else {
1604
-                // it's not you. It just doesn't exist
1605
-                throw new RestException(
1606
-                    sprintf('rest_%s_invalid_id', $lowercase_model_name),
1607
-                    sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1608
-                    ['status' => 404]
1609
-                );
1610
-            }
1611
-        }
1612
-    }
1613
-
1614
-
1615
-    /**
1616
-     * Checks that if this content requires a password to be read, that it's been provided and is correct.
1617
-     *
1618
-     * @param EEM_Base        $model
1619
-     * @param array           $model_row
1620
-     * @param array           $query_params Adds 'default_where_conditions' => 'minimum'
1621
-     *                                      to ensure we don't confuse trashed with password protected.
1622
-     * @param WP_REST_Request $request
1623
-     * @throws EE_Error
1624
-     * @throws InvalidArgumentException
1625
-     * @throws InvalidDataTypeException
1626
-     * @throws InvalidInterfaceException
1627
-     * @throws RestPasswordRequiredException
1628
-     * @throws RestPasswordIncorrectException
1629
-     * @throws ModelConfigurationException
1630
-     * @throws ReflectionException
1631
-     * @since 4.9.74.p
1632
-     */
1633
-    protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request)
1634
-    {
1635
-        $query_params['default_where_conditions'] = 'minimum';
1636
-        // stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1637
-        // or you don't.
1638
-        $request_caps = $request->get_param('caps');
1639
-        if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1640
-            return;
1641
-        }
1642
-        // if this entity requires a password, they better give it and it better be right!
1643
-        if (
1644
-            $model->hasPassword()
1645
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1646
-        ) {
1647
-            if (empty($request['password'])) {
1648
-                throw new RestPasswordRequiredException();
1649
-            }
1650
-            if (
1651
-                ! hash_equals(
1652
-                    $model_row[ $model->getPasswordField()->get_qualified_column() ],
1653
-                    $request['password']
1654
-                )
1655
-            ) {
1656
-                throw new RestPasswordIncorrectException();
1657
-            }
1658
-        } elseif (
1659
-            // wait! maybe this content is password protected
1660
-            $model->restrictedByRelatedModelPassword()
1661
-            && $request->get_param('caps') === EEM_Base::caps_read
1662
-        ) {
1663
-            $password_supplied = $request->get_param('password');
1664
-            if (empty($password_supplied)) {
1665
-                $query_params['exclude_protected'] = true;
1666
-                if (! $model->exists($query_params)) {
1667
-                    throw new RestPasswordRequiredException();
1668
-                }
1669
-            } else {
1670
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1671
-                if (! $model->exists($query_params)) {
1672
-                    throw new RestPasswordIncorrectException();
1673
-                }
1674
-            }
1675
-        }
1676
-    }
52
+	/**
53
+	 * @var CalculatedModelFields
54
+	 */
55
+	protected $fields_calculator;
56
+
57
+
58
+	/**
59
+	 * Read constructor.
60
+	 *
61
+	 * @param CalculatedModelFields $fields_calculator
62
+	 */
63
+	public function __construct(CalculatedModelFields $fields_calculator)
64
+	{
65
+		parent::__construct();
66
+		$this->fields_calculator = $fields_calculator;
67
+	}
68
+
69
+
70
+	/**
71
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
72
+	 *
73
+	 * @param WP_REST_Request $request
74
+	 * @param string          $version
75
+	 * @param string          $model_name
76
+	 * @return WP_REST_Response|WP_Error
77
+	 * @throws InvalidArgumentException
78
+	 * @throws InvalidDataTypeException
79
+	 * @throws InvalidInterfaceException
80
+	 */
81
+	public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
82
+	{
83
+		$controller =
84
+			LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
85
+		try {
86
+			$controller->setRequestedVersion($version);
87
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
88
+				return $controller->sendResponse(
89
+					new WP_Error(
90
+						'endpoint_parsing_error',
91
+						sprintf(
92
+							esc_html__(
93
+								'There is no model for endpoint %s. Please contact event espresso support',
94
+								'event_espresso'
95
+							),
96
+							$model_name
97
+						)
98
+					)
99
+				);
100
+			}
101
+			return $controller->sendResponse(
102
+				$controller->getEntitiesFromModel(
103
+					$controller->getModelVersionInfo()->loadModel($model_name),
104
+					$request
105
+				)
106
+			);
107
+		} catch (Exception $e) {
108
+			return $controller->sendResponse($e);
109
+		}
110
+	}
111
+
112
+
113
+	/**
114
+	 * Prepares and returns schema for any OPTIONS request.
115
+	 *
116
+	 * @param string $version    The API endpoint version being used.
117
+	 * @param string $model_name Something like `Event` or `Registration`
118
+	 * @return array
119
+	 * @throws InvalidArgumentException
120
+	 * @throws InvalidDataTypeException
121
+	 * @throws InvalidInterfaceException
122
+	 */
123
+	public static function handleSchemaRequest($version, $model_name)
124
+	{
125
+		$controller =
126
+			LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
127
+		try {
128
+			$controller->setRequestedVersion($version);
129
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
130
+				return [];
131
+			}
132
+			// get the model for this version
133
+			$model        = $controller->getModelVersionInfo()->loadModel($model_name);
134
+			$model_schema = new JsonModelSchema(
135
+				$model,
136
+				LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields')
137
+			);
138
+			return $model_schema->getModelSchemaForRelations(
139
+				$controller->getModelVersionInfo()->relationSettings($model),
140
+				$controller->customizeSchemaForRestResponse(
141
+					$model,
142
+					$model_schema->getModelSchemaForFields(
143
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
144
+						$model_schema->getInitialSchemaStructure()
145
+					)
146
+				)
147
+			);
148
+		} catch (Exception $e) {
149
+			return [];
150
+		}
151
+	}
152
+
153
+
154
+	/**
155
+	 * This loops through each field in the given schema for the model and does the following:
156
+	 * - add any extra fields that are REST API specific and related to existing fields.
157
+	 * - transform default values into the correct format for a REST API response.
158
+	 *
159
+	 * @param EEM_Base $model
160
+	 * @param array    $schema
161
+	 * @return array  The final schema.
162
+	 * @throws EE_Error
163
+	 * @throws EE_Error
164
+	 */
165
+	protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
166
+	{
167
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
168
+			$schema = $this->translateDefaultsForRestResponse(
169
+				$field_name,
170
+				$field,
171
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
172
+			);
173
+		}
174
+		return $schema;
175
+	}
176
+
177
+
178
+	/**
179
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
180
+	 * response.
181
+	 *
182
+	 * @param                      $field_name
183
+	 * @param EE_Model_Field_Base  $field
184
+	 * @param array                $schema
185
+	 * @return array
186
+	 * @throws RestException  if a default value has a PHP object, which we should never do
187
+	 *                                  (but if we did, let's know about it ASAP, so let the exception bubble up)
188
+	 * @throws EE_Error
189
+	 *
190
+	 */
191
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
192
+	{
193
+		if (isset($schema['properties'][ $field_name ]['default'])) {
194
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
195
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
196
+					if ($default_key === 'raw') {
197
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
198
+							ModelDataTranslator::prepareFieldValueForJson(
199
+								$field,
200
+								$default_value,
201
+								$this->getModelVersionInfo()->requestedVersion()
202
+							);
203
+					}
204
+				}
205
+			} else {
206
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
207
+					$field,
208
+					$schema['properties'][ $field_name ]['default'],
209
+					$this->getModelVersionInfo()->requestedVersion()
210
+				);
211
+			}
212
+		}
213
+		return $schema;
214
+	}
215
+
216
+
217
+	/**
218
+	 * Adds additional fields to the schema
219
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
220
+	 * needs to be added to the schema.
221
+	 *
222
+	 * @param                      $field_name
223
+	 * @param EE_Model_Field_Base  $field
224
+	 * @param array                $schema
225
+	 * @return array
226
+	 */
227
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
228
+	{
229
+		if ($field instanceof EE_Datetime_Field) {
230
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
231
+			// modify the description
232
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
233
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
234
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
235
+			);
236
+		}
237
+		return $schema;
238
+	}
239
+
240
+
241
+	/**
242
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
243
+	 *
244
+	 * @return string
245
+	 */
246
+	protected function getRouteFromRequest()
247
+	{
248
+		if (
249
+			isset($GLOBALS['wp'])
250
+			&& $GLOBALS['wp'] instanceof WP
251
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
252
+		) {
253
+			return $GLOBALS['wp']->query_vars['rest_route'];
254
+		} else {
255
+			/** @var RequestInterface $request */
256
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
257
+			return $request->serverParamIsSet('PATH_INFO')
258
+				? $request->getServerParam('PATH_INFO')
259
+				: '/';
260
+		}
261
+	}
262
+
263
+
264
+	/**
265
+	 * Gets a single entity related to the model indicated in the path and its id
266
+	 *
267
+	 * @param WP_REST_Request $request
268
+	 * @param string          $version
269
+	 * @param string          $model_name
270
+	 * @return WP_REST_Response|WP_Error
271
+	 * @throws InvalidDataTypeException
272
+	 * @throws InvalidInterfaceException
273
+	 * @throws InvalidArgumentException
274
+	 */
275
+	public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
276
+	{
277
+		$controller =
278
+			LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
279
+		try {
280
+			$controller->setRequestedVersion($version);
281
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
282
+				return $controller->sendResponse(
283
+					new WP_Error(
284
+						'endpoint_parsing_error',
285
+						sprintf(
286
+							esc_html__(
287
+								'There is no model for endpoint %s. Please contact event espresso support',
288
+								'event_espresso'
289
+							),
290
+							$model_name
291
+						)
292
+					)
293
+				);
294
+			}
295
+			return $controller->sendResponse(
296
+				$controller->getEntityFromModel(
297
+					$controller->getModelVersionInfo()->loadModel($model_name),
298
+					$request
299
+				)
300
+			);
301
+		} catch (Exception $e) {
302
+			return $controller->sendResponse($e);
303
+		}
304
+	}
305
+
306
+
307
+	/**
308
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
309
+	 * to the item with the given id
310
+	 *
311
+	 * @param WP_REST_Request $request
312
+	 * @param string          $version
313
+	 * @param string          $model_name
314
+	 * @param string          $related_model_name
315
+	 * @return WP_REST_Response|WP_Error
316
+	 * @throws InvalidDataTypeException
317
+	 * @throws InvalidInterfaceException
318
+	 * @throws InvalidArgumentException
319
+	 */
320
+	public static function handleRequestGetRelated(
321
+		WP_REST_Request $request,
322
+		$version,
323
+		$model_name,
324
+		$related_model_name
325
+	) {
326
+		$controller =
327
+			LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
328
+		try {
329
+			$controller->setRequestedVersion($version);
330
+			$main_model = $controller->validateModel($model_name);
331
+			$controller->validateModel($related_model_name);
332
+			return $controller->sendResponse(
333
+				$controller->getEntitiesFromRelation(
334
+					$request->get_param('id'),
335
+					$main_model->related_settings_for($related_model_name),
336
+					$request
337
+				)
338
+			);
339
+		} catch (Exception $e) {
340
+			return $controller->sendResponse($e);
341
+		}
342
+	}
343
+
344
+
345
+	/**
346
+	 * Gets a collection for the given model and filters
347
+	 *
348
+	 * @param EEM_Base        $model
349
+	 * @param WP_REST_Request $request
350
+	 * @return array
351
+	 * @throws EE_Error
352
+	 * @throws InvalidArgumentException
353
+	 * @throws InvalidDataTypeException
354
+	 * @throws InvalidInterfaceException
355
+	 * @throws ReflectionException
356
+	 * @throws RestException
357
+	 */
358
+	public function getEntitiesFromModel($model, $request)
359
+	{
360
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
361
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
362
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
363
+			throw new RestException(
364
+				sprintf('rest_%s_cannot_list', $model_name_plural),
365
+				sprintf(
366
+					esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
367
+					$model_name_plural,
368
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
369
+				),
370
+				['status' => 403]
371
+			);
372
+		}
373
+		if (! $request->get_header('no_rest_headers')) {
374
+			$this->setHeadersFromQueryParams($model, $query_params);
375
+		}
376
+		/** @type array $results */
377
+		$results      = $model->get_all_wpdb_results($query_params);
378
+		$nice_results = [];
379
+		foreach ($results as $result) {
380
+			$nice_results[] = $this->createEntityFromWpdbResult(
381
+				$model,
382
+				$result,
383
+				$request
384
+			);
385
+		}
386
+		return $nice_results;
387
+	}
388
+
389
+
390
+	/**
391
+	 * Gets the collection for given relation object
392
+	 * The same as Read::get_entities_from_model(), except if the relation
393
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
394
+	 * the join-model-object into the results
395
+	 *
396
+	 * @param array                  $primary_model_query_params  query params for finding the item from which
397
+	 *                                                            relations will be based
398
+	 * @param EE_Model_Relation_Base $relation
399
+	 * @param WP_REST_Request        $request
400
+	 * @return array
401
+	 * @throws EE_Error
402
+	 * @throws InvalidArgumentException
403
+	 * @throws InvalidDataTypeException
404
+	 * @throws InvalidInterfaceException
405
+	 * @throws ReflectionException
406
+	 * @throws RestException
407
+	 * @throws ModelConfigurationException
408
+	 */
409
+	protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
410
+	{
411
+		$context       = $this->validateContext($request->get_param('caps'));
412
+		$model         = $relation->get_this_model();
413
+		$related_model = $relation->get_other_model();
414
+		if (! isset($primary_model_query_params[0])) {
415
+			$primary_model_query_params[0] = [];
416
+		}
417
+		// check if they can access the 1st model object
418
+		$primary_model_query_params = [
419
+			0       => $primary_model_query_params[0],
420
+			'limit' => 1,
421
+		];
422
+		if ($model instanceof EEM_Soft_Delete_Base) {
423
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
424
+				$primary_model_query_params
425
+			);
426
+		}
427
+		$restricted_query_params          = $primary_model_query_params;
428
+		$restricted_query_params['caps']  = $context;
429
+		$restricted_query_params['limit'] = 1;
430
+		$this->setDebugInfo('main model query params', $restricted_query_params);
431
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
432
+		$primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
433
+		$primary_model_row  = null;
434
+		if (is_array($primary_model_rows)) {
435
+			$primary_model_row = reset($primary_model_rows);
436
+		}
437
+		if (
438
+			! (
439
+				$primary_model_row
440
+				&& Capabilities::currentUserHasPartialAccessTo($related_model, $context)
441
+			)
442
+		) {
443
+			if ($relation instanceof EE_Belongs_To_Relation) {
444
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
445
+			} else {
446
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
447
+					$related_model->get_this_model_name()
448
+				);
449
+			}
450
+			throw new RestException(
451
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
452
+				sprintf(
453
+					esc_html__(
454
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
455
+						'event_espresso'
456
+					),
457
+					$related_model_name_maybe_plural,
458
+					$relation->get_this_model()->get_this_model_name(),
459
+					implode(
460
+						',',
461
+						array_keys(
462
+							Capabilities::getMissingPermissions($related_model, $context)
463
+						)
464
+					)
465
+				),
466
+				['status' => 403]
467
+			);
468
+		}
469
+
470
+		$this->checkPassword(
471
+			$model,
472
+			$primary_model_row,
473
+			$restricted_query_params,
474
+			$request
475
+		);
476
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
477
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
478
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
479
+							  . '.'
480
+							  . $where_condition_key ] = $where_condition_value;
481
+		}
482
+		$query_params['default_where_conditions'] = 'none';
483
+		$query_params['caps']                     = $context;
484
+		if (! $request->get_header('no_rest_headers')) {
485
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
486
+		}
487
+		/** @type array $results */
488
+		$results      = $relation->get_other_model()->get_all_wpdb_results($query_params);
489
+		$nice_results = [];
490
+		foreach ($results as $result) {
491
+			$nice_result = $this->createEntityFromWpdbResult(
492
+				$relation->get_other_model(),
493
+				$result,
494
+				$request
495
+			);
496
+			if ($relation instanceof EE_HABTM_Relation) {
497
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
498
+				// if there are conflicts we prefer the properties from the main model
499
+				$join_model_result = $this->createEntityFromWpdbResult(
500
+					$relation->get_join_model(),
501
+					$result,
502
+					$request
503
+				);
504
+				$joined_result     = array_merge($join_model_result, $nice_result);
505
+				// but keep the meta stuff from the main model
506
+				if (isset($nice_result['meta'])) {
507
+					$joined_result['meta'] = $nice_result['meta'];
508
+				}
509
+				$nice_result = $joined_result;
510
+			}
511
+			$nice_results[] = $nice_result;
512
+		}
513
+		if ($relation instanceof EE_Belongs_To_Relation) {
514
+			return array_shift($nice_results);
515
+		} else {
516
+			return $nice_results;
517
+		}
518
+	}
519
+
520
+
521
+	/**
522
+	 * Gets the collection for given relation object
523
+	 * The same as Read::get_entities_from_model(), except if the relation
524
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
525
+	 * the join-model-object into the results
526
+	 *
527
+	 * @param string                 $id the ID of the thing we are fetching related stuff from
528
+	 * @param EE_Model_Relation_Base $relation
529
+	 * @param WP_REST_Request        $request
530
+	 * @return array
531
+	 * @throws EE_Error
532
+	 * @throws ReflectionException
533
+	 */
534
+	public function getEntitiesFromRelation($id, $relation, $request)
535
+	{
536
+		if (! $relation->get_this_model()->has_primary_key_field()) {
537
+			throw new EE_Error(
538
+				sprintf(
539
+					esc_html__(
540
+					// @codingStandardsIgnoreStart
541
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
542
+						// @codingStandardsIgnoreEnd
543
+						'event_espresso'
544
+					),
545
+					$relation->get_this_model()->get_this_model_name()
546
+				)
547
+			);
548
+		}
549
+		// can we edit that main item?
550
+		// if not, show nothing but an error
551
+		// otherwise, please proceed
552
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
553
+			[
554
+				[
555
+					$relation->get_this_model()->primary_key_name() => $id,
556
+				],
557
+			],
558
+			$relation,
559
+			$request
560
+		);
561
+	}
562
+
563
+
564
+	/**
565
+	 * Sets the headers that are based on the model and query params,
566
+	 * like the total records. This should only be called on the original request
567
+	 * from the client, not on subsequent internal
568
+	 *
569
+	 * @param EEM_Base $model
570
+	 * @param array    $query_params
571
+	 * @return void
572
+	 * @throws EE_Error
573
+	 * @throws EE_Error
574
+	 */
575
+	protected function setHeadersFromQueryParams($model, $query_params)
576
+	{
577
+		$this->setDebugInfo('model query params', $query_params);
578
+		$this->setDebugInfo(
579
+			'missing caps',
580
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
581
+		);
582
+		// normally the limit to a 2-part array, where the 2nd item is the limit
583
+		if (! isset($query_params['limit'])) {
584
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
585
+		}
586
+		if (is_array($query_params['limit'])) {
587
+			$limit_parts = $query_params['limit'];
588
+		} else {
589
+			$limit_parts = explode(',', $query_params['limit']);
590
+			if (count($limit_parts) == 1) {
591
+				$limit_parts = [0, $limit_parts[0]];
592
+			}
593
+		}
594
+		// remove the group by and having parts of the query, as those will
595
+		// make the sql query return an array of values, instead of just a single value
596
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
597
+		$count = $model->count($query_params, null, true);
598
+		$pages = $count / $limit_parts[1];
599
+		$this->setResponseHeader('Total', $count, false);
600
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
601
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
602
+	}
603
+
604
+
605
+	/**
606
+	 * Changes database results into REST API entities
607
+	 *
608
+	 * @param EEM_Base        $model
609
+	 * @param array           $db_row     like results from $wpdb->get_results()
610
+	 * @param WP_REST_Request $rest_request
611
+	 * @param string          $deprecated no longer used
612
+	 * @return array ready for being converted into json for sending to client
613
+	 * @throws EE_Error
614
+	 * @throws RestException
615
+	 * @throws InvalidDataTypeException
616
+	 * @throws InvalidInterfaceException
617
+	 * @throws InvalidArgumentException
618
+	 * @throws ReflectionException
619
+	 */
620
+	public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
621
+	{
622
+		if (! $rest_request instanceof WP_REST_Request) {
623
+			// ok so this was called in the old style, where the 3rd arg was
624
+			// $include, and the 4th arg was $context
625
+			// now setup the request just to avoid fatal errors, although we won't be able
626
+			// to truly make use of it because it's kinda devoid of info
627
+			$rest_request = new WP_REST_Request();
628
+			$rest_request->set_param('include', $rest_request);
629
+			$rest_request->set_param('caps', $deprecated);
630
+		}
631
+		if ($rest_request->get_param('caps') == null) {
632
+			$rest_request->set_param('caps', EEM_Base::caps_read);
633
+		}
634
+		$current_user_full_access_to_entity = $model->currentUserCan(
635
+			EEM_Base::caps_read_admin,
636
+			$model->deduce_fields_n_values_from_cols_n_values($db_row)
637
+		);
638
+		$entity_array                       = $this->createBareEntityFromWpdbResults($model, $db_row);
639
+		$entity_array                       = $this->addExtraFields($model, $db_row, $entity_array);
640
+		$entity_array['_links']             = $this->getEntityLinks($model, $db_row, $entity_array);
641
+		// when it's a regular read request for a model with a password and the password wasn't provided
642
+		// remove the password protected fields
643
+		$has_protected_fields = false;
644
+		try {
645
+			$this->checkPassword(
646
+				$model,
647
+				$db_row,
648
+				$model->alter_query_params_to_restrict_by_ID(
649
+					$model->get_index_primary_key_string(
650
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
651
+					)
652
+				),
653
+				$rest_request
654
+			);
655
+		} catch (RestPasswordRequiredException $e) {
656
+			if ($model->hasPassword()) {
657
+				// just remove protected fields
658
+				$has_protected_fields = true;
659
+				$entity_array         = Capabilities::filterOutPasswordProtectedFields(
660
+					$entity_array,
661
+					$model,
662
+					$this->getModelVersionInfo()
663
+				);
664
+			} else {
665
+				// that's a problem. None of this should be accessible if no password was provided
666
+				throw $e;
667
+			}
668
+		}
669
+
670
+		$entity_array['_calculated_fields'] =
671
+			$this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields);
672
+		$entity_array                       = apply_filters(
673
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
674
+			$entity_array,
675
+			$model,
676
+			$rest_request->get_param('caps'),
677
+			$rest_request,
678
+			$this
679
+		);
680
+		// add an empty protected property for now. If it's still around after we remove everything the request didn't
681
+		// want, we'll populate it then. k?
682
+		$entity_array['_protected'] = [];
683
+		// remove any properties the request didn't want. This way _protected won't bother mentioning them
684
+		$entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
685
+		$entity_array =
686
+			$this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields);
687
+		// if they still wanted the _protected property, add it.
688
+		if (isset($entity_array['_protected'])) {
689
+			$entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
690
+		}
691
+		$entity_array = apply_filters(
692
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
693
+			$entity_array,
694
+			$model,
695
+			$rest_request->get_param('caps'),
696
+			$rest_request,
697
+			$this
698
+		);
699
+		if (! $current_user_full_access_to_entity) {
700
+			$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
701
+				$entity_array,
702
+				$model,
703
+				$rest_request->get_param('caps'),
704
+				$this->getModelVersionInfo()
705
+			);
706
+		} else {
707
+			$result_without_inaccessible_fields = $entity_array;
708
+		}
709
+		$this->setDebugInfo(
710
+			'inaccessible fields',
711
+			array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
712
+		);
713
+		return apply_filters(
714
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
715
+			$result_without_inaccessible_fields,
716
+			$model,
717
+			$rest_request->get_param('caps')
718
+		);
719
+	}
720
+
721
+
722
+	/**
723
+	 * Returns an array describing which fields can be protected, and which actually were removed this request
724
+	 *
725
+	 * @param EEM_Base $model
726
+	 * @param array    $results_so_far
727
+	 * @param bool     $protected
728
+	 * @return array results
729
+	 * @throws EE_Error
730
+	 * @since 4.9.74.p
731
+	 */
732
+	protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
733
+	{
734
+		if (! $model->hasPassword() || ! $protected) {
735
+			return $results_so_far;
736
+		}
737
+		$password_field  = $model->getPasswordField();
738
+		$all_protected   = array_merge(
739
+			[$password_field->get_name()],
740
+			$password_field->protectedFields()
741
+		);
742
+		$fields_included = array_keys($results_so_far);
743
+		$fields_included = array_intersect(
744
+			$all_protected,
745
+			$fields_included
746
+		);
747
+		foreach ($fields_included as $field_name) {
748
+			$results_so_far['_protected'][] = $field_name;
749
+		}
750
+		return $results_so_far;
751
+	}
752
+
753
+
754
+	/**
755
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
756
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
757
+	 * from $wpdb->get_row( $sql, ARRAY_A)
758
+	 *
759
+	 * @param EEM_Base $model
760
+	 * @param array    $db_row
761
+	 * @return array entity mostly ready for converting to JSON and sending in the response
762
+	 * @throws EE_Error
763
+	 * @throws ReflectionException
764
+	 * @throws RestException
765
+	 */
766
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
767
+	{
768
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
769
+		$result = array_intersect_key(
770
+			$result,
771
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
772
+		);
773
+		// if this is a CPT, we need to set the global $post to it,
774
+		// otherwise shortcodes etc won't work properly while rendering it
775
+		if ($model instanceof EEM_CPT_Base) {
776
+			$do_chevy_shuffle = true;
777
+		} else {
778
+			$do_chevy_shuffle = false;
779
+		}
780
+		if ($do_chevy_shuffle) {
781
+			global $post;
782
+			$old_post = $post;
783
+			$post     = get_post($result[ $model->primary_key_name() ]);
784
+			if (! $post instanceof WP_Post) {
785
+				// well that's weird, because $result is what we JUST fetched from the database
786
+				throw new RestException(
787
+					'error_fetching_post_from_database_results',
788
+					esc_html__(
789
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
790
+						'event_espresso'
791
+					)
792
+				);
793
+			}
794
+			$model_object_classname          = 'EE_' . $model->get_this_model_name();
795
+			$post->{$model_object_classname} = EE_Registry::instance()->load_class(
796
+				$model_object_classname,
797
+				$result,
798
+				false,
799
+				false
800
+			);
801
+		}
802
+		foreach ($result as $field_name => $field_value) {
803
+			$field_obj = $model->field_settings_for($field_name);
804
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
805
+				unset($result[ $field_name ]);
806
+			} elseif (
807
+				$this->isSubclassOfOne(
808
+					$field_obj,
809
+					$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
810
+				)
811
+			) {
812
+				$result[ $field_name ] = [
813
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
814
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
815
+				];
816
+			} elseif (
817
+				$this->isSubclassOfOne(
818
+					$field_obj,
819
+					$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
820
+				)
821
+			) {
822
+				$result[ $field_name ] = [
823
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
824
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
825
+				];
826
+			} elseif ($field_obj instanceof EE_Datetime_Field) {
827
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
828
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
829
+				if (is_null($field_value)) {
830
+					$field_value = $field_obj->getDefaultDateTimeObj();
831
+				}
832
+				if (is_null($field_value)) {
833
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
834
+						$field_obj,
835
+						$field_value,
836
+						$this->getModelVersionInfo()->requestedVersion()
837
+					);
838
+				} else {
839
+					$timezone = $field_value->getTimezone();
840
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
841
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
842
+						$field_obj,
843
+						$field_value,
844
+						$this->getModelVersionInfo()->requestedVersion()
845
+					);
846
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
847
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
848
+						$field_obj,
849
+						$field_value,
850
+						$this->getModelVersionInfo()->requestedVersion()
851
+					);
852
+				}
853
+				$result[ $field_name . '_gmt' ] = $gmt_date;
854
+				$result[ $field_name ]          = $local_date;
855
+			} else {
856
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
857
+			}
858
+		}
859
+		if ($do_chevy_shuffle) {
860
+			$post = $old_post;
861
+		}
862
+		return $result;
863
+	}
864
+
865
+
866
+	/**
867
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
868
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
869
+	 * representation using $field_obj->prepare_for_set_from_db())
870
+	 *
871
+	 * @param EE_Model_Field_Base $field_obj
872
+	 * @param mixed               $value  as it's stored on a model object
873
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
874
+	 * @return array
875
+	 * @throws RestException if $value contains a PHP object
876
+	 * @throws EE_Error
877
+	 */
878
+	protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
879
+	{
880
+		$value = $field_obj->prepare_for_set_from_db($value);
881
+		switch ($format) {
882
+			case 'pretty':
883
+				$value = $field_obj->prepare_for_pretty_echoing($value);
884
+				break;
885
+			case 'normal':
886
+			default:
887
+				$value = $field_obj->prepare_for_get($value);
888
+				break;
889
+		}
890
+		return ModelDataTranslator::prepareFieldValuesForJson(
891
+			$field_obj,
892
+			$value,
893
+			$this->getModelVersionInfo()->requestedVersion()
894
+		);
895
+	}
896
+
897
+
898
+	/**
899
+	 * Adds a few extra fields to the entity response
900
+	 *
901
+	 * @param EEM_Base $model
902
+	 * @param array    $db_row
903
+	 * @param array    $entity_array
904
+	 * @return array modified entity
905
+	 * @throws EE_Error
906
+	 * @throws EE_Error
907
+	 */
908
+	protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
909
+	{
910
+		if ($model instanceof EEM_CPT_Base) {
911
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
912
+		}
913
+		return $entity_array;
914
+	}
915
+
916
+
917
+	/**
918
+	 * Gets links we want to add to the response
919
+	 *
920
+	 * @param EEM_Base        $model
921
+	 * @param array           $db_row
922
+	 * @param array           $entity_array
923
+	 * @return array the _links item in the entity
924
+	 * @throws EE_Error
925
+	 * @throws EE_Error
926
+	 * @global WP_REST_Server $wp_rest_server
927
+	 */
928
+	protected function getEntityLinks($model, $db_row, $entity_array)
929
+	{
930
+		// add basic links
931
+		$links = [];
932
+		if ($model->has_primary_key_field()) {
933
+			$links['self'] = [
934
+				[
935
+					'href' => $this->getVersionedLinkTo(
936
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
937
+						. '/'
938
+						. $entity_array[ $model->primary_key_name() ]
939
+					),
940
+				],
941
+			];
942
+		}
943
+		$links['collection'] = [
944
+			[
945
+				'href' => $this->getVersionedLinkTo(
946
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
947
+				),
948
+			],
949
+		];
950
+		// add links to related models
951
+		if ($model->has_primary_key_field()) {
952
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
953
+				$related_model_part                                                      =
954
+					Read::getRelatedEntityName($relation_name, $relation_obj);
955
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
956
+					[
957
+						'href'   => $this->getVersionedLinkTo(
958
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
959
+							. '/'
960
+							. $entity_array[ $model->primary_key_name() ]
961
+							. '/'
962
+							. $related_model_part
963
+						),
964
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation,
965
+					],
966
+				];
967
+			}
968
+		}
969
+		return $links;
970
+	}
971
+
972
+
973
+	/**
974
+	 * Adds the included models indicated in the request to the entity provided
975
+	 *
976
+	 * @param EEM_Base        $model
977
+	 * @param WP_REST_Request $rest_request
978
+	 * @param array           $entity_array
979
+	 * @param array           $db_row
980
+	 * @param boolean         $included_items_protected if the original item is password protected, don't include any
981
+	 *                                                  related models.
982
+	 * @return array the modified entity
983
+	 * @throws EE_Error
984
+	 * @throws ReflectionException
985
+	 */
986
+	protected function includeRequestedModels(
987
+		EEM_Base $model,
988
+		WP_REST_Request $rest_request,
989
+		$entity_array,
990
+		$db_row = [],
991
+		$included_items_protected = false
992
+	) {
993
+		// if $db_row not included, hope the entity array has what we need
994
+		if (! $db_row) {
995
+			$db_row = $entity_array;
996
+		}
997
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
998
+		foreach ($relation_settings as $relation_name => $relation_obj) {
999
+			$related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1000
+				$rest_request->get_param('include'),
1001
+				$relation_name
1002
+			);
1003
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
1004
+				$rest_request->get_param('calculate'),
1005
+				$relation_name
1006
+			);
1007
+			// did they specify they wanted to include a related model, or
1008
+			// specific fields from a related model?
1009
+			// or did they specify to calculate a field from a related model?
1010
+			if ($related_fields_to_include || $related_fields_to_calculate) {
1011
+				// if so, we should include at least some part of the related model
1012
+				$pretend_related_request = new WP_REST_Request();
1013
+				$pretend_related_request->set_query_params(
1014
+					[
1015
+						'caps'      => $rest_request->get_param('caps'),
1016
+						'include'   => $related_fields_to_include,
1017
+						'calculate' => $related_fields_to_calculate,
1018
+						'password'  => $rest_request->get_param('password'),
1019
+					]
1020
+				);
1021
+				$pretend_related_request->add_header('no_rest_headers', true);
1022
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
1023
+					$model->get_index_primary_key_string(
1024
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
1025
+					)
1026
+				);
1027
+				if (! $included_items_protected) {
1028
+					try {
1029
+						$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1030
+							$primary_model_query_params,
1031
+							$relation_obj,
1032
+							$pretend_related_request
1033
+						);
1034
+					} catch (RestException $e) {
1035
+						$related_results = null;
1036
+					}
1037
+				} else {
1038
+					// they're protected, hide them.
1039
+					$related_results              = null;
1040
+					$entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
1041
+				}
1042
+				if ($related_results instanceof WP_Error || $related_results === null) {
1043
+					$related_results =
1044
+						$relation_obj instanceof EE_Belongs_To_Relation
1045
+							? null
1046
+							: [];
1047
+				}
1048
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1049
+			}
1050
+		}
1051
+		return $entity_array;
1052
+	}
1053
+
1054
+
1055
+	/**
1056
+	 * If the user has requested only specific properties (including meta properties like _links or _protected)
1057
+	 * remove everything else.
1058
+	 *
1059
+	 * @param EEM_Base        $model
1060
+	 * @param WP_REST_Request $rest_request
1061
+	 * @param                 $entity_array
1062
+	 * @return array
1063
+	 * @throws EE_Error
1064
+	 * @since 4.9.74.p
1065
+	 */
1066
+	protected function includeOnlyRequestedProperties(
1067
+		EEM_Base $model,
1068
+		WP_REST_Request $rest_request,
1069
+		$entity_array
1070
+	) {
1071
+
1072
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1073
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1074
+		// if they passed in * or didn't specify any includes, return everything
1075
+		if (
1076
+			! in_array('*', $includes_for_this_model)
1077
+			&& ! empty($includes_for_this_model)
1078
+		) {
1079
+			if ($model->has_primary_key_field()) {
1080
+				// always include the primary key. ya just gotta know that at least
1081
+				$includes_for_this_model[] = $model->primary_key_name();
1082
+			}
1083
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1084
+				$includes_for_this_model[] = '_calculated_fields';
1085
+			}
1086
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1087
+		}
1088
+		return $entity_array;
1089
+	}
1090
+
1091
+
1092
+	/**
1093
+	 * Returns a new array with all the names of models removed. Eg
1094
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1095
+	 *
1096
+	 * @param array $arr
1097
+	 * @return array
1098
+	 */
1099
+	private function removeModelNamesFromArray($arr)
1100
+	{
1101
+		return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
1102
+	}
1103
+
1104
+
1105
+	/**
1106
+	 * Gets the calculated fields for the response
1107
+	 *
1108
+	 * @param EEM_Base        $model
1109
+	 * @param array           $wpdb_row
1110
+	 * @param WP_REST_Request $rest_request
1111
+	 * @param boolean         $row_is_protected whether this row is password protected or not
1112
+	 * @return stdClass the _calculations item in the entity
1113
+	 * @throws RestException if a default value has a PHP object, which should never do (and if we
1114
+	 * @throws EE_Error
1115
+	 *                                          did, let's know about it ASAP, so let the exception bubble up)
1116
+	 */
1117
+	protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false)
1118
+	{
1119
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1120
+			$rest_request->get_param('calculate'),
1121
+			''
1122
+		);
1123
+		// note: setting calculate=* doesn't do anything
1124
+		$calculated_fields_to_return = new stdClass();
1125
+		$protected_fields            = [];
1126
+		foreach ($calculated_fields as $field_to_calculate) {
1127
+			try {
1128
+				// it's password protected, so they shouldn't be able to read this. Remove the value
1129
+				$schema = $this->fields_calculator->getJsonSchemaForModel($model);
1130
+				if (
1131
+					$row_is_protected
1132
+					&& isset($schema['properties'][ $field_to_calculate ]['protected'])
1133
+					&& $schema['properties'][ $field_to_calculate ]['protected']
1134
+				) {
1135
+					$calculated_value   = null;
1136
+					$protected_fields[] = $field_to_calculate;
1137
+					if ($schema['properties'][ $field_to_calculate ]['type']) {
1138
+						switch ($schema['properties'][ $field_to_calculate ]['type']) {
1139
+							case 'boolean':
1140
+								$calculated_value = false;
1141
+								break;
1142
+							case 'integer':
1143
+								$calculated_value = 0;
1144
+								break;
1145
+							case 'string':
1146
+								$calculated_value = '';
1147
+								break;
1148
+							case 'array':
1149
+								$calculated_value = [];
1150
+								break;
1151
+							case 'object':
1152
+								$calculated_value = new stdClass();
1153
+								break;
1154
+						}
1155
+					}
1156
+				} else {
1157
+					$calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1158
+						null,
1159
+						$this->fields_calculator->retrieveCalculatedFieldValue(
1160
+							$model,
1161
+							$field_to_calculate,
1162
+							$wpdb_row,
1163
+							$rest_request,
1164
+							$this
1165
+						),
1166
+						$this->getModelVersionInfo()->requestedVersion()
1167
+					);
1168
+				}
1169
+				$calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1170
+			} catch (RestException $e) {
1171
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
1172
+				$this->setResponseHeader(
1173
+					'Notices-Field-Calculation-Errors['
1174
+					. $e->getStringCode()
1175
+					. ']['
1176
+					. $model->get_this_model_name()
1177
+					. ']['
1178
+					. $field_to_calculate
1179
+					. ']',
1180
+					$e->getMessage(),
1181
+					true
1182
+				);
1183
+			}
1184
+		}
1185
+		$calculated_fields_to_return->_protected = $protected_fields;
1186
+		return $calculated_fields_to_return;
1187
+	}
1188
+
1189
+
1190
+	/**
1191
+	 * Gets the full URL to the resource, taking the requested version into account
1192
+	 *
1193
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1194
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1195
+	 * @throws EE_Error
1196
+	 * @throws EE_Error
1197
+	 */
1198
+	public function getVersionedLinkTo($link_part_after_version_and_slash)
1199
+	{
1200
+		return rest_url(
1201
+			EED_Core_Rest_Api::get_versioned_route_to(
1202
+				$link_part_after_version_and_slash,
1203
+				$this->getModelVersionInfo()->requestedVersion()
1204
+			)
1205
+		);
1206
+	}
1207
+
1208
+
1209
+	/**
1210
+	 * Gets the correct lowercase name for the relation in the API according
1211
+	 * to the relation's type
1212
+	 *
1213
+	 * @param string                 $relation_name
1214
+	 * @param EE_Model_Relation_Base $relation_obj
1215
+	 * @return string
1216
+	 */
1217
+	public static function getRelatedEntityName($relation_name, $relation_obj)
1218
+	{
1219
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1220
+			return strtolower($relation_name);
1221
+		} else {
1222
+			return EEH_Inflector::pluralize_and_lower($relation_name);
1223
+		}
1224
+	}
1225
+
1226
+
1227
+	/**
1228
+	 * Gets the one model object with the specified id for the specified model
1229
+	 *
1230
+	 * @param EEM_Base        $model
1231
+	 * @param WP_REST_Request $request
1232
+	 * @return array
1233
+	 * @throws EE_Error
1234
+	 * @throws EE_Error
1235
+	 * @throws ReflectionException
1236
+	 */
1237
+	public function getEntityFromModel($model, $request)
1238
+	{
1239
+		$context = $this->validateContext($request->get_param('caps'));
1240
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1241
+	}
1242
+
1243
+
1244
+	/**
1245
+	 * If a context is provided which isn't valid, maybe it was added in a future
1246
+	 * version so just treat it as a default read
1247
+	 *
1248
+	 * @param string $context
1249
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1250
+	 */
1251
+	public function validateContext($context)
1252
+	{
1253
+		if (! $context) {
1254
+			$context = EEM_Base::caps_read;
1255
+		}
1256
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1257
+		if (in_array($context, $valid_contexts)) {
1258
+			return $context;
1259
+		} else {
1260
+			return EEM_Base::caps_read;
1261
+		}
1262
+	}
1263
+
1264
+
1265
+	/**
1266
+	 * Verifies the passed in value is an allowable default where conditions value.
1267
+	 *
1268
+	 * @param $default_query_params
1269
+	 * @return string
1270
+	 */
1271
+	public function validateDefaultQueryParams($default_query_params)
1272
+	{
1273
+		$valid_default_where_conditions_for_api_calls = [
1274
+			EEM_Base::default_where_conditions_all,
1275
+			EEM_Base::default_where_conditions_minimum_all,
1276
+			EEM_Base::default_where_conditions_minimum_others,
1277
+		];
1278
+		if (! $default_query_params) {
1279
+			$default_query_params = EEM_Base::default_where_conditions_all;
1280
+		}
1281
+		if (
1282
+			in_array(
1283
+				$default_query_params,
1284
+				$valid_default_where_conditions_for_api_calls,
1285
+				true
1286
+			)
1287
+		) {
1288
+			return $default_query_params;
1289
+		}
1290
+		return EEM_Base::default_where_conditions_all;
1291
+	}
1292
+
1293
+
1294
+	/**
1295
+	 * Translates API filter get parameter into model query params @see
1296
+	 * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1297
+	 * Note: right now the query parameter keys for fields (and related fields) can be left as-is, but it's quite
1298
+	 * possible this will change someday. Also, this method's contents might be candidate for moving to
1299
+	 * Model_Data_Translator
1300
+	 *
1301
+	 * @param EEM_Base $model
1302
+	 * @param array    $query_params
1303
+	 * @return array model query params (@see
1304
+	 *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1305
+	 *               or FALSE to indicate that absolutely no results should be returned
1306
+	 * @throws EE_Error
1307
+	 * @throws RestException
1308
+	 */
1309
+	public function createModelQueryParams($model, $query_params)
1310
+	{
1311
+		$model_query_params = [];
1312
+		if (isset($query_params['where'])) {
1313
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1314
+				$query_params['where'],
1315
+				$model,
1316
+				$this->getModelVersionInfo()->requestedVersion()
1317
+			);
1318
+		}
1319
+		if (isset($query_params['order_by'])) {
1320
+			$order_by = $query_params['order_by'];
1321
+		} elseif (isset($query_params['orderby'])) {
1322
+			$order_by = $query_params['orderby'];
1323
+		} else {
1324
+			$order_by = null;
1325
+		}
1326
+		if ($order_by !== null) {
1327
+			if (is_array($order_by)) {
1328
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1329
+			} else {
1330
+				// it's a single item
1331
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1332
+			}
1333
+			$model_query_params['order_by'] = $order_by;
1334
+		}
1335
+		if (isset($query_params['group_by'])) {
1336
+			$group_by = $query_params['group_by'];
1337
+		} elseif (isset($query_params['groupby'])) {
1338
+			$group_by = $query_params['groupby'];
1339
+		} else {
1340
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1341
+		}
1342
+		// make sure they're all real names
1343
+		if (is_array($group_by)) {
1344
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1345
+		}
1346
+		if ($group_by !== null) {
1347
+			$model_query_params['group_by'] = $group_by;
1348
+		}
1349
+		if (isset($query_params['having'])) {
1350
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1351
+				$query_params['having'],
1352
+				$model,
1353
+				$this->getModelVersionInfo()->requestedVersion()
1354
+			);
1355
+		}
1356
+		if (isset($query_params['order'])) {
1357
+			$model_query_params['order'] = $query_params['order'];
1358
+		}
1359
+		if (isset($query_params['mine'])) {
1360
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1361
+		}
1362
+		if (isset($query_params['limit'])) {
1363
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1364
+			if (! is_array($query_params['limit'])) {
1365
+				$limit_array = explode(',', (string) $query_params['limit']);
1366
+			} else {
1367
+				$limit_array = $query_params['limit'];
1368
+			}
1369
+			$sanitized_limit = [];
1370
+			foreach ($limit_array as $limit_part) {
1371
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1372
+					throw new EE_Error(
1373
+						sprintf(
1374
+							esc_html__(
1375
+							// @codingStandardsIgnoreStart
1376
+								'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.',
1377
+								// @codingStandardsIgnoreEnd
1378
+								'event_espresso'
1379
+							),
1380
+							wp_json_encode($query_params['limit'])
1381
+						)
1382
+					);
1383
+				}
1384
+				$sanitized_limit[] = (int) $limit_part;
1385
+			}
1386
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1387
+		} else {
1388
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1389
+		}
1390
+		if (isset($query_params['caps'])) {
1391
+			$model_query_params['caps'] = $this->validateContext($query_params['caps']);
1392
+		} else {
1393
+			$model_query_params['caps'] = EEM_Base::caps_read;
1394
+		}
1395
+		if (isset($query_params['default_where_conditions'])) {
1396
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1397
+				$query_params['default_where_conditions']
1398
+			);
1399
+		}
1400
+		// if this is a model protected by a password on another model, exclude the password protected
1401
+		// entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1402
+		// though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1403
+		if (
1404
+			! $model->hasPassword()
1405
+			&& $model->restrictedByRelatedModelPassword()
1406
+			&& $model_query_params['caps'] === EEM_Base::caps_read
1407
+		) {
1408
+			if (empty($query_params['password'])) {
1409
+				$model_query_params['exclude_protected'] = true;
1410
+			}
1411
+		}
1412
+
1413
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1414
+	}
1415
+
1416
+
1417
+	/**
1418
+	 * Changes the REST-style query params for use in the models
1419
+	 *
1420
+	 * @param EEM_Base $model
1421
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1422
+	 * @return array
1423
+	 * @deprecated
1424
+	 */
1425
+	public function prepareRestQueryParamsKeyForModels($model, $query_params)
1426
+	{
1427
+		$model_ready_query_params = [];
1428
+		foreach ($query_params as $key => $value) {
1429
+			$model_ready_query_params[ $key ] = is_array($value)
1430
+				? $this->prepareRestQueryParamsKeyForModels($model, $value)
1431
+				: $value;
1432
+		}
1433
+		return $model_ready_query_params;
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * @param $model
1439
+	 * @param $query_params
1440
+	 * @return array
1441
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1442
+	 */
1443
+	public function prepareRestQueryParamsValuesForModels($model, $query_params)
1444
+	{
1445
+		$model_ready_query_params = [];
1446
+		foreach ($query_params as $key => $value) {
1447
+			if (is_array($value)) {
1448
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1449
+			} else {
1450
+				$model_ready_query_params[ $key ] = $value;
1451
+			}
1452
+		}
1453
+		return $model_ready_query_params;
1454
+	}
1455
+
1456
+
1457
+	/**
1458
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1459
+	 * If no prefix is specified, returns items with no period.
1460
+	 *
1461
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1462
+	 * @param string       $prefix            "Event" or "foobar"
1463
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1464
+	 *                                        we only return strings starting with that and a period; if no prefix was
1465
+	 *                                        specified we return all items containing NO periods
1466
+	 */
1467
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1468
+	{
1469
+		if (is_string($string_to_explode)) {
1470
+			$exploded_contents = explode(',', $string_to_explode);
1471
+		} elseif (is_array($string_to_explode)) {
1472
+			$exploded_contents = $string_to_explode;
1473
+		} else {
1474
+			$exploded_contents = [];
1475
+		}
1476
+		// if the string was empty, we want an empty array
1477
+		$exploded_contents    = array_filter($exploded_contents);
1478
+		$contents_with_prefix = [];
1479
+		foreach ($exploded_contents as $item) {
1480
+			$item = trim($item);
1481
+			// if no prefix was provided, so we look for items with no "." in them
1482
+			if (! $prefix) {
1483
+				// does this item have a period?
1484
+				if (strpos($item, '.') === false) {
1485
+					// if not, then its what we're looking for
1486
+					$contents_with_prefix[] = $item;
1487
+				}
1488
+			} elseif (strpos($item, $prefix . '.') === 0) {
1489
+				// this item has the prefix and a period, grab it
1490
+				$contents_with_prefix[] = substr(
1491
+					$item,
1492
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1493
+				);
1494
+			} elseif ($item === $prefix) {
1495
+				// this item is JUST the prefix
1496
+				// so let's grab everything after, which is a blank string
1497
+				$contents_with_prefix[] = '';
1498
+			}
1499
+		}
1500
+		return $contents_with_prefix;
1501
+	}
1502
+
1503
+
1504
+	/**
1505
+	 * @param string $include_string @see Read:handle_request_get_all
1506
+	 * @param string $model_name
1507
+	 * @return array of fields for this model. If $model_name is provided, then
1508
+	 *                               the fields for that model, with the model's name removed from each.
1509
+	 *                               If $include_string was blank or '*' returns an empty array
1510
+	 * @throws EE_Error
1511
+	 * @throws EE_Error
1512
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1513
+	 *                               Deprecated because its return values were really quite confusing- sometimes it
1514
+	 *                               returned an empty array (when the include string was blank or '*') or sometimes it
1515
+	 *                               returned array('*') (when you provided a model and a model of that kind was
1516
+	 *                               found). Parses the $include_string so we fetch all the field names relating to
1517
+	 *                               THIS model
1518
+	 *                               (ie have NO period in them), or for the provided model (ie start with the model
1519
+	 *                               name and then a period).
1520
+	 */
1521
+	public function extractIncludesForThisModel($include_string, $model_name = null)
1522
+	{
1523
+		if (is_array($include_string)) {
1524
+			$include_string = implode(',', $include_string);
1525
+		}
1526
+		if ($include_string === '*' || $include_string === '') {
1527
+			return [];
1528
+		}
1529
+		$includes                    = explode(',', $include_string);
1530
+		$extracted_fields_to_include = [];
1531
+		if ($model_name) {
1532
+			foreach ($includes as $field_to_include) {
1533
+				$field_to_include = trim($field_to_include);
1534
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1535
+					// found the model name at the exact start
1536
+					$field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1537
+					$extracted_fields_to_include[] = $field_sans_model_name;
1538
+				} elseif ($field_to_include == $model_name) {
1539
+					$extracted_fields_to_include[] = '*';
1540
+				}
1541
+			}
1542
+		} else {
1543
+			// look for ones with no period
1544
+			foreach ($includes as $field_to_include) {
1545
+				$field_to_include = trim($field_to_include);
1546
+				if (
1547
+					strpos($field_to_include, '.') === false
1548
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1549
+				) {
1550
+					$extracted_fields_to_include[] = $field_to_include;
1551
+				}
1552
+			}
1553
+		}
1554
+		return $extracted_fields_to_include;
1555
+	}
1556
+
1557
+
1558
+	/**
1559
+	 * Gets the single item using the model according to the request in the context given, otherwise
1560
+	 * returns that it's inaccessible to the current user
1561
+	 *
1562
+	 * @param EEM_Base        $model
1563
+	 * @param WP_REST_Request $request
1564
+	 * @param null            $context
1565
+	 * @return array
1566
+	 * @throws EE_Error
1567
+	 * @throws ReflectionException
1568
+	 */
1569
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1570
+	{
1571
+		$query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1];
1572
+		if ($model instanceof EEM_Soft_Delete_Base) {
1573
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1574
+		}
1575
+		$restricted_query_params         = $query_params;
1576
+		$restricted_query_params['caps'] = $context;
1577
+		$this->setDebugInfo('model query params', $restricted_query_params);
1578
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1579
+		if (! empty($model_rows)) {
1580
+			return $this->createEntityFromWpdbResult(
1581
+				$model,
1582
+				reset($model_rows),
1583
+				$request
1584
+			);
1585
+		} else {
1586
+			// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1587
+			$lowercase_model_name = strtolower($model->get_this_model_name());
1588
+			if ($model->exists($query_params)) {
1589
+				// you got shafted- it existed but we didn't want to tell you!
1590
+				throw new RestException(
1591
+					'rest_user_cannot_' . $context,
1592
+					sprintf(
1593
+						esc_html__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1594
+						$context,
1595
+						$lowercase_model_name,
1596
+						Capabilities::getMissingPermissionsString(
1597
+							$model,
1598
+							$context
1599
+						)
1600
+					),
1601
+					['status' => 403]
1602
+				);
1603
+			} else {
1604
+				// it's not you. It just doesn't exist
1605
+				throw new RestException(
1606
+					sprintf('rest_%s_invalid_id', $lowercase_model_name),
1607
+					sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1608
+					['status' => 404]
1609
+				);
1610
+			}
1611
+		}
1612
+	}
1613
+
1614
+
1615
+	/**
1616
+	 * Checks that if this content requires a password to be read, that it's been provided and is correct.
1617
+	 *
1618
+	 * @param EEM_Base        $model
1619
+	 * @param array           $model_row
1620
+	 * @param array           $query_params Adds 'default_where_conditions' => 'minimum'
1621
+	 *                                      to ensure we don't confuse trashed with password protected.
1622
+	 * @param WP_REST_Request $request
1623
+	 * @throws EE_Error
1624
+	 * @throws InvalidArgumentException
1625
+	 * @throws InvalidDataTypeException
1626
+	 * @throws InvalidInterfaceException
1627
+	 * @throws RestPasswordRequiredException
1628
+	 * @throws RestPasswordIncorrectException
1629
+	 * @throws ModelConfigurationException
1630
+	 * @throws ReflectionException
1631
+	 * @since 4.9.74.p
1632
+	 */
1633
+	protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request)
1634
+	{
1635
+		$query_params['default_where_conditions'] = 'minimum';
1636
+		// stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1637
+		// or you don't.
1638
+		$request_caps = $request->get_param('caps');
1639
+		if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1640
+			return;
1641
+		}
1642
+		// if this entity requires a password, they better give it and it better be right!
1643
+		if (
1644
+			$model->hasPassword()
1645
+			&& $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1646
+		) {
1647
+			if (empty($request['password'])) {
1648
+				throw new RestPasswordRequiredException();
1649
+			}
1650
+			if (
1651
+				! hash_equals(
1652
+					$model_row[ $model->getPasswordField()->get_qualified_column() ],
1653
+					$request['password']
1654
+				)
1655
+			) {
1656
+				throw new RestPasswordIncorrectException();
1657
+			}
1658
+		} elseif (
1659
+			// wait! maybe this content is password protected
1660
+			$model->restrictedByRelatedModelPassword()
1661
+			&& $request->get_param('caps') === EEM_Base::caps_read
1662
+		) {
1663
+			$password_supplied = $request->get_param('password');
1664
+			if (empty($password_supplied)) {
1665
+				$query_params['exclude_protected'] = true;
1666
+				if (! $model->exists($query_params)) {
1667
+					throw new RestPasswordRequiredException();
1668
+				}
1669
+			} else {
1670
+				$query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1671
+				if (! $model->exists($query_params)) {
1672
+					throw new RestPasswordIncorrectException();
1673
+				}
1674
+			}
1675
+		}
1676
+	}
1677 1677
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Write.php 2 patches
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -134,9 +134,9 @@  discard block
 block discarded – undo
134 134
     {
135 135
         Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
136 136
         $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
137
-        if (! current_user_can($default_cap_to_check_for)) {
137
+        if ( ! current_user_can($default_cap_to_check_for)) {
138 138
             throw new RestException(
139
-                'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
139
+                'rest_cannot_create_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
140 140
                 sprintf(
141 141
                     esc_html__(
142 142
                     // @codingStandardsIgnoreStart
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
         );
165 165
         $model_obj->save();
166 166
         $new_id = $model_obj->ID();
167
-        if (! $new_id) {
167
+        if ( ! $new_id) {
168 168
             throw new RestException(
169 169
                 'rest_insertion_failed',
170 170
                 sprintf(esc_html__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
@@ -186,9 +186,9 @@  discard block
 block discarded – undo
186 186
     {
187 187
         Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
188 188
         $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
189
-        if (! current_user_can($default_cap_to_check_for)) {
189
+        if ( ! current_user_can($default_cap_to_check_for)) {
190 190
             throw new RestException(
191
-                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
191
+                'rest_cannot_edit_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
192 192
                 sprintf(
193 193
                     esc_html__(
194 194
                     // @codingStandardsIgnoreStart
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
             );
203 203
         }
204 204
         $obj_id = $request->get_param('id');
205
-        if (! $obj_id) {
205
+        if ( ! $obj_id) {
206 206
             throw new RestException(
207 207
                 'rest_edit_failed',
208 208
                 sprintf(esc_html__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
@@ -215,7 +215,7 @@  discard block
 block discarded – undo
215 215
             true
216 216
         );
217 217
         $model_obj = $model->get_one_by_ID($obj_id);
218
-        if (! $model_obj instanceof EE_Base_Class) {
218
+        if ( ! $model_obj instanceof EE_Base_Class) {
219 219
             $lowercase_model_name = strtolower($model->get_this_model_name());
220 220
             throw new RestException(
221 221
                 sprintf('rest_%s_invalid_id', $lowercase_model_name),
@@ -240,9 +240,9 @@  discard block
 block discarded – undo
240 240
     {
241 241
         Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
242 242
         $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
243
-        if (! current_user_can($default_cap_to_check_for)) {
243
+        if ( ! current_user_can($default_cap_to_check_for)) {
244 244
             throw new RestException(
245
-                'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
245
+                'rest_cannot_delete_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
246 246
                 sprintf(
247 247
                     esc_html__(
248 248
                     // @codingStandardsIgnoreStart
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
         $obj_id = $request->get_param('id');
259 259
         // this is where we would apply more fine-grained caps
260 260
         $model_obj = $model->get_one_by_ID($obj_id);
261
-        if (! $model_obj instanceof EE_Base_Class) {
261
+        if ( ! $model_obj instanceof EE_Base_Class) {
262 262
             $lowercase_model_name = strtolower($model->get_this_model_name());
263 263
             throw new RestException(
264 264
                 sprintf('rest_%s_invalid_id', $lowercase_model_name),
@@ -316,7 +316,7 @@  discard block
 block discarded – undo
316 316
             } else {
317 317
                 $raw_value = $model_obj->get_raw($field_name);
318 318
             }
319
-            $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value);
319
+            $simulated_db_row[$field_obj->get_qualified_column()] = $field_obj->prepare_for_use_in_db($raw_value);
320 320
         }
321 321
         $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
322 322
         $read_controller->setRequestedVersion($this->getRequestedVersion());
@@ -447,7 +447,7 @@  discard block
 block discarded – undo
447 447
                     )
448 448
                 )
449 449
             );
450
-            $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
450
+            $response['join'][strtolower($relation->get_join_model()->get_this_model_name())] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
451 451
         }
452 452
         return $response;
453 453
     }
@@ -495,7 +495,7 @@  discard block
 block discarded – undo
495 495
     {
496 496
         // This endpoint doesn't accept body parameters (it's understandable to think it might, so let developers know
497 497
         // up-front that it doesn't.)
498
-        if (!empty($request->get_body_params())) {
498
+        if ( ! empty($request->get_body_params())) {
499 499
             $body_params = $request->get_body_params();
500 500
             throw new RestException(
501 501
                 'invalid_field',
@@ -537,9 +537,9 @@  discard block
 block discarded – undo
537 537
                 )
538 538
             );
539 539
             if ($join_model_obj instanceof EE_Base_Class) {
540
-                $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
540
+                $response['join'][strtolower($relation->get_join_model()->get_this_model_name())] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
541 541
             } else {
542
-                $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = null;
542
+                $response['join'][strtolower($relation->get_join_model()->get_this_model_name())] = null;
543 543
             }
544 544
         }
545 545
         return $response;
@@ -564,9 +564,9 @@  discard block
 block discarded – undo
564 564
         // Check generic caps. For now, we're only allowing access to this endpoint to full admins.
565 565
         Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
566 566
         $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
567
-        if (! current_user_can($default_cap_to_check_for)) {
567
+        if ( ! current_user_can($default_cap_to_check_for)) {
568 568
             throw new RestException(
569
-                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
569
+                'rest_cannot_edit_'.EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
570 570
                 sprintf(
571 571
                     esc_html__(
572 572
                         // @codingStandardsIgnoreStart
@@ -583,7 +583,7 @@  discard block
 block discarded – undo
583 583
         $model_obj = $this->getOneOrThrowException($model, $request->get_param('id'));
584 584
         // For now, we require the other model object to exist too. This might be relaxed later.
585 585
         $other_obj = $this->getOneOrThrowException($relation->get_other_model(), $request->get_param('related_id'));
586
-        return array($model_obj,$other_obj);
586
+        return array($model_obj, $other_obj);
587 587
     }
588 588
 
589 589
     /**
Please login to merge, or discard this patch.
Indentation   +546 added lines, -546 removed lines patch added patch discarded remove patch
@@ -37,573 +37,573 @@
 block discarded – undo
37 37
  */
38 38
 class Write extends Base
39 39
 {
40
-    public function __construct()
41
-    {
42
-        parent::__construct();
43
-        EE_Registry::instance()->load_helper('Inflector');
44
-    }
40
+	public function __construct()
41
+	{
42
+		parent::__construct();
43
+		EE_Registry::instance()->load_helper('Inflector');
44
+	}
45 45
 
46 46
 
47
-    /**
48
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
49
-     *
50
-     * @param WP_REST_Request $request
51
-     * @param string          $version
52
-     * @param string          $model_name
53
-     * @return WP_REST_Response|\WP_Error
54
-     */
55
-    public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name)
56
-    {
57
-        $controller = new Write();
58
-        try {
59
-            $controller->setRequestedVersion($version);
60
-            return $controller->sendResponse(
61
-                $controller->insert(
62
-                    $controller->getModelVersionInfo()->loadModel($model_name),
63
-                    $request
64
-                )
65
-            );
66
-        } catch (Exception $e) {
67
-            return $controller->sendResponse($e);
68
-        }
69
-    }
47
+	/**
48
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
49
+	 *
50
+	 * @param WP_REST_Request $request
51
+	 * @param string          $version
52
+	 * @param string          $model_name
53
+	 * @return WP_REST_Response|\WP_Error
54
+	 */
55
+	public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name)
56
+	{
57
+		$controller = new Write();
58
+		try {
59
+			$controller->setRequestedVersion($version);
60
+			return $controller->sendResponse(
61
+				$controller->insert(
62
+					$controller->getModelVersionInfo()->loadModel($model_name),
63
+					$request
64
+				)
65
+			);
66
+		} catch (Exception $e) {
67
+			return $controller->sendResponse($e);
68
+		}
69
+	}
70 70
 
71 71
 
72
-    /**
73
-     * Handles a request from \WP_REST_Server to update an EE model
74
-     *
75
-     * @param WP_REST_Request $request
76
-     * @param string          $version
77
-     * @param string          $model_name
78
-     * @return WP_REST_Response|\WP_Error
79
-     */
80
-    public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name)
81
-    {
82
-        $controller = new Write();
83
-        try {
84
-            $controller->setRequestedVersion($version);
85
-            return $controller->sendResponse(
86
-                $controller->update(
87
-                    $controller->getModelVersionInfo()->loadModel($model_name),
88
-                    $request
89
-                )
90
-            );
91
-        } catch (Exception $e) {
92
-            return $controller->sendResponse($e);
93
-        }
94
-    }
72
+	/**
73
+	 * Handles a request from \WP_REST_Server to update an EE model
74
+	 *
75
+	 * @param WP_REST_Request $request
76
+	 * @param string          $version
77
+	 * @param string          $model_name
78
+	 * @return WP_REST_Response|\WP_Error
79
+	 */
80
+	public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name)
81
+	{
82
+		$controller = new Write();
83
+		try {
84
+			$controller->setRequestedVersion($version);
85
+			return $controller->sendResponse(
86
+				$controller->update(
87
+					$controller->getModelVersionInfo()->loadModel($model_name),
88
+					$request
89
+				)
90
+			);
91
+		} catch (Exception $e) {
92
+			return $controller->sendResponse($e);
93
+		}
94
+	}
95 95
 
96 96
 
97
-    /**
98
-     * Deletes a single model object and returns it. Unless
99
-     *
100
-     * @param WP_REST_Request $request
101
-     * @param string          $version
102
-     * @param string          $model_name
103
-     * @return WP_REST_Response|\WP_Error
104
-     */
105
-    public static function handleRequestDelete(WP_REST_Request $request, $version, $model_name)
106
-    {
107
-        $controller = new Write();
108
-        try {
109
-            $controller->setRequestedVersion($version);
110
-            return $controller->sendResponse(
111
-                $controller->delete(
112
-                    $controller->getModelVersionInfo()->loadModel($model_name),
113
-                    $request
114
-                )
115
-            );
116
-        } catch (Exception $e) {
117
-            return $controller->sendResponse($e);
118
-        }
119
-    }
97
+	/**
98
+	 * Deletes a single model object and returns it. Unless
99
+	 *
100
+	 * @param WP_REST_Request $request
101
+	 * @param string          $version
102
+	 * @param string          $model_name
103
+	 * @return WP_REST_Response|\WP_Error
104
+	 */
105
+	public static function handleRequestDelete(WP_REST_Request $request, $version, $model_name)
106
+	{
107
+		$controller = new Write();
108
+		try {
109
+			$controller->setRequestedVersion($version);
110
+			return $controller->sendResponse(
111
+				$controller->delete(
112
+					$controller->getModelVersionInfo()->loadModel($model_name),
113
+					$request
114
+				)
115
+			);
116
+		} catch (Exception $e) {
117
+			return $controller->sendResponse($e);
118
+		}
119
+	}
120 120
 
121 121
 
122
-    /**
123
-     * Inserts a new model object according to the $request
124
-     *
125
-     * @param EEM_Base        $model
126
-     * @param WP_REST_Request $request
127
-     * @return array
128
-     * @throws EE_Error
129
-     * @throws RestException
130
-     */
131
-    public function insert(EEM_Base $model, WP_REST_Request $request)
132
-    {
133
-        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
134
-        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
135
-        if (! current_user_can($default_cap_to_check_for)) {
136
-            throw new RestException(
137
-                'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
138
-                sprintf(
139
-                    esc_html__(
140
-                    // @codingStandardsIgnoreStart
141
-                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.',
142
-                        // @codingStandardsIgnoreEnd
143
-                        'event_espresso'
144
-                    ),
145
-                    $default_cap_to_check_for
146
-                ),
147
-                array('status' => 403)
148
-            );
149
-        }
150
-        $submitted_json_data = array_merge((array) $request->get_body_params(), (array) $request->get_json_params());
151
-        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
152
-            $submitted_json_data,
153
-            $model,
154
-            $this->getModelVersionInfo()->requestedVersion(),
155
-            true
156
-        );
157
-        $model_obj = EE_Registry::instance()->load_class(
158
-            $model->get_this_model_name(),
159
-            array($model_data, $model->get_timezone()),
160
-            false,
161
-            false
162
-        );
163
-        $model_obj->save();
164
-        $new_id = $model_obj->ID();
165
-        if (! $new_id) {
166
-            throw new RestException(
167
-                'rest_insertion_failed',
168
-                sprintf(esc_html__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
169
-            );
170
-        }
171
-        return $this->returnModelObjAsJsonResponse($model_obj, $request);
172
-    }
122
+	/**
123
+	 * Inserts a new model object according to the $request
124
+	 *
125
+	 * @param EEM_Base        $model
126
+	 * @param WP_REST_Request $request
127
+	 * @return array
128
+	 * @throws EE_Error
129
+	 * @throws RestException
130
+	 */
131
+	public function insert(EEM_Base $model, WP_REST_Request $request)
132
+	{
133
+		Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
134
+		$default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
135
+		if (! current_user_can($default_cap_to_check_for)) {
136
+			throw new RestException(
137
+				'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
138
+				sprintf(
139
+					esc_html__(
140
+					// @codingStandardsIgnoreStart
141
+						'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.',
142
+						// @codingStandardsIgnoreEnd
143
+						'event_espresso'
144
+					),
145
+					$default_cap_to_check_for
146
+				),
147
+				array('status' => 403)
148
+			);
149
+		}
150
+		$submitted_json_data = array_merge((array) $request->get_body_params(), (array) $request->get_json_params());
151
+		$model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
152
+			$submitted_json_data,
153
+			$model,
154
+			$this->getModelVersionInfo()->requestedVersion(),
155
+			true
156
+		);
157
+		$model_obj = EE_Registry::instance()->load_class(
158
+			$model->get_this_model_name(),
159
+			array($model_data, $model->get_timezone()),
160
+			false,
161
+			false
162
+		);
163
+		$model_obj->save();
164
+		$new_id = $model_obj->ID();
165
+		if (! $new_id) {
166
+			throw new RestException(
167
+				'rest_insertion_failed',
168
+				sprintf(esc_html__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
169
+			);
170
+		}
171
+		return $this->returnModelObjAsJsonResponse($model_obj, $request);
172
+	}
173 173
 
174 174
 
175
-    /**
176
-     * Updates an existing model object according to the $request
177
-     *
178
-     * @param EEM_Base        $model
179
-     * @param WP_REST_Request $request
180
-     * @return array
181
-     * @throws EE_Error
182
-     */
183
-    public function update(EEM_Base $model, WP_REST_Request $request)
184
-    {
185
-        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
186
-        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
187
-        if (! current_user_can($default_cap_to_check_for)) {
188
-            throw new RestException(
189
-                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
190
-                sprintf(
191
-                    esc_html__(
192
-                    // @codingStandardsIgnoreStart
193
-                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.',
194
-                        // @codingStandardsIgnoreEnd
195
-                        'event_espresso'
196
-                    ),
197
-                    $default_cap_to_check_for
198
-                ),
199
-                array('status' => 403)
200
-            );
201
-        }
202
-        $obj_id = $request->get_param('id');
203
-        if (! $obj_id) {
204
-            throw new RestException(
205
-                'rest_edit_failed',
206
-                sprintf(esc_html__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
207
-            );
208
-        }
209
-        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
210
-            $this->getBodyParams($request),
211
-            $model,
212
-            $this->getModelVersionInfo()->requestedVersion(),
213
-            true
214
-        );
215
-        $model_obj = $model->get_one_by_ID($obj_id);
216
-        if (! $model_obj instanceof EE_Base_Class) {
217
-            $lowercase_model_name = strtolower($model->get_this_model_name());
218
-            throw new RestException(
219
-                sprintf('rest_%s_invalid_id', $lowercase_model_name),
220
-                sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
221
-                array('status' => 404)
222
-            );
223
-        }
224
-        $model_obj->save($model_data);
225
-        return $this->returnModelObjAsJsonResponse($model_obj, $request);
226
-    }
175
+	/**
176
+	 * Updates an existing model object according to the $request
177
+	 *
178
+	 * @param EEM_Base        $model
179
+	 * @param WP_REST_Request $request
180
+	 * @return array
181
+	 * @throws EE_Error
182
+	 */
183
+	public function update(EEM_Base $model, WP_REST_Request $request)
184
+	{
185
+		Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
186
+		$default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
187
+		if (! current_user_can($default_cap_to_check_for)) {
188
+			throw new RestException(
189
+				'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
190
+				sprintf(
191
+					esc_html__(
192
+					// @codingStandardsIgnoreStart
193
+						'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.',
194
+						// @codingStandardsIgnoreEnd
195
+						'event_espresso'
196
+					),
197
+					$default_cap_to_check_for
198
+				),
199
+				array('status' => 403)
200
+			);
201
+		}
202
+		$obj_id = $request->get_param('id');
203
+		if (! $obj_id) {
204
+			throw new RestException(
205
+				'rest_edit_failed',
206
+				sprintf(esc_html__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
207
+			);
208
+		}
209
+		$model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
210
+			$this->getBodyParams($request),
211
+			$model,
212
+			$this->getModelVersionInfo()->requestedVersion(),
213
+			true
214
+		);
215
+		$model_obj = $model->get_one_by_ID($obj_id);
216
+		if (! $model_obj instanceof EE_Base_Class) {
217
+			$lowercase_model_name = strtolower($model->get_this_model_name());
218
+			throw new RestException(
219
+				sprintf('rest_%s_invalid_id', $lowercase_model_name),
220
+				sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
221
+				array('status' => 404)
222
+			);
223
+		}
224
+		$model_obj->save($model_data);
225
+		return $this->returnModelObjAsJsonResponse($model_obj, $request);
226
+	}
227 227
 
228 228
 
229
-    /**
230
-     * Updates an existing model object according to the $request
231
-     *
232
-     * @param EEM_Base        $model
233
-     * @param WP_REST_Request $request
234
-     * @return array of either the soft-deleted item, or
235
-     * @throws EE_Error
236
-     */
237
-    public function delete(EEM_Base $model, WP_REST_Request $request)
238
-    {
239
-        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
240
-        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
241
-        if (! current_user_can($default_cap_to_check_for)) {
242
-            throw new RestException(
243
-                'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
244
-                sprintf(
245
-                    esc_html__(
246
-                    // @codingStandardsIgnoreStart
247
-                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.',
248
-                        // @codingStandardsIgnoreEnd
249
-                        'event_espresso'
250
-                    ),
251
-                    $default_cap_to_check_for
252
-                ),
253
-                array('status' => 403)
254
-            );
255
-        }
256
-        $obj_id = $request->get_param('id');
257
-        // this is where we would apply more fine-grained caps
258
-        $model_obj = $model->get_one_by_ID($obj_id);
259
-        if (! $model_obj instanceof EE_Base_Class) {
260
-            $lowercase_model_name = strtolower($model->get_this_model_name());
261
-            throw new RestException(
262
-                sprintf('rest_%s_invalid_id', $lowercase_model_name),
263
-                sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
264
-                array('status' => 404)
265
-            );
266
-        }
267
-        $requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN);
268
-        $requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN);
269
-        if ($requested_permanent_delete) {
270
-            $previous = $this->returnModelObjAsJsonResponse($model_obj, $request);
271
-            $deleted = (bool) $model->delete_permanently_by_ID($obj_id, $requested_allow_blocking);
272
-            return array(
273
-                'deleted'  => $deleted,
274
-                'previous' => $previous,
275
-            );
276
-        } else {
277
-            if ($model instanceof EEM_Soft_Delete_Base) {
278
-                $model->delete_by_ID($obj_id, $requested_allow_blocking);
279
-                return $this->returnModelObjAsJsonResponse($model_obj, $request);
280
-            } else {
281
-                throw new RestException(
282
-                    'rest_trash_not_supported',
283
-                    501,
284
-                    sprintf(
285
-                        esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'),
286
-                        EEH_Inflector::pluralize($model->get_this_model_name())
287
-                    )
288
-                );
289
-            }
290
-        }
291
-    }
229
+	/**
230
+	 * Updates an existing model object according to the $request
231
+	 *
232
+	 * @param EEM_Base        $model
233
+	 * @param WP_REST_Request $request
234
+	 * @return array of either the soft-deleted item, or
235
+	 * @throws EE_Error
236
+	 */
237
+	public function delete(EEM_Base $model, WP_REST_Request $request)
238
+	{
239
+		Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
240
+		$default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
241
+		if (! current_user_can($default_cap_to_check_for)) {
242
+			throw new RestException(
243
+				'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
244
+				sprintf(
245
+					esc_html__(
246
+					// @codingStandardsIgnoreStart
247
+						'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.',
248
+						// @codingStandardsIgnoreEnd
249
+						'event_espresso'
250
+					),
251
+					$default_cap_to_check_for
252
+				),
253
+				array('status' => 403)
254
+			);
255
+		}
256
+		$obj_id = $request->get_param('id');
257
+		// this is where we would apply more fine-grained caps
258
+		$model_obj = $model->get_one_by_ID($obj_id);
259
+		if (! $model_obj instanceof EE_Base_Class) {
260
+			$lowercase_model_name = strtolower($model->get_this_model_name());
261
+			throw new RestException(
262
+				sprintf('rest_%s_invalid_id', $lowercase_model_name),
263
+				sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
264
+				array('status' => 404)
265
+			);
266
+		}
267
+		$requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN);
268
+		$requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN);
269
+		if ($requested_permanent_delete) {
270
+			$previous = $this->returnModelObjAsJsonResponse($model_obj, $request);
271
+			$deleted = (bool) $model->delete_permanently_by_ID($obj_id, $requested_allow_blocking);
272
+			return array(
273
+				'deleted'  => $deleted,
274
+				'previous' => $previous,
275
+			);
276
+		} else {
277
+			if ($model instanceof EEM_Soft_Delete_Base) {
278
+				$model->delete_by_ID($obj_id, $requested_allow_blocking);
279
+				return $this->returnModelObjAsJsonResponse($model_obj, $request);
280
+			} else {
281
+				throw new RestException(
282
+					'rest_trash_not_supported',
283
+					501,
284
+					sprintf(
285
+						esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'),
286
+						EEH_Inflector::pluralize($model->get_this_model_name())
287
+					)
288
+				);
289
+			}
290
+		}
291
+	}
292 292
 
293 293
 
294
-    /**
295
-     * Returns an array ready to be converted into a JSON response, based solely on the model object
296
-     *
297
-     * @param EE_Base_Class   $model_obj
298
-     * @param WP_REST_Request $request
299
-     * @return array ready for a response
300
-     */
301
-    protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request)
302
-    {
303
-        $model = $model_obj->get_model();
304
-        // create an array exactly like the wpdb results row,
305
-        // so we can pass it to controllers/model/Read::create_entity_from_wpdb_result()
306
-        $simulated_db_row = array();
307
-        foreach ($model->field_settings(true) as $field_name => $field_obj) {
308
-            // we need to reconstruct the normal wpdb results, including the db-only fields
309
-            // like a secondary table's primary key. The models expect those (but don't care what value they have)
310
-            if ($field_obj instanceof EE_DB_Only_Field_Base) {
311
-                $raw_value = true;
312
-            } elseif ($field_obj instanceof EE_Datetime_Field) {
313
-                $raw_value = $model_obj->get_DateTime_object($field_name);
314
-            } else {
315
-                $raw_value = $model_obj->get_raw($field_name);
316
-            }
317
-            $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value);
318
-        }
319
-        $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
320
-        $read_controller->setRequestedVersion($this->getRequestedVersion());
321
-        // the simulates request really doesn't need any info downstream
322
-        $simulated_request = new WP_REST_Request('GET');
323
-        // set the caps context on the simulated according to the original request.
324
-        switch ($request->get_method()) {
325
-            case 'POST':
326
-            case 'PUT':
327
-                $caps_context = EEM_Base::caps_edit;
328
-                break;
329
-            case 'DELETE':
330
-                $caps_context = EEM_Base::caps_delete;
331
-                break;
332
-            default:
333
-                $caps_context = EEM_Base::caps_read_admin;
334
-        }
335
-        $simulated_request->set_param('caps', $caps_context);
336
-        return $read_controller->createEntityFromWpdbResult(
337
-            $model_obj->get_model(),
338
-            $simulated_db_row,
339
-            $simulated_request
340
-        );
341
-    }
294
+	/**
295
+	 * Returns an array ready to be converted into a JSON response, based solely on the model object
296
+	 *
297
+	 * @param EE_Base_Class   $model_obj
298
+	 * @param WP_REST_Request $request
299
+	 * @return array ready for a response
300
+	 */
301
+	protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request)
302
+	{
303
+		$model = $model_obj->get_model();
304
+		// create an array exactly like the wpdb results row,
305
+		// so we can pass it to controllers/model/Read::create_entity_from_wpdb_result()
306
+		$simulated_db_row = array();
307
+		foreach ($model->field_settings(true) as $field_name => $field_obj) {
308
+			// we need to reconstruct the normal wpdb results, including the db-only fields
309
+			// like a secondary table's primary key. The models expect those (but don't care what value they have)
310
+			if ($field_obj instanceof EE_DB_Only_Field_Base) {
311
+				$raw_value = true;
312
+			} elseif ($field_obj instanceof EE_Datetime_Field) {
313
+				$raw_value = $model_obj->get_DateTime_object($field_name);
314
+			} else {
315
+				$raw_value = $model_obj->get_raw($field_name);
316
+			}
317
+			$simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value);
318
+		}
319
+		$read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
320
+		$read_controller->setRequestedVersion($this->getRequestedVersion());
321
+		// the simulates request really doesn't need any info downstream
322
+		$simulated_request = new WP_REST_Request('GET');
323
+		// set the caps context on the simulated according to the original request.
324
+		switch ($request->get_method()) {
325
+			case 'POST':
326
+			case 'PUT':
327
+				$caps_context = EEM_Base::caps_edit;
328
+				break;
329
+			case 'DELETE':
330
+				$caps_context = EEM_Base::caps_delete;
331
+				break;
332
+			default:
333
+				$caps_context = EEM_Base::caps_read_admin;
334
+		}
335
+		$simulated_request->set_param('caps', $caps_context);
336
+		return $read_controller->createEntityFromWpdbResult(
337
+			$model_obj->get_model(),
338
+			$simulated_db_row,
339
+			$simulated_request
340
+		);
341
+	}
342 342
 
343 343
 
344
-    /**
345
-     * Gets the item affected by this request
346
-     *
347
-     * @param EEM_Base        $model
348
-     * @param WP_REST_Request $request
349
-     * @param  int|string     $obj_id
350
-     * @return \WP_Error|array
351
-     */
352
-    protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id)
353
-    {
354
-        $requested_version = $this->getRequestedVersion($request->get_route());
355
-        $get_request = new WP_REST_Request(
356
-            'GET',
357
-            EED_Core_Rest_Api::ee_api_namespace
358
-            . $requested_version
359
-            . '/'
360
-            . EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
361
-            . '/'
362
-            . $obj_id
363
-        );
364
-        $get_request->set_url_params(
365
-            array(
366
-                'id'      => $obj_id,
367
-                'include' => $request->get_param('include'),
368
-            )
369
-        );
370
-        $read_controller = new Read();
371
-        $read_controller->setRequestedVersion($this->getRequestedVersion());
372
-        return $read_controller->getEntityFromModel($model, $get_request);
373
-    }
344
+	/**
345
+	 * Gets the item affected by this request
346
+	 *
347
+	 * @param EEM_Base        $model
348
+	 * @param WP_REST_Request $request
349
+	 * @param  int|string     $obj_id
350
+	 * @return \WP_Error|array
351
+	 */
352
+	protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id)
353
+	{
354
+		$requested_version = $this->getRequestedVersion($request->get_route());
355
+		$get_request = new WP_REST_Request(
356
+			'GET',
357
+			EED_Core_Rest_Api::ee_api_namespace
358
+			. $requested_version
359
+			. '/'
360
+			. EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
361
+			. '/'
362
+			. $obj_id
363
+		);
364
+		$get_request->set_url_params(
365
+			array(
366
+				'id'      => $obj_id,
367
+				'include' => $request->get_param('include'),
368
+			)
369
+		);
370
+		$read_controller = new Read();
371
+		$read_controller->setRequestedVersion($this->getRequestedVersion());
372
+		return $read_controller->getEntityFromModel($model, $get_request);
373
+	}
374 374
 
375
-    /**
376
-     * Adds a relation between the specified models (if it doesn't already exist.)
377
-     * @since 4.9.76.p
378
-     * @param WP_REST_Request $request
379
-     * @return WP_REST_Response
380
-     */
381
-    public static function handleRequestAddRelation(WP_REST_Request $request, $version, $model_name, $related_model_name)
382
-    {
383
-        $controller = new Write();
384
-        try {
385
-            $controller->setRequestedVersion($version);
386
-            $main_model = $controller->validateModel($model_name);
387
-            $controller->validateModel($related_model_name);
388
-            return $controller->sendResponse(
389
-                $controller->addRelation(
390
-                    $main_model,
391
-                    $main_model->related_settings_for($related_model_name),
392
-                    $request
393
-                )
394
-            );
395
-        } catch (Exception $e) {
396
-            return $controller->sendResponse($e);
397
-        }
398
-    }
375
+	/**
376
+	 * Adds a relation between the specified models (if it doesn't already exist.)
377
+	 * @since 4.9.76.p
378
+	 * @param WP_REST_Request $request
379
+	 * @return WP_REST_Response
380
+	 */
381
+	public static function handleRequestAddRelation(WP_REST_Request $request, $version, $model_name, $related_model_name)
382
+	{
383
+		$controller = new Write();
384
+		try {
385
+			$controller->setRequestedVersion($version);
386
+			$main_model = $controller->validateModel($model_name);
387
+			$controller->validateModel($related_model_name);
388
+			return $controller->sendResponse(
389
+				$controller->addRelation(
390
+					$main_model,
391
+					$main_model->related_settings_for($related_model_name),
392
+					$request
393
+				)
394
+			);
395
+		} catch (Exception $e) {
396
+			return $controller->sendResponse($e);
397
+		}
398
+	}
399 399
 
400
-    /**
401
-     * Adds a relation between the two model specified model objects.
402
-     * @since 4.9.76.p
403
-     * @param EEM_Base $model
404
-     * @param EE_Model_Relation_Base $relation
405
-     * @param WP_REST_Request $request
406
-     * @return array
407
-     * @throws EE_Error
408
-     * @throws InvalidArgumentException
409
-     * @throws InvalidDataTypeException
410
-     * @throws InvalidInterfaceException
411
-     * @throws RestException
412
-     * @throws DomainException
413
-     */
414
-    public function addRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
415
-    {
416
-        list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request);
417
-        $extra_params = array();
418
-        if ($relation instanceof EE_HABTM_Relation) {
419
-            $extra_params = array_intersect_key(
420
-                ModelDataTranslator::prepareConditionsQueryParamsForModels(
421
-                    $request->get_body_params(),
422
-                    $relation->get_join_model(),
423
-                    $this->getModelVersionInfo()->requestedVersion(),
424
-                    true
425
-                ),
426
-                $relation->getNonKeyFields()
427
-            );
428
-        }
429
-        // Add a relation.
430
-        $related_obj = $model_obj->_add_relation_to(
431
-            $other_obj,
432
-            $relation->get_other_model()->get_this_model_name(),
433
-            $extra_params
434
-        );
435
-        $response = array(
436
-            strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request),
437
-            strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request),
438
-        );
439
-        if ($relation instanceof EE_HABTM_Relation) {
440
-            $join_model_obj = $relation->get_join_model()->get_one(
441
-                array(
442
-                    array(
443
-                        $relation->get_join_model()->get_foreign_key_to($model->get_this_model_name())->get_name() => $model_obj->ID(),
444
-                        $relation->get_join_model()->get_foreign_key_to($relation->get_other_model()->get_this_model_name())->get_name() => $related_obj->ID()
445
-                    )
446
-                )
447
-            );
448
-            $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
449
-        }
450
-        return $response;
451
-    }
400
+	/**
401
+	 * Adds a relation between the two model specified model objects.
402
+	 * @since 4.9.76.p
403
+	 * @param EEM_Base $model
404
+	 * @param EE_Model_Relation_Base $relation
405
+	 * @param WP_REST_Request $request
406
+	 * @return array
407
+	 * @throws EE_Error
408
+	 * @throws InvalidArgumentException
409
+	 * @throws InvalidDataTypeException
410
+	 * @throws InvalidInterfaceException
411
+	 * @throws RestException
412
+	 * @throws DomainException
413
+	 */
414
+	public function addRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
415
+	{
416
+		list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request);
417
+		$extra_params = array();
418
+		if ($relation instanceof EE_HABTM_Relation) {
419
+			$extra_params = array_intersect_key(
420
+				ModelDataTranslator::prepareConditionsQueryParamsForModels(
421
+					$request->get_body_params(),
422
+					$relation->get_join_model(),
423
+					$this->getModelVersionInfo()->requestedVersion(),
424
+					true
425
+				),
426
+				$relation->getNonKeyFields()
427
+			);
428
+		}
429
+		// Add a relation.
430
+		$related_obj = $model_obj->_add_relation_to(
431
+			$other_obj,
432
+			$relation->get_other_model()->get_this_model_name(),
433
+			$extra_params
434
+		);
435
+		$response = array(
436
+			strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request),
437
+			strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request),
438
+		);
439
+		if ($relation instanceof EE_HABTM_Relation) {
440
+			$join_model_obj = $relation->get_join_model()->get_one(
441
+				array(
442
+					array(
443
+						$relation->get_join_model()->get_foreign_key_to($model->get_this_model_name())->get_name() => $model_obj->ID(),
444
+						$relation->get_join_model()->get_foreign_key_to($relation->get_other_model()->get_this_model_name())->get_name() => $related_obj->ID()
445
+					)
446
+				)
447
+			);
448
+			$response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
449
+		}
450
+		return $response;
451
+	}
452 452
 
453 453
 
454
-    /**
455
-     * Removes the relation between the specified models (if it exists).
456
-     * @since 4.9.76.p
457
-     * @param WP_REST_Request $request
458
-     * @return WP_REST_Response
459
-     */
460
-    public static function handleRequestRemoveRelation(WP_REST_Request $request, $version, $model_name, $related_model_name)
461
-    {
462
-        $controller = new Write();
463
-        try {
464
-            $controller->setRequestedVersion($version);
465
-            $main_model = $controller->getModelVersionInfo()->loadModel($model_name);
466
-            return $controller->sendResponse(
467
-                $controller->removeRelation(
468
-                    $main_model,
469
-                    $main_model->related_settings_for($related_model_name),
470
-                    $request
471
-                )
472
-            );
473
-        } catch (Exception $e) {
474
-            return $controller->sendResponse($e);
475
-        }
476
-    }
454
+	/**
455
+	 * Removes the relation between the specified models (if it exists).
456
+	 * @since 4.9.76.p
457
+	 * @param WP_REST_Request $request
458
+	 * @return WP_REST_Response
459
+	 */
460
+	public static function handleRequestRemoveRelation(WP_REST_Request $request, $version, $model_name, $related_model_name)
461
+	{
462
+		$controller = new Write();
463
+		try {
464
+			$controller->setRequestedVersion($version);
465
+			$main_model = $controller->getModelVersionInfo()->loadModel($model_name);
466
+			return $controller->sendResponse(
467
+				$controller->removeRelation(
468
+					$main_model,
469
+					$main_model->related_settings_for($related_model_name),
470
+					$request
471
+				)
472
+			);
473
+		} catch (Exception $e) {
474
+			return $controller->sendResponse($e);
475
+		}
476
+	}
477 477
 
478
-    /**
479
-     * Adds a relation between the two model specified model objects.
480
-     * @since 4.9.76.p
481
-     * @param EEM_Base $model
482
-     * @param EE_Model_Relation_Base $relation
483
-     * @param WP_REST_Request $request
484
-     * @return array
485
-     * @throws DomainException
486
-     * @throws EE_Error
487
-     * @throws InvalidArgumentException
488
-     * @throws InvalidDataTypeException
489
-     * @throws InvalidInterfaceException
490
-     * @throws RestException
491
-     */
492
-    public function removeRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
493
-    {
494
-        // This endpoint doesn't accept body parameters (it's understandable to think it might, so let developers know
495
-        // up-front that it doesn't.)
496
-        if (!empty($request->get_body_params())) {
497
-            $body_params = $request->get_body_params();
498
-            throw new RestException(
499
-                'invalid_field',
500
-                sprintf(
501
-                    esc_html__('This endpoint doesn\'t accept post body arguments, you sent in %1$s', 'event_espresso'),
502
-                    implode(array_keys($body_params))
503
-                )
504
-            );
505
-        }
506
-        list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request);
507
-        // Remember the old relation, if it used a join entry.
508
-        $join_model_obj = null;
509
-        if ($relation instanceof EE_HABTM_Relation) {
510
-            $join_model_obj = $relation->get_join_model()->get_one(
511
-                array(
512
-                    array(
513
-                        $model->primary_key_name() => $model_obj->ID(),
514
-                        $relation->get_other_model()->primary_key_name() => $other_obj->ID()
515
-                    )
516
-                )
517
-            );
518
-        }
519
-        // Remove the relation.
520
-        $related_obj = $model_obj->_remove_relation_to(
521
-            $other_obj,
522
-            $relation->get_other_model()->get_this_model_name()
523
-        );
524
-        $response = array(
525
-            strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request),
526
-            strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request),
527
-        );
528
-        if ($relation instanceof EE_HABTM_Relation) {
529
-            $join_model_obj_after_removal = $relation->get_join_model()->get_one(
530
-                array(
531
-                    array(
532
-                        $model->primary_key_name() => $model_obj->ID(),
533
-                        $relation->get_other_model()->primary_key_name() => $other_obj->ID()
534
-                    )
535
-                )
536
-            );
537
-            if ($join_model_obj instanceof EE_Base_Class) {
538
-                $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
539
-            } else {
540
-                $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = null;
541
-            }
542
-        }
543
-        return $response;
544
-    }
478
+	/**
479
+	 * Adds a relation between the two model specified model objects.
480
+	 * @since 4.9.76.p
481
+	 * @param EEM_Base $model
482
+	 * @param EE_Model_Relation_Base $relation
483
+	 * @param WP_REST_Request $request
484
+	 * @return array
485
+	 * @throws DomainException
486
+	 * @throws EE_Error
487
+	 * @throws InvalidArgumentException
488
+	 * @throws InvalidDataTypeException
489
+	 * @throws InvalidInterfaceException
490
+	 * @throws RestException
491
+	 */
492
+	public function removeRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
493
+	{
494
+		// This endpoint doesn't accept body parameters (it's understandable to think it might, so let developers know
495
+		// up-front that it doesn't.)
496
+		if (!empty($request->get_body_params())) {
497
+			$body_params = $request->get_body_params();
498
+			throw new RestException(
499
+				'invalid_field',
500
+				sprintf(
501
+					esc_html__('This endpoint doesn\'t accept post body arguments, you sent in %1$s', 'event_espresso'),
502
+					implode(array_keys($body_params))
503
+				)
504
+			);
505
+		}
506
+		list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request);
507
+		// Remember the old relation, if it used a join entry.
508
+		$join_model_obj = null;
509
+		if ($relation instanceof EE_HABTM_Relation) {
510
+			$join_model_obj = $relation->get_join_model()->get_one(
511
+				array(
512
+					array(
513
+						$model->primary_key_name() => $model_obj->ID(),
514
+						$relation->get_other_model()->primary_key_name() => $other_obj->ID()
515
+					)
516
+				)
517
+			);
518
+		}
519
+		// Remove the relation.
520
+		$related_obj = $model_obj->_remove_relation_to(
521
+			$other_obj,
522
+			$relation->get_other_model()->get_this_model_name()
523
+		);
524
+		$response = array(
525
+			strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request),
526
+			strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request),
527
+		);
528
+		if ($relation instanceof EE_HABTM_Relation) {
529
+			$join_model_obj_after_removal = $relation->get_join_model()->get_one(
530
+				array(
531
+					array(
532
+						$model->primary_key_name() => $model_obj->ID(),
533
+						$relation->get_other_model()->primary_key_name() => $other_obj->ID()
534
+					)
535
+				)
536
+			);
537
+			if ($join_model_obj instanceof EE_Base_Class) {
538
+				$response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
539
+			} else {
540
+				$response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = null;
541
+			}
542
+		}
543
+		return $response;
544
+	}
545 545
 
546
-    /**
547
-     * Gets the model objects indicated by the model, relation object, and request.
548
-     * Throws an exception if the first object doesn't exist, and currently if the related object also doesn't exist.
549
-     * However, this behaviour may change, as we may add support for simultaneously creating and relating data.
550
-     * @since 4.9.76.p
551
-     * @param EEM_Base $model
552
-     * @param EE_Model_Relation_Base $relation
553
-     * @param WP_REST_Request $request
554
-     * @return array {
555
-     * @type EE_Base_Class $model_obj
556
-     * @type EE_Base_Class|null $other_model_obj
557
-     * }
558
-     * @throws RestException
559
-     */
560
-    protected function getBothModelObjects(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
561
-    {
562
-        // Check generic caps. For now, we're only allowing access to this endpoint to full admins.
563
-        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
564
-        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
565
-        if (! current_user_can($default_cap_to_check_for)) {
566
-            throw new RestException(
567
-                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
568
-                sprintf(
569
-                    esc_html__(
570
-                        // @codingStandardsIgnoreStart
571
-                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to add relations in Event Espresso.',
572
-                        // @codingStandardsIgnoreEnd
573
-                        'event_espresso'
574
-                    ),
575
-                    $default_cap_to_check_for
576
-                ),
577
-                array('status' => 403)
578
-            );
579
-        }
580
-        // Get the main model object.
581
-        $model_obj = $this->getOneOrThrowException($model, $request->get_param('id'));
582
-        // For now, we require the other model object to exist too. This might be relaxed later.
583
-        $other_obj = $this->getOneOrThrowException($relation->get_other_model(), $request->get_param('related_id'));
584
-        return array($model_obj,$other_obj);
585
-    }
546
+	/**
547
+	 * Gets the model objects indicated by the model, relation object, and request.
548
+	 * Throws an exception if the first object doesn't exist, and currently if the related object also doesn't exist.
549
+	 * However, this behaviour may change, as we may add support for simultaneously creating and relating data.
550
+	 * @since 4.9.76.p
551
+	 * @param EEM_Base $model
552
+	 * @param EE_Model_Relation_Base $relation
553
+	 * @param WP_REST_Request $request
554
+	 * @return array {
555
+	 * @type EE_Base_Class $model_obj
556
+	 * @type EE_Base_Class|null $other_model_obj
557
+	 * }
558
+	 * @throws RestException
559
+	 */
560
+	protected function getBothModelObjects(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
561
+	{
562
+		// Check generic caps. For now, we're only allowing access to this endpoint to full admins.
563
+		Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
564
+		$default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
565
+		if (! current_user_can($default_cap_to_check_for)) {
566
+			throw new RestException(
567
+				'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
568
+				sprintf(
569
+					esc_html__(
570
+						// @codingStandardsIgnoreStart
571
+						'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to add relations in Event Espresso.',
572
+						// @codingStandardsIgnoreEnd
573
+						'event_espresso'
574
+					),
575
+					$default_cap_to_check_for
576
+				),
577
+				array('status' => 403)
578
+			);
579
+		}
580
+		// Get the main model object.
581
+		$model_obj = $this->getOneOrThrowException($model, $request->get_param('id'));
582
+		// For now, we require the other model object to exist too. This might be relaxed later.
583
+		$other_obj = $this->getOneOrThrowException($relation->get_other_model(), $request->get_param('related_id'));
584
+		return array($model_obj,$other_obj);
585
+	}
586 586
 
587
-    /**
588
-     * Gets the model with that ID or throws a REST exception.
589
-     * @since 4.9.76.p
590
-     * @param EEM_Base $model
591
-     * @param $id
592
-     * @return EE_Base_Class
593
-     * @throws RestException
594
-     */
595
-    protected function getOneOrThrowException(EEM_Base $model, $id)
596
-    {
597
-        $model_obj = $model->get_one_by_ID($id);
598
-        // @todo: check they can permission for it. For now unnecessary because only full admins can use this endpoint.
599
-        if ($model_obj instanceof EE_Base_Class) {
600
-            return $model_obj;
601
-        }
602
-        $lowercase_model_name = strtolower($model->get_this_model_name());
603
-        throw new RestException(
604
-            sprintf('rest_%s_invalid_id', $lowercase_model_name),
605
-            sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
606
-            array('status' => 404)
607
-        );
608
-    }
587
+	/**
588
+	 * Gets the model with that ID or throws a REST exception.
589
+	 * @since 4.9.76.p
590
+	 * @param EEM_Base $model
591
+	 * @param $id
592
+	 * @return EE_Base_Class
593
+	 * @throws RestException
594
+	 */
595
+	protected function getOneOrThrowException(EEM_Base $model, $id)
596
+	{
597
+		$model_obj = $model->get_one_by_ID($id);
598
+		// @todo: check they can permission for it. For now unnecessary because only full admins can use this endpoint.
599
+		if ($model_obj instanceof EE_Base_Class) {
600
+			return $model_obj;
601
+		}
602
+		$lowercase_model_name = strtolower($model->get_this_model_name());
603
+		throw new RestException(
604
+			sprintf('rest_%s_invalid_id', $lowercase_model_name),
605
+			sprintf(esc_html__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
606
+			array('status' => 404)
607
+		);
608
+	}
609 609
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/changes/ChangesInBase.php 2 patches
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -37,74 +37,74 @@
 block discarded – undo
37 37
 abstract class ChangesInBase
38 38
 {
39 39
 
40
-    /**
41
-     * The version that these changes happened
42
-     *
43
-     * @var string
44
-     */
45
-    protected $version = null;
40
+	/**
41
+	 * The version that these changes happened
42
+	 *
43
+	 * @var string
44
+	 */
45
+	protected $version = null;
46 46
 
47 47
 
48
-    /**
49
-     * Called when an EE4 REST API request is made to an earlier version than
50
-     * what is indicated in this class' name.
51
-     * Uses WordPress' add_filter and add_action to modify the EE4 REST API's response
52
-     * so that regardless of what version of EE4 core is running, API clients
53
-     * will have a consistent response
54
-     *
55
-     * @return void
56
-     */
57
-    abstract public function setHooks();
48
+	/**
49
+	 * Called when an EE4 REST API request is made to an earlier version than
50
+	 * what is indicated in this class' name.
51
+	 * Uses WordPress' add_filter and add_action to modify the EE4 REST API's response
52
+	 * so that regardless of what version of EE4 core is running, API clients
53
+	 * will have a consistent response
54
+	 *
55
+	 * @return void
56
+	 */
57
+	abstract public function setHooks();
58 58
 
59 59
 
60
-    /**
61
-     * Returns whether or not this class' name indicates its hooks should
62
-     * apply when a request comes in for $requested_version. A class can use
63
-     * other conditions when determining whether to perform their callbacks or not,
64
-     * but this will typically be enough
65
-     *
66
-     * @param string $requested_version eg "4.8.33"
67
-     * @return boolean true: this class' name indicates its filters and actions
68
-     *                                  should take effect. False: this class' name indicates it shouldn't do anything
69
-     */
70
-    public function appliesToVersion($requested_version)
71
-    {
72
-        if ($this->version() > $requested_version) {
73
-            return true;
74
-        }
75
-        return false;
76
-    }
60
+	/**
61
+	 * Returns whether or not this class' name indicates its hooks should
62
+	 * apply when a request comes in for $requested_version. A class can use
63
+	 * other conditions when determining whether to perform their callbacks or not,
64
+	 * but this will typically be enough
65
+	 *
66
+	 * @param string $requested_version eg "4.8.33"
67
+	 * @return boolean true: this class' name indicates its filters and actions
68
+	 *                                  should take effect. False: this class' name indicates it shouldn't do anything
69
+	 */
70
+	public function appliesToVersion($requested_version)
71
+	{
72
+		if ($this->version() > $requested_version) {
73
+			return true;
74
+		}
75
+		return false;
76
+	}
77 77
 
78 78
 
79
-    /**
80
-     * Gets the EE core version when this changes were made to the rest api.
81
-     * Any requests to earlier versions should have modifications made to them
82
-     * by the callbacks of this class.
83
-     *
84
-     * @return string eg "4.8.33"
85
-     * @throws EE_Error
86
-     */
87
-    public function version()
88
-    {
89
-        if ($this->version === null) {
90
-            $matches = array();
91
-            $regex = '~ChangesIn(\d)(\d\d)(\d\d)$~';
92
-            $success = preg_match(
93
-                $regex,
94
-                get_class($this),
95
-                $matches
96
-            );
97
-            if (! $success) {
98
-                throw new EE_Error(
99
-                    sprintf(
100
-                        esc_html__('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'),
101
-                        get_class($this),
102
-                        $regex
103
-                    )
104
-                );
105
-            }
106
-            $this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3];
107
-        }
108
-        return $this->version;
109
-    }
79
+	/**
80
+	 * Gets the EE core version when this changes were made to the rest api.
81
+	 * Any requests to earlier versions should have modifications made to them
82
+	 * by the callbacks of this class.
83
+	 *
84
+	 * @return string eg "4.8.33"
85
+	 * @throws EE_Error
86
+	 */
87
+	public function version()
88
+	{
89
+		if ($this->version === null) {
90
+			$matches = array();
91
+			$regex = '~ChangesIn(\d)(\d\d)(\d\d)$~';
92
+			$success = preg_match(
93
+				$regex,
94
+				get_class($this),
95
+				$matches
96
+			);
97
+			if (! $success) {
98
+				throw new EE_Error(
99
+					sprintf(
100
+						esc_html__('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'),
101
+						get_class($this),
102
+						$regex
103
+					)
104
+				);
105
+			}
106
+			$this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3];
107
+		}
108
+		return $this->version;
109
+	}
110 110
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
                 get_class($this),
95 95
                 $matches
96 96
             );
97
-            if (! $success) {
97
+            if ( ! $success) {
98 98
                 throw new EE_Error(
99 99
                     sprintf(
100 100
                         esc_html__('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'),
@@ -103,7 +103,7 @@  discard block
 block discarded – undo
103 103
                     )
104 104
                 );
105 105
             }
106
-            $this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3];
106
+            $this->version = (int) $matches[1].'.'.(int) $matches[2].'.'.(int) $matches[3];
107 107
         }
108 108
         return $this->version;
109 109
     }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Datetime.php 2 patches
Indentation   +200 added lines, -200 removed lines patch added patch discarded remove patch
@@ -17,214 +17,214 @@
 block discarded – undo
17 17
 
18 18
 class Datetime extends DatetimeCalculationBase
19 19
 {
20
-    /**
21
-     * @var EEM_Datetime
22
-     */
23
-    protected $datetime_model;
20
+	/**
21
+	 * @var EEM_Datetime
22
+	 */
23
+	protected $datetime_model;
24 24
 
25
-    /**
26
-     * @var EEM_Registration
27
-     */
28
-    protected $registration_model;
29
-    public function __construct(EEM_Datetime $datetime_model, EEM_Registration $registration_model)
30
-    {
31
-        $this->datetime_model = $datetime_model;
32
-        $this->registration_model = $registration_model;
33
-    }
25
+	/**
26
+	 * @var EEM_Registration
27
+	 */
28
+	protected $registration_model;
29
+	public function __construct(EEM_Datetime $datetime_model, EEM_Registration $registration_model)
30
+	{
31
+		$this->datetime_model = $datetime_model;
32
+		$this->registration_model = $registration_model;
33
+	}
34 34
 
35
-    /**
36
-     * Calculates the total spaces available on the datetime, taking into account
37
-     * ticket limits too.
38
-     *
39
-     * @see EE_Datetime::spaces_remaining( true )
40
-     * @param array            $wpdb_row
41
-     * @param WP_REST_Request $request
42
-     * @param DatetimeControllerBase  $controller
43
-     * @return int
44
-     * @throws EE_Error
45
-     * @throws InvalidDataTypeException
46
-     * @throws InvalidInterfaceException
47
-     * @throws InvalidArgumentException
48
-     * @throws ReflectionException
49
-     */
50
-    public function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
51
-    {
52
-        if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
53
-            $dtt_obj = $this->datetime_model->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
54
-        } else {
55
-            $dtt_obj = null;
56
-        }
57
-        if ($dtt_obj instanceof EE_Datetime) {
58
-            return $dtt_obj->spaces_remaining(true);
59
-        }
60
-        throw new EE_Error(
61
-            sprintf(
62
-                esc_html__(
63
-                // @codingStandardsIgnoreStart
64
-                    'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
65
-                    // @codingStandardsIgnoreEnd
66
-                    'event_espresso'
67
-                ),
68
-                $wpdb_row['Datetime.DTT_ID'],
69
-                print_r($wpdb_row, true)
70
-            )
71
-        );
72
-    }
35
+	/**
36
+	 * Calculates the total spaces available on the datetime, taking into account
37
+	 * ticket limits too.
38
+	 *
39
+	 * @see EE_Datetime::spaces_remaining( true )
40
+	 * @param array            $wpdb_row
41
+	 * @param WP_REST_Request $request
42
+	 * @param DatetimeControllerBase  $controller
43
+	 * @return int
44
+	 * @throws EE_Error
45
+	 * @throws InvalidDataTypeException
46
+	 * @throws InvalidInterfaceException
47
+	 * @throws InvalidArgumentException
48
+	 * @throws ReflectionException
49
+	 */
50
+	public function spacesRemainingConsideringTickets($wpdb_row, $request, $controller)
51
+	{
52
+		if (is_array($wpdb_row) && isset($wpdb_row['Datetime.DTT_ID'])) {
53
+			$dtt_obj = $this->datetime_model->get_one_by_ID($wpdb_row['Datetime.DTT_ID']);
54
+		} else {
55
+			$dtt_obj = null;
56
+		}
57
+		if ($dtt_obj instanceof EE_Datetime) {
58
+			return $dtt_obj->spaces_remaining(true);
59
+		}
60
+		throw new EE_Error(
61
+			sprintf(
62
+				esc_html__(
63
+				// @codingStandardsIgnoreStart
64
+					'Cannot calculate spaces_remaining_considering_tickets because the datetime with ID %1$s (from database row %2$s) was not found',
65
+					// @codingStandardsIgnoreEnd
66
+					'event_espresso'
67
+				),
68
+				$wpdb_row['Datetime.DTT_ID'],
69
+				print_r($wpdb_row, true)
70
+			)
71
+		);
72
+	}
73 73
 
74 74
 
75
-    /**
76
-     * Counts registrations who have checked into this datetime
77
-     *
78
-     * @param array           $wpdb_row
79
-     * @param WP_REST_Request $request
80
-     * @param DatetimeControllerBase $controller
81
-     * @return int
82
-     * @throws EE_Error
83
-     * @throws InvalidArgumentException
84
-     * @throws InvalidDataTypeException
85
-     * @throws InvalidInterfaceException
86
-     * @throws RestException
87
-     */
88
-    public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89
-    {
90
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91
-            throw new EE_Error(
92
-                sprintf(
93
-                    esc_html__(
94
-                    // @codingStandardsIgnoreStart
95
-                        'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
96
-                        // @codingStandardsIgnoreEnd
97
-                        'event_espresso'
98
-                    ),
99
-                    print_r($wpdb_row, true)
100
-                )
101
-            );
102
-        }
103
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
104
-        return $this->registration_model
105
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
106
-    }
75
+	/**
76
+	 * Counts registrations who have checked into this datetime
77
+	 *
78
+	 * @param array           $wpdb_row
79
+	 * @param WP_REST_Request $request
80
+	 * @param DatetimeControllerBase $controller
81
+	 * @return int
82
+	 * @throws EE_Error
83
+	 * @throws InvalidArgumentException
84
+	 * @throws InvalidDataTypeException
85
+	 * @throws InvalidInterfaceException
86
+	 * @throws RestException
87
+	 */
88
+	public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89
+	{
90
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91
+			throw new EE_Error(
92
+				sprintf(
93
+					esc_html__(
94
+					// @codingStandardsIgnoreStart
95
+						'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
96
+						// @codingStandardsIgnoreEnd
97
+						'event_espresso'
98
+					),
99
+					print_r($wpdb_row, true)
100
+				)
101
+			);
102
+		}
103
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
104
+		return $this->registration_model
105
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], true);
106
+	}
107 107
 
108 108
 
109
-    /**
110
-     * Counts registrations who have checked out of this datetime
111
-     *
112
-     * @param array           $wpdb_row
113
-     * @param WP_REST_Request $request
114
-     * @param DatetimeControllerBase $controller
115
-     * @return int
116
-     * @throws EE_Error
117
-     * @throws InvalidArgumentException
118
-     * @throws InvalidDataTypeException
119
-     * @throws InvalidInterfaceException
120
-     * @throws RestException
121
-     */
122
-    public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123
-    {
124
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125
-            throw new EE_Error(
126
-                sprintf(
127
-                    esc_html__(
128
-                    // @codingStandardsIgnoreStart
129
-                        'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
130
-                        // @codingStandardsIgnoreEnd
131
-                        'event_espresso'
132
-                    ),
133
-                    print_r($wpdb_row, true)
134
-                )
135
-            );
136
-        }
137
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
138
-        return $this->registration_model
139
-                               ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
140
-    }
109
+	/**
110
+	 * Counts registrations who have checked out of this datetime
111
+	 *
112
+	 * @param array           $wpdb_row
113
+	 * @param WP_REST_Request $request
114
+	 * @param DatetimeControllerBase $controller
115
+	 * @return int
116
+	 * @throws EE_Error
117
+	 * @throws InvalidArgumentException
118
+	 * @throws InvalidDataTypeException
119
+	 * @throws InvalidInterfaceException
120
+	 * @throws RestException
121
+	 */
122
+	public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123
+	{
124
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125
+			throw new EE_Error(
126
+				sprintf(
127
+					esc_html__(
128
+					// @codingStandardsIgnoreStart
129
+						'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
130
+						// @codingStandardsIgnoreEnd
131
+						'event_espresso'
132
+					),
133
+					print_r($wpdb_row, true)
134
+				)
135
+			);
136
+		}
137
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
138
+		return $this->registration_model
139
+							   ->count_registrations_checked_into_datetime($wpdb_row['Datetime.DTT_ID'], false);
140
+	}
141 141
 
142 142
 
143
-    /**
144
-     * Counts the number of pending-payment registrations for this event (regardless
145
-     * of how many datetimes each registrations' ticket purchase is for)
146
-     *
147
-     * @param array           $wpdb_row
148
-     * @param WP_REST_Request $request
149
-     * @param DatetimeControllerBase $controller
150
-     * @return int
151
-     * @throws EE_Error
152
-     * @throws InvalidArgumentException
153
-     * @throws InvalidDataTypeException
154
-     * @throws InvalidInterfaceException
155
-     * @throws RestException
156
-     */
157
-    public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158
-    {
159
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160
-            throw new EE_Error(
161
-                sprintf(
162
-                    esc_html__(
163
-                    // @codingStandardsIgnoreStart
164
-                        'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
165
-                        // @codingStandardsIgnoreEnd
166
-                        'event_espresso'
167
-                    ),
168
-                    print_r($wpdb_row, true)
169
-                )
170
-            );
171
-        }
172
-        $this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
173
-        return $this->registration_model->count(
174
-            array(
175
-                array(
176
-                    'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
177
-                    'STS_ID'                 => EEM_Registration::status_id_pending_payment,
178
-                ),
179
-            ),
180
-            'REG_ID',
181
-            true
182
-        );
183
-    }
143
+	/**
144
+	 * Counts the number of pending-payment registrations for this event (regardless
145
+	 * of how many datetimes each registrations' ticket purchase is for)
146
+	 *
147
+	 * @param array           $wpdb_row
148
+	 * @param WP_REST_Request $request
149
+	 * @param DatetimeControllerBase $controller
150
+	 * @return int
151
+	 * @throws EE_Error
152
+	 * @throws InvalidArgumentException
153
+	 * @throws InvalidDataTypeException
154
+	 * @throws InvalidInterfaceException
155
+	 * @throws RestException
156
+	 */
157
+	public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158
+	{
159
+		if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160
+			throw new EE_Error(
161
+				sprintf(
162
+					esc_html__(
163
+					// @codingStandardsIgnoreStart
164
+						'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Datetime.DTT_ID"',
165
+						// @codingStandardsIgnoreEnd
166
+						'event_espresso'
167
+					),
168
+					print_r($wpdb_row, true)
169
+				)
170
+			);
171
+		}
172
+		$this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
173
+		return $this->registration_model->count(
174
+			array(
175
+				array(
176
+					'Ticket.Datetime.DTT_ID' => $wpdb_row['Datetime.DTT_ID'],
177
+					'STS_ID'                 => EEM_Registration::status_id_pending_payment,
178
+				),
179
+			),
180
+			'REG_ID',
181
+			true
182
+		);
183
+	}
184 184
 
185 185
 
186
-    /**
187
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
188
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
189
-     *
190
-     * @since 4.9.68.p
191
-     * @return array
192
-     */
193
-    public function schemaForCalculations()
194
-    {
195
-        return array(
196
-            'spaces_remaining_considering_tickets' => array(
197
-                'description' => esc_html__(
198
-                    'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
199
-                    'event_espresso'
200
-                ),
201
-                'type' => 'number',
202
-                'protected' => true,
203
-            ),
204
-            'registrations_checked_in_count' => array(
205
-                'description' => esc_html__(
206
-                    'Counts registrations who have checked into this datetime.',
207
-                    'event_espresso'
208
-                ),
209
-                'type' => 'number',
210
-                'protected' => true,
211
-            ),
212
-            'registrations_checked_out_count' => array(
213
-                'description' => esc_html__(
214
-                    'Counts registrations who have checked out of this datetime.',
215
-                    'event_espresso'
216
-                ),
217
-                'type' => 'number',
218
-                'protected' => true,
219
-            ),
220
-            'spots_taken_pending_payment' => array(
221
-                'description' => esc_html__(
222
-                    'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
223
-                    'event_espresso'
224
-                ),
225
-                'type' => 'number',
226
-                'protected' => true,
227
-            ),
228
-        );
229
-    }
186
+	/**
187
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
188
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
189
+	 *
190
+	 * @since 4.9.68.p
191
+	 * @return array
192
+	 */
193
+	public function schemaForCalculations()
194
+	{
195
+		return array(
196
+			'spaces_remaining_considering_tickets' => array(
197
+				'description' => esc_html__(
198
+					'Calculates the total spaces available on the datetime, taking into account ticket limits too.',
199
+					'event_espresso'
200
+				),
201
+				'type' => 'number',
202
+				'protected' => true,
203
+			),
204
+			'registrations_checked_in_count' => array(
205
+				'description' => esc_html__(
206
+					'Counts registrations who have checked into this datetime.',
207
+					'event_espresso'
208
+				),
209
+				'type' => 'number',
210
+				'protected' => true,
211
+			),
212
+			'registrations_checked_out_count' => array(
213
+				'description' => esc_html__(
214
+					'Counts registrations who have checked out of this datetime.',
215
+					'event_espresso'
216
+				),
217
+				'type' => 'number',
218
+				'protected' => true,
219
+			),
220
+			'spots_taken_pending_payment' => array(
221
+				'description' => esc_html__(
222
+					'The count of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for',
223
+					'event_espresso'
224
+				),
225
+				'type' => 'number',
226
+				'protected' => true,
227
+			),
228
+		);
229
+	}
230 230
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
      */
88 88
     public function registrationsCheckedInCount($wpdb_row, $request, $controller)
89 89
     {
90
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
90
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
91 91
             throw new EE_Error(
92 92
                 sprintf(
93 93
                     esc_html__(
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
      */
122 122
     public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
123 123
     {
124
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
124
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
125 125
             throw new EE_Error(
126 126
                 sprintf(
127 127
                     esc_html__(
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
      */
157 157
     public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
158 158
     {
159
-        if (! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
159
+        if ( ! is_array($wpdb_row) || ! isset($wpdb_row['Datetime.DTT_ID'])) {
160 160
             throw new EE_Error(
161 161
                 sprintf(
162 162
                     esc_html__(
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Event.php 2 patches
Indentation   +567 added lines, -567 removed lines patch added patch discarded remove patch
@@ -26,571 +26,571 @@
 block discarded – undo
26 26
  */
27 27
 class Event extends EventCalculationBase
28 28
 {
29
-    /**
30
-     * @var EEM_Event
31
-     */
32
-    protected $event_model;
33
-
34
-    /**
35
-     * @var EEM_Registration
36
-     */
37
-    protected $registration_model;
38
-    public function __construct(EEM_Event $event_model, EEM_Registration $registration_model)
39
-    {
40
-        $this->event_model = $event_model;
41
-        $this->registration_model = $registration_model;
42
-    }
43
-
44
-    /**
45
-     * Calculates the total spaces on the event (not subtracting sales, but taking
46
-     * sales into account; so this is the optimum sales that CAN still be achieved)
47
-     * See EE_Event::total_available_spaces( true );
48
-     *
49
-     * @param array               $wpdb_row
50
-     * @param WP_REST_Request     $request
51
-     * @param EventControllerBase $controller
52
-     * @return int
53
-     * @throws EE_Error
54
-     * @throws DomainException
55
-     * @throws InvalidDataTypeException
56
-     * @throws InvalidInterfaceException
57
-     * @throws UnexpectedEntityException
58
-     * @throws InvalidArgumentException
59
-     */
60
-    public function optimumSalesAtStart($wpdb_row, $request, $controller)
61
-    {
62
-        $event_obj = null;
63
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
64
-            $event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
65
-        }
66
-        if ($event_obj instanceof EE_Event) {
67
-            return $event_obj->total_available_spaces();
68
-        }
69
-        throw new EE_Error(
70
-            sprintf(
71
-                esc_html__(
72
-                // @codingStandardsIgnoreStart
73
-                    'Cannot calculate optimum_sales_at_start because the event with ID %1$s (from database row %2$s) was not found',
74
-                    // @codingStandardsIgnoreEnd
75
-                    'event_espresso'
76
-                ),
77
-                $wpdb_row['Event_CPT.ID'],
78
-                print_r($wpdb_row, true)
79
-            )
80
-        );
81
-    }
82
-
83
-
84
-    /**
85
-     * Calculates the total spaces on the event (ignoring all sales; so this is the optimum
86
-     * sales that COULD have been achieved)
87
-     * See EE_Event::total_available_spaces( true );
88
-     *
89
-     * @param array               $wpdb_row
90
-     * @param WP_REST_Request     $request
91
-     * @param EventControllerBase $controller
92
-     * @return int
93
-     * @throws DomainException
94
-     * @throws EE_Error
95
-     * @throws InvalidArgumentException
96
-     * @throws InvalidDataTypeException
97
-     * @throws InvalidInterfaceException
98
-     * @throws UnexpectedEntityException
99
-     */
100
-    public function optimumSalesNow($wpdb_row, $request, $controller)
101
-    {
102
-        $event_obj = null;
103
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
104
-            $event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
105
-        }
106
-        if ($event_obj instanceof EE_Event) {
107
-            return $event_obj->total_available_spaces(true);
108
-        }
109
-        throw new EE_Error(
110
-            sprintf(
111
-                esc_html__(
112
-                // @codingStandardsIgnoreStart
113
-                    'Cannot calculate optimum_sales_now because the event with ID %1$s (from database row %2$s) was not found',
114
-                    // @codingStandardsIgnoreEnd
115
-                    'event_espresso'
116
-                ),
117
-                $wpdb_row['Event_CPT.ID'],
118
-                print_r($wpdb_row, true)
119
-            )
120
-        );
121
-    }
122
-
123
-
124
-    /**
125
-     * Like optimum_sales_now, but minus total sales so far.
126
-     * See EE_Event::spaces_remaining_for_sale( true );
127
-     *
128
-     * @param array               $wpdb_row
129
-     * @param WP_REST_Request     $request
130
-     * @param EventControllerBase $controller
131
-     * @return int
132
-     * @throws DomainException
133
-     * @throws EE_Error
134
-     * @throws InvalidArgumentException
135
-     * @throws InvalidDataTypeException
136
-     * @throws InvalidInterfaceException
137
-     * @throws UnexpectedEntityException
138
-     */
139
-    public function spacesRemaining($wpdb_row, $request, $controller)
140
-    {
141
-        $event_obj = null;
142
-        if (Event::wpdbRowHasEventId($wpdb_row)) {
143
-            $event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
144
-        }
145
-        if ($event_obj instanceof EE_Event) {
146
-            return $event_obj->spaces_remaining_for_sale();
147
-        }
148
-        throw new EE_Error(
149
-            sprintf(
150
-                esc_html__(
151
-                // @codingStandardsIgnoreStart
152
-                    'Cannot calculate spaces_remaining because the event with ID %1$s (from database row %2$s) was not found',
153
-                    // @codingStandardsIgnoreEnd
154
-                    'event_espresso'
155
-                ),
156
-                $wpdb_row['Event_CPT.ID'],
157
-                print_r($wpdb_row, true)
158
-            )
159
-        );
160
-    }
161
-
162
-
163
-    /**
164
-     * Counts the number of approved registrations for this event (regardless
165
-     * of how many datetimes each registrations' ticket purchase is for)
166
-     *
167
-     * @param array               $wpdb_row
168
-     * @param WP_REST_Request     $request
169
-     * @param EventControllerBase $controller
170
-     * @return int
171
-     * @throws EE_Error
172
-     * @throws InvalidArgumentException
173
-     * @throws InvalidDataTypeException
174
-     * @throws InvalidInterfaceException
175
-     */
176
-    public function spotsTaken($wpdb_row, $request, $controller)
177
-    {
178
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
179
-            throw new EE_Error(
180
-                sprintf(
181
-                    esc_html__(
182
-                    // @codingStandardsIgnoreStart
183
-                        'Cannot calculate spots_taken because the database row %1$s does not have a valid entry for "Event_CPT.ID"',
184
-                        // @codingStandardsIgnoreEnd
185
-                        'event_espresso'
186
-                    ),
187
-                    print_r($wpdb_row, true)
188
-                )
189
-            );
190
-        }
191
-        return $this->registration_model->count(
192
-            array(
193
-                array(
194
-                    'EVT_ID' => $wpdb_row['Event_CPT.ID'],
195
-                    'STS_ID' => EEM_Registration::status_id_approved,
196
-                ),
197
-            ),
198
-            'REG_ID',
199
-            true
200
-        );
201
-    }
202
-
203
-
204
-    /**
205
-     * Counts the number of pending-payment registrations for this event (regardless
206
-     * of how many datetimes each registrations' ticket purchase is for)
207
-     *
208
-     * @param array               $wpdb_row
209
-     * @param WP_REST_Request     $request
210
-     * @param EventControllerBase $controller
211
-     * @return int
212
-     * @throws EE_Error
213
-     * @throws InvalidArgumentException
214
-     * @throws InvalidDataTypeException
215
-     * @throws InvalidInterfaceException
216
-     * @throws RestException
217
-     */
218
-    public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
219
-    {
220
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
221
-            throw new EE_Error(
222
-                sprintf(
223
-                    esc_html__(
224
-                    // @codingStandardsIgnoreStart
225
-                        'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Event_CPT.ID"',
226
-                        // @codingStandardsIgnoreEnd
227
-                        'event_espresso'
228
-                    ),
229
-                    print_r($wpdb_row, true)
230
-                )
231
-            );
232
-        }
233
-        $this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
234
-        return $this->registration_model->count(
235
-            array(
236
-                array(
237
-                    'EVT_ID' => $wpdb_row['Event_CPT.ID'],
238
-                    'STS_ID' => EEM_Registration::status_id_pending_payment,
239
-                ),
240
-            ),
241
-            'REG_ID',
242
-            true
243
-        );
244
-    }
245
-
246
-
247
-    /**
248
-     * Counts all the registrations who have checked into one of this events' datetimes
249
-     * See EE_Event::total_available_spaces( false );
250
-     *
251
-     * @param array               $wpdb_row
252
-     * @param WP_REST_Request     $request
253
-     * @param EventControllerBase $controller
254
-     * @return int|null if permission denied
255
-     * @throws EE_Error
256
-     * @throws InvalidArgumentException
257
-     * @throws InvalidDataTypeException
258
-     * @throws InvalidInterfaceException
259
-     * @throws RestException
260
-     */
261
-    public function registrationsCheckedInCount($wpdb_row, $request, $controller)
262
-    {
263
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
264
-            throw new EE_Error(
265
-                sprintf(
266
-                    esc_html__(
267
-                    // @codingStandardsIgnoreStart
268
-                        'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
269
-                        // @codingStandardsIgnoreEnd
270
-                        'event_espresso'
271
-                    ),
272
-                    print_r($wpdb_row, true)
273
-                )
274
-            );
275
-        }
276
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
277
-        return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], true);
278
-    }
279
-
280
-
281
-    /**
282
-     * Counts all the registrations who have checked out of one of this events' datetimes
283
-     * See EE_Event::total_available_spaces( false );
284
-     *
285
-     * @param array               $wpdb_row
286
-     * @param WP_REST_Request     $request
287
-     * @param EventControllerBase $controller
288
-     * @return int
289
-     * @throws EE_Error
290
-     * @throws InvalidArgumentException
291
-     * @throws InvalidDataTypeException
292
-     * @throws InvalidInterfaceException
293
-     * @throws RestException
294
-     */
295
-    public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
296
-    {
297
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
298
-            throw new EE_Error(
299
-                sprintf(
300
-                    esc_html__(
301
-                    // @codingStandardsIgnoreStart
302
-                        'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
303
-                        // @codingStandardsIgnoreEnd
304
-                        'event_espresso'
305
-                    ),
306
-                    print_r($wpdb_row, true)
307
-                )
308
-            );
309
-        }
310
-        $this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
311
-        return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], false);
312
-    }
313
-
314
-
315
-    /**
316
-     * Gets the thumbnail image
317
-     *
318
-     * @param array               $wpdb_row
319
-     * @param WP_REST_Request     $request
320
-     * @param EventControllerBase $controller
321
-     * @return array
322
-     * @throws EE_Error
323
-     */
324
-    public function imageThumbnail($wpdb_row, $request, $controller)
325
-    {
326
-        return self::calculateImageData($wpdb_row, 'thumbnail');
327
-    }
328
-
329
-
330
-    /**
331
-     * Gets the medium image
332
-     *
333
-     * @param array               $wpdb_row
334
-     * @param WP_REST_Request     $request
335
-     * @param EventControllerBase $controller
336
-     * @return array
337
-     * @throws EE_Error
338
-     */
339
-    public function imageMedium($wpdb_row, $request, $controller)
340
-    {
341
-        return self::calculateImageData($wpdb_row, 'medium');
342
-    }
343
-
344
-
345
-    /**
346
-     * Gets the medium-large image
347
-     *
348
-     * @param array               $wpdb_row
349
-     * @param WP_REST_Request     $request
350
-     * @param EventControllerBase $controller
351
-     * @return array
352
-     * @throws EE_Error
353
-     */
354
-    public function imageMediumLarge($wpdb_row, $request, $controller)
355
-    {
356
-        return self::calculateImageData($wpdb_row, 'medium_large');
357
-    }
358
-
359
-
360
-    /**
361
-     * Gets the large image
362
-     *
363
-     * @param array               $wpdb_row
364
-     * @param WP_REST_Request     $request
365
-     * @param EventControllerBase $controller
366
-     * @return array
367
-     * @throws EE_Error
368
-     */
369
-    public function imageLarge($wpdb_row, $request, $controller)
370
-    {
371
-        return self::calculateImageData($wpdb_row, 'large');
372
-    }
373
-
374
-
375
-    /**
376
-     * Gets the post-thumbnail image
377
-     *
378
-     * @param array               $wpdb_row
379
-     * @param WP_REST_Request     $request
380
-     * @param EventControllerBase $controller
381
-     * @return array
382
-     * @throws EE_Error
383
-     */
384
-    public function imagePostThumbnail($wpdb_row, $request, $controller)
385
-    {
386
-        return self::calculateImageData($wpdb_row, 'post-thumbnail');
387
-    }
388
-
389
-
390
-    /**
391
-     * Gets the full size image
392
-     *
393
-     * @param array               $wpdb_row
394
-     * @param WP_REST_Request     $request
395
-     * @param EventControllerBase $controller
396
-     * @return array
397
-     * @throws EE_Error
398
-     */
399
-    public function imageFull($wpdb_row, $request, $controller)
400
-    {
401
-        return self::calculateImageData($wpdb_row, 'full');
402
-    }
403
-
404
-
405
-    /**
406
-     * Gets image specs and formats them for the display in the API,
407
-     * according to the image size requested
408
-     *
409
-     * @param array  $wpdb_row
410
-     * @param string $image_size one of these: thumbnail, medium, medium_large, large, post-thumbnail, full
411
-     * @return array|false if no such image exists. If array it will have keys 'url', 'width', 'height' and 'original'
412
-     * @throws EE_Error
413
-     */
414
-    protected function calculateImageData($wpdb_row, $image_size)
415
-    {
416
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
417
-            throw new EE_Error(
418
-                sprintf(
419
-                    esc_html__(
420
-                    // @codingStandardsIgnoreStart
421
-                        'Cannot calculate image because the database row %1$s does not have an entry for "Event_CPT.ID"',
422
-                        // @codingStandardsIgnoreEnd
423
-                        'event_espresso'
424
-                    ),
425
-                    print_r($wpdb_row, true)
426
-                )
427
-            );
428
-        }
429
-        $EVT_ID = $wpdb_row['Event_CPT.ID'];
430
-        $attachment_id = get_post_thumbnail_id($EVT_ID);
431
-        $data = wp_get_attachment_image_src($attachment_id, $image_size);
432
-        if (! $data) {
433
-            return null;
434
-        }
435
-        $generated = true;
436
-        if (isset($data[3])) {
437
-            $generated = $data[3];
438
-        }
439
-        return array(
440
-            'url'       => $data[0],
441
-            'width'     => $data[1],
442
-            'height'    => $data[2],
443
-            'generated' => $generated,
444
-        );
445
-    }
446
-
447
-
448
-    /**
449
-     * Returns true if the array of data contains 'Event_CPT.ID'. False otherwise
450
-     *
451
-     * @param array $wpdb_row
452
-     * @return bool
453
-     */
454
-    protected function wpdbRowHasEventId($wpdb_row)
455
-    {
456
-        return (is_array($wpdb_row) && isset($wpdb_row['Event_CPT.ID']) && absint($wpdb_row['Event_CPT.ID']));
457
-    }
458
-
459
-
460
-    /**
461
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
462
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
463
-     *
464
-     * @since 4.9.68.p
465
-     * @return array
466
-     */
467
-    public function schemaForCalculations()
468
-    {
469
-        $image_object_properties = array(
470
-            'url'       => array(
471
-                'type' => 'string',
472
-            ),
473
-            'width'     => array(
474
-                'type' => 'number',
475
-            ),
476
-            'height'    => array(
477
-                'type' => 'number',
478
-            ),
479
-            'generated' => array(
480
-                'type' => 'boolean',
481
-            ),
482
-        );
483
-        return array(
484
-            'optimum_sales_at_start'          => array(
485
-                'description' => esc_html__(
486
-                    'The total spaces on the event (not subtracting sales, but taking sales into account; so this is the optimum sales that CAN still be achieved.',
487
-                    'event_espresso'
488
-                ),
489
-                'type'        => 'number',
490
-                'protected' => true,
491
-            ),
492
-            'optimum_sales_now'               => array(
493
-                'description' => esc_html__(
494
-                    'The total spaces on the event (ignoring all sales; so this is the optimum sales that could have been achieved.',
495
-                    'event_espresso'
496
-                ),
497
-                'type'        => 'number',
498
-                'protected' => true,
499
-            ),
500
-            'spaces_remaining'                => array(
501
-                'description' => esc_html__(
502
-                    'The optimum_sales_number result, minus total sales so far.',
503
-                    'event_espresso'
504
-                ),
505
-                'type'        => 'number',
506
-                'protected' => true,
507
-            ),
508
-            'spots_taken'                     => array(
509
-                'description' => esc_html__(
510
-                    'The number of approved registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
511
-                    'event_espresso'
512
-                ),
513
-                'type'        => 'number',
514
-                'protected' => true,
515
-            ),
516
-            'spots_taken_pending_payment'     => array(
517
-                'description' => esc_html__(
518
-                    'The number of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
519
-                    'event_espresso'
520
-                ),
521
-                'type'        => 'number',
522
-                'protected' => true,
523
-            ),
524
-            'registrations_checked_in_count'  => array(
525
-                'description' => esc_html__(
526
-                    'The count of all the registrations who have checked into one of this event\'s datetimes.',
527
-                    'event_espresso'
528
-                ),
529
-                'type'        => 'number',
530
-                'protected' => true,
531
-            ),
532
-            'registrations_checked_out_count' => array(
533
-                'description' => esc_html__(
534
-                    'The count of all registrations who have checked out of one of this event\'s datetimes.',
535
-                    'event_espresso'
536
-                ),
537
-                'type'        => 'number',
538
-                'protected' => true,
539
-            ),
540
-            'image_thumbnail'                 => array(
541
-                'description'          => esc_html__(
542
-                    'The thumbnail image data.',
543
-                    'event_espresso'
544
-                ),
545
-                'type'                 => 'object',
546
-                'properties'           => $image_object_properties,
547
-                'additionalProperties' => false,
548
-            ),
549
-            'image_medium'                    => array(
550
-                'description'          => esc_html__(
551
-                    'The medium image data.',
552
-                    'event_espresso'
553
-                ),
554
-                'type'                 => 'object',
555
-                'properties'           => $image_object_properties,
556
-                'additionalProperties' => false,
557
-            ),
558
-            'image_medium_large'              => array(
559
-                'description'          => esc_html__(
560
-                    'The medium-large image data.',
561
-                    'event_espresso'
562
-                ),
563
-                'type'                 => 'object',
564
-                'properties'           => $image_object_properties,
565
-                'additionalProperties' => false,
566
-            ),
567
-            'image_large'                     => array(
568
-                'description'          => esc_html__(
569
-                    'The large image data.',
570
-                    'event_espresso'
571
-                ),
572
-                'type'                 => 'object',
573
-                'properties'           => $image_object_properties,
574
-                'additionalProperties' => false,
575
-            ),
576
-            'image_post_thumbnail'            => array(
577
-                'description'          => esc_html__(
578
-                    'The post-thumbnail image data.',
579
-                    'event_espresso'
580
-                ),
581
-                'type'                 => 'object',
582
-                'properties'           => $image_object_properties,
583
-                'additionalProperties' => false,
584
-            ),
585
-            'image_full'                      => array(
586
-                'description'          => esc_html__(
587
-                    'The full size image data',
588
-                    'event_espresso'
589
-                ),
590
-                'type'                 => 'object',
591
-                'properties'           => $image_object_properties,
592
-                'additionalProperties' => false,
593
-            ),
594
-        );
595
-    }
29
+	/**
30
+	 * @var EEM_Event
31
+	 */
32
+	protected $event_model;
33
+
34
+	/**
35
+	 * @var EEM_Registration
36
+	 */
37
+	protected $registration_model;
38
+	public function __construct(EEM_Event $event_model, EEM_Registration $registration_model)
39
+	{
40
+		$this->event_model = $event_model;
41
+		$this->registration_model = $registration_model;
42
+	}
43
+
44
+	/**
45
+	 * Calculates the total spaces on the event (not subtracting sales, but taking
46
+	 * sales into account; so this is the optimum sales that CAN still be achieved)
47
+	 * See EE_Event::total_available_spaces( true );
48
+	 *
49
+	 * @param array               $wpdb_row
50
+	 * @param WP_REST_Request     $request
51
+	 * @param EventControllerBase $controller
52
+	 * @return int
53
+	 * @throws EE_Error
54
+	 * @throws DomainException
55
+	 * @throws InvalidDataTypeException
56
+	 * @throws InvalidInterfaceException
57
+	 * @throws UnexpectedEntityException
58
+	 * @throws InvalidArgumentException
59
+	 */
60
+	public function optimumSalesAtStart($wpdb_row, $request, $controller)
61
+	{
62
+		$event_obj = null;
63
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
64
+			$event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
65
+		}
66
+		if ($event_obj instanceof EE_Event) {
67
+			return $event_obj->total_available_spaces();
68
+		}
69
+		throw new EE_Error(
70
+			sprintf(
71
+				esc_html__(
72
+				// @codingStandardsIgnoreStart
73
+					'Cannot calculate optimum_sales_at_start because the event with ID %1$s (from database row %2$s) was not found',
74
+					// @codingStandardsIgnoreEnd
75
+					'event_espresso'
76
+				),
77
+				$wpdb_row['Event_CPT.ID'],
78
+				print_r($wpdb_row, true)
79
+			)
80
+		);
81
+	}
82
+
83
+
84
+	/**
85
+	 * Calculates the total spaces on the event (ignoring all sales; so this is the optimum
86
+	 * sales that COULD have been achieved)
87
+	 * See EE_Event::total_available_spaces( true );
88
+	 *
89
+	 * @param array               $wpdb_row
90
+	 * @param WP_REST_Request     $request
91
+	 * @param EventControllerBase $controller
92
+	 * @return int
93
+	 * @throws DomainException
94
+	 * @throws EE_Error
95
+	 * @throws InvalidArgumentException
96
+	 * @throws InvalidDataTypeException
97
+	 * @throws InvalidInterfaceException
98
+	 * @throws UnexpectedEntityException
99
+	 */
100
+	public function optimumSalesNow($wpdb_row, $request, $controller)
101
+	{
102
+		$event_obj = null;
103
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
104
+			$event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
105
+		}
106
+		if ($event_obj instanceof EE_Event) {
107
+			return $event_obj->total_available_spaces(true);
108
+		}
109
+		throw new EE_Error(
110
+			sprintf(
111
+				esc_html__(
112
+				// @codingStandardsIgnoreStart
113
+					'Cannot calculate optimum_sales_now because the event with ID %1$s (from database row %2$s) was not found',
114
+					// @codingStandardsIgnoreEnd
115
+					'event_espresso'
116
+				),
117
+				$wpdb_row['Event_CPT.ID'],
118
+				print_r($wpdb_row, true)
119
+			)
120
+		);
121
+	}
122
+
123
+
124
+	/**
125
+	 * Like optimum_sales_now, but minus total sales so far.
126
+	 * See EE_Event::spaces_remaining_for_sale( true );
127
+	 *
128
+	 * @param array               $wpdb_row
129
+	 * @param WP_REST_Request     $request
130
+	 * @param EventControllerBase $controller
131
+	 * @return int
132
+	 * @throws DomainException
133
+	 * @throws EE_Error
134
+	 * @throws InvalidArgumentException
135
+	 * @throws InvalidDataTypeException
136
+	 * @throws InvalidInterfaceException
137
+	 * @throws UnexpectedEntityException
138
+	 */
139
+	public function spacesRemaining($wpdb_row, $request, $controller)
140
+	{
141
+		$event_obj = null;
142
+		if (Event::wpdbRowHasEventId($wpdb_row)) {
143
+			$event_obj = $this->event_model->get_one_by_ID($wpdb_row['Event_CPT.ID']);
144
+		}
145
+		if ($event_obj instanceof EE_Event) {
146
+			return $event_obj->spaces_remaining_for_sale();
147
+		}
148
+		throw new EE_Error(
149
+			sprintf(
150
+				esc_html__(
151
+				// @codingStandardsIgnoreStart
152
+					'Cannot calculate spaces_remaining because the event with ID %1$s (from database row %2$s) was not found',
153
+					// @codingStandardsIgnoreEnd
154
+					'event_espresso'
155
+				),
156
+				$wpdb_row['Event_CPT.ID'],
157
+				print_r($wpdb_row, true)
158
+			)
159
+		);
160
+	}
161
+
162
+
163
+	/**
164
+	 * Counts the number of approved registrations for this event (regardless
165
+	 * of how many datetimes each registrations' ticket purchase is for)
166
+	 *
167
+	 * @param array               $wpdb_row
168
+	 * @param WP_REST_Request     $request
169
+	 * @param EventControllerBase $controller
170
+	 * @return int
171
+	 * @throws EE_Error
172
+	 * @throws InvalidArgumentException
173
+	 * @throws InvalidDataTypeException
174
+	 * @throws InvalidInterfaceException
175
+	 */
176
+	public function spotsTaken($wpdb_row, $request, $controller)
177
+	{
178
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
179
+			throw new EE_Error(
180
+				sprintf(
181
+					esc_html__(
182
+					// @codingStandardsIgnoreStart
183
+						'Cannot calculate spots_taken because the database row %1$s does not have a valid entry for "Event_CPT.ID"',
184
+						// @codingStandardsIgnoreEnd
185
+						'event_espresso'
186
+					),
187
+					print_r($wpdb_row, true)
188
+				)
189
+			);
190
+		}
191
+		return $this->registration_model->count(
192
+			array(
193
+				array(
194
+					'EVT_ID' => $wpdb_row['Event_CPT.ID'],
195
+					'STS_ID' => EEM_Registration::status_id_approved,
196
+				),
197
+			),
198
+			'REG_ID',
199
+			true
200
+		);
201
+	}
202
+
203
+
204
+	/**
205
+	 * Counts the number of pending-payment registrations for this event (regardless
206
+	 * of how many datetimes each registrations' ticket purchase is for)
207
+	 *
208
+	 * @param array               $wpdb_row
209
+	 * @param WP_REST_Request     $request
210
+	 * @param EventControllerBase $controller
211
+	 * @return int
212
+	 * @throws EE_Error
213
+	 * @throws InvalidArgumentException
214
+	 * @throws InvalidDataTypeException
215
+	 * @throws InvalidInterfaceException
216
+	 * @throws RestException
217
+	 */
218
+	public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
219
+	{
220
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
221
+			throw new EE_Error(
222
+				sprintf(
223
+					esc_html__(
224
+					// @codingStandardsIgnoreStart
225
+						'Cannot calculate spots_taken_pending_payment because the database row %1$s does not have an entry for "Event_CPT.ID"',
226
+						// @codingStandardsIgnoreEnd
227
+						'event_espresso'
228
+					),
229
+					print_r($wpdb_row, true)
230
+				)
231
+			);
232
+		}
233
+		$this->verifyCurrentUserCan('ee_read_registrations', 'spots_taken_pending_payment');
234
+		return $this->registration_model->count(
235
+			array(
236
+				array(
237
+					'EVT_ID' => $wpdb_row['Event_CPT.ID'],
238
+					'STS_ID' => EEM_Registration::status_id_pending_payment,
239
+				),
240
+			),
241
+			'REG_ID',
242
+			true
243
+		);
244
+	}
245
+
246
+
247
+	/**
248
+	 * Counts all the registrations who have checked into one of this events' datetimes
249
+	 * See EE_Event::total_available_spaces( false );
250
+	 *
251
+	 * @param array               $wpdb_row
252
+	 * @param WP_REST_Request     $request
253
+	 * @param EventControllerBase $controller
254
+	 * @return int|null if permission denied
255
+	 * @throws EE_Error
256
+	 * @throws InvalidArgumentException
257
+	 * @throws InvalidDataTypeException
258
+	 * @throws InvalidInterfaceException
259
+	 * @throws RestException
260
+	 */
261
+	public function registrationsCheckedInCount($wpdb_row, $request, $controller)
262
+	{
263
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
264
+			throw new EE_Error(
265
+				sprintf(
266
+					esc_html__(
267
+					// @codingStandardsIgnoreStart
268
+						'Cannot calculate registrations_checked_in_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
269
+						// @codingStandardsIgnoreEnd
270
+						'event_espresso'
271
+					),
272
+					print_r($wpdb_row, true)
273
+				)
274
+			);
275
+		}
276
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_in_count');
277
+		return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], true);
278
+	}
279
+
280
+
281
+	/**
282
+	 * Counts all the registrations who have checked out of one of this events' datetimes
283
+	 * See EE_Event::total_available_spaces( false );
284
+	 *
285
+	 * @param array               $wpdb_row
286
+	 * @param WP_REST_Request     $request
287
+	 * @param EventControllerBase $controller
288
+	 * @return int
289
+	 * @throws EE_Error
290
+	 * @throws InvalidArgumentException
291
+	 * @throws InvalidDataTypeException
292
+	 * @throws InvalidInterfaceException
293
+	 * @throws RestException
294
+	 */
295
+	public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
296
+	{
297
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
298
+			throw new EE_Error(
299
+				sprintf(
300
+					esc_html__(
301
+					// @codingStandardsIgnoreStart
302
+						'Cannot calculate registrations_checked_out_count because the database row %1$s does not have an entry for "Event_CPT.ID"',
303
+						// @codingStandardsIgnoreEnd
304
+						'event_espresso'
305
+					),
306
+					print_r($wpdb_row, true)
307
+				)
308
+			);
309
+		}
310
+		$this->verifyCurrentUserCan('ee_read_checkins', 'registrations_checked_out_count');
311
+		return $this->registration_model->count_registrations_checked_into_event($wpdb_row['Event_CPT.ID'], false);
312
+	}
313
+
314
+
315
+	/**
316
+	 * Gets the thumbnail image
317
+	 *
318
+	 * @param array               $wpdb_row
319
+	 * @param WP_REST_Request     $request
320
+	 * @param EventControllerBase $controller
321
+	 * @return array
322
+	 * @throws EE_Error
323
+	 */
324
+	public function imageThumbnail($wpdb_row, $request, $controller)
325
+	{
326
+		return self::calculateImageData($wpdb_row, 'thumbnail');
327
+	}
328
+
329
+
330
+	/**
331
+	 * Gets the medium image
332
+	 *
333
+	 * @param array               $wpdb_row
334
+	 * @param WP_REST_Request     $request
335
+	 * @param EventControllerBase $controller
336
+	 * @return array
337
+	 * @throws EE_Error
338
+	 */
339
+	public function imageMedium($wpdb_row, $request, $controller)
340
+	{
341
+		return self::calculateImageData($wpdb_row, 'medium');
342
+	}
343
+
344
+
345
+	/**
346
+	 * Gets the medium-large image
347
+	 *
348
+	 * @param array               $wpdb_row
349
+	 * @param WP_REST_Request     $request
350
+	 * @param EventControllerBase $controller
351
+	 * @return array
352
+	 * @throws EE_Error
353
+	 */
354
+	public function imageMediumLarge($wpdb_row, $request, $controller)
355
+	{
356
+		return self::calculateImageData($wpdb_row, 'medium_large');
357
+	}
358
+
359
+
360
+	/**
361
+	 * Gets the large image
362
+	 *
363
+	 * @param array               $wpdb_row
364
+	 * @param WP_REST_Request     $request
365
+	 * @param EventControllerBase $controller
366
+	 * @return array
367
+	 * @throws EE_Error
368
+	 */
369
+	public function imageLarge($wpdb_row, $request, $controller)
370
+	{
371
+		return self::calculateImageData($wpdb_row, 'large');
372
+	}
373
+
374
+
375
+	/**
376
+	 * Gets the post-thumbnail image
377
+	 *
378
+	 * @param array               $wpdb_row
379
+	 * @param WP_REST_Request     $request
380
+	 * @param EventControllerBase $controller
381
+	 * @return array
382
+	 * @throws EE_Error
383
+	 */
384
+	public function imagePostThumbnail($wpdb_row, $request, $controller)
385
+	{
386
+		return self::calculateImageData($wpdb_row, 'post-thumbnail');
387
+	}
388
+
389
+
390
+	/**
391
+	 * Gets the full size image
392
+	 *
393
+	 * @param array               $wpdb_row
394
+	 * @param WP_REST_Request     $request
395
+	 * @param EventControllerBase $controller
396
+	 * @return array
397
+	 * @throws EE_Error
398
+	 */
399
+	public function imageFull($wpdb_row, $request, $controller)
400
+	{
401
+		return self::calculateImageData($wpdb_row, 'full');
402
+	}
403
+
404
+
405
+	/**
406
+	 * Gets image specs and formats them for the display in the API,
407
+	 * according to the image size requested
408
+	 *
409
+	 * @param array  $wpdb_row
410
+	 * @param string $image_size one of these: thumbnail, medium, medium_large, large, post-thumbnail, full
411
+	 * @return array|false if no such image exists. If array it will have keys 'url', 'width', 'height' and 'original'
412
+	 * @throws EE_Error
413
+	 */
414
+	protected function calculateImageData($wpdb_row, $image_size)
415
+	{
416
+		if (! Event::wpdbRowHasEventId($wpdb_row)) {
417
+			throw new EE_Error(
418
+				sprintf(
419
+					esc_html__(
420
+					// @codingStandardsIgnoreStart
421
+						'Cannot calculate image because the database row %1$s does not have an entry for "Event_CPT.ID"',
422
+						// @codingStandardsIgnoreEnd
423
+						'event_espresso'
424
+					),
425
+					print_r($wpdb_row, true)
426
+				)
427
+			);
428
+		}
429
+		$EVT_ID = $wpdb_row['Event_CPT.ID'];
430
+		$attachment_id = get_post_thumbnail_id($EVT_ID);
431
+		$data = wp_get_attachment_image_src($attachment_id, $image_size);
432
+		if (! $data) {
433
+			return null;
434
+		}
435
+		$generated = true;
436
+		if (isset($data[3])) {
437
+			$generated = $data[3];
438
+		}
439
+		return array(
440
+			'url'       => $data[0],
441
+			'width'     => $data[1],
442
+			'height'    => $data[2],
443
+			'generated' => $generated,
444
+		);
445
+	}
446
+
447
+
448
+	/**
449
+	 * Returns true if the array of data contains 'Event_CPT.ID'. False otherwise
450
+	 *
451
+	 * @param array $wpdb_row
452
+	 * @return bool
453
+	 */
454
+	protected function wpdbRowHasEventId($wpdb_row)
455
+	{
456
+		return (is_array($wpdb_row) && isset($wpdb_row['Event_CPT.ID']) && absint($wpdb_row['Event_CPT.ID']));
457
+	}
458
+
459
+
460
+	/**
461
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
462
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
463
+	 *
464
+	 * @since 4.9.68.p
465
+	 * @return array
466
+	 */
467
+	public function schemaForCalculations()
468
+	{
469
+		$image_object_properties = array(
470
+			'url'       => array(
471
+				'type' => 'string',
472
+			),
473
+			'width'     => array(
474
+				'type' => 'number',
475
+			),
476
+			'height'    => array(
477
+				'type' => 'number',
478
+			),
479
+			'generated' => array(
480
+				'type' => 'boolean',
481
+			),
482
+		);
483
+		return array(
484
+			'optimum_sales_at_start'          => array(
485
+				'description' => esc_html__(
486
+					'The total spaces on the event (not subtracting sales, but taking sales into account; so this is the optimum sales that CAN still be achieved.',
487
+					'event_espresso'
488
+				),
489
+				'type'        => 'number',
490
+				'protected' => true,
491
+			),
492
+			'optimum_sales_now'               => array(
493
+				'description' => esc_html__(
494
+					'The total spaces on the event (ignoring all sales; so this is the optimum sales that could have been achieved.',
495
+					'event_espresso'
496
+				),
497
+				'type'        => 'number',
498
+				'protected' => true,
499
+			),
500
+			'spaces_remaining'                => array(
501
+				'description' => esc_html__(
502
+					'The optimum_sales_number result, minus total sales so far.',
503
+					'event_espresso'
504
+				),
505
+				'type'        => 'number',
506
+				'protected' => true,
507
+			),
508
+			'spots_taken'                     => array(
509
+				'description' => esc_html__(
510
+					'The number of approved registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
511
+					'event_espresso'
512
+				),
513
+				'type'        => 'number',
514
+				'protected' => true,
515
+			),
516
+			'spots_taken_pending_payment'     => array(
517
+				'description' => esc_html__(
518
+					'The number of pending-payment registrations for this event (regardless of how many datetimes each registration\'s ticket purchase is for)',
519
+					'event_espresso'
520
+				),
521
+				'type'        => 'number',
522
+				'protected' => true,
523
+			),
524
+			'registrations_checked_in_count'  => array(
525
+				'description' => esc_html__(
526
+					'The count of all the registrations who have checked into one of this event\'s datetimes.',
527
+					'event_espresso'
528
+				),
529
+				'type'        => 'number',
530
+				'protected' => true,
531
+			),
532
+			'registrations_checked_out_count' => array(
533
+				'description' => esc_html__(
534
+					'The count of all registrations who have checked out of one of this event\'s datetimes.',
535
+					'event_espresso'
536
+				),
537
+				'type'        => 'number',
538
+				'protected' => true,
539
+			),
540
+			'image_thumbnail'                 => array(
541
+				'description'          => esc_html__(
542
+					'The thumbnail image data.',
543
+					'event_espresso'
544
+				),
545
+				'type'                 => 'object',
546
+				'properties'           => $image_object_properties,
547
+				'additionalProperties' => false,
548
+			),
549
+			'image_medium'                    => array(
550
+				'description'          => esc_html__(
551
+					'The medium image data.',
552
+					'event_espresso'
553
+				),
554
+				'type'                 => 'object',
555
+				'properties'           => $image_object_properties,
556
+				'additionalProperties' => false,
557
+			),
558
+			'image_medium_large'              => array(
559
+				'description'          => esc_html__(
560
+					'The medium-large image data.',
561
+					'event_espresso'
562
+				),
563
+				'type'                 => 'object',
564
+				'properties'           => $image_object_properties,
565
+				'additionalProperties' => false,
566
+			),
567
+			'image_large'                     => array(
568
+				'description'          => esc_html__(
569
+					'The large image data.',
570
+					'event_espresso'
571
+				),
572
+				'type'                 => 'object',
573
+				'properties'           => $image_object_properties,
574
+				'additionalProperties' => false,
575
+			),
576
+			'image_post_thumbnail'            => array(
577
+				'description'          => esc_html__(
578
+					'The post-thumbnail image data.',
579
+					'event_espresso'
580
+				),
581
+				'type'                 => 'object',
582
+				'properties'           => $image_object_properties,
583
+				'additionalProperties' => false,
584
+			),
585
+			'image_full'                      => array(
586
+				'description'          => esc_html__(
587
+					'The full size image data',
588
+					'event_espresso'
589
+				),
590
+				'type'                 => 'object',
591
+				'properties'           => $image_object_properties,
592
+				'additionalProperties' => false,
593
+			),
594
+		);
595
+	}
596 596
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
      */
176 176
     public function spotsTaken($wpdb_row, $request, $controller)
177 177
     {
178
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
178
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
179 179
             throw new EE_Error(
180 180
                 sprintf(
181 181
                     esc_html__(
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
      */
218 218
     public function spotsTakenPendingPayment($wpdb_row, $request, $controller)
219 219
     {
220
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
220
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
221 221
             throw new EE_Error(
222 222
                 sprintf(
223 223
                     esc_html__(
@@ -260,7 +260,7 @@  discard block
 block discarded – undo
260 260
      */
261 261
     public function registrationsCheckedInCount($wpdb_row, $request, $controller)
262 262
     {
263
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
263
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
264 264
             throw new EE_Error(
265 265
                 sprintf(
266 266
                     esc_html__(
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
      */
295 295
     public function registrationsCheckedOutCount($wpdb_row, $request, $controller)
296 296
     {
297
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
297
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
298 298
             throw new EE_Error(
299 299
                 sprintf(
300 300
                     esc_html__(
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
      */
414 414
     protected function calculateImageData($wpdb_row, $image_size)
415 415
     {
416
-        if (! Event::wpdbRowHasEventId($wpdb_row)) {
416
+        if ( ! Event::wpdbRowHasEventId($wpdb_row)) {
417 417
             throw new EE_Error(
418 418
                 sprintf(
419 419
                     esc_html__(
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
         $EVT_ID = $wpdb_row['Event_CPT.ID'];
430 430
         $attachment_id = get_post_thumbnail_id($EVT_ID);
431 431
         $data = wp_get_attachment_image_src($attachment_id, $image_size);
432
-        if (! $data) {
432
+        if ( ! $data) {
433 433
             return null;
434 434
         }
435 435
         $generated = true;
Please login to merge, or discard this patch.
line_item_display/EE_Receipt_Line_Item_Display_Strategy.strategy.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -15,88 +15,88 @@
 block discarded – undo
15 15
  * ------------------------------------------------------------------------
16 16
  */
17 17
  /**
18
- *
19
- * Class EE_Receipt_Line_Item_Display_Strategy
20
- *
21
- * Description
22
- *
23
- * @package         Event Espresso
24
- * @subpackage    core
25
- * @author              Brent Christensen
26
- *
27
- *
28
- */
18
+  *
19
+  * Class EE_Receipt_Line_Item_Display_Strategy
20
+  *
21
+  * Description
22
+  *
23
+  * @package         Event Espresso
24
+  * @subpackage    core
25
+  * @author              Brent Christensen
26
+  *
27
+  *
28
+  */
29 29
 
30 30
 class EE_Receipt_Line_Item_Display_Strategy implements EEI_Line_Item_Display
31 31
 {
32 32
 
33
-    /**
34
-     * @param EE_Line_Item $line_item
35
-     * @param array        $options
36
-     * @return mixed
37
-     */
38
-    public function display_line_item(EE_Line_Item $line_item, $options = array())
39
-    {
33
+	/**
34
+	 * @param EE_Line_Item $line_item
35
+	 * @param array        $options
36
+	 * @return mixed
37
+	 */
38
+	public function display_line_item(EE_Line_Item $line_item, $options = array())
39
+	{
40 40
 
41
-        $html = '';
42
-        // set some default options and merge with incoming
43
-        $default_options = array(
44
-            'show_desc' => true,
45
-            'odd' => false
46
-        );
47
-        $options = array_merge($default_options, (array) $options);
48
-        switch ($line_item->type()) {
49
-            case EEM_Line_Item::type_total:
50
-                // loop thru children
51
-                foreach ($line_item->children() as $child_line_item) {
52
-                    // recursively feed children back into this method
41
+		$html = '';
42
+		// set some default options and merge with incoming
43
+		$default_options = array(
44
+			'show_desc' => true,
45
+			'odd' => false
46
+		);
47
+		$options = array_merge($default_options, (array) $options);
48
+		switch ($line_item->type()) {
49
+			case EEM_Line_Item::type_total:
50
+				// loop thru children
51
+				foreach ($line_item->children() as $child_line_item) {
52
+					// recursively feed children back into this method
53 53
 //                  $html .= $this->display_line_item( $child_line_item, $options );
54
-                }
54
+				}
55 55
 //              $html .= $this->_separator_row( $options );
56 56
 //              $html .= $this->_total_row( $line_item, esc_html__('Total', 'event_espresso'), $options );
57
-                break;
57
+				break;
58 58
 
59 59
 
60
-            case EEM_Line_Item::type_sub_total:
61
-                // loop thru children
62
-                foreach ($line_item->children() as $child_line_item) {
63
-                    // recursively feed children back into this method
60
+			case EEM_Line_Item::type_sub_total:
61
+				// loop thru children
62
+				foreach ($line_item->children() as $child_line_item) {
63
+					// recursively feed children back into this method
64 64
 //                  $html .= $this->display_line_item( $child_line_item, $options );
65
-                }
65
+				}
66 66
 //              $html .= $this->_total_row( $line_item, esc_html__('Sub-Total', 'event_espresso'), $options );
67
-                break;
67
+				break;
68 68
 
69 69
 
70
-            case EEM_Line_Item::type_tax_sub_total:
71
-                // loop thru children
72
-                foreach ($line_item->children() as $child_line_item) {
73
-                    // recursively feed children back into this method
70
+			case EEM_Line_Item::type_tax_sub_total:
71
+				// loop thru children
72
+				foreach ($line_item->children() as $child_line_item) {
73
+					// recursively feed children back into this method
74 74
 //                  $html .= $this->display_line_item( $child_line_item, $options );
75
-                }
75
+				}
76 76
 //              $html .= $this->_total_row( $line_item, esc_html__('Tax Total', 'event_espresso'), $options );
77
-                break;
77
+				break;
78 78
 
79 79
 
80
-            case EEM_Line_Item::type_line_item:
81
-                // item row
80
+			case EEM_Line_Item::type_line_item:
81
+				// item row
82 82
 //              $html .= $this->_item_row( $line_item, $options );
83
-                // got any kids?
84
-                foreach ($line_item->children() as $child_line_item) {
83
+				// got any kids?
84
+				foreach ($line_item->children() as $child_line_item) {
85 85
 //                  $this->display_line_item( $child_line_item, $options );
86
-                }
87
-                break;
86
+				}
87
+				break;
88 88
 
89 89
 
90
-            case EEM_Line_Item::type_sub_line_item:
90
+			case EEM_Line_Item::type_sub_line_item:
91 91
 //              $html .= $this->_sub_item_row( $line_item, $options );
92
-                break;
92
+				break;
93 93
 
94 94
 
95
-            case EEM_Line_Item::type_tax:
95
+			case EEM_Line_Item::type_tax:
96 96
 //              $html .= $this->_tax_row( $line_item, $options );
97
-                break;
98
-        }
97
+				break;
98
+		}
99 99
 
100
-        return $html;
101
-    }
100
+		return $html;
101
+	}
102 102
 }
Please login to merge, or discard this patch.
line_item_display/EE_Admin_Table_Line_Item_Display_Strategy.strategy.php 2 patches
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -118,7 +118,7 @@  discard block
 block discarded – undo
118 118
                 $html .= $this->_taxes_html;
119 119
                 $html .= $this->_total_row($line_item, $options);
120 120
                 if ($options['use_table_wrapper']) {
121
-                    $html = $this->_table_header($options) . $html . $this->_table_footer($options);
121
+                    $html = $this->_table_header($options).$html.$this->_table_footer($options);
122 122
                 }
123 123
                 break;
124 124
         }
@@ -157,7 +157,7 @@  discard block
 block discarded – undo
157 157
      */
158 158
     protected function _table_footer($options)
159 159
     {
160
-        return EEH_HTML::tbodyx() .  EEH_HTML::tablex();
160
+        return EEH_HTML::tbodyx().EEH_HTML::tablex();
161 161
     }
162 162
 
163 163
 
@@ -188,16 +188,16 @@  discard block
 block discarded – undo
188 188
 
189 189
 
190 190
         $name_html = $line_item_related_object instanceof EEI_Line_Item_Object ? $line_item_related_object->name() : $line_item->name();
191
-        $name_html = $name_link ? '<a href="' . $name_link . '">' . $name_html . '</a>' : $name_html;
191
+        $name_html = $name_link ? '<a href="'.$name_link.'">'.$name_html.'</a>' : $name_html;
192 192
         $name_html .= $line_item->is_taxable() ? ' *' : '';
193 193
         // maybe preface with icon?
194
-        $name_html = $line_item_related_object instanceof EEI_Has_Icon ? $line_item_related_object->get_icon() . $name_html : $name_html;
195
-        $name_html = '<span class="ee-line-item-name linked">' . $name_html . '</span><br>';
196
-        $name_html .=  sprintf(
194
+        $name_html = $line_item_related_object instanceof EEI_Has_Icon ? $line_item_related_object->get_icon().$name_html : $name_html;
195
+        $name_html = '<span class="ee-line-item-name linked">'.$name_html.'</span><br>';
196
+        $name_html .= sprintf(
197 197
             _x('%1$sfor the %2$s: %3$s%4$s', 'eg. "for the Event: My Cool Event"', 'event_espresso'),
198 198
             '<span class="ee-line-item-related-parent-object">',
199 199
             $line_item->parent() instanceof EE_Line_Item ? $line_item->parent()->OBJ_type_i18n() : esc_html__('Item:', 'event_espresso'),
200
-            $parent_related_object_link ? '<a href="' . $parent_related_object_link . '">' . $parent_related_object_name . '</a>' : $parent_related_object_name,
200
+            $parent_related_object_link ? '<a href="'.$parent_related_object_link.'">'.$parent_related_object_name.'</a>' : $parent_related_object_name,
201 201
             '</span>'
202 202
         );
203 203
 
@@ -214,13 +214,13 @@  discard block
 block discarded – undo
214 214
         $type_html .= $this->_get_cancellations($line_item);
215 215
         $type_html .= $line_item->OBJ_type() ? '<br />' : '';
216 216
         $code = $line_item_related_object instanceof EEI_Has_Code ? $line_item_related_object->code() : '';
217
-        $type_html .= ! empty($code) ? '<span class="ee-line-item-id">' . sprintf(esc_html__('Code: %s', 'event_espresso'), $code) . '</span>' : '';
217
+        $type_html .= ! empty($code) ? '<span class="ee-line-item-id">'.sprintf(esc_html__('Code: %s', 'event_espresso'), $code).'</span>' : '';
218 218
         $html .= EEH_HTML::td($type_html, '', 'jst-left');
219 219
 
220 220
 
221 221
         // Amount Column
222 222
         if ($line_item->is_percent()) {
223
-            $html .= EEH_HTML::td($line_item->percent() . '%', '', 'jst-rght');
223
+            $html .= EEH_HTML::td($line_item->percent().'%', '', 'jst-rght');
224 224
         } else {
225 225
             $html .= EEH_HTML::td($line_item->unit_price_no_code(), '', 'jst-rght');
226 226
         }
@@ -295,7 +295,7 @@  discard block
 block discarded – undo
295 295
         // start of row
296 296
         $html = EEH_HTML::tr('', 'admin-primary-mbox-taxes-tr');
297 297
         // name th
298
-        $html .= EEH_HTML::th($line_item->name() . '(' . $line_item->get_pretty('LIN_percent') . '%)', '', 'jst-rght', '', ' colspan="4"');
298
+        $html .= EEH_HTML::th($line_item->name().'('.$line_item->get_pretty('LIN_percent').'%)', '', 'jst-rght', '', ' colspan="4"');
299 299
         // total th
300 300
         $html .= EEH_HTML::th(EEH_Template::format_currency($line_item->total(), false, false), '', 'jst-rght');
301 301
         // end of row
@@ -334,7 +334,7 @@  discard block
 block discarded – undo
334 334
         // start of row
335 335
         $html = EEH_HTML::tr('', '', 'admin-primary-mbox-total-tr');
336 336
         // Total th label
337
-        $total_label = sprintf(esc_html__('Transaction Total %s', 'event_espresso'), '(' . EE_Registry::instance()->CFG->currency->code . ')');
337
+        $total_label = sprintf(esc_html__('Transaction Total %s', 'event_espresso'), '('.EE_Registry::instance()->CFG->currency->code.')');
338 338
         $html .= EEH_HTML::th($total_label, '', 'jst-rght', '', ' colspan="4"');
339 339
         // total th
340 340
 
Please login to merge, or discard this patch.
Indentation   +328 added lines, -328 removed lines patch added patch discarded remove patch
@@ -13,332 +13,332 @@
 block discarded – undo
13 13
 
14 14
 class EE_Admin_Table_Line_Item_Display_Strategy implements EEI_Line_Item_Display
15 15
 {
16
-    /**
17
-     * whether to display the taxes row or not
18
-     * @type bool $_show_taxes
19
-     */
20
-    protected $_show_taxes = false;
21
-
22
-    /**
23
-     * html for any tax rows
24
-     * @type string $_show_taxes
25
-     */
26
-    protected $_taxes_html = '';
27
-
28
-
29
-    /**
30
-     * total amount including tax we can bill for at this time
31
-     * @type float $_grand_total
32
-     */
33
-    protected $_grand_total = 0.00;
34
-
35
-
36
-
37
-    /**
38
-     * @return float
39
-     */
40
-    public function grand_total()
41
-    {
42
-        return $this->_grand_total;
43
-    }
44
-
45
-
46
-
47
-    /**
48
-     * This is used to output a single
49
-     * @param EE_Line_Item $line_item
50
-     * @param array        $options
51
-     * @return mixed
52
-     */
53
-    public function display_line_item(EE_Line_Item $line_item, $options = array())
54
-    {
55
-
56
-        $html = '';
57
-        // set some default options and merge with incoming
58
-        $default_options = array(
59
-            'odd' => true,
60
-            'use_table_wrapper' => true,
61
-            'table_css_class' => 'admin-primary-mbox-tbl',
62
-            'taxes_tr_css_class' => 'admin-primary-mbox-taxes-tr',
63
-            'total_tr_css_class' => 'admin-primary-mbox-total-tr'
64
-        );
65
-        $options = array_merge($default_options, (array) $options);
66
-
67
-        switch ($line_item->type()) {
68
-            case EEM_Line_Item::type_line_item:
69
-                // item row
70
-                $html .= $this->_item_row($line_item, $options);
71
-                break;
72
-
73
-            case EEM_Line_Item::type_sub_line_item:
74
-                $html .= $this->_sub_item_row($line_item, $options);
75
-                break;
76
-
77
-            case EEM_Line_Item::type_sub_total:
78
-                if ($line_item->quantity() === 0) {
79
-                    return $html;
80
-                }
81
-                // loop through children
82
-                $child_line_items = $line_item->children();
83
-                // loop through children
84
-                foreach ($child_line_items as $child_line_item) {
85
-                    // recursively feed children back into this method
86
-                    $html .= $this->display_line_item($child_line_item, $options);
87
-                }
88
-                $html .= $this->_sub_total_row($line_item, $options);
89
-                break;
90
-
91
-            case EEM_Line_Item::type_tax:
92
-                if ($this->_show_taxes) {
93
-                    $this->_taxes_html .= $this->_tax_row($line_item, $options);
94
-                }
95
-                break;
96
-
97
-            case EEM_Line_Item::type_tax_sub_total:
98
-                foreach ($line_item->children() as $child_line_item) {
99
-                    if ($child_line_item->type() == EEM_Line_Item::type_tax) {
100
-                        $this->display_line_item($child_line_item, $options);
101
-                    }
102
-                }
103
-                break;
104
-
105
-            case EEM_Line_Item::type_total:
106
-                // determine whether to display taxes or not
107
-                $this->_show_taxes = $line_item->get_total_tax() > 0 ? true : false;
108
-                // get all child line items
109
-                $children = $line_item->children();
110
-
111
-                // loop thru all non-tax child line items
112
-                foreach ($children as $child_line_item) {
113
-                        $html .= $this->display_line_item($child_line_item, $options);
114
-                }
115
-
116
-                $html .= $this->_taxes_html;
117
-                $html .= $this->_total_row($line_item, $options);
118
-                if ($options['use_table_wrapper']) {
119
-                    $html = $this->_table_header($options) . $html . $this->_table_footer($options);
120
-                }
121
-                break;
122
-        }
123
-
124
-        return $html;
125
-    }
126
-
127
-
128
-
129
-    /**
130
-     * Table header for display.
131
-     * @since   4.8
132
-     * @param array $options
133
-     * @return string
134
-     */
135
-    protected function _table_header($options)
136
-    {
137
-        $html = EEH_HTML::table('', '', $options['table_css_class']);
138
-        $html .= EEH_HTML::thead();
139
-        $html .= EEH_HTML::tr();
140
-        $html .= EEH_HTML::th(esc_html__('Name', 'event_espresso'), '', 'jst-left');
141
-        $html .= EEH_HTML::th(esc_html__('Type', 'event_espresso'), '', 'jst-left');
142
-        $html .= EEH_HTML::th(esc_html__('Amount', 'event_espresso'), '', 'jst-cntr');
143
-        $html .= EEH_HTML::th(esc_html__('Qty', 'event_espresso'), '', 'jst-cntr');
144
-        $html .= EEH_HTML::th(esc_html__('Line Total', 'event_espresso'), '', 'jst-cntr');
145
-        $html .= EEH_HTML::tbody();
146
-        return $html;
147
-    }
148
-
149
-
150
-    /**
151
-     * Table footer for display
152
-     * @since 4.8
153
-     * @param array $options array of options for the table.
154
-     * @return string
155
-     */
156
-    protected function _table_footer($options)
157
-    {
158
-        return EEH_HTML::tbodyx() .  EEH_HTML::tablex();
159
-    }
160
-
161
-
162
-
163
-    /**
164
-     *    _item_row
165
-     *
166
-     * @param EE_Line_Item $line_item
167
-     * @param array        $options
168
-     * @return mixed
169
-     */
170
-    protected function _item_row(EE_Line_Item $line_item, $options = array())
171
-    {
172
-        $line_item_related_object = $line_item->get_object();
173
-        $parent_line_item_related_object = $line_item->parent() instanceof EE_Line_Item ? $line_item->parent()->get_object() : null;
174
-        // start of row
175
-        $row_class = $options['odd'] ? 'item odd' : 'item';
176
-        $html = EEH_HTML::tr('', '', $row_class);
177
-
178
-
179
-        // Name Column
180
-        $name_link = $line_item_related_object instanceof EEI_Admin_Links ? $line_item_related_object->get_admin_details_link() : '';
181
-
182
-        // related object scope.
183
-        $parent_related_object_name = $parent_line_item_related_object instanceof EEI_Line_Item_Object ? $parent_line_item_related_object->name() : '';
184
-        $parent_related_object_name = empty($parent_related_object_name) && $line_item->parent() instanceof EE_Line_Item ? $line_item->parent()->name() : $parent_related_object_name;
185
-        $parent_related_object_link = $parent_line_item_related_object instanceof EEI_Admin_Links ? $parent_line_item_related_object->get_admin_details_link() : '';
186
-
187
-
188
-        $name_html = $line_item_related_object instanceof EEI_Line_Item_Object ? $line_item_related_object->name() : $line_item->name();
189
-        $name_html = $name_link ? '<a href="' . $name_link . '">' . $name_html . '</a>' : $name_html;
190
-        $name_html .= $line_item->is_taxable() ? ' *' : '';
191
-        // maybe preface with icon?
192
-        $name_html = $line_item_related_object instanceof EEI_Has_Icon ? $line_item_related_object->get_icon() . $name_html : $name_html;
193
-        $name_html = '<span class="ee-line-item-name linked">' . $name_html . '</span><br>';
194
-        $name_html .=  sprintf(
195
-            _x('%1$sfor the %2$s: %3$s%4$s', 'eg. "for the Event: My Cool Event"', 'event_espresso'),
196
-            '<span class="ee-line-item-related-parent-object">',
197
-            $line_item->parent() instanceof EE_Line_Item ? $line_item->parent()->OBJ_type_i18n() : esc_html__('Item:', 'event_espresso'),
198
-            $parent_related_object_link ? '<a href="' . $parent_related_object_link . '">' . $parent_related_object_name . '</a>' : $parent_related_object_name,
199
-            '</span>'
200
-        );
201
-
202
-        $name_html = apply_filters(
203
-            'FHEE__EE_Admin_Table_Line_Item_Display_Strategy___item_row__name_html',
204
-            $name_html,
205
-            $line_item,
206
-            $options
207
-        );
208
-
209
-        $html .= EEH_HTML::td($name_html, '', 'jst-left');
210
-        // Type Column
211
-        $type_html = $line_item->OBJ_type() ? $line_item->OBJ_type_i18n() : '';
212
-        $type_html .= $this->_get_cancellations($line_item);
213
-        $type_html .= $line_item->OBJ_type() ? '<br />' : '';
214
-        $code = $line_item_related_object instanceof EEI_Has_Code ? $line_item_related_object->code() : '';
215
-        $type_html .= ! empty($code) ? '<span class="ee-line-item-id">' . sprintf(esc_html__('Code: %s', 'event_espresso'), $code) . '</span>' : '';
216
-        $html .= EEH_HTML::td($type_html, '', 'jst-left');
217
-
218
-
219
-        // Amount Column
220
-        if ($line_item->is_percent()) {
221
-            $html .= EEH_HTML::td($line_item->percent() . '%', '', 'jst-rght');
222
-        } else {
223
-            $html .= EEH_HTML::td($line_item->unit_price_no_code(), '', 'jst-rght');
224
-        }
225
-
226
-        // QTY column
227
-        $html .= EEH_HTML::td($line_item->quantity(), '', 'jst-rght');
228
-
229
-        // total column
230
-        $html .= EEH_HTML::td(EEH_Template::format_currency($line_item->total(), false, false), '', 'jst-rght');
231
-
232
-        // finish things off and return
233
-        $html .= EEH_HTML::trx();
234
-        return $html;
235
-    }
236
-
237
-
238
-
239
-    /**
240
-     *    _get_cancellations
241
-     *
242
-     * @param EE_Line_Item $line_item
243
-     * @return string
244
-     */
245
-    protected function _get_cancellations(EE_Line_Item $line_item)
246
-    {
247
-        $html = '';
248
-        $cancellations = $line_item->get_cancellations();
249
-        $cancellation = reset($cancellations);
250
-        // \EEH_Debug_Tools::printr( $cancellation, '$cancellation', __FILE__, __LINE__ );
251
-        if ($cancellation instanceof EE_Line_Item) {
252
-            $html .= ' <span class="ee-line-item-id">';
253
-            $html .= sprintf(
254
-                _n(
255
-                    '(%1$s Cancellation)',
256
-                    '(%1$s Cancellations)',
257
-                    $cancellation->quantity(),
258
-                    'event_espresso'
259
-                ),
260
-                $cancellation->quantity()
261
-            );
262
-            $html .= '</span>';
263
-        }
264
-        return $html;
265
-    }
266
-
267
-
268
-
269
-    /**
270
-     *  _sub_item_row
271
-     *
272
-     * @param EE_Line_Item $line_item
273
-     * @param array        $options
274
-     * @return mixed
275
-     */
276
-    protected function _sub_item_row(EE_Line_Item $line_item, $options = array())
277
-    {
278
-        // for now we're not showing sub-items
279
-        return '';
280
-    }
281
-
282
-
283
-
284
-    /**
285
-     *  _tax_row
286
-     *
287
-     * @param EE_Line_Item $line_item
288
-     * @param array        $options
289
-     * @return mixed
290
-     */
291
-    protected function _tax_row(EE_Line_Item $line_item, $options = array())
292
-    {
293
-        // start of row
294
-        $html = EEH_HTML::tr('', 'admin-primary-mbox-taxes-tr');
295
-        // name th
296
-        $html .= EEH_HTML::th($line_item->name() . '(' . $line_item->get_pretty('LIN_percent') . '%)', '', 'jst-rght', '', ' colspan="4"');
297
-        // total th
298
-        $html .= EEH_HTML::th(EEH_Template::format_currency($line_item->total(), false, false), '', 'jst-rght');
299
-        // end of row
300
-        $html .= EEH_HTML::trx();
301
-        return $html;
302
-    }
303
-
304
-
305
-
306
-
307
-    /**
308
-     *  _total_row
309
-     *
310
-     * @param EE_Line_Item $line_item
311
-     * @param string       $text
312
-     * @param array        $options
313
-     * @return mixed
314
-     */
315
-    protected function _sub_total_row(EE_Line_Item $line_item, $text = '', $options = array())
316
-    {
317
-        // currently not showing subtotal row
318
-        return '';
319
-    }
320
-
321
-
322
-
323
-    /**
324
-     *  _total_row
325
-     *
326
-     * @param EE_Line_Item $line_item
327
-     * @param array        $options
328
-     * @return mixed
329
-     */
330
-    protected function _total_row(EE_Line_Item $line_item, $options = array())
331
-    {
332
-        // start of row
333
-        $html = EEH_HTML::tr('', '', 'admin-primary-mbox-total-tr');
334
-        // Total th label
335
-        $total_label = sprintf(esc_html__('Transaction Total %s', 'event_espresso'), '(' . EE_Registry::instance()->CFG->currency->code . ')');
336
-        $html .= EEH_HTML::th($total_label, '', 'jst-rght', '', ' colspan="4"');
337
-        // total th
338
-
339
-        $html .= EEH_HTML::th(EEH_Template::format_currency($line_item->total(), false, false), '', 'jst-rght');
340
-        // end of row
341
-        $html .= EEH_HTML::trx();
342
-        return $html;
343
-    }
16
+	/**
17
+	 * whether to display the taxes row or not
18
+	 * @type bool $_show_taxes
19
+	 */
20
+	protected $_show_taxes = false;
21
+
22
+	/**
23
+	 * html for any tax rows
24
+	 * @type string $_show_taxes
25
+	 */
26
+	protected $_taxes_html = '';
27
+
28
+
29
+	/**
30
+	 * total amount including tax we can bill for at this time
31
+	 * @type float $_grand_total
32
+	 */
33
+	protected $_grand_total = 0.00;
34
+
35
+
36
+
37
+	/**
38
+	 * @return float
39
+	 */
40
+	public function grand_total()
41
+	{
42
+		return $this->_grand_total;
43
+	}
44
+
45
+
46
+
47
+	/**
48
+	 * This is used to output a single
49
+	 * @param EE_Line_Item $line_item
50
+	 * @param array        $options
51
+	 * @return mixed
52
+	 */
53
+	public function display_line_item(EE_Line_Item $line_item, $options = array())
54
+	{
55
+
56
+		$html = '';
57
+		// set some default options and merge with incoming
58
+		$default_options = array(
59
+			'odd' => true,
60
+			'use_table_wrapper' => true,
61
+			'table_css_class' => 'admin-primary-mbox-tbl',
62
+			'taxes_tr_css_class' => 'admin-primary-mbox-taxes-tr',
63
+			'total_tr_css_class' => 'admin-primary-mbox-total-tr'
64
+		);
65
+		$options = array_merge($default_options, (array) $options);
66
+
67
+		switch ($line_item->type()) {
68
+			case EEM_Line_Item::type_line_item:
69
+				// item row
70
+				$html .= $this->_item_row($line_item, $options);
71
+				break;
72
+
73
+			case EEM_Line_Item::type_sub_line_item:
74
+				$html .= $this->_sub_item_row($line_item, $options);
75
+				break;
76
+
77
+			case EEM_Line_Item::type_sub_total:
78
+				if ($line_item->quantity() === 0) {
79
+					return $html;
80
+				}
81
+				// loop through children
82
+				$child_line_items = $line_item->children();
83
+				// loop through children
84
+				foreach ($child_line_items as $child_line_item) {
85
+					// recursively feed children back into this method
86
+					$html .= $this->display_line_item($child_line_item, $options);
87
+				}
88
+				$html .= $this->_sub_total_row($line_item, $options);
89
+				break;
90
+
91
+			case EEM_Line_Item::type_tax:
92
+				if ($this->_show_taxes) {
93
+					$this->_taxes_html .= $this->_tax_row($line_item, $options);
94
+				}
95
+				break;
96
+
97
+			case EEM_Line_Item::type_tax_sub_total:
98
+				foreach ($line_item->children() as $child_line_item) {
99
+					if ($child_line_item->type() == EEM_Line_Item::type_tax) {
100
+						$this->display_line_item($child_line_item, $options);
101
+					}
102
+				}
103
+				break;
104
+
105
+			case EEM_Line_Item::type_total:
106
+				// determine whether to display taxes or not
107
+				$this->_show_taxes = $line_item->get_total_tax() > 0 ? true : false;
108
+				// get all child line items
109
+				$children = $line_item->children();
110
+
111
+				// loop thru all non-tax child line items
112
+				foreach ($children as $child_line_item) {
113
+						$html .= $this->display_line_item($child_line_item, $options);
114
+				}
115
+
116
+				$html .= $this->_taxes_html;
117
+				$html .= $this->_total_row($line_item, $options);
118
+				if ($options['use_table_wrapper']) {
119
+					$html = $this->_table_header($options) . $html . $this->_table_footer($options);
120
+				}
121
+				break;
122
+		}
123
+
124
+		return $html;
125
+	}
126
+
127
+
128
+
129
+	/**
130
+	 * Table header for display.
131
+	 * @since   4.8
132
+	 * @param array $options
133
+	 * @return string
134
+	 */
135
+	protected function _table_header($options)
136
+	{
137
+		$html = EEH_HTML::table('', '', $options['table_css_class']);
138
+		$html .= EEH_HTML::thead();
139
+		$html .= EEH_HTML::tr();
140
+		$html .= EEH_HTML::th(esc_html__('Name', 'event_espresso'), '', 'jst-left');
141
+		$html .= EEH_HTML::th(esc_html__('Type', 'event_espresso'), '', 'jst-left');
142
+		$html .= EEH_HTML::th(esc_html__('Amount', 'event_espresso'), '', 'jst-cntr');
143
+		$html .= EEH_HTML::th(esc_html__('Qty', 'event_espresso'), '', 'jst-cntr');
144
+		$html .= EEH_HTML::th(esc_html__('Line Total', 'event_espresso'), '', 'jst-cntr');
145
+		$html .= EEH_HTML::tbody();
146
+		return $html;
147
+	}
148
+
149
+
150
+	/**
151
+	 * Table footer for display
152
+	 * @since 4.8
153
+	 * @param array $options array of options for the table.
154
+	 * @return string
155
+	 */
156
+	protected function _table_footer($options)
157
+	{
158
+		return EEH_HTML::tbodyx() .  EEH_HTML::tablex();
159
+	}
160
+
161
+
162
+
163
+	/**
164
+	 *    _item_row
165
+	 *
166
+	 * @param EE_Line_Item $line_item
167
+	 * @param array        $options
168
+	 * @return mixed
169
+	 */
170
+	protected function _item_row(EE_Line_Item $line_item, $options = array())
171
+	{
172
+		$line_item_related_object = $line_item->get_object();
173
+		$parent_line_item_related_object = $line_item->parent() instanceof EE_Line_Item ? $line_item->parent()->get_object() : null;
174
+		// start of row
175
+		$row_class = $options['odd'] ? 'item odd' : 'item';
176
+		$html = EEH_HTML::tr('', '', $row_class);
177
+
178
+
179
+		// Name Column
180
+		$name_link = $line_item_related_object instanceof EEI_Admin_Links ? $line_item_related_object->get_admin_details_link() : '';
181
+
182
+		// related object scope.
183
+		$parent_related_object_name = $parent_line_item_related_object instanceof EEI_Line_Item_Object ? $parent_line_item_related_object->name() : '';
184
+		$parent_related_object_name = empty($parent_related_object_name) && $line_item->parent() instanceof EE_Line_Item ? $line_item->parent()->name() : $parent_related_object_name;
185
+		$parent_related_object_link = $parent_line_item_related_object instanceof EEI_Admin_Links ? $parent_line_item_related_object->get_admin_details_link() : '';
186
+
187
+
188
+		$name_html = $line_item_related_object instanceof EEI_Line_Item_Object ? $line_item_related_object->name() : $line_item->name();
189
+		$name_html = $name_link ? '<a href="' . $name_link . '">' . $name_html . '</a>' : $name_html;
190
+		$name_html .= $line_item->is_taxable() ? ' *' : '';
191
+		// maybe preface with icon?
192
+		$name_html = $line_item_related_object instanceof EEI_Has_Icon ? $line_item_related_object->get_icon() . $name_html : $name_html;
193
+		$name_html = '<span class="ee-line-item-name linked">' . $name_html . '</span><br>';
194
+		$name_html .=  sprintf(
195
+			_x('%1$sfor the %2$s: %3$s%4$s', 'eg. "for the Event: My Cool Event"', 'event_espresso'),
196
+			'<span class="ee-line-item-related-parent-object">',
197
+			$line_item->parent() instanceof EE_Line_Item ? $line_item->parent()->OBJ_type_i18n() : esc_html__('Item:', 'event_espresso'),
198
+			$parent_related_object_link ? '<a href="' . $parent_related_object_link . '">' . $parent_related_object_name . '</a>' : $parent_related_object_name,
199
+			'</span>'
200
+		);
201
+
202
+		$name_html = apply_filters(
203
+			'FHEE__EE_Admin_Table_Line_Item_Display_Strategy___item_row__name_html',
204
+			$name_html,
205
+			$line_item,
206
+			$options
207
+		);
208
+
209
+		$html .= EEH_HTML::td($name_html, '', 'jst-left');
210
+		// Type Column
211
+		$type_html = $line_item->OBJ_type() ? $line_item->OBJ_type_i18n() : '';
212
+		$type_html .= $this->_get_cancellations($line_item);
213
+		$type_html .= $line_item->OBJ_type() ? '<br />' : '';
214
+		$code = $line_item_related_object instanceof EEI_Has_Code ? $line_item_related_object->code() : '';
215
+		$type_html .= ! empty($code) ? '<span class="ee-line-item-id">' . sprintf(esc_html__('Code: %s', 'event_espresso'), $code) . '</span>' : '';
216
+		$html .= EEH_HTML::td($type_html, '', 'jst-left');
217
+
218
+
219
+		// Amount Column
220
+		if ($line_item->is_percent()) {
221
+			$html .= EEH_HTML::td($line_item->percent() . '%', '', 'jst-rght');
222
+		} else {
223
+			$html .= EEH_HTML::td($line_item->unit_price_no_code(), '', 'jst-rght');
224
+		}
225
+
226
+		// QTY column
227
+		$html .= EEH_HTML::td($line_item->quantity(), '', 'jst-rght');
228
+
229
+		// total column
230
+		$html .= EEH_HTML::td(EEH_Template::format_currency($line_item->total(), false, false), '', 'jst-rght');
231
+
232
+		// finish things off and return
233
+		$html .= EEH_HTML::trx();
234
+		return $html;
235
+	}
236
+
237
+
238
+
239
+	/**
240
+	 *    _get_cancellations
241
+	 *
242
+	 * @param EE_Line_Item $line_item
243
+	 * @return string
244
+	 */
245
+	protected function _get_cancellations(EE_Line_Item $line_item)
246
+	{
247
+		$html = '';
248
+		$cancellations = $line_item->get_cancellations();
249
+		$cancellation = reset($cancellations);
250
+		// \EEH_Debug_Tools::printr( $cancellation, '$cancellation', __FILE__, __LINE__ );
251
+		if ($cancellation instanceof EE_Line_Item) {
252
+			$html .= ' <span class="ee-line-item-id">';
253
+			$html .= sprintf(
254
+				_n(
255
+					'(%1$s Cancellation)',
256
+					'(%1$s Cancellations)',
257
+					$cancellation->quantity(),
258
+					'event_espresso'
259
+				),
260
+				$cancellation->quantity()
261
+			);
262
+			$html .= '</span>';
263
+		}
264
+		return $html;
265
+	}
266
+
267
+
268
+
269
+	/**
270
+	 *  _sub_item_row
271
+	 *
272
+	 * @param EE_Line_Item $line_item
273
+	 * @param array        $options
274
+	 * @return mixed
275
+	 */
276
+	protected function _sub_item_row(EE_Line_Item $line_item, $options = array())
277
+	{
278
+		// for now we're not showing sub-items
279
+		return '';
280
+	}
281
+
282
+
283
+
284
+	/**
285
+	 *  _tax_row
286
+	 *
287
+	 * @param EE_Line_Item $line_item
288
+	 * @param array        $options
289
+	 * @return mixed
290
+	 */
291
+	protected function _tax_row(EE_Line_Item $line_item, $options = array())
292
+	{
293
+		// start of row
294
+		$html = EEH_HTML::tr('', 'admin-primary-mbox-taxes-tr');
295
+		// name th
296
+		$html .= EEH_HTML::th($line_item->name() . '(' . $line_item->get_pretty('LIN_percent') . '%)', '', 'jst-rght', '', ' colspan="4"');
297
+		// total th
298
+		$html .= EEH_HTML::th(EEH_Template::format_currency($line_item->total(), false, false), '', 'jst-rght');
299
+		// end of row
300
+		$html .= EEH_HTML::trx();
301
+		return $html;
302
+	}
303
+
304
+
305
+
306
+
307
+	/**
308
+	 *  _total_row
309
+	 *
310
+	 * @param EE_Line_Item $line_item
311
+	 * @param string       $text
312
+	 * @param array        $options
313
+	 * @return mixed
314
+	 */
315
+	protected function _sub_total_row(EE_Line_Item $line_item, $text = '', $options = array())
316
+	{
317
+		// currently not showing subtotal row
318
+		return '';
319
+	}
320
+
321
+
322
+
323
+	/**
324
+	 *  _total_row
325
+	 *
326
+	 * @param EE_Line_Item $line_item
327
+	 * @param array        $options
328
+	 * @return mixed
329
+	 */
330
+	protected function _total_row(EE_Line_Item $line_item, $options = array())
331
+	{
332
+		// start of row
333
+		$html = EEH_HTML::tr('', '', 'admin-primary-mbox-total-tr');
334
+		// Total th label
335
+		$total_label = sprintf(esc_html__('Transaction Total %s', 'event_espresso'), '(' . EE_Registry::instance()->CFG->currency->code . ')');
336
+		$html .= EEH_HTML::th($total_label, '', 'jst-rght', '', ' colspan="4"');
337
+		// total th
338
+
339
+		$html .= EEH_HTML::th(EEH_Template::format_currency($line_item->total(), false, false), '', 'jst-rght');
340
+		// end of row
341
+		$html .= EEH_HTML::trx();
342
+		return $html;
343
+	}
344 344
 }
Please login to merge, or discard this patch.