Completed
Branch FET/event-question-group-refac... (19fbf8)
by
unknown
09:05 queued 20s
created
core/domain/services/event/EventSpacesCalculator.php 1 patch
Indentation   +711 added lines, -711 removed lines patch added patch discarded remove patch
@@ -26,715 +26,715 @@
 block discarded – undo
26 26
 class EventSpacesCalculator
27 27
 {
28 28
 
29
-    /**
30
-     * @var EE_Event $event
31
-     */
32
-    private $event;
33
-
34
-    /**
35
-     * @var array $datetime_query_params
36
-     */
37
-    private $datetime_query_params;
38
-
39
-    /**
40
-     * @var EE_Ticket[] $active_tickets
41
-     */
42
-    private $active_tickets = array();
43
-
44
-    /**
45
-     * @var EE_Datetime[] $datetimes
46
-     */
47
-    private $datetimes = array();
48
-
49
-    /**
50
-     * Array of Ticket IDs grouped by Datetime
51
-     *
52
-     * @var array $datetimes
53
-     */
54
-    private $datetime_tickets = array();
55
-
56
-    /**
57
-     * Max spaces for each Datetime (reg limit - previous sold)
58
-     *
59
-     * @var array $datetime_spaces
60
-     */
61
-    private $datetime_spaces = array();
62
-
63
-    /**
64
-     * Array of Datetime IDs grouped by Ticket
65
-     *
66
-     * @var array[] $ticket_datetimes
67
-     */
68
-    private $ticket_datetimes = array();
69
-
70
-    /**
71
-     * maximum ticket quantities for each ticket (adjusted for reg limit)
72
-     *
73
-     * @var array $ticket_quantities
74
-     */
75
-    private $ticket_quantities = array();
76
-
77
-    /**
78
-     * total quantity of sold and reserved for each ticket
79
-     *
80
-     * @var array $tickets_sold
81
-     */
82
-    private $tickets_sold = array();
83
-
84
-    /**
85
-     * total spaces available across all datetimes
86
-     *
87
-     * @var array $total_spaces
88
-     */
89
-    private $total_spaces = array();
90
-
91
-    /**
92
-     * @var boolean $debug
93
-     */
94
-    private $debug = false; // true false
95
-
96
-    /**
97
-     * @var null|int $spaces_remaining
98
-     */
99
-    private $spaces_remaining;
100
-
101
-    /**
102
-     * @var null|int $total_spaces_available
103
-     */
104
-    private $total_spaces_available;
105
-
106
-
107
-    /**
108
-     * EventSpacesCalculator constructor.
109
-     *
110
-     * @param EE_Event $event
111
-     * @param array    $datetime_query_params
112
-     * @throws EE_Error
113
-     */
114
-    public function __construct(EE_Event $event, array $datetime_query_params = array())
115
-    {
116
-        if ($this->debug) {
117
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 1);
118
-            \EEH_Debug_Tools::printr((string) $event->ID(), 'For event', __FILE__, __LINE__);
119
-        }
120
-        $this->event = $event;
121
-        $this->datetime_query_params = $datetime_query_params + array('order_by' => array('DTT_reg_limit' => 'ASC'));
122
-        $this->setHooks();
123
-    }
124
-
125
-
126
-    /**
127
-     * @return void
128
-     */
129
-    private function setHooks()
130
-    {
131
-        add_action('AHEE__EE_Ticket__increase_sold', array($this, 'clearResults'));
132
-        add_action('AHEE__EE_Ticket__decrease_sold', array($this, 'clearResults'));
133
-        add_action('AHEE__EE_Datetime__increase_sold', array($this, 'clearResults'));
134
-        add_action('AHEE__EE_Datetime__decrease_sold', array($this, 'clearResults'));
135
-        add_action('AHEE__EE_Ticket__increase_reserved', array($this, 'clearResults'));
136
-        add_action('AHEE__EE_Ticket__decrease_reserved', array($this, 'clearResults'));
137
-        add_action('AHEE__EE_Datetime__increase_reserved', array($this, 'clearResults'));
138
-        add_action('AHEE__EE_Datetime__decrease_reserved', array($this, 'clearResults'));
139
-    }
140
-
141
-
142
-    /**
143
-     * @return void
144
-     */
145
-    public function clearResults()
146
-    {
147
-        if ($this->debug) {
148
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 1);
149
-        }
150
-        $this->spaces_remaining = null;
151
-        $this->total_spaces_available = null;
152
-    }
153
-
154
-
155
-    /**
156
-     * @return EE_Ticket[]
157
-     * @throws EE_Error
158
-     * @throws InvalidDataTypeException
159
-     * @throws InvalidInterfaceException
160
-     * @throws InvalidArgumentException
161
-     */
162
-    public function getActiveTickets()
163
-    {
164
-        if (empty($this->active_tickets)) {
165
-            $this->active_tickets = $this->event->tickets(
166
-                array(
167
-                    array('TKT_deleted' => false),
168
-                    'order_by' => array('TKT_qty' => 'ASC'),
169
-                )
170
-            );
171
-        }
172
-        return $this->active_tickets;
173
-    }
174
-
175
-
176
-    /**
177
-     * @param EE_Ticket[] $active_tickets
178
-     * @throws EE_Error
179
-     * @throws DomainException
180
-     * @throws UnexpectedEntityException
181
-     */
182
-    public function setActiveTickets(array $active_tickets = array())
183
-    {
184
-        if (! empty($active_tickets)) {
185
-            foreach ($active_tickets as $active_ticket) {
186
-                $this->validateTicket($active_ticket);
187
-            }
188
-            // sort incoming array by ticket quantity (asc)
189
-            usort(
190
-                $active_tickets,
191
-                function (EE_Ticket $a, EE_Ticket $b) {
192
-                    if ($a->qty() === $b->qty()) {
193
-                        return 0;
194
-                    }
195
-                    return ($a->qty() < $b->qty())
196
-                        ? -1
197
-                        : 1;
198
-                }
199
-            );
200
-        }
201
-        $this->active_tickets = $active_tickets;
202
-    }
203
-
204
-
205
-    /**
206
-     * @param $ticket
207
-     * @throws DomainException
208
-     * @throws EE_Error
209
-     * @throws UnexpectedEntityException
210
-     */
211
-    private function validateTicket($ticket)
212
-    {
213
-        if (! $ticket instanceof EE_Ticket) {
214
-            throw new DomainException(
215
-                esc_html__(
216
-                    'Invalid Ticket. Only EE_Ticket objects can be used to calculate event space availability.',
217
-                    'event_espresso'
218
-                )
219
-            );
220
-        }
221
-        if ($ticket->get_event_ID() !== $this->event->ID()) {
222
-            throw new DomainException(
223
-                sprintf(
224
-                    esc_html__(
225
-                        'An EE_Ticket for Event %1$d was supplied while calculating event space availability for Event %2$d.',
226
-                        'event_espresso'
227
-                    ),
228
-                    $ticket->get_event_ID(),
229
-                    $this->event->ID()
230
-                )
231
-            );
232
-        }
233
-    }
234
-
235
-
236
-    /**
237
-     * @return EE_Datetime[]
238
-     */
239
-    public function getDatetimes()
240
-    {
241
-        return $this->datetimes;
242
-    }
243
-
244
-
245
-    /**
246
-     * @param EE_Datetime $datetime
247
-     * @throws EE_Error
248
-     * @throws DomainException
249
-     */
250
-    public function setDatetime(EE_Datetime $datetime)
251
-    {
252
-        if ($datetime->event()->ID() !== $this->event->ID()) {
253
-            throw new DomainException(
254
-                sprintf(
255
-                    esc_html__(
256
-                        'An EE_Datetime for Event %1$d was supplied while calculating event space availability for Event %2$d.',
257
-                        'event_espresso'
258
-                    ),
259
-                    $datetime->event()->ID(),
260
-                    $this->event->ID()
261
-                )
262
-            );
263
-        }
264
-        $this->datetimes[ $datetime->ID() ] = $datetime;
265
-    }
266
-
267
-
268
-    /**
269
-     * calculate spaces remaining based on "saleable" tickets
270
-     *
271
-     * @return float|int
272
-     * @throws EE_Error
273
-     * @throws DomainException
274
-     * @throws UnexpectedEntityException
275
-     * @throws InvalidDataTypeException
276
-     * @throws InvalidInterfaceException
277
-     * @throws InvalidArgumentException
278
-     */
279
-    public function spacesRemaining()
280
-    {
281
-        if ($this->debug) {
282
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
283
-        }
284
-        if ($this->spaces_remaining === null) {
285
-            $this->initialize();
286
-            $this->spaces_remaining = $this->calculate();
287
-        }
288
-        return $this->spaces_remaining;
289
-    }
290
-
291
-
292
-    /**
293
-     * calculates total available spaces for an event with no regard for sold tickets
294
-     *
295
-     * @return int|float
296
-     * @throws EE_Error
297
-     * @throws DomainException
298
-     * @throws UnexpectedEntityException
299
-     * @throws InvalidDataTypeException
300
-     * @throws InvalidInterfaceException
301
-     * @throws InvalidArgumentException
302
-     */
303
-    public function totalSpacesAvailable()
304
-    {
305
-        if ($this->debug) {
306
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
307
-        }
308
-        if ($this->total_spaces_available === null) {
309
-            $this->initialize();
310
-            $this->total_spaces_available = $this->calculate(false);
311
-        }
312
-        return $this->total_spaces_available;
313
-    }
314
-
315
-
316
-    /**
317
-     * Loops through the active tickets for the event
318
-     * and builds a series of data arrays that will be used for calculating
319
-     * the total maximum available spaces, as well as the spaces remaining.
320
-     * Because ticket quantities affect datetime spaces and vice versa,
321
-     * we need to be constantly updating these data arrays as things change,
322
-     * which is the entire reason for their existence.
323
-     *
324
-     * @throws EE_Error
325
-     * @throws DomainException
326
-     * @throws UnexpectedEntityException
327
-     * @throws InvalidDataTypeException
328
-     * @throws InvalidInterfaceException
329
-     * @throws InvalidArgumentException
330
-     */
331
-    private function initialize()
332
-    {
333
-        if ($this->debug) {
334
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
335
-        }
336
-        $this->datetime_tickets = array();
337
-        $this->datetime_spaces = array();
338
-        $this->ticket_datetimes = array();
339
-        $this->ticket_quantities = array();
340
-        $this->tickets_sold = array();
341
-        $this->total_spaces = array();
342
-        $active_tickets = $this->getActiveTickets();
343
-        if (! empty($active_tickets)) {
344
-            foreach ($active_tickets as $ticket) {
345
-                $this->validateTicket($ticket);
346
-                // we need to index our data arrays using strings for the purpose of sorting,
347
-                // but we also need them to be unique, so  we'll just prepend a letter T to the ID
348
-                $ticket_identifier = "T{$ticket->ID()}";
349
-                // to start, we'll just consider the raw qty to be the maximum availability for this ticket,
350
-                // unless the ticket is past its "sell until" date, in which case the qty will be 0
351
-                $max_tickets = $ticket->is_expired() ? 0 : $ticket->qty();
352
-                // but we'll adjust that after looping over each datetime for the ticket and checking reg limits
353
-                $ticket_datetimes = $ticket->datetimes($this->datetime_query_params);
354
-                foreach ($ticket_datetimes as $datetime) {
355
-                    // save all datetimes
356
-                    $this->setDatetime($datetime);
357
-                    $datetime_identifier = "D{$datetime->ID()}";
358
-                    $reg_limit = $datetime->reg_limit();
359
-                    // ticket quantity can not exceed datetime reg limit
360
-                    $max_tickets = min($max_tickets, $reg_limit);
361
-                    // as described earlier, because we need to be able to constantly adjust numbers for things,
362
-                    // we are going to move all of our data into the following arrays:
363
-                    // datetime spaces initially represents the reg limit for each datetime,
364
-                    // but this will get adjusted as tickets are accounted for
365
-                    $this->datetime_spaces[ $datetime_identifier ] = $reg_limit;
366
-                    // just an array of ticket IDs grouped by datetime
367
-                    $this->datetime_tickets[ $datetime_identifier ][] = $ticket_identifier;
368
-                    // and an array of datetime IDs grouped by ticket
369
-                    $this->ticket_datetimes[ $ticket_identifier ][] = $datetime_identifier;
370
-                }
371
-                // total quantity of sold and reserved for each ticket
372
-                $this->tickets_sold[ $ticket_identifier ] = $ticket->sold() + $ticket->reserved();
373
-                // and the maximum ticket quantities for each ticket (adjusted for reg limit)
374
-                $this->ticket_quantities[ $ticket_identifier ] = $max_tickets;
375
-            }
376
-        }
377
-        // sort datetime spaces by reg limit, but maintain our string indexes
378
-        asort($this->datetime_spaces, SORT_NUMERIC);
379
-        // datetime tickets need to be sorted in the SAME order as the above array...
380
-        // so we'll just use array_merge() to take the structure of datetime_spaces
381
-        // but overwrite all of the data with that from datetime_tickets
382
-        $this->datetime_tickets = array_merge(
383
-            $this->datetime_spaces,
384
-            $this->datetime_tickets
385
-        );
386
-        if ($this->debug) {
387
-            \EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
388
-            \EEH_Debug_Tools::printr($this->datetime_tickets, 'datetime_tickets', __FILE__, __LINE__);
389
-            \EEH_Debug_Tools::printr($this->ticket_quantities, 'ticket_quantities', __FILE__, __LINE__);
390
-        }
391
-    }
392
-
393
-
394
-    /**
395
-     * performs calculations on initialized data
396
-     *
397
-     * @param bool $consider_sold
398
-     * @return int|float
399
-     */
400
-    private function calculate($consider_sold = true)
401
-    {
402
-        if ($this->debug) {
403
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
404
-            \EEH_Debug_Tools::printr($consider_sold, '$consider_sold', __FILE__, __LINE__);
405
-        }
406
-        if ($consider_sold) {
407
-            // subtract amounts sold from all ticket quantities and datetime spaces
408
-            $this->adjustTicketQuantitiesDueToSales();
409
-        }
410
-        foreach ($this->datetime_tickets as $datetime_identifier => $tickets) {
411
-            $this->trackAvailableSpacesForDatetimes($datetime_identifier, $tickets);
412
-        }
413
-        // total spaces available is just the sum of the spaces available for each datetime
414
-        $spaces_remaining = array_sum($this->total_spaces);
415
-        if ($this->debug) {
416
-            \EEH_Debug_Tools::printr($this->total_spaces, '$this->total_spaces', __FILE__, __LINE__);
417
-            \EEH_Debug_Tools::printr($this->tickets_sold, '$this->tickets_sold', __FILE__, __LINE__);
418
-            \EEH_Debug_Tools::printr($spaces_remaining, '$spaces_remaining', __FILE__, __LINE__);
419
-        }
420
-        return $spaces_remaining;
421
-    }
422
-
423
-
424
-    /**
425
-     * subtracts amount of  tickets sold from ticket quantities and datetime spaces
426
-     */
427
-    private function adjustTicketQuantitiesDueToSales()
428
-    {
429
-        if ($this->debug) {
430
-            \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
431
-        }
432
-        foreach ($this->tickets_sold as $ticket_identifier => $tickets_sold) {
433
-            if (isset($this->ticket_quantities[ $ticket_identifier ])) {
434
-                $this->ticket_quantities[ $ticket_identifier ] -= $tickets_sold;
435
-                // don't let values go below zero
436
-                $this->ticket_quantities[ $ticket_identifier ] = max(
437
-                    $this->ticket_quantities[ $ticket_identifier ],
438
-                    0
439
-                );
440
-                if ($this->debug) {
441
-                    \EEH_Debug_Tools::printr(
442
-                        "{$tickets_sold} sales for ticket {$ticket_identifier} ",
443
-                        'subtracting',
444
-                        __FILE__,
445
-                        __LINE__
446
-                    );
447
-                }
448
-            }
449
-            if (isset($this->ticket_datetimes[ $ticket_identifier ])
450
-                && is_array($this->ticket_datetimes[ $ticket_identifier ])
451
-            ) {
452
-                foreach ($this->ticket_datetimes[ $ticket_identifier ] as $ticket_datetime) {
453
-                    if (isset($this->ticket_quantities[ $ticket_identifier ])) {
454
-                        $this->datetime_spaces[ $ticket_datetime ] -= $tickets_sold;
455
-                        // don't let values go below zero
456
-                        $this->datetime_spaces[ $ticket_datetime ] = max(
457
-                            $this->datetime_spaces[ $ticket_datetime ],
458
-                            0
459
-                        );
460
-                        if ($this->debug) {
461
-                            \EEH_Debug_Tools::printr(
462
-                                "{$tickets_sold} sales for datetime {$ticket_datetime} ",
463
-                                'subtracting',
464
-                                __FILE__,
465
-                                __LINE__
466
-                            );
467
-                        }
468
-                    }
469
-                }
470
-            }
471
-        }
472
-    }
473
-
474
-
475
-    /**
476
-     * @param string $datetime_identifier
477
-     * @param array  $tickets
478
-     */
479
-    private function trackAvailableSpacesForDatetimes($datetime_identifier, array $tickets)
480
-    {
481
-        // make sure a reg limit is set for the datetime
482
-        $reg_limit = isset($this->datetime_spaces[ $datetime_identifier ])
483
-            ? $this->datetime_spaces[ $datetime_identifier ]
484
-            : 0;
485
-        // and bail if it is not
486
-        if (! $reg_limit) {
487
-            if ($this->debug) {
488
-                \EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__);
489
-            }
490
-            return;
491
-        }
492
-        if ($this->debug) {
493
-            \EEH_Debug_Tools::printr($datetime_identifier, '* $datetime_identifier', __FILE__, __LINE__, 1);
494
-            \EEH_Debug_Tools::printr(
495
-                "{$reg_limit}",
496
-                'REG LIMIT',
497
-                __FILE__,
498
-                __LINE__
499
-            );
500
-        }
501
-        // number of allocated spaces always starts at zero
502
-        $spaces_allocated = 0;
503
-        $this->total_spaces[ $datetime_identifier ] = 0;
504
-        foreach ($tickets as $ticket_identifier) {
505
-            $spaces_allocated = $this->calculateAvailableSpacesForTicket(
506
-                $datetime_identifier,
507
-                $reg_limit,
508
-                $ticket_identifier,
509
-                $spaces_allocated
510
-            );
511
-        }
512
-        // spaces can't be negative
513
-        $spaces_allocated = max($spaces_allocated, 0);
514
-        if ($spaces_allocated) {
515
-            // track any non-zero values
516
-            $this->total_spaces[ $datetime_identifier ] += $spaces_allocated;
517
-            if ($this->debug) {
518
-                \EEH_Debug_Tools::printr((string) $spaces_allocated, ' . $spaces_allocated: ', __FILE__, __LINE__);
519
-            }
520
-        } else {
521
-            if ($this->debug) {
522
-                \EEH_Debug_Tools::printr(' ', ' . NO TICKETS AVAILABLE FOR DATETIME', __FILE__, __LINE__);
523
-            }
524
-        }
525
-        if ($this->debug) {
526
-            \EEH_Debug_Tools::printr(
527
-                $this->total_spaces[ $datetime_identifier ],
528
-                '$total_spaces',
529
-                __FILE__,
530
-                __LINE__
531
-            );
532
-            \EEH_Debug_Tools::printr($this->ticket_quantities, '$ticket_quantities', __FILE__, __LINE__);
533
-            \EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
534
-        }
535
-    }
536
-
537
-
538
-    /**
539
-     * @param string $datetime_identifier
540
-     * @param int    $reg_limit
541
-     * @param string $ticket_identifier
542
-     * @param int    $spaces_allocated
543
-     * @return int
544
-     */
545
-    private function calculateAvailableSpacesForTicket(
546
-        $datetime_identifier,
547
-        $reg_limit,
548
-        $ticket_identifier,
549
-        $spaces_allocated
550
-    ) {
551
-        // make sure ticket quantity is set
552
-        $ticket_quantity = isset($this->ticket_quantities[ $ticket_identifier ])
553
-            ? $this->ticket_quantities[ $ticket_identifier ]
554
-            : 0;
555
-        if ($this->debug) {
556
-            \EEH_Debug_Tools::printr("{$spaces_allocated}", '$spaces_allocated', __FILE__, __LINE__);
557
-            \EEH_Debug_Tools::printr(
558
-                "{$ticket_quantity}",
559
-                "ticket $ticket_identifier quantity: ",
560
-                __FILE__,
561
-                __LINE__,
562
-                2
563
-            );
564
-        }
565
-        if ($ticket_quantity) {
566
-            if ($this->debug) {
567
-                \EEH_Debug_Tools::printr(
568
-                    ($spaces_allocated <= $reg_limit)
569
-                        ? 'true'
570
-                        : 'false',
571
-                    ' . spaces_allocated <= reg_limit = ',
572
-                    __FILE__,
573
-                    __LINE__
574
-                );
575
-            }
576
-            // if the datetime is NOT at full capacity yet
577
-            if ($spaces_allocated <= $reg_limit) {
578
-                // then the maximum ticket quantity we can allocate is the lowest value of either:
579
-                //  the number of remaining spaces for the datetime, which is the limit - spaces already taken
580
-                //  or the maximum ticket quantity
581
-                $ticket_quantity = min($reg_limit - $spaces_allocated, $ticket_quantity);
582
-                // adjust the available quantity in our tracking array
583
-                $this->ticket_quantities[ $ticket_identifier ] -= $ticket_quantity;
584
-                // and increment spaces allocated for this datetime
585
-                $spaces_allocated += $ticket_quantity;
586
-                $at_capacity = $spaces_allocated >= $reg_limit;
587
-                if ($this->debug) {
588
-                    \EEH_Debug_Tools::printr(
589
-                        "{$ticket_quantity} {$ticket_identifier} tickets",
590
-                        ' > > allocate ',
591
-                        __FILE__,
592
-                        __LINE__,
593
-                        3
594
-                    );
595
-                    if ($at_capacity) {
596
-                        \EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__, 3);
597
-                    }
598
-                }
599
-                // now adjust all other datetimes that allow access to this ticket
600
-                $this->adjustDatetimes(
601
-                    $datetime_identifier,
602
-                    $ticket_identifier,
603
-                    $ticket_quantity,
604
-                    $at_capacity
605
-                );
606
-            }
607
-        }
608
-        return $spaces_allocated;
609
-    }
610
-
611
-
612
-    /**
613
-     * subtracts ticket amounts from all datetime reg limits
614
-     * that allow access to the ticket specified,
615
-     * because that ticket could be used
616
-     * to attend any of the datetimes it has access to
617
-     *
618
-     * @param string $datetime_identifier
619
-     * @param string $ticket_identifier
620
-     * @param bool   $at_capacity
621
-     * @param int    $ticket_quantity
622
-     */
623
-    private function adjustDatetimes(
624
-        $datetime_identifier,
625
-        $ticket_identifier,
626
-        $ticket_quantity,
627
-        $at_capacity
628
-    ) {
629
-        /** @var array $datetime_tickets */
630
-        foreach ($this->datetime_tickets as $datetime_ID => $datetime_tickets) {
631
-            if ($datetime_ID !== $datetime_identifier || ! is_array($datetime_tickets)) {
632
-                continue;
633
-            }
634
-            $adjusted = $this->adjustDatetimeSpaces(
635
-                $datetime_ID,
636
-                $ticket_identifier,
637
-                $ticket_quantity
638
-            );
639
-            // skip to next ticket if nothing changed
640
-            if (! ($adjusted || $at_capacity)) {
641
-                continue;
642
-            }
643
-            // then all of it's tickets are now unavailable
644
-            foreach ($datetime_tickets as $datetime_ticket) {
645
-                if (($ticket_identifier === $datetime_ticket || $at_capacity)
646
-                    && isset($this->ticket_quantities[ $datetime_ticket ])
647
-                    && $this->ticket_quantities[ $datetime_ticket ] > 0
648
-                ) {
649
-                    if ($this->debug) {
650
-                        \EEH_Debug_Tools::printr(
651
-                            $datetime_ticket,
652
-                            ' . . . adjust ticket quantities for',
653
-                            __FILE__,
654
-                            __LINE__
655
-                        );
656
-                    }
657
-                    // if this datetime is at full capacity, set any tracked available quantities to zero
658
-                    // otherwise just subtract the ticket quantity
659
-                    $new_quantity = $at_capacity
660
-                        ? 0
661
-                        : $this->ticket_quantities[ $datetime_ticket ] - $ticket_quantity;
662
-                    // don't let ticket quantity go below zero
663
-                    $this->ticket_quantities[ $datetime_ticket ] = max($new_quantity, 0);
664
-                    if ($this->debug) {
665
-                        \EEH_Debug_Tools::printr(
666
-                            $at_capacity
667
-                                ? "0 because Datetime {$datetime_identifier} is at capacity"
668
-                                : "{$this->ticket_quantities[ $datetime_ticket ]}",
669
-                            " . . . . {$datetime_ticket} quantity set to ",
670
-                            __FILE__,
671
-                            __LINE__
672
-                        );
673
-                    }
674
-                }
675
-                // but we also need to adjust spaces for any other datetimes this ticket has access to
676
-                if ($datetime_ticket === $ticket_identifier) {
677
-                    if (isset($this->ticket_datetimes[ $datetime_ticket ])
678
-                        && is_array($this->ticket_datetimes[ $datetime_ticket ])
679
-                    ) {
680
-                        if ($this->debug) {
681
-                            \EEH_Debug_Tools::printr(
682
-                                $datetime_ticket,
683
-                                ' . . adjust other Datetimes for',
684
-                                __FILE__,
685
-                                __LINE__
686
-                            );
687
-                        }
688
-                        foreach ($this->ticket_datetimes[ $datetime_ticket ] as $datetime) {
689
-                            // don't adjust the current datetime twice
690
-                            if ($datetime !== $datetime_identifier) {
691
-                                $this->adjustDatetimeSpaces(
692
-                                    $datetime,
693
-                                    $datetime_ticket,
694
-                                    $ticket_quantity
695
-                                );
696
-                            }
697
-                        }
698
-                    }
699
-                }
700
-            }
701
-        }
702
-    }
703
-
704
-    private function adjustDatetimeSpaces($datetime_identifier, $ticket_identifier, $ticket_quantity = 0)
705
-    {
706
-        // does datetime have spaces available?
707
-        // and does the supplied ticket have access to this datetime ?
708
-        if ($this->datetime_spaces[ $datetime_identifier ] > 0
709
-            && isset($this->datetime_spaces[ $datetime_identifier ], $this->datetime_tickets[ $datetime_identifier ])
710
-            && in_array($ticket_identifier, $this->datetime_tickets[ $datetime_identifier ], true)
711
-        ) {
712
-            if ($this->debug) {
713
-                \EEH_Debug_Tools::printr($datetime_identifier, ' . . adjust Datetime Spaces for', __FILE__, __LINE__);
714
-                \EEH_Debug_Tools::printr(
715
-                    "{$this->datetime_spaces[ $datetime_identifier ]}",
716
-                    " . . current  {$datetime_identifier} spaces available",
717
-                    __FILE__,
718
-                    __LINE__
719
-                );
720
-            }
721
-            // then decrement the available spaces for the datetime
722
-            $this->datetime_spaces[ $datetime_identifier ] -= $ticket_quantity;
723
-            // but don't let quantities go below zero
724
-            $this->datetime_spaces[ $datetime_identifier ] = max(
725
-                $this->datetime_spaces[ $datetime_identifier ],
726
-                0
727
-            );
728
-            if ($this->debug) {
729
-                \EEH_Debug_Tools::printr(
730
-                    "{$ticket_quantity}",
731
-                    " . . . {$datetime_identifier} capacity reduced by",
732
-                    __FILE__,
733
-                    __LINE__
734
-                );
735
-            }
736
-            return true;
737
-        }
738
-        return false;
739
-    }
29
+	/**
30
+	 * @var EE_Event $event
31
+	 */
32
+	private $event;
33
+
34
+	/**
35
+	 * @var array $datetime_query_params
36
+	 */
37
+	private $datetime_query_params;
38
+
39
+	/**
40
+	 * @var EE_Ticket[] $active_tickets
41
+	 */
42
+	private $active_tickets = array();
43
+
44
+	/**
45
+	 * @var EE_Datetime[] $datetimes
46
+	 */
47
+	private $datetimes = array();
48
+
49
+	/**
50
+	 * Array of Ticket IDs grouped by Datetime
51
+	 *
52
+	 * @var array $datetimes
53
+	 */
54
+	private $datetime_tickets = array();
55
+
56
+	/**
57
+	 * Max spaces for each Datetime (reg limit - previous sold)
58
+	 *
59
+	 * @var array $datetime_spaces
60
+	 */
61
+	private $datetime_spaces = array();
62
+
63
+	/**
64
+	 * Array of Datetime IDs grouped by Ticket
65
+	 *
66
+	 * @var array[] $ticket_datetimes
67
+	 */
68
+	private $ticket_datetimes = array();
69
+
70
+	/**
71
+	 * maximum ticket quantities for each ticket (adjusted for reg limit)
72
+	 *
73
+	 * @var array $ticket_quantities
74
+	 */
75
+	private $ticket_quantities = array();
76
+
77
+	/**
78
+	 * total quantity of sold and reserved for each ticket
79
+	 *
80
+	 * @var array $tickets_sold
81
+	 */
82
+	private $tickets_sold = array();
83
+
84
+	/**
85
+	 * total spaces available across all datetimes
86
+	 *
87
+	 * @var array $total_spaces
88
+	 */
89
+	private $total_spaces = array();
90
+
91
+	/**
92
+	 * @var boolean $debug
93
+	 */
94
+	private $debug = false; // true false
95
+
96
+	/**
97
+	 * @var null|int $spaces_remaining
98
+	 */
99
+	private $spaces_remaining;
100
+
101
+	/**
102
+	 * @var null|int $total_spaces_available
103
+	 */
104
+	private $total_spaces_available;
105
+
106
+
107
+	/**
108
+	 * EventSpacesCalculator constructor.
109
+	 *
110
+	 * @param EE_Event $event
111
+	 * @param array    $datetime_query_params
112
+	 * @throws EE_Error
113
+	 */
114
+	public function __construct(EE_Event $event, array $datetime_query_params = array())
115
+	{
116
+		if ($this->debug) {
117
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 1);
118
+			\EEH_Debug_Tools::printr((string) $event->ID(), 'For event', __FILE__, __LINE__);
119
+		}
120
+		$this->event = $event;
121
+		$this->datetime_query_params = $datetime_query_params + array('order_by' => array('DTT_reg_limit' => 'ASC'));
122
+		$this->setHooks();
123
+	}
124
+
125
+
126
+	/**
127
+	 * @return void
128
+	 */
129
+	private function setHooks()
130
+	{
131
+		add_action('AHEE__EE_Ticket__increase_sold', array($this, 'clearResults'));
132
+		add_action('AHEE__EE_Ticket__decrease_sold', array($this, 'clearResults'));
133
+		add_action('AHEE__EE_Datetime__increase_sold', array($this, 'clearResults'));
134
+		add_action('AHEE__EE_Datetime__decrease_sold', array($this, 'clearResults'));
135
+		add_action('AHEE__EE_Ticket__increase_reserved', array($this, 'clearResults'));
136
+		add_action('AHEE__EE_Ticket__decrease_reserved', array($this, 'clearResults'));
137
+		add_action('AHEE__EE_Datetime__increase_reserved', array($this, 'clearResults'));
138
+		add_action('AHEE__EE_Datetime__decrease_reserved', array($this, 'clearResults'));
139
+	}
140
+
141
+
142
+	/**
143
+	 * @return void
144
+	 */
145
+	public function clearResults()
146
+	{
147
+		if ($this->debug) {
148
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 1);
149
+		}
150
+		$this->spaces_remaining = null;
151
+		$this->total_spaces_available = null;
152
+	}
153
+
154
+
155
+	/**
156
+	 * @return EE_Ticket[]
157
+	 * @throws EE_Error
158
+	 * @throws InvalidDataTypeException
159
+	 * @throws InvalidInterfaceException
160
+	 * @throws InvalidArgumentException
161
+	 */
162
+	public function getActiveTickets()
163
+	{
164
+		if (empty($this->active_tickets)) {
165
+			$this->active_tickets = $this->event->tickets(
166
+				array(
167
+					array('TKT_deleted' => false),
168
+					'order_by' => array('TKT_qty' => 'ASC'),
169
+				)
170
+			);
171
+		}
172
+		return $this->active_tickets;
173
+	}
174
+
175
+
176
+	/**
177
+	 * @param EE_Ticket[] $active_tickets
178
+	 * @throws EE_Error
179
+	 * @throws DomainException
180
+	 * @throws UnexpectedEntityException
181
+	 */
182
+	public function setActiveTickets(array $active_tickets = array())
183
+	{
184
+		if (! empty($active_tickets)) {
185
+			foreach ($active_tickets as $active_ticket) {
186
+				$this->validateTicket($active_ticket);
187
+			}
188
+			// sort incoming array by ticket quantity (asc)
189
+			usort(
190
+				$active_tickets,
191
+				function (EE_Ticket $a, EE_Ticket $b) {
192
+					if ($a->qty() === $b->qty()) {
193
+						return 0;
194
+					}
195
+					return ($a->qty() < $b->qty())
196
+						? -1
197
+						: 1;
198
+				}
199
+			);
200
+		}
201
+		$this->active_tickets = $active_tickets;
202
+	}
203
+
204
+
205
+	/**
206
+	 * @param $ticket
207
+	 * @throws DomainException
208
+	 * @throws EE_Error
209
+	 * @throws UnexpectedEntityException
210
+	 */
211
+	private function validateTicket($ticket)
212
+	{
213
+		if (! $ticket instanceof EE_Ticket) {
214
+			throw new DomainException(
215
+				esc_html__(
216
+					'Invalid Ticket. Only EE_Ticket objects can be used to calculate event space availability.',
217
+					'event_espresso'
218
+				)
219
+			);
220
+		}
221
+		if ($ticket->get_event_ID() !== $this->event->ID()) {
222
+			throw new DomainException(
223
+				sprintf(
224
+					esc_html__(
225
+						'An EE_Ticket for Event %1$d was supplied while calculating event space availability for Event %2$d.',
226
+						'event_espresso'
227
+					),
228
+					$ticket->get_event_ID(),
229
+					$this->event->ID()
230
+				)
231
+			);
232
+		}
233
+	}
234
+
235
+
236
+	/**
237
+	 * @return EE_Datetime[]
238
+	 */
239
+	public function getDatetimes()
240
+	{
241
+		return $this->datetimes;
242
+	}
243
+
244
+
245
+	/**
246
+	 * @param EE_Datetime $datetime
247
+	 * @throws EE_Error
248
+	 * @throws DomainException
249
+	 */
250
+	public function setDatetime(EE_Datetime $datetime)
251
+	{
252
+		if ($datetime->event()->ID() !== $this->event->ID()) {
253
+			throw new DomainException(
254
+				sprintf(
255
+					esc_html__(
256
+						'An EE_Datetime for Event %1$d was supplied while calculating event space availability for Event %2$d.',
257
+						'event_espresso'
258
+					),
259
+					$datetime->event()->ID(),
260
+					$this->event->ID()
261
+				)
262
+			);
263
+		}
264
+		$this->datetimes[ $datetime->ID() ] = $datetime;
265
+	}
266
+
267
+
268
+	/**
269
+	 * calculate spaces remaining based on "saleable" tickets
270
+	 *
271
+	 * @return float|int
272
+	 * @throws EE_Error
273
+	 * @throws DomainException
274
+	 * @throws UnexpectedEntityException
275
+	 * @throws InvalidDataTypeException
276
+	 * @throws InvalidInterfaceException
277
+	 * @throws InvalidArgumentException
278
+	 */
279
+	public function spacesRemaining()
280
+	{
281
+		if ($this->debug) {
282
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
283
+		}
284
+		if ($this->spaces_remaining === null) {
285
+			$this->initialize();
286
+			$this->spaces_remaining = $this->calculate();
287
+		}
288
+		return $this->spaces_remaining;
289
+	}
290
+
291
+
292
+	/**
293
+	 * calculates total available spaces for an event with no regard for sold tickets
294
+	 *
295
+	 * @return int|float
296
+	 * @throws EE_Error
297
+	 * @throws DomainException
298
+	 * @throws UnexpectedEntityException
299
+	 * @throws InvalidDataTypeException
300
+	 * @throws InvalidInterfaceException
301
+	 * @throws InvalidArgumentException
302
+	 */
303
+	public function totalSpacesAvailable()
304
+	{
305
+		if ($this->debug) {
306
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
307
+		}
308
+		if ($this->total_spaces_available === null) {
309
+			$this->initialize();
310
+			$this->total_spaces_available = $this->calculate(false);
311
+		}
312
+		return $this->total_spaces_available;
313
+	}
314
+
315
+
316
+	/**
317
+	 * Loops through the active tickets for the event
318
+	 * and builds a series of data arrays that will be used for calculating
319
+	 * the total maximum available spaces, as well as the spaces remaining.
320
+	 * Because ticket quantities affect datetime spaces and vice versa,
321
+	 * we need to be constantly updating these data arrays as things change,
322
+	 * which is the entire reason for their existence.
323
+	 *
324
+	 * @throws EE_Error
325
+	 * @throws DomainException
326
+	 * @throws UnexpectedEntityException
327
+	 * @throws InvalidDataTypeException
328
+	 * @throws InvalidInterfaceException
329
+	 * @throws InvalidArgumentException
330
+	 */
331
+	private function initialize()
332
+	{
333
+		if ($this->debug) {
334
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
335
+		}
336
+		$this->datetime_tickets = array();
337
+		$this->datetime_spaces = array();
338
+		$this->ticket_datetimes = array();
339
+		$this->ticket_quantities = array();
340
+		$this->tickets_sold = array();
341
+		$this->total_spaces = array();
342
+		$active_tickets = $this->getActiveTickets();
343
+		if (! empty($active_tickets)) {
344
+			foreach ($active_tickets as $ticket) {
345
+				$this->validateTicket($ticket);
346
+				// we need to index our data arrays using strings for the purpose of sorting,
347
+				// but we also need them to be unique, so  we'll just prepend a letter T to the ID
348
+				$ticket_identifier = "T{$ticket->ID()}";
349
+				// to start, we'll just consider the raw qty to be the maximum availability for this ticket,
350
+				// unless the ticket is past its "sell until" date, in which case the qty will be 0
351
+				$max_tickets = $ticket->is_expired() ? 0 : $ticket->qty();
352
+				// but we'll adjust that after looping over each datetime for the ticket and checking reg limits
353
+				$ticket_datetimes = $ticket->datetimes($this->datetime_query_params);
354
+				foreach ($ticket_datetimes as $datetime) {
355
+					// save all datetimes
356
+					$this->setDatetime($datetime);
357
+					$datetime_identifier = "D{$datetime->ID()}";
358
+					$reg_limit = $datetime->reg_limit();
359
+					// ticket quantity can not exceed datetime reg limit
360
+					$max_tickets = min($max_tickets, $reg_limit);
361
+					// as described earlier, because we need to be able to constantly adjust numbers for things,
362
+					// we are going to move all of our data into the following arrays:
363
+					// datetime spaces initially represents the reg limit for each datetime,
364
+					// but this will get adjusted as tickets are accounted for
365
+					$this->datetime_spaces[ $datetime_identifier ] = $reg_limit;
366
+					// just an array of ticket IDs grouped by datetime
367
+					$this->datetime_tickets[ $datetime_identifier ][] = $ticket_identifier;
368
+					// and an array of datetime IDs grouped by ticket
369
+					$this->ticket_datetimes[ $ticket_identifier ][] = $datetime_identifier;
370
+				}
371
+				// total quantity of sold and reserved for each ticket
372
+				$this->tickets_sold[ $ticket_identifier ] = $ticket->sold() + $ticket->reserved();
373
+				// and the maximum ticket quantities for each ticket (adjusted for reg limit)
374
+				$this->ticket_quantities[ $ticket_identifier ] = $max_tickets;
375
+			}
376
+		}
377
+		// sort datetime spaces by reg limit, but maintain our string indexes
378
+		asort($this->datetime_spaces, SORT_NUMERIC);
379
+		// datetime tickets need to be sorted in the SAME order as the above array...
380
+		// so we'll just use array_merge() to take the structure of datetime_spaces
381
+		// but overwrite all of the data with that from datetime_tickets
382
+		$this->datetime_tickets = array_merge(
383
+			$this->datetime_spaces,
384
+			$this->datetime_tickets
385
+		);
386
+		if ($this->debug) {
387
+			\EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
388
+			\EEH_Debug_Tools::printr($this->datetime_tickets, 'datetime_tickets', __FILE__, __LINE__);
389
+			\EEH_Debug_Tools::printr($this->ticket_quantities, 'ticket_quantities', __FILE__, __LINE__);
390
+		}
391
+	}
392
+
393
+
394
+	/**
395
+	 * performs calculations on initialized data
396
+	 *
397
+	 * @param bool $consider_sold
398
+	 * @return int|float
399
+	 */
400
+	private function calculate($consider_sold = true)
401
+	{
402
+		if ($this->debug) {
403
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
404
+			\EEH_Debug_Tools::printr($consider_sold, '$consider_sold', __FILE__, __LINE__);
405
+		}
406
+		if ($consider_sold) {
407
+			// subtract amounts sold from all ticket quantities and datetime spaces
408
+			$this->adjustTicketQuantitiesDueToSales();
409
+		}
410
+		foreach ($this->datetime_tickets as $datetime_identifier => $tickets) {
411
+			$this->trackAvailableSpacesForDatetimes($datetime_identifier, $tickets);
412
+		}
413
+		// total spaces available is just the sum of the spaces available for each datetime
414
+		$spaces_remaining = array_sum($this->total_spaces);
415
+		if ($this->debug) {
416
+			\EEH_Debug_Tools::printr($this->total_spaces, '$this->total_spaces', __FILE__, __LINE__);
417
+			\EEH_Debug_Tools::printr($this->tickets_sold, '$this->tickets_sold', __FILE__, __LINE__);
418
+			\EEH_Debug_Tools::printr($spaces_remaining, '$spaces_remaining', __FILE__, __LINE__);
419
+		}
420
+		return $spaces_remaining;
421
+	}
422
+
423
+
424
+	/**
425
+	 * subtracts amount of  tickets sold from ticket quantities and datetime spaces
426
+	 */
427
+	private function adjustTicketQuantitiesDueToSales()
428
+	{
429
+		if ($this->debug) {
430
+			\EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
431
+		}
432
+		foreach ($this->tickets_sold as $ticket_identifier => $tickets_sold) {
433
+			if (isset($this->ticket_quantities[ $ticket_identifier ])) {
434
+				$this->ticket_quantities[ $ticket_identifier ] -= $tickets_sold;
435
+				// don't let values go below zero
436
+				$this->ticket_quantities[ $ticket_identifier ] = max(
437
+					$this->ticket_quantities[ $ticket_identifier ],
438
+					0
439
+				);
440
+				if ($this->debug) {
441
+					\EEH_Debug_Tools::printr(
442
+						"{$tickets_sold} sales for ticket {$ticket_identifier} ",
443
+						'subtracting',
444
+						__FILE__,
445
+						__LINE__
446
+					);
447
+				}
448
+			}
449
+			if (isset($this->ticket_datetimes[ $ticket_identifier ])
450
+				&& is_array($this->ticket_datetimes[ $ticket_identifier ])
451
+			) {
452
+				foreach ($this->ticket_datetimes[ $ticket_identifier ] as $ticket_datetime) {
453
+					if (isset($this->ticket_quantities[ $ticket_identifier ])) {
454
+						$this->datetime_spaces[ $ticket_datetime ] -= $tickets_sold;
455
+						// don't let values go below zero
456
+						$this->datetime_spaces[ $ticket_datetime ] = max(
457
+							$this->datetime_spaces[ $ticket_datetime ],
458
+							0
459
+						);
460
+						if ($this->debug) {
461
+							\EEH_Debug_Tools::printr(
462
+								"{$tickets_sold} sales for datetime {$ticket_datetime} ",
463
+								'subtracting',
464
+								__FILE__,
465
+								__LINE__
466
+							);
467
+						}
468
+					}
469
+				}
470
+			}
471
+		}
472
+	}
473
+
474
+
475
+	/**
476
+	 * @param string $datetime_identifier
477
+	 * @param array  $tickets
478
+	 */
479
+	private function trackAvailableSpacesForDatetimes($datetime_identifier, array $tickets)
480
+	{
481
+		// make sure a reg limit is set for the datetime
482
+		$reg_limit = isset($this->datetime_spaces[ $datetime_identifier ])
483
+			? $this->datetime_spaces[ $datetime_identifier ]
484
+			: 0;
485
+		// and bail if it is not
486
+		if (! $reg_limit) {
487
+			if ($this->debug) {
488
+				\EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__);
489
+			}
490
+			return;
491
+		}
492
+		if ($this->debug) {
493
+			\EEH_Debug_Tools::printr($datetime_identifier, '* $datetime_identifier', __FILE__, __LINE__, 1);
494
+			\EEH_Debug_Tools::printr(
495
+				"{$reg_limit}",
496
+				'REG LIMIT',
497
+				__FILE__,
498
+				__LINE__
499
+			);
500
+		}
501
+		// number of allocated spaces always starts at zero
502
+		$spaces_allocated = 0;
503
+		$this->total_spaces[ $datetime_identifier ] = 0;
504
+		foreach ($tickets as $ticket_identifier) {
505
+			$spaces_allocated = $this->calculateAvailableSpacesForTicket(
506
+				$datetime_identifier,
507
+				$reg_limit,
508
+				$ticket_identifier,
509
+				$spaces_allocated
510
+			);
511
+		}
512
+		// spaces can't be negative
513
+		$spaces_allocated = max($spaces_allocated, 0);
514
+		if ($spaces_allocated) {
515
+			// track any non-zero values
516
+			$this->total_spaces[ $datetime_identifier ] += $spaces_allocated;
517
+			if ($this->debug) {
518
+				\EEH_Debug_Tools::printr((string) $spaces_allocated, ' . $spaces_allocated: ', __FILE__, __LINE__);
519
+			}
520
+		} else {
521
+			if ($this->debug) {
522
+				\EEH_Debug_Tools::printr(' ', ' . NO TICKETS AVAILABLE FOR DATETIME', __FILE__, __LINE__);
523
+			}
524
+		}
525
+		if ($this->debug) {
526
+			\EEH_Debug_Tools::printr(
527
+				$this->total_spaces[ $datetime_identifier ],
528
+				'$total_spaces',
529
+				__FILE__,
530
+				__LINE__
531
+			);
532
+			\EEH_Debug_Tools::printr($this->ticket_quantities, '$ticket_quantities', __FILE__, __LINE__);
533
+			\EEH_Debug_Tools::printr($this->datetime_spaces, 'datetime_spaces', __FILE__, __LINE__);
534
+		}
535
+	}
536
+
537
+
538
+	/**
539
+	 * @param string $datetime_identifier
540
+	 * @param int    $reg_limit
541
+	 * @param string $ticket_identifier
542
+	 * @param int    $spaces_allocated
543
+	 * @return int
544
+	 */
545
+	private function calculateAvailableSpacesForTicket(
546
+		$datetime_identifier,
547
+		$reg_limit,
548
+		$ticket_identifier,
549
+		$spaces_allocated
550
+	) {
551
+		// make sure ticket quantity is set
552
+		$ticket_quantity = isset($this->ticket_quantities[ $ticket_identifier ])
553
+			? $this->ticket_quantities[ $ticket_identifier ]
554
+			: 0;
555
+		if ($this->debug) {
556
+			\EEH_Debug_Tools::printr("{$spaces_allocated}", '$spaces_allocated', __FILE__, __LINE__);
557
+			\EEH_Debug_Tools::printr(
558
+				"{$ticket_quantity}",
559
+				"ticket $ticket_identifier quantity: ",
560
+				__FILE__,
561
+				__LINE__,
562
+				2
563
+			);
564
+		}
565
+		if ($ticket_quantity) {
566
+			if ($this->debug) {
567
+				\EEH_Debug_Tools::printr(
568
+					($spaces_allocated <= $reg_limit)
569
+						? 'true'
570
+						: 'false',
571
+					' . spaces_allocated <= reg_limit = ',
572
+					__FILE__,
573
+					__LINE__
574
+				);
575
+			}
576
+			// if the datetime is NOT at full capacity yet
577
+			if ($spaces_allocated <= $reg_limit) {
578
+				// then the maximum ticket quantity we can allocate is the lowest value of either:
579
+				//  the number of remaining spaces for the datetime, which is the limit - spaces already taken
580
+				//  or the maximum ticket quantity
581
+				$ticket_quantity = min($reg_limit - $spaces_allocated, $ticket_quantity);
582
+				// adjust the available quantity in our tracking array
583
+				$this->ticket_quantities[ $ticket_identifier ] -= $ticket_quantity;
584
+				// and increment spaces allocated for this datetime
585
+				$spaces_allocated += $ticket_quantity;
586
+				$at_capacity = $spaces_allocated >= $reg_limit;
587
+				if ($this->debug) {
588
+					\EEH_Debug_Tools::printr(
589
+						"{$ticket_quantity} {$ticket_identifier} tickets",
590
+						' > > allocate ',
591
+						__FILE__,
592
+						__LINE__,
593
+						3
594
+					);
595
+					if ($at_capacity) {
596
+						\EEH_Debug_Tools::printr('AT CAPACITY', " . {$datetime_identifier}", __FILE__, __LINE__, 3);
597
+					}
598
+				}
599
+				// now adjust all other datetimes that allow access to this ticket
600
+				$this->adjustDatetimes(
601
+					$datetime_identifier,
602
+					$ticket_identifier,
603
+					$ticket_quantity,
604
+					$at_capacity
605
+				);
606
+			}
607
+		}
608
+		return $spaces_allocated;
609
+	}
610
+
611
+
612
+	/**
613
+	 * subtracts ticket amounts from all datetime reg limits
614
+	 * that allow access to the ticket specified,
615
+	 * because that ticket could be used
616
+	 * to attend any of the datetimes it has access to
617
+	 *
618
+	 * @param string $datetime_identifier
619
+	 * @param string $ticket_identifier
620
+	 * @param bool   $at_capacity
621
+	 * @param int    $ticket_quantity
622
+	 */
623
+	private function adjustDatetimes(
624
+		$datetime_identifier,
625
+		$ticket_identifier,
626
+		$ticket_quantity,
627
+		$at_capacity
628
+	) {
629
+		/** @var array $datetime_tickets */
630
+		foreach ($this->datetime_tickets as $datetime_ID => $datetime_tickets) {
631
+			if ($datetime_ID !== $datetime_identifier || ! is_array($datetime_tickets)) {
632
+				continue;
633
+			}
634
+			$adjusted = $this->adjustDatetimeSpaces(
635
+				$datetime_ID,
636
+				$ticket_identifier,
637
+				$ticket_quantity
638
+			);
639
+			// skip to next ticket if nothing changed
640
+			if (! ($adjusted || $at_capacity)) {
641
+				continue;
642
+			}
643
+			// then all of it's tickets are now unavailable
644
+			foreach ($datetime_tickets as $datetime_ticket) {
645
+				if (($ticket_identifier === $datetime_ticket || $at_capacity)
646
+					&& isset($this->ticket_quantities[ $datetime_ticket ])
647
+					&& $this->ticket_quantities[ $datetime_ticket ] > 0
648
+				) {
649
+					if ($this->debug) {
650
+						\EEH_Debug_Tools::printr(
651
+							$datetime_ticket,
652
+							' . . . adjust ticket quantities for',
653
+							__FILE__,
654
+							__LINE__
655
+						);
656
+					}
657
+					// if this datetime is at full capacity, set any tracked available quantities to zero
658
+					// otherwise just subtract the ticket quantity
659
+					$new_quantity = $at_capacity
660
+						? 0
661
+						: $this->ticket_quantities[ $datetime_ticket ] - $ticket_quantity;
662
+					// don't let ticket quantity go below zero
663
+					$this->ticket_quantities[ $datetime_ticket ] = max($new_quantity, 0);
664
+					if ($this->debug) {
665
+						\EEH_Debug_Tools::printr(
666
+							$at_capacity
667
+								? "0 because Datetime {$datetime_identifier} is at capacity"
668
+								: "{$this->ticket_quantities[ $datetime_ticket ]}",
669
+							" . . . . {$datetime_ticket} quantity set to ",
670
+							__FILE__,
671
+							__LINE__
672
+						);
673
+					}
674
+				}
675
+				// but we also need to adjust spaces for any other datetimes this ticket has access to
676
+				if ($datetime_ticket === $ticket_identifier) {
677
+					if (isset($this->ticket_datetimes[ $datetime_ticket ])
678
+						&& is_array($this->ticket_datetimes[ $datetime_ticket ])
679
+					) {
680
+						if ($this->debug) {
681
+							\EEH_Debug_Tools::printr(
682
+								$datetime_ticket,
683
+								' . . adjust other Datetimes for',
684
+								__FILE__,
685
+								__LINE__
686
+							);
687
+						}
688
+						foreach ($this->ticket_datetimes[ $datetime_ticket ] as $datetime) {
689
+							// don't adjust the current datetime twice
690
+							if ($datetime !== $datetime_identifier) {
691
+								$this->adjustDatetimeSpaces(
692
+									$datetime,
693
+									$datetime_ticket,
694
+									$ticket_quantity
695
+								);
696
+							}
697
+						}
698
+					}
699
+				}
700
+			}
701
+		}
702
+	}
703
+
704
+	private function adjustDatetimeSpaces($datetime_identifier, $ticket_identifier, $ticket_quantity = 0)
705
+	{
706
+		// does datetime have spaces available?
707
+		// and does the supplied ticket have access to this datetime ?
708
+		if ($this->datetime_spaces[ $datetime_identifier ] > 0
709
+			&& isset($this->datetime_spaces[ $datetime_identifier ], $this->datetime_tickets[ $datetime_identifier ])
710
+			&& in_array($ticket_identifier, $this->datetime_tickets[ $datetime_identifier ], true)
711
+		) {
712
+			if ($this->debug) {
713
+				\EEH_Debug_Tools::printr($datetime_identifier, ' . . adjust Datetime Spaces for', __FILE__, __LINE__);
714
+				\EEH_Debug_Tools::printr(
715
+					"{$this->datetime_spaces[ $datetime_identifier ]}",
716
+					" . . current  {$datetime_identifier} spaces available",
717
+					__FILE__,
718
+					__LINE__
719
+				);
720
+			}
721
+			// then decrement the available spaces for the datetime
722
+			$this->datetime_spaces[ $datetime_identifier ] -= $ticket_quantity;
723
+			// but don't let quantities go below zero
724
+			$this->datetime_spaces[ $datetime_identifier ] = max(
725
+				$this->datetime_spaces[ $datetime_identifier ],
726
+				0
727
+			);
728
+			if ($this->debug) {
729
+				\EEH_Debug_Tools::printr(
730
+					"{$ticket_quantity}",
731
+					" . . . {$datetime_identifier} capacity reduced by",
732
+					__FILE__,
733
+					__LINE__
734
+				);
735
+			}
736
+			return true;
737
+		}
738
+		return false;
739
+	}
740 740
 }
Please login to merge, or discard this patch.
core/services/database/TableManager.php 1 patch
Indentation   +231 added lines, -231 removed lines patch added patch discarded remove patch
@@ -13,254 +13,254 @@
 block discarded – undo
13 13
 class TableManager extends \EE_Base
14 14
 {
15 15
 
16
-    /**
17
-     * @var TableAnalysis $table_analysis
18
-     */
19
-    private $table_analysis;
16
+	/**
17
+	 * @var TableAnalysis $table_analysis
18
+	 */
19
+	private $table_analysis;
20 20
 
21 21
 
22
-    /**
23
-     * TableManager constructor.
24
-     *
25
-     * @param TableAnalysis $TableAnalysis
26
-     */
27
-    public function __construct(TableAnalysis $TableAnalysis)
28
-    {
29
-        $this->table_analysis = $TableAnalysis;
30
-    }
22
+	/**
23
+	 * TableManager constructor.
24
+	 *
25
+	 * @param TableAnalysis $TableAnalysis
26
+	 */
27
+	public function __construct(TableAnalysis $TableAnalysis)
28
+	{
29
+		$this->table_analysis = $TableAnalysis;
30
+	}
31 31
 
32 32
 
33
-    /**
34
-     * Gets the injected table analyzer, or throws an exception
35
-     *
36
-     * @return TableAnalysis
37
-     * @throws \EE_Error
38
-     */
39
-    protected function getTableAnalysis()
40
-    {
41
-        if ($this->table_analysis instanceof TableAnalysis) {
42
-            return $this->table_analysis;
43
-        } else {
44
-            throw new \EE_Error(
45
-                sprintf(
46
-                    __('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
47
-                    get_class($this)
48
-                )
49
-            );
50
-        }
51
-    }
33
+	/**
34
+	 * Gets the injected table analyzer, or throws an exception
35
+	 *
36
+	 * @return TableAnalysis
37
+	 * @throws \EE_Error
38
+	 */
39
+	protected function getTableAnalysis()
40
+	{
41
+		if ($this->table_analysis instanceof TableAnalysis) {
42
+			return $this->table_analysis;
43
+		} else {
44
+			throw new \EE_Error(
45
+				sprintf(
46
+					__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
47
+					get_class($this)
48
+				)
49
+			);
50
+		}
51
+	}
52 52
 
53 53
 
54
-    /**
55
-     * @param string $table_name which can optionally start with $wpdb->prefix or not
56
-     * @param string $column_name
57
-     * @param string $column_info
58
-     * @return bool|false|int
59
-     */
60
-    public function addColumn($table_name, $column_name, $column_info = 'INT UNSIGNED NOT NULL')
61
-    {
62
-        if (apply_filters('FHEE__EEH_Activation__add_column_if_it_doesnt_exist__short_circuit', false)) {
63
-            return false;
64
-        }
65
-        global $wpdb;
66
-        $full_table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
67
-        $columns = $this->getTableColumns($table_name);
68
-        if (! in_array($column_name, $columns)) {
69
-            $alter_query = "ALTER TABLE {$full_table_name} ADD {$column_name} {$column_info}";
70
-            return $wpdb->query($alter_query);
71
-        }
72
-        return true;
73
-    }
54
+	/**
55
+	 * @param string $table_name which can optionally start with $wpdb->prefix or not
56
+	 * @param string $column_name
57
+	 * @param string $column_info
58
+	 * @return bool|false|int
59
+	 */
60
+	public function addColumn($table_name, $column_name, $column_info = 'INT UNSIGNED NOT NULL')
61
+	{
62
+		if (apply_filters('FHEE__EEH_Activation__add_column_if_it_doesnt_exist__short_circuit', false)) {
63
+			return false;
64
+		}
65
+		global $wpdb;
66
+		$full_table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
67
+		$columns = $this->getTableColumns($table_name);
68
+		if (! in_array($column_name, $columns)) {
69
+			$alter_query = "ALTER TABLE {$full_table_name} ADD {$column_name} {$column_info}";
70
+			return $wpdb->query($alter_query);
71
+		}
72
+		return true;
73
+	}
74 74
 
75 75
 
76
-    /**
77
-     * Gets the name of all columns on the  table. $table_name can
78
-     * optionally start with $wpdb->prefix or not
79
-     *
80
-     * @global \wpdb $wpdb
81
-     * @param string $table_name
82
-     * @return array
83
-     */
84
-    public function getTableColumns($table_name)
85
-    {
86
-        global $wpdb;
87
-        $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
88
-        $field_array = array();
89
-        if (! empty($table_name)) {
90
-            $columns = $wpdb->get_results("SHOW COLUMNS FROM {$table_name} ");
91
-            if ($columns !== false) {
92
-                foreach ($columns as $column) {
93
-                    $field_array[] = $column->Field;
94
-                }
95
-            }
96
-        }
97
-        return $field_array;
98
-    }
76
+	/**
77
+	 * Gets the name of all columns on the  table. $table_name can
78
+	 * optionally start with $wpdb->prefix or not
79
+	 *
80
+	 * @global \wpdb $wpdb
81
+	 * @param string $table_name
82
+	 * @return array
83
+	 */
84
+	public function getTableColumns($table_name)
85
+	{
86
+		global $wpdb;
87
+		$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
88
+		$field_array = array();
89
+		if (! empty($table_name)) {
90
+			$columns = $wpdb->get_results("SHOW COLUMNS FROM {$table_name} ");
91
+			if ($columns !== false) {
92
+				foreach ($columns as $column) {
93
+					$field_array[] = $column->Field;
94
+				}
95
+			}
96
+		}
97
+		return $field_array;
98
+	}
99 99
 
100 100
 
101
-    /**
102
-     * Drops the specified table from the database. $table_name can
103
-     * optionally start with $wpdb->prefix or not
104
-     *
105
-     * @global \wpdb $wpdb
106
-     * @param string $table_name
107
-     * @return int
108
-     */
109
-    public function dropTable($table_name)
110
-    {
111
-        global $wpdb;
112
-        if ($this->getTableAnalysis()->tableExists($table_name)) {
113
-            $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
114
-            return $wpdb->query("DROP TABLE IF EXISTS {$table_name}");
115
-        }
116
-        return 0;
117
-    }
101
+	/**
102
+	 * Drops the specified table from the database. $table_name can
103
+	 * optionally start with $wpdb->prefix or not
104
+	 *
105
+	 * @global \wpdb $wpdb
106
+	 * @param string $table_name
107
+	 * @return int
108
+	 */
109
+	public function dropTable($table_name)
110
+	{
111
+		global $wpdb;
112
+		if ($this->getTableAnalysis()->tableExists($table_name)) {
113
+			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
114
+			return $wpdb->query("DROP TABLE IF EXISTS {$table_name}");
115
+		}
116
+		return 0;
117
+	}
118 118
 
119 119
 
120
-    /**
121
-     * Drops all the tables mentioned in a single MYSQL query. Double-checks
122
-     * each table name provided has a wpdb prefix attached, and that it exists.
123
-     * Returns the list actually deleted
124
-     *
125
-     * @global WPDB $wpdb
126
-     * @param array $table_names
127
-     * @return array of table names which we deleted
128
-     */
129
-    public function dropTables($table_names)
130
-    {
131
-        $tables_to_delete = array();
132
-        foreach ($table_names as $table_name) {
133
-            $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
134
-            if ($this->getTableAnalysis()->tableExists($table_name)) {
135
-                $tables_to_delete[ $table_name ] = $table_name;
136
-            }
137
-        }
138
-        if (! empty($tables_to_delete)) {
139
-            global $wpdb;
140
-            // make sure we only have a unique strings in the array.
141
-            $tables_to_delete = array_unique($tables_to_delete);
142
-            $wpdb->query('DROP TABLE ' . implode(', ', $tables_to_delete));
143
-        }
144
-        return $tables_to_delete;
145
-    }
120
+	/**
121
+	 * Drops all the tables mentioned in a single MYSQL query. Double-checks
122
+	 * each table name provided has a wpdb prefix attached, and that it exists.
123
+	 * Returns the list actually deleted
124
+	 *
125
+	 * @global WPDB $wpdb
126
+	 * @param array $table_names
127
+	 * @return array of table names which we deleted
128
+	 */
129
+	public function dropTables($table_names)
130
+	{
131
+		$tables_to_delete = array();
132
+		foreach ($table_names as $table_name) {
133
+			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
134
+			if ($this->getTableAnalysis()->tableExists($table_name)) {
135
+				$tables_to_delete[ $table_name ] = $table_name;
136
+			}
137
+		}
138
+		if (! empty($tables_to_delete)) {
139
+			global $wpdb;
140
+			// make sure we only have a unique strings in the array.
141
+			$tables_to_delete = array_unique($tables_to_delete);
142
+			$wpdb->query('DROP TABLE ' . implode(', ', $tables_to_delete));
143
+		}
144
+		return $tables_to_delete;
145
+	}
146 146
 
147 147
 
148
-    /**
149
-     * Drops the specified index from the specified table. $table_name can
150
-     * optionally start with $wpdb->prefix or not
151
-     *
152
-     * @global \wpdb $wpdb
153
-     * @param string $table_name
154
-     * @param string $index_name
155
-     * @return int the number of indexes dropped. False if there was a datbase error
156
-     */
157
-    public function dropIndex($table_name, $index_name)
158
-    {
159
-        if (apply_filters('FHEE__EEH_Activation__drop_index__short_circuit', false)) {
160
-            return 0;
161
-        }
162
-        global $wpdb;
163
-        $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
164
-        $index_exists_query = "SHOW INDEX FROM {$table_name} WHERE key_name = '{$index_name}'";
165
-        if ($this->getTableAnalysis()->tableExists($table_name)
166
-            && $wpdb->get_var($index_exists_query)
167
-               === $table_name // using get_var with the $index_exists_query returns the table's name
168
-        ) {
169
-            return $wpdb->query("ALTER TABLE {$table_name} DROP INDEX {$index_name}");
170
-        }
171
-        return 0;
172
-    }
148
+	/**
149
+	 * Drops the specified index from the specified table. $table_name can
150
+	 * optionally start with $wpdb->prefix or not
151
+	 *
152
+	 * @global \wpdb $wpdb
153
+	 * @param string $table_name
154
+	 * @param string $index_name
155
+	 * @return int the number of indexes dropped. False if there was a datbase error
156
+	 */
157
+	public function dropIndex($table_name, $index_name)
158
+	{
159
+		if (apply_filters('FHEE__EEH_Activation__drop_index__short_circuit', false)) {
160
+			return 0;
161
+		}
162
+		global $wpdb;
163
+		$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
164
+		$index_exists_query = "SHOW INDEX FROM {$table_name} WHERE key_name = '{$index_name}'";
165
+		if ($this->getTableAnalysis()->tableExists($table_name)
166
+			&& $wpdb->get_var($index_exists_query)
167
+			   === $table_name // using get_var with the $index_exists_query returns the table's name
168
+		) {
169
+			return $wpdb->query("ALTER TABLE {$table_name} DROP INDEX {$index_name}");
170
+		}
171
+		return 0;
172
+	}
173 173
 
174 174
 
175
-    /**
176
-     * Just creates the requested table. $table_name can
177
-     * optionally start with $wpdb->prefix or not
178
-     *
179
-     * @param string $table_name
180
-     * @param string $create_sql defining the table's columns and indexes
181
-     * @param string $engine     (no need to specify "ENGINE=", that's implied)
182
-     * @return void
183
-     * @throws \EE_Error
184
-     */
185
-    public function createTable($table_name, $create_sql, $engine = 'MyISAM')
186
-    {
187
-        $engine = apply_filters(
188
-            'FHEE__EventEspresso_core_services_database_TableManager__createTable__engine',
189
-            $engine,
190
-            $table_name,
191
-            $create_sql
192
-        );
193
-        // does $sql contain valid column information? ( LPT: https://regex101.com/ is great for working out regex patterns )
194
-        if (preg_match('((((.*?))(,\s))+)', $create_sql, $valid_column_data)) {
195
-            $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
196
-            /** @var \wpdb $wpdb */
197
-            global $wpdb;
198
-            $SQL = "CREATE TABLE {$table_name} ( {$create_sql} ) ENGINE={$engine} " . $wpdb->get_charset_collate();
175
+	/**
176
+	 * Just creates the requested table. $table_name can
177
+	 * optionally start with $wpdb->prefix or not
178
+	 *
179
+	 * @param string $table_name
180
+	 * @param string $create_sql defining the table's columns and indexes
181
+	 * @param string $engine     (no need to specify "ENGINE=", that's implied)
182
+	 * @return void
183
+	 * @throws \EE_Error
184
+	 */
185
+	public function createTable($table_name, $create_sql, $engine = 'MyISAM')
186
+	{
187
+		$engine = apply_filters(
188
+			'FHEE__EventEspresso_core_services_database_TableManager__createTable__engine',
189
+			$engine,
190
+			$table_name,
191
+			$create_sql
192
+		);
193
+		// does $sql contain valid column information? ( LPT: https://regex101.com/ is great for working out regex patterns )
194
+		if (preg_match('((((.*?))(,\s))+)', $create_sql, $valid_column_data)) {
195
+			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
196
+			/** @var \wpdb $wpdb */
197
+			global $wpdb;
198
+			$SQL = "CREATE TABLE {$table_name} ( {$create_sql} ) ENGINE={$engine} " . $wpdb->get_charset_collate();
199 199
 
200
-            // get $wpdb to echo errors, but buffer them. This way at least WE know an error
201
-            // happened. And then we can choose to tell the end user
202
-            $old_show_errors_policy = $wpdb->show_errors(true);
203
-            $old_error_suppression_policy = $wpdb->suppress_errors(false);
204
-            ob_start();
205
-            dbDelta($SQL);
206
-            $output = ob_get_contents();
207
-            ob_end_clean();
208
-            $wpdb->show_errors($old_show_errors_policy);
209
-            $wpdb->suppress_errors($old_error_suppression_policy);
210
-            if (! empty($output)) {
211
-                throw new \EE_Error($output);
212
-            }
213
-        } else {
214
-            throw new \EE_Error(
215
-                sprintf(
216
-                    __(
217
-                        'The following table creation SQL does not contain valid information about the table columns: %1$s %2$s',
218
-                        'event_espresso'
219
-                    ),
220
-                    '<br />',
221
-                    $create_sql
222
-                )
223
-            );
224
-        }
225
-    }
200
+			// get $wpdb to echo errors, but buffer them. This way at least WE know an error
201
+			// happened. And then we can choose to tell the end user
202
+			$old_show_errors_policy = $wpdb->show_errors(true);
203
+			$old_error_suppression_policy = $wpdb->suppress_errors(false);
204
+			ob_start();
205
+			dbDelta($SQL);
206
+			$output = ob_get_contents();
207
+			ob_end_clean();
208
+			$wpdb->show_errors($old_show_errors_policy);
209
+			$wpdb->suppress_errors($old_error_suppression_policy);
210
+			if (! empty($output)) {
211
+				throw new \EE_Error($output);
212
+			}
213
+		} else {
214
+			throw new \EE_Error(
215
+				sprintf(
216
+					__(
217
+						'The following table creation SQL does not contain valid information about the table columns: %1$s %2$s',
218
+						'event_espresso'
219
+					),
220
+					'<br />',
221
+					$create_sql
222
+				)
223
+			);
224
+		}
225
+	}
226 226
 
227 227
 
228
-    /**
229
-     * Drops the specified index if it's size differs from $desired_index_size.
230
-     * WordPress' dbdelta method doesn't automatically change index sizes, so this
231
-     * method can be used to only drop the index if needed, and afterwards dbdelta can be used as normal.
232
-     * If the table doesn't exist, or it exists but the index does not, or returns false
233
-     *
234
-     * @param string     $table_name
235
-     * @param string     $index_name
236
-     * @param string     $column_name        if none is provided, we assume the column name matches the index (often
237
-     *                                       true in EE)
238
-     * @param string|int $desired_index_size defaults to TableAnalysis::index_col_size, the max for utf8mb4.
239
-     * @return bool whether an index was dropped or not
240
-     * @throws /EE_Error if table analysis object isn't defined
241
-     */
242
-    public function dropIndexIfSizeNot(
243
-        $table_name,
244
-        $index_name,
245
-        $column_name = null,
246
-        $desired_index_size = TableAnalysis::INDEX_COLUMN_SIZE
247
-    ) {
248
-        if ($column_name === null) {
249
-            $column_name = $index_name;
250
-        }
251
-        if (! $this->getTableAnalysis()->tableExists($table_name)) {
252
-            return false;
253
-        }
254
-        $index_entries = $this->getTableAnalysis()->showIndexes($table_name, $index_name);
255
-        if (empty($index_entries)) {
256
-            return false;
257
-        }
258
-        foreach ($index_entries as $index_entry) {
259
-            if ($column_name === $index_entry->Column_name
260
-                && (string) $desired_index_size !== $index_entry->Sub_part) {
261
-                return $this->dropIndex($table_name, $index_name);
262
-            }
263
-        }
264
-        return false;
265
-    }
228
+	/**
229
+	 * Drops the specified index if it's size differs from $desired_index_size.
230
+	 * WordPress' dbdelta method doesn't automatically change index sizes, so this
231
+	 * method can be used to only drop the index if needed, and afterwards dbdelta can be used as normal.
232
+	 * If the table doesn't exist, or it exists but the index does not, or returns false
233
+	 *
234
+	 * @param string     $table_name
235
+	 * @param string     $index_name
236
+	 * @param string     $column_name        if none is provided, we assume the column name matches the index (often
237
+	 *                                       true in EE)
238
+	 * @param string|int $desired_index_size defaults to TableAnalysis::index_col_size, the max for utf8mb4.
239
+	 * @return bool whether an index was dropped or not
240
+	 * @throws /EE_Error if table analysis object isn't defined
241
+	 */
242
+	public function dropIndexIfSizeNot(
243
+		$table_name,
244
+		$index_name,
245
+		$column_name = null,
246
+		$desired_index_size = TableAnalysis::INDEX_COLUMN_SIZE
247
+	) {
248
+		if ($column_name === null) {
249
+			$column_name = $index_name;
250
+		}
251
+		if (! $this->getTableAnalysis()->tableExists($table_name)) {
252
+			return false;
253
+		}
254
+		$index_entries = $this->getTableAnalysis()->showIndexes($table_name, $index_name);
255
+		if (empty($index_entries)) {
256
+			return false;
257
+		}
258
+		foreach ($index_entries as $index_entry) {
259
+			if ($column_name === $index_entry->Column_name
260
+				&& (string) $desired_index_size !== $index_entry->Sub_part) {
261
+				return $this->dropIndex($table_name, $index_name);
262
+			}
263
+		}
264
+		return false;
265
+	}
266 266
 }
Please login to merge, or discard this patch.
core/domain/services/assets/CoreAssetManager.php 1 patch
Indentation   +531 added lines, -531 removed lines patch added patch discarded remove patch
@@ -31,554 +31,554 @@
 block discarded – undo
31 31
 class CoreAssetManager extends AssetManager
32 32
 {
33 33
 
34
-    // WordPress core / Third party JS asset handles
35
-    const JS_HANDLE_JQUERY = 'jquery';
34
+	// WordPress core / Third party JS asset handles
35
+	const JS_HANDLE_JQUERY = 'jquery';
36 36
 
37
-    const JS_HANDLE_JQUERY_VALIDATE = 'jquery-validate';
37
+	const JS_HANDLE_JQUERY_VALIDATE = 'jquery-validate';
38 38
 
39
-    const JS_HANDLE_JQUERY_VALIDATE_EXTRA = 'jquery-validate-extra-methods';
39
+	const JS_HANDLE_JQUERY_VALIDATE_EXTRA = 'jquery-validate-extra-methods';
40 40
 
41
-    const JS_HANDLE_UNDERSCORE = 'underscore';
41
+	const JS_HANDLE_UNDERSCORE = 'underscore';
42 42
 
43
-    const JS_HANDLE_ACCOUNTING_CORE = 'ee-accounting-core';
43
+	const JS_HANDLE_ACCOUNTING_CORE = 'ee-accounting-core';
44 44
 
45
-    /**
46
-     * @since 4.9.71.p
47
-     */
48
-    const JS_HANDLE_REACT = 'react';
45
+	/**
46
+	 * @since 4.9.71.p
47
+	 */
48
+	const JS_HANDLE_REACT = 'react';
49 49
 
50
-    /**
51
-     * @since 4.9.71.p
52
-     */
53
-    const JS_HANDLE_REACT_DOM = 'react-dom';
50
+	/**
51
+	 * @since 4.9.71.p
52
+	 */
53
+	const JS_HANDLE_REACT_DOM = 'react-dom';
54 54
 
55
-    /**
56
-     * @since 4.9.71.p
57
-     */
58
-    const JS_HANDLE_LODASH = 'lodash';
55
+	/**
56
+	 * @since 4.9.71.p
57
+	 */
58
+	const JS_HANDLE_LODASH = 'lodash';
59 59
 
60
-    // EE JS assets handles
61
-    const JS_HANDLE_MANIFEST = 'ee-manifest';
60
+	// EE JS assets handles
61
+	const JS_HANDLE_MANIFEST = 'ee-manifest';
62 62
 
63
-    const JS_HANDLE_JS_CORE = 'eejs-core';
63
+	const JS_HANDLE_JS_CORE = 'eejs-core';
64 64
 
65
-    const JS_HANDLE_VENDOR = 'eventespresso-vendor';
65
+	const JS_HANDLE_VENDOR = 'eventespresso-vendor';
66 66
 
67
-    const JS_HANDLE_DATA_STORES = 'eventespresso-data-stores';
67
+	const JS_HANDLE_DATA_STORES = 'eventespresso-data-stores';
68 68
 
69
-    const JS_HANDLE_HELPERS = 'eventespresso-helpers';
69
+	const JS_HANDLE_HELPERS = 'eventespresso-helpers';
70 70
 
71
-    const JS_HANDLE_MODEL = 'eventespresso-model';
71
+	const JS_HANDLE_MODEL = 'eventespresso-model';
72 72
 
73
-    const JS_HANDLE_VALUE_OBJECTS = 'eventespresso-value-objects';
73
+	const JS_HANDLE_VALUE_OBJECTS = 'eventespresso-value-objects';
74 74
 
75
-    const JS_HANDLE_HOCS = 'eventespresso-hocs';
75
+	const JS_HANDLE_HOCS = 'eventespresso-hocs';
76 76
 
77
-    const JS_HANDLE_COMPONENTS = 'eventespresso-components';
78
-
79
-    const JS_HANDLE_EDITOR_HOCS = 'eventespresso-editor-hocs';
77
+	const JS_HANDLE_COMPONENTS = 'eventespresso-components';
78
+
79
+	const JS_HANDLE_EDITOR_HOCS = 'eventespresso-editor-hocs';
80 80
 
81
-    const JS_HANDLE_VALIDATORS = 'eventespresso-validators';
81
+	const JS_HANDLE_VALIDATORS = 'eventespresso-validators';
82 82
 
83
-    const JS_HANDLE_CORE = 'espresso_core';
83
+	const JS_HANDLE_CORE = 'espresso_core';
84 84
 
85
-    const JS_HANDLE_I18N = 'eei18n';
86
-
87
-    const JS_HANDLE_ACCOUNTING = 'ee-accounting';
88
-
89
-    const JS_HANDLE_WP_PLUGINS_PAGE = 'ee-wp-plugins-page';
90
-
91
-    // EE CSS assets handles
92
-    const CSS_HANDLE_DEFAULT = 'espresso_default';
93
-
94
-    const CSS_HANDLE_CUSTOM = 'espresso_custom_css';
95
-
96
-    const CSS_HANDLE_COMPONENTS = 'eventespresso-components';
97
-
98
-    /**
99
-     * @var EE_Currency_Config $currency_config
100
-     */
101
-    protected $currency_config;
102
-
103
-    /**
104
-     * @var EE_Template_Config $template_config
105
-     */
106
-    protected $template_config;
107
-
108
-
109
-    /**
110
-     * CoreAssetRegister constructor.
111
-     *
112
-     * @param AssetCollection    $assets
113
-     * @param EE_Currency_Config $currency_config
114
-     * @param EE_Template_Config $template_config
115
-     * @param DomainInterface    $domain
116
-     * @param Registry           $registry
117
-     */
118
-    public function __construct(
119
-        AssetCollection $assets,
120
-        EE_Currency_Config $currency_config,
121
-        EE_Template_Config $template_config,
122
-        DomainInterface $domain,
123
-        Registry $registry
124
-    ) {
125
-        $this->currency_config = $currency_config;
126
-        $this->template_config = $template_config;
127
-        parent::__construct($domain, $assets, $registry);
128
-    }
129
-
130
-
131
-    /**
132
-     * @since 4.9.62.p
133
-     * @throws DomainException
134
-     * @throws DuplicateCollectionIdentifierException
135
-     * @throws InvalidArgumentException
136
-     * @throws InvalidDataTypeException
137
-     * @throws InvalidEntityException
138
-     * @throws InvalidInterfaceException
139
-     */
140
-    public function addAssets()
141
-    {
142
-        $this->addJavascriptFiles();
143
-        $this->addStylesheetFiles();
144
-    }
145
-
146
-
147
-    /**
148
-     * @since 4.9.62.p
149
-     * @throws DomainException
150
-     * @throws DuplicateCollectionIdentifierException
151
-     * @throws InvalidArgumentException
152
-     * @throws InvalidDataTypeException
153
-     * @throws InvalidEntityException
154
-     * @throws InvalidInterfaceException
155
-     */
156
-    public function addJavascriptFiles()
157
-    {
158
-        $this->loadCoreJs();
159
-        $this->loadJqueryValidate();
160
-        $this->loadAccountingJs();
161
-        add_action(
162
-            'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__before_script',
163
-            array($this, 'loadQtipJs')
164
-        );
165
-        $this->registerAdminAssets();
166
-    }
167
-
168
-
169
-    /**
170
-     * @since 4.9.62.p
171
-     * @throws DuplicateCollectionIdentifierException
172
-     * @throws InvalidDataTypeException
173
-     * @throws InvalidEntityException
174
-     */
175
-    public function addStylesheetFiles()
176
-    {
177
-        $this->loadCoreCss();
178
-    }
179
-
180
-
181
-    /**
182
-     * core default javascript
183
-     *
184
-     * @since 4.9.62.p
185
-     * @throws DomainException
186
-     * @throws DuplicateCollectionIdentifierException
187
-     * @throws InvalidArgumentException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidEntityException
190
-     * @throws InvalidInterfaceException
191
-     */
192
-    private function loadCoreJs()
193
-    {
194
-        // conditionally load third-party libraries that WP core MIGHT have.
195
-        $this->registerWpAssets();
196
-
197
-        $this->addJavascript(
198
-            CoreAssetManager::JS_HANDLE_MANIFEST,
199
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'manifest')
200
-        );
201
-
202
-        $this->addJavascript(
203
-            CoreAssetManager::JS_HANDLE_JS_CORE,
204
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'eejs'),
205
-            array(CoreAssetManager::JS_HANDLE_MANIFEST)
206
-        )
207
-        ->setHasInlineData();
208
-
209
-        $this->addJavascript(
210
-            CoreAssetManager::JS_HANDLE_VENDOR,
211
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'vendor'),
212
-            array(
213
-                CoreAssetManager::JS_HANDLE_JS_CORE,
214
-                CoreAssetManager::JS_HANDLE_REACT,
215
-                CoreAssetManager::JS_HANDLE_REACT_DOM,
216
-                CoreAssetManager::JS_HANDLE_LODASH,
217
-            )
218
-        );
219
-
220
-        $this->addJavascript(
221
-            CoreAssetManager::JS_HANDLE_VALIDATORS,
222
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'validators')
223
-        )->setRequiresTranslation();
224
-
225
-        $this->addJavascript(
226
-            CoreAssetManager::JS_HANDLE_HELPERS,
227
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'helpers'),
228
-            array(
229
-                CoreAssetManager::JS_HANDLE_VALIDATORS
230
-            )
231
-        )->setRequiresTranslation();
232
-
233
-        $this->addJavascript(
234
-            CoreAssetManager::JS_HANDLE_MODEL,
235
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'model'),
236
-            array(
237
-                CoreAssetManager::JS_HANDLE_HELPERS
238
-            )
239
-        )->setRequiresTranslation();
240
-
241
-        $this->addJavascript(
242
-            CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
243
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'valueObjects'),
244
-            array(
245
-                CoreAssetManager::JS_HANDLE_MODEL
246
-            )
247
-        )->setRequiresTranslation();
248
-
249
-        $this->addJavascript(
250
-            CoreAssetManager::JS_HANDLE_DATA_STORES,
251
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'data-stores'),
252
-            array(
253
-                CoreAssetManager::JS_HANDLE_VENDOR,
254
-                'wp-data',
255
-                'wp-api-fetch',
256
-                CoreAssetManager::JS_HANDLE_VALUE_OBJECTS
257
-            )
258
-        )
259
-             ->setRequiresTranslation()
260
-             ->setInlineDataCallback(
261
-                 function() {
262
-                     wp_add_inline_script(
263
-                         CoreAssetManager::JS_HANDLE_DATA_STORES,
264
-                         is_admin()
265
-                             ? 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware( eejs.middleWares.apiFetch.CONTEXT_CAPS_EDIT ) )'
266
-                             : 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware )'
267
-                     );
268
-                 }
269
-             );
270
-
271
-        $this->addJavascript(
272
-            CoreAssetManager::JS_HANDLE_HOCS,
273
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'hocs'),
274
-            array(
275
-                CoreAssetManager::JS_HANDLE_DATA_STORES,
276
-                CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
277
-                'wp-components',
278
-            )
279
-        )->setRequiresTranslation();
280
-
281
-        $this->addJavascript(
282
-            CoreAssetManager::JS_HANDLE_COMPONENTS,
283
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'components'),
284
-            array(
285
-                CoreAssetManager::JS_HANDLE_DATA_STORES,
286
-                CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
287
-                'wp-components',
288
-            )
289
-        )
290
-        ->setRequiresTranslation();
291
-
292
-        $this->addJavascript(
293
-            CoreAssetManager::JS_HANDLE_EDITOR_HOCS,
294
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'editor-hocs'),
295
-            array(
296
-                CoreAssetManager::JS_HANDLE_COMPONENTS
297
-            )
298
-        )->setRequiresTranslation();
299
-
300
-        $this->registry->addData('eejs_api_nonce', wp_create_nonce('wp_rest'));
301
-        $this->registry->addData(
302
-            'paths',
303
-            array(
304
-                'base_rest_route' => rest_url(),
305
-                'rest_route' => rest_url('ee/v4.8.36/'),
306
-                'collection_endpoints' => EED_Core_Rest_Api::getCollectionRoutesIndexedByModelName(),
307
-                'primary_keys' => EED_Core_Rest_Api::getPrimaryKeyNamesIndexedByModelName(),
308
-                'site_url' => site_url('/'),
309
-                'admin_url' => admin_url('/'),
310
-            )
311
-        );
312
-        /** site formatting values **/
313
-        $this->registry->addData(
314
-            'site_formats',
315
-            array(
316
-                'date_formats' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats()
317
-            )
318
-        );
319
-        /** currency data **/
320
-        $this->registry->addData(
321
-            'currency_config',
322
-            $this->getCurrencySettings()
323
-        );
324
-        /** site timezone */
325
-        $this->registry->addData(
326
-            'default_timezone',
327
-            array(
328
-                'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
329
-                'string' => get_option('timezone_string'),
330
-                'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
331
-            )
332
-        );
333
-        /** site locale (user locale if user logged in) */
334
-        $this->registry->addData(
335
-            'locale',
336
-            array(
337
-                'user' => get_user_locale(),
338
-                'site' => get_locale()
339
-            )
340
-        );
341
-
342
-        $this->addJavascript(
343
-            CoreAssetManager::JS_HANDLE_CORE,
344
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
345
-            array(CoreAssetManager::JS_HANDLE_JQUERY)
346
-        )
347
-        ->setInlineDataCallback(
348
-            function () {
349
-                wp_localize_script(
350
-                    CoreAssetManager::JS_HANDLE_CORE,
351
-                    CoreAssetManager::JS_HANDLE_I18N,
352
-                    EE_Registry::$i18n_js_strings
353
-                );
354
-            }
355
-        );
356
-    }
357
-
358
-
359
-    /**
360
-     * Registers vendor files that are bundled with a later version WP but might not be for the current version of
361
-     * WordPress in the running environment.
362
-     *
363
-     * @throws DuplicateCollectionIdentifierException
364
-     * @throws InvalidDataTypeException
365
-     * @throws InvalidEntityException
366
-     * @throws DomainException
367
-     * @since 4.9.71.p
368
-     */
369
-    private function registerWpAssets()
370
-    {
371
-        global $wp_version;
372
-        if (version_compare($wp_version, '5.0.beta', '>=')) {
373
-            return;
374
-        }
375
-        $this->addVendorJavascript(CoreAssetManager::JS_HANDLE_REACT)
376
-            ->setVersion('16.6.0');
377
-        $this->addVendorJavascript(
378
-            CoreAssetManager::JS_HANDLE_REACT_DOM,
379
-            array(CoreAssetManager::JS_HANDLE_REACT)
380
-        )->setVersion('16.6.0');
381
-        $this->addVendorJavascript(CoreAssetManager::JS_HANDLE_LODASH)
382
-            ->setInlineDataCallback(
383
-                function() {
384
-                    wp_add_inline_script(
385
-                        CoreAssetManager::JS_HANDLE_LODASH,
386
-                        'window.lodash = _.noConflict();'
387
-                    );
388
-                }
389
-            )
390
-            ->setVersion('4.17.11');
391
-    }
392
-
393
-
394
-    /**
395
-     * Returns configuration data for the accounting-js library.
396
-     * @since 4.9.71.p
397
-     * @return array
398
-     */
399
-    private function getAccountingSettings() {
400
-        return array(
401
-            'currency' => array(
402
-                'symbol'    => $this->currency_config->sign,
403
-                'format'    => array(
404
-                    'pos'  => $this->currency_config->sign_b4 ? '%s%v' : '%v%s',
405
-                    'neg'  => $this->currency_config->sign_b4 ? '- %s%v' : '- %v%s',
406
-                    'zero' => $this->currency_config->sign_b4 ? '%s--' : '--%s',
407
-                ),
408
-                'decimal'   => $this->currency_config->dec_mrk,
409
-                'thousand'  => $this->currency_config->thsnds,
410
-                'precision' => $this->currency_config->dec_plc,
411
-            ),
412
-            'number'   => array(
413
-                'precision' => $this->currency_config->dec_plc,
414
-                'thousand'  => $this->currency_config->thsnds,
415
-                'decimal'   => $this->currency_config->dec_mrk,
416
-            ),
417
-        );
418
-    }
419
-
420
-
421
-    /**
422
-     * Returns configuration data for the js Currency VO.
423
-     * @since 4.9.71.p
424
-     * @return array
425
-     */
426
-    private function getCurrencySettings()
427
-    {
428
-        return array(
429
-            'code' => $this->currency_config->code,
430
-            'singularLabel' => $this->currency_config->name,
431
-            'pluralLabel' => $this->currency_config->plural,
432
-            'sign' => $this->currency_config->sign,
433
-            'signB4' => $this->currency_config->sign_b4,
434
-            'decimalPlaces' => $this->currency_config->dec_plc,
435
-            'decimalMark' => $this->currency_config->dec_mrk,
436
-            'thousandsSeparator' => $this->currency_config->thsnds,
437
-        );
438
-    }
439
-
440
-
441
-    /**
442
-     * @since 4.9.62.p
443
-     * @throws DuplicateCollectionIdentifierException
444
-     * @throws InvalidDataTypeException
445
-     * @throws InvalidEntityException
446
-     */
447
-    private function loadCoreCss()
448
-    {
449
-        if ($this->template_config->enable_default_style && ! is_admin()) {
450
-            $this->addStylesheet(
451
-                CoreAssetManager::CSS_HANDLE_DEFAULT,
452
-                is_readable(EVENT_ESPRESSO_UPLOAD_DIR . 'css/style.css')
453
-                    ? EVENT_ESPRESSO_UPLOAD_DIR . 'css/espresso_default.css'
454
-                    : EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
455
-                array('dashicons')
456
-            );
457
-            //Load custom style sheet if available
458
-            if ($this->template_config->custom_style_sheet !== null) {
459
-                $this->addStylesheet(
460
-                    CoreAssetManager::CSS_HANDLE_CUSTOM,
461
-                    EVENT_ESPRESSO_UPLOAD_URL . 'css/' . $this->template_config->custom_style_sheet,
462
-                    array(CoreAssetManager::CSS_HANDLE_DEFAULT)
463
-                );
464
-            }
465
-        }
466
-        $this->addStylesheet(
467
-            CoreAssetManager::CSS_HANDLE_COMPONENTS,
468
-            $this->registry->getCssUrl(
469
-                $this->domain->assetNamespace(),
470
-                'components'
471
-            )
472
-        );
473
-    }
474
-
475
-
476
-    /**
477
-     * jQuery Validate for form validation
478
-     *
479
-     * @since 4.9.62.p
480
-     * @throws DomainException
481
-     * @throws DuplicateCollectionIdentifierException
482
-     * @throws InvalidDataTypeException
483
-     * @throws InvalidEntityException
484
-     */
485
-    private function loadJqueryValidate()
486
-    {
487
-        $this->addJavascript(
488
-            CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE,
489
-            EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.min.js',
490
-            array(CoreAssetManager::JS_HANDLE_JQUERY)
491
-        )
492
-        ->setVersion('1.15.0');
493
-
494
-        $this->addJavascript(
495
-            CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE_EXTRA,
496
-            EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.additional-methods.min.js',
497
-            array(CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE)
498
-        )
499
-        ->setVersion('1.15.0');
500
-    }
501
-
502
-
503
-    /**
504
-     * accounting.js for performing client-side calculations
505
-     *
506
-     * @since 4.9.62.p
507
-     * @throws DomainException
508
-     * @throws DuplicateCollectionIdentifierException
509
-     * @throws InvalidDataTypeException
510
-     * @throws InvalidEntityException
511
-     */
512
-    private function loadAccountingJs()
513
-    {
514
-        //accounting.js library
515
-        // @link http://josscrowcroft.github.io/accounting.js/
516
-        $this->addJavascript(
517
-            CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE,
518
-            EE_THIRD_PARTY_URL . 'accounting/accounting.js',
519
-            array(CoreAssetManager::JS_HANDLE_UNDERSCORE)
520
-        )
521
-        ->setVersion('0.3.2');
522
-
523
-        $this->addJavascript(
524
-            CoreAssetManager::JS_HANDLE_ACCOUNTING,
525
-            EE_GLOBAL_ASSETS_URL . 'scripts/ee-accounting-config.js',
526
-            array(CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE)
527
-        )
528
-        ->setInlineDataCallback(
529
-            function () {
530
-                 wp_localize_script(
531
-                     CoreAssetManager::JS_HANDLE_ACCOUNTING,
532
-                     'EE_ACCOUNTING_CFG',
533
-                     $this->getAccountingSettings()
534
-                 );
535
-            }
536
-        )
537
-        ->setVersion();
538
-    }
539
-
540
-
541
-    /**
542
-     * registers assets for cleaning your ears
543
-     *
544
-     * @param JavascriptAsset $script
545
-     */
546
-    public function loadQtipJs(JavascriptAsset $script)
547
-    {
548
-        // qtip is turned OFF by default, but prior to the wp_enqueue_scripts hook,
549
-        // can be turned back on again via: add_filter('FHEE_load_qtip', '__return_true' );
550
-        if (
551
-            $script->handle() === CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE
552
-            && apply_filters('FHEE_load_qtip', false)
553
-        ) {
554
-            EEH_Qtip_Loader::instance()->register_and_enqueue();
555
-        }
556
-    }
557
-
558
-
559
-    /**
560
-     * assets that are used in the WordPress admin
561
-     *
562
-     * @since 4.9.62.p
563
-     * @throws DuplicateCollectionIdentifierException
564
-     * @throws InvalidDataTypeException
565
-     * @throws InvalidEntityException
566
-     */
567
-    private function registerAdminAssets()
568
-    {
569
-        $this->addJavascript(
570
-            CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
571
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'wp-plugins-page'),
572
-            array(
573
-                CoreAssetManager::JS_HANDLE_JQUERY,
574
-                CoreAssetManager::JS_HANDLE_VENDOR,
575
-            )
576
-        )
577
-        ->setRequiresTranslation();
578
-
579
-        $this->addStylesheet(
580
-            CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
581
-            $this->registry->getCssUrl($this->domain->assetNamespace(), 'wp-plugins-page')
582
-        );
583
-    }
85
+	const JS_HANDLE_I18N = 'eei18n';
86
+
87
+	const JS_HANDLE_ACCOUNTING = 'ee-accounting';
88
+
89
+	const JS_HANDLE_WP_PLUGINS_PAGE = 'ee-wp-plugins-page';
90
+
91
+	// EE CSS assets handles
92
+	const CSS_HANDLE_DEFAULT = 'espresso_default';
93
+
94
+	const CSS_HANDLE_CUSTOM = 'espresso_custom_css';
95
+
96
+	const CSS_HANDLE_COMPONENTS = 'eventespresso-components';
97
+
98
+	/**
99
+	 * @var EE_Currency_Config $currency_config
100
+	 */
101
+	protected $currency_config;
102
+
103
+	/**
104
+	 * @var EE_Template_Config $template_config
105
+	 */
106
+	protected $template_config;
107
+
108
+
109
+	/**
110
+	 * CoreAssetRegister constructor.
111
+	 *
112
+	 * @param AssetCollection    $assets
113
+	 * @param EE_Currency_Config $currency_config
114
+	 * @param EE_Template_Config $template_config
115
+	 * @param DomainInterface    $domain
116
+	 * @param Registry           $registry
117
+	 */
118
+	public function __construct(
119
+		AssetCollection $assets,
120
+		EE_Currency_Config $currency_config,
121
+		EE_Template_Config $template_config,
122
+		DomainInterface $domain,
123
+		Registry $registry
124
+	) {
125
+		$this->currency_config = $currency_config;
126
+		$this->template_config = $template_config;
127
+		parent::__construct($domain, $assets, $registry);
128
+	}
129
+
130
+
131
+	/**
132
+	 * @since 4.9.62.p
133
+	 * @throws DomainException
134
+	 * @throws DuplicateCollectionIdentifierException
135
+	 * @throws InvalidArgumentException
136
+	 * @throws InvalidDataTypeException
137
+	 * @throws InvalidEntityException
138
+	 * @throws InvalidInterfaceException
139
+	 */
140
+	public function addAssets()
141
+	{
142
+		$this->addJavascriptFiles();
143
+		$this->addStylesheetFiles();
144
+	}
145
+
146
+
147
+	/**
148
+	 * @since 4.9.62.p
149
+	 * @throws DomainException
150
+	 * @throws DuplicateCollectionIdentifierException
151
+	 * @throws InvalidArgumentException
152
+	 * @throws InvalidDataTypeException
153
+	 * @throws InvalidEntityException
154
+	 * @throws InvalidInterfaceException
155
+	 */
156
+	public function addJavascriptFiles()
157
+	{
158
+		$this->loadCoreJs();
159
+		$this->loadJqueryValidate();
160
+		$this->loadAccountingJs();
161
+		add_action(
162
+			'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__before_script',
163
+			array($this, 'loadQtipJs')
164
+		);
165
+		$this->registerAdminAssets();
166
+	}
167
+
168
+
169
+	/**
170
+	 * @since 4.9.62.p
171
+	 * @throws DuplicateCollectionIdentifierException
172
+	 * @throws InvalidDataTypeException
173
+	 * @throws InvalidEntityException
174
+	 */
175
+	public function addStylesheetFiles()
176
+	{
177
+		$this->loadCoreCss();
178
+	}
179
+
180
+
181
+	/**
182
+	 * core default javascript
183
+	 *
184
+	 * @since 4.9.62.p
185
+	 * @throws DomainException
186
+	 * @throws DuplicateCollectionIdentifierException
187
+	 * @throws InvalidArgumentException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidEntityException
190
+	 * @throws InvalidInterfaceException
191
+	 */
192
+	private function loadCoreJs()
193
+	{
194
+		// conditionally load third-party libraries that WP core MIGHT have.
195
+		$this->registerWpAssets();
196
+
197
+		$this->addJavascript(
198
+			CoreAssetManager::JS_HANDLE_MANIFEST,
199
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'manifest')
200
+		);
201
+
202
+		$this->addJavascript(
203
+			CoreAssetManager::JS_HANDLE_JS_CORE,
204
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'eejs'),
205
+			array(CoreAssetManager::JS_HANDLE_MANIFEST)
206
+		)
207
+		->setHasInlineData();
208
+
209
+		$this->addJavascript(
210
+			CoreAssetManager::JS_HANDLE_VENDOR,
211
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'vendor'),
212
+			array(
213
+				CoreAssetManager::JS_HANDLE_JS_CORE,
214
+				CoreAssetManager::JS_HANDLE_REACT,
215
+				CoreAssetManager::JS_HANDLE_REACT_DOM,
216
+				CoreAssetManager::JS_HANDLE_LODASH,
217
+			)
218
+		);
219
+
220
+		$this->addJavascript(
221
+			CoreAssetManager::JS_HANDLE_VALIDATORS,
222
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'validators')
223
+		)->setRequiresTranslation();
224
+
225
+		$this->addJavascript(
226
+			CoreAssetManager::JS_HANDLE_HELPERS,
227
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'helpers'),
228
+			array(
229
+				CoreAssetManager::JS_HANDLE_VALIDATORS
230
+			)
231
+		)->setRequiresTranslation();
232
+
233
+		$this->addJavascript(
234
+			CoreAssetManager::JS_HANDLE_MODEL,
235
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'model'),
236
+			array(
237
+				CoreAssetManager::JS_HANDLE_HELPERS
238
+			)
239
+		)->setRequiresTranslation();
240
+
241
+		$this->addJavascript(
242
+			CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
243
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'valueObjects'),
244
+			array(
245
+				CoreAssetManager::JS_HANDLE_MODEL
246
+			)
247
+		)->setRequiresTranslation();
248
+
249
+		$this->addJavascript(
250
+			CoreAssetManager::JS_HANDLE_DATA_STORES,
251
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'data-stores'),
252
+			array(
253
+				CoreAssetManager::JS_HANDLE_VENDOR,
254
+				'wp-data',
255
+				'wp-api-fetch',
256
+				CoreAssetManager::JS_HANDLE_VALUE_OBJECTS
257
+			)
258
+		)
259
+			 ->setRequiresTranslation()
260
+			 ->setInlineDataCallback(
261
+				 function() {
262
+					 wp_add_inline_script(
263
+						 CoreAssetManager::JS_HANDLE_DATA_STORES,
264
+						 is_admin()
265
+							 ? 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware( eejs.middleWares.apiFetch.CONTEXT_CAPS_EDIT ) )'
266
+							 : 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware )'
267
+					 );
268
+				 }
269
+			 );
270
+
271
+		$this->addJavascript(
272
+			CoreAssetManager::JS_HANDLE_HOCS,
273
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'hocs'),
274
+			array(
275
+				CoreAssetManager::JS_HANDLE_DATA_STORES,
276
+				CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
277
+				'wp-components',
278
+			)
279
+		)->setRequiresTranslation();
280
+
281
+		$this->addJavascript(
282
+			CoreAssetManager::JS_HANDLE_COMPONENTS,
283
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'components'),
284
+			array(
285
+				CoreAssetManager::JS_HANDLE_DATA_STORES,
286
+				CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
287
+				'wp-components',
288
+			)
289
+		)
290
+		->setRequiresTranslation();
291
+
292
+		$this->addJavascript(
293
+			CoreAssetManager::JS_HANDLE_EDITOR_HOCS,
294
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'editor-hocs'),
295
+			array(
296
+				CoreAssetManager::JS_HANDLE_COMPONENTS
297
+			)
298
+		)->setRequiresTranslation();
299
+
300
+		$this->registry->addData('eejs_api_nonce', wp_create_nonce('wp_rest'));
301
+		$this->registry->addData(
302
+			'paths',
303
+			array(
304
+				'base_rest_route' => rest_url(),
305
+				'rest_route' => rest_url('ee/v4.8.36/'),
306
+				'collection_endpoints' => EED_Core_Rest_Api::getCollectionRoutesIndexedByModelName(),
307
+				'primary_keys' => EED_Core_Rest_Api::getPrimaryKeyNamesIndexedByModelName(),
308
+				'site_url' => site_url('/'),
309
+				'admin_url' => admin_url('/'),
310
+			)
311
+		);
312
+		/** site formatting values **/
313
+		$this->registry->addData(
314
+			'site_formats',
315
+			array(
316
+				'date_formats' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats()
317
+			)
318
+		);
319
+		/** currency data **/
320
+		$this->registry->addData(
321
+			'currency_config',
322
+			$this->getCurrencySettings()
323
+		);
324
+		/** site timezone */
325
+		$this->registry->addData(
326
+			'default_timezone',
327
+			array(
328
+				'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
329
+				'string' => get_option('timezone_string'),
330
+				'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
331
+			)
332
+		);
333
+		/** site locale (user locale if user logged in) */
334
+		$this->registry->addData(
335
+			'locale',
336
+			array(
337
+				'user' => get_user_locale(),
338
+				'site' => get_locale()
339
+			)
340
+		);
341
+
342
+		$this->addJavascript(
343
+			CoreAssetManager::JS_HANDLE_CORE,
344
+			EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
345
+			array(CoreAssetManager::JS_HANDLE_JQUERY)
346
+		)
347
+		->setInlineDataCallback(
348
+			function () {
349
+				wp_localize_script(
350
+					CoreAssetManager::JS_HANDLE_CORE,
351
+					CoreAssetManager::JS_HANDLE_I18N,
352
+					EE_Registry::$i18n_js_strings
353
+				);
354
+			}
355
+		);
356
+	}
357
+
358
+
359
+	/**
360
+	 * Registers vendor files that are bundled with a later version WP but might not be for the current version of
361
+	 * WordPress in the running environment.
362
+	 *
363
+	 * @throws DuplicateCollectionIdentifierException
364
+	 * @throws InvalidDataTypeException
365
+	 * @throws InvalidEntityException
366
+	 * @throws DomainException
367
+	 * @since 4.9.71.p
368
+	 */
369
+	private function registerWpAssets()
370
+	{
371
+		global $wp_version;
372
+		if (version_compare($wp_version, '5.0.beta', '>=')) {
373
+			return;
374
+		}
375
+		$this->addVendorJavascript(CoreAssetManager::JS_HANDLE_REACT)
376
+			->setVersion('16.6.0');
377
+		$this->addVendorJavascript(
378
+			CoreAssetManager::JS_HANDLE_REACT_DOM,
379
+			array(CoreAssetManager::JS_HANDLE_REACT)
380
+		)->setVersion('16.6.0');
381
+		$this->addVendorJavascript(CoreAssetManager::JS_HANDLE_LODASH)
382
+			->setInlineDataCallback(
383
+				function() {
384
+					wp_add_inline_script(
385
+						CoreAssetManager::JS_HANDLE_LODASH,
386
+						'window.lodash = _.noConflict();'
387
+					);
388
+				}
389
+			)
390
+			->setVersion('4.17.11');
391
+	}
392
+
393
+
394
+	/**
395
+	 * Returns configuration data for the accounting-js library.
396
+	 * @since 4.9.71.p
397
+	 * @return array
398
+	 */
399
+	private function getAccountingSettings() {
400
+		return array(
401
+			'currency' => array(
402
+				'symbol'    => $this->currency_config->sign,
403
+				'format'    => array(
404
+					'pos'  => $this->currency_config->sign_b4 ? '%s%v' : '%v%s',
405
+					'neg'  => $this->currency_config->sign_b4 ? '- %s%v' : '- %v%s',
406
+					'zero' => $this->currency_config->sign_b4 ? '%s--' : '--%s',
407
+				),
408
+				'decimal'   => $this->currency_config->dec_mrk,
409
+				'thousand'  => $this->currency_config->thsnds,
410
+				'precision' => $this->currency_config->dec_plc,
411
+			),
412
+			'number'   => array(
413
+				'precision' => $this->currency_config->dec_plc,
414
+				'thousand'  => $this->currency_config->thsnds,
415
+				'decimal'   => $this->currency_config->dec_mrk,
416
+			),
417
+		);
418
+	}
419
+
420
+
421
+	/**
422
+	 * Returns configuration data for the js Currency VO.
423
+	 * @since 4.9.71.p
424
+	 * @return array
425
+	 */
426
+	private function getCurrencySettings()
427
+	{
428
+		return array(
429
+			'code' => $this->currency_config->code,
430
+			'singularLabel' => $this->currency_config->name,
431
+			'pluralLabel' => $this->currency_config->plural,
432
+			'sign' => $this->currency_config->sign,
433
+			'signB4' => $this->currency_config->sign_b4,
434
+			'decimalPlaces' => $this->currency_config->dec_plc,
435
+			'decimalMark' => $this->currency_config->dec_mrk,
436
+			'thousandsSeparator' => $this->currency_config->thsnds,
437
+		);
438
+	}
439
+
440
+
441
+	/**
442
+	 * @since 4.9.62.p
443
+	 * @throws DuplicateCollectionIdentifierException
444
+	 * @throws InvalidDataTypeException
445
+	 * @throws InvalidEntityException
446
+	 */
447
+	private function loadCoreCss()
448
+	{
449
+		if ($this->template_config->enable_default_style && ! is_admin()) {
450
+			$this->addStylesheet(
451
+				CoreAssetManager::CSS_HANDLE_DEFAULT,
452
+				is_readable(EVENT_ESPRESSO_UPLOAD_DIR . 'css/style.css')
453
+					? EVENT_ESPRESSO_UPLOAD_DIR . 'css/espresso_default.css'
454
+					: EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
455
+				array('dashicons')
456
+			);
457
+			//Load custom style sheet if available
458
+			if ($this->template_config->custom_style_sheet !== null) {
459
+				$this->addStylesheet(
460
+					CoreAssetManager::CSS_HANDLE_CUSTOM,
461
+					EVENT_ESPRESSO_UPLOAD_URL . 'css/' . $this->template_config->custom_style_sheet,
462
+					array(CoreAssetManager::CSS_HANDLE_DEFAULT)
463
+				);
464
+			}
465
+		}
466
+		$this->addStylesheet(
467
+			CoreAssetManager::CSS_HANDLE_COMPONENTS,
468
+			$this->registry->getCssUrl(
469
+				$this->domain->assetNamespace(),
470
+				'components'
471
+			)
472
+		);
473
+	}
474
+
475
+
476
+	/**
477
+	 * jQuery Validate for form validation
478
+	 *
479
+	 * @since 4.9.62.p
480
+	 * @throws DomainException
481
+	 * @throws DuplicateCollectionIdentifierException
482
+	 * @throws InvalidDataTypeException
483
+	 * @throws InvalidEntityException
484
+	 */
485
+	private function loadJqueryValidate()
486
+	{
487
+		$this->addJavascript(
488
+			CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE,
489
+			EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.min.js',
490
+			array(CoreAssetManager::JS_HANDLE_JQUERY)
491
+		)
492
+		->setVersion('1.15.0');
493
+
494
+		$this->addJavascript(
495
+			CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE_EXTRA,
496
+			EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.additional-methods.min.js',
497
+			array(CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE)
498
+		)
499
+		->setVersion('1.15.0');
500
+	}
501
+
502
+
503
+	/**
504
+	 * accounting.js for performing client-side calculations
505
+	 *
506
+	 * @since 4.9.62.p
507
+	 * @throws DomainException
508
+	 * @throws DuplicateCollectionIdentifierException
509
+	 * @throws InvalidDataTypeException
510
+	 * @throws InvalidEntityException
511
+	 */
512
+	private function loadAccountingJs()
513
+	{
514
+		//accounting.js library
515
+		// @link http://josscrowcroft.github.io/accounting.js/
516
+		$this->addJavascript(
517
+			CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE,
518
+			EE_THIRD_PARTY_URL . 'accounting/accounting.js',
519
+			array(CoreAssetManager::JS_HANDLE_UNDERSCORE)
520
+		)
521
+		->setVersion('0.3.2');
522
+
523
+		$this->addJavascript(
524
+			CoreAssetManager::JS_HANDLE_ACCOUNTING,
525
+			EE_GLOBAL_ASSETS_URL . 'scripts/ee-accounting-config.js',
526
+			array(CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE)
527
+		)
528
+		->setInlineDataCallback(
529
+			function () {
530
+				 wp_localize_script(
531
+					 CoreAssetManager::JS_HANDLE_ACCOUNTING,
532
+					 'EE_ACCOUNTING_CFG',
533
+					 $this->getAccountingSettings()
534
+				 );
535
+			}
536
+		)
537
+		->setVersion();
538
+	}
539
+
540
+
541
+	/**
542
+	 * registers assets for cleaning your ears
543
+	 *
544
+	 * @param JavascriptAsset $script
545
+	 */
546
+	public function loadQtipJs(JavascriptAsset $script)
547
+	{
548
+		// qtip is turned OFF by default, but prior to the wp_enqueue_scripts hook,
549
+		// can be turned back on again via: add_filter('FHEE_load_qtip', '__return_true' );
550
+		if (
551
+			$script->handle() === CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE
552
+			&& apply_filters('FHEE_load_qtip', false)
553
+		) {
554
+			EEH_Qtip_Loader::instance()->register_and_enqueue();
555
+		}
556
+	}
557
+
558
+
559
+	/**
560
+	 * assets that are used in the WordPress admin
561
+	 *
562
+	 * @since 4.9.62.p
563
+	 * @throws DuplicateCollectionIdentifierException
564
+	 * @throws InvalidDataTypeException
565
+	 * @throws InvalidEntityException
566
+	 */
567
+	private function registerAdminAssets()
568
+	{
569
+		$this->addJavascript(
570
+			CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
571
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'wp-plugins-page'),
572
+			array(
573
+				CoreAssetManager::JS_HANDLE_JQUERY,
574
+				CoreAssetManager::JS_HANDLE_VENDOR,
575
+			)
576
+		)
577
+		->setRequiresTranslation();
578
+
579
+		$this->addStylesheet(
580
+			CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
581
+			$this->registry->getCssUrl($this->domain->assetNamespace(), 'wp-plugins-page')
582
+		);
583
+	}
584 584
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Indentation   +1554 added lines, -1554 removed lines patch added patch discarded remove patch
@@ -45,1558 +45,1558 @@
 block discarded – undo
45 45
 {
46 46
 
47 47
 
48
-    /**
49
-     * @var CalculatedModelFields
50
-     */
51
-    protected $fields_calculator;
52
-
53
-
54
-    /**
55
-     * Read constructor.
56
-     * @param CalculatedModelFields $fields_calculator
57
-     */
58
-    public function __construct(CalculatedModelFields $fields_calculator)
59
-    {
60
-        parent::__construct();
61
-        $this->fields_calculator = $fields_calculator;
62
-    }
63
-
64
-
65
-    /**
66
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
67
-     *
68
-     * @param WP_REST_Request $request
69
-     * @param string $version
70
-     * @param string $model_name
71
-     * @return WP_REST_Response|WP_Error
72
-     * @throws InvalidArgumentException
73
-     * @throws InvalidDataTypeException
74
-     * @throws InvalidInterfaceException
75
-     */
76
-    public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
77
-    {
78
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
79
-        try {
80
-            $controller->setRequestedVersion($version);
81
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
82
-                return $controller->sendResponse(
83
-                    new WP_Error(
84
-                        'endpoint_parsing_error',
85
-                        sprintf(
86
-                            __(
87
-                                'There is no model for endpoint %s. Please contact event espresso support',
88
-                                'event_espresso'
89
-                            ),
90
-                            $model_name
91
-                        )
92
-                    )
93
-                );
94
-            }
95
-            return $controller->sendResponse(
96
-                $controller->getEntitiesFromModel(
97
-                    $controller->getModelVersionInfo()->loadModel($model_name),
98
-                    $request
99
-                )
100
-            );
101
-        } catch (Exception $e) {
102
-            return $controller->sendResponse($e);
103
-        }
104
-    }
105
-
106
-
107
-    /**
108
-     * Prepares and returns schema for any OPTIONS request.
109
-     *
110
-     * @param string $version The API endpoint version being used.
111
-     * @param string $model_name Something like `Event` or `Registration`
112
-     * @return array
113
-     * @throws InvalidArgumentException
114
-     * @throws InvalidDataTypeException
115
-     * @throws InvalidInterfaceException
116
-     */
117
-    public static function handleSchemaRequest($version, $model_name)
118
-    {
119
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
120
-        try {
121
-            $controller->setRequestedVersion($version);
122
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
123
-                return array();
124
-            }
125
-            // get the model for this version
126
-            $model = $controller->getModelVersionInfo()->loadModel($model_name);
127
-            $model_schema = new JsonModelSchema($model, LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields'));
128
-            return $model_schema->getModelSchemaForRelations(
129
-                $controller->getModelVersionInfo()->relationSettings($model),
130
-                $controller->customizeSchemaForRestResponse(
131
-                    $model,
132
-                    $model_schema->getModelSchemaForFields(
133
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
134
-                        $model_schema->getInitialSchemaStructure()
135
-                    )
136
-                )
137
-            );
138
-        } catch (Exception $e) {
139
-            return array();
140
-        }
141
-    }
142
-
143
-
144
-    /**
145
-     * This loops through each field in the given schema for the model and does the following:
146
-     * - add any extra fields that are REST API specific and related to existing fields.
147
-     * - transform default values into the correct format for a REST API response.
148
-     *
149
-     * @param EEM_Base $model
150
-     * @param array    $schema
151
-     * @return array  The final schema.
152
-     */
153
-    protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
154
-    {
155
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
156
-            $schema = $this->translateDefaultsForRestResponse(
157
-                $field_name,
158
-                $field,
159
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
160
-            );
161
-        }
162
-        return $schema;
163
-    }
164
-
165
-
166
-    /**
167
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
168
-     * response.
169
-     *
170
-     * @param                      $field_name
171
-     * @param EE_Model_Field_Base  $field
172
-     * @param array                $schema
173
-     * @return array
174
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
175
-     * did, let's know about it ASAP, so let the exception bubble up)
176
-     */
177
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
178
-    {
179
-        if (isset($schema['properties'][ $field_name ]['default'])) {
180
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
181
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
182
-                    if ($default_key === 'raw') {
183
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
184
-                            ModelDataTranslator::prepareFieldValueForJson(
185
-                                $field,
186
-                                $default_value,
187
-                                $this->getModelVersionInfo()->requestedVersion()
188
-                            );
189
-                    }
190
-                }
191
-            } else {
192
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
193
-                    $field,
194
-                    $schema['properties'][ $field_name ]['default'],
195
-                    $this->getModelVersionInfo()->requestedVersion()
196
-                );
197
-            }
198
-        }
199
-        return $schema;
200
-    }
201
-
202
-
203
-    /**
204
-     * Adds additional fields to the schema
205
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
206
-     * needs to be added to the schema.
207
-     *
208
-     * @param                      $field_name
209
-     * @param EE_Model_Field_Base  $field
210
-     * @param array                $schema
211
-     * @return array
212
-     */
213
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
214
-    {
215
-        if ($field instanceof EE_Datetime_Field) {
216
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
217
-            // modify the description
218
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
219
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
220
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
221
-            );
222
-        }
223
-        return $schema;
224
-    }
225
-
226
-
227
-    /**
228
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
229
-     *
230
-     * @return string
231
-     */
232
-    protected function getRouteFromRequest()
233
-    {
234
-        if (isset($GLOBALS['wp'])
235
-            && $GLOBALS['wp'] instanceof \WP
236
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
237
-        ) {
238
-            return $GLOBALS['wp']->query_vars['rest_route'];
239
-        } else {
240
-            return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
241
-        }
242
-    }
243
-
244
-
245
-    /**
246
-     * Gets a single entity related to the model indicated in the path and its id
247
-     *
248
-     * @param WP_REST_Request $request
249
-     * @param string $version
250
-     * @param string $model_name
251
-     * @return WP_REST_Response|WP_Error
252
-     * @throws InvalidDataTypeException
253
-     * @throws InvalidInterfaceException
254
-     * @throws InvalidArgumentException
255
-     */
256
-    public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
257
-    {
258
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
259
-        try {
260
-            $controller->setRequestedVersion($version);
261
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
262
-                return $controller->sendResponse(
263
-                    new WP_Error(
264
-                        'endpoint_parsing_error',
265
-                        sprintf(
266
-                            __(
267
-                                'There is no model for endpoint %s. Please contact event espresso support',
268
-                                'event_espresso'
269
-                            ),
270
-                            $model_name
271
-                        )
272
-                    )
273
-                );
274
-            }
275
-            return $controller->sendResponse(
276
-                $controller->getEntityFromModel(
277
-                    $controller->getModelVersionInfo()->loadModel($model_name),
278
-                    $request
279
-                )
280
-            );
281
-        } catch (Exception $e) {
282
-            return $controller->sendResponse($e);
283
-        }
284
-    }
285
-
286
-
287
-    /**
288
-     * Gets all the related entities (or if its a belongs-to relation just the one)
289
-     * to the item with the given id
290
-     *
291
-     * @param WP_REST_Request $request
292
-     * @param string $version
293
-     * @param string $model_name
294
-     * @param string $related_model_name
295
-     * @return WP_REST_Response|WP_Error
296
-     * @throws InvalidDataTypeException
297
-     * @throws InvalidInterfaceException
298
-     * @throws InvalidArgumentException
299
-     */
300
-    public static function handleRequestGetRelated(
301
-        WP_REST_Request $request,
302
-        $version,
303
-        $model_name,
304
-        $related_model_name
305
-    ) {
306
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
307
-        try {
308
-            $controller->setRequestedVersion($version);
309
-            $main_model = $controller->validateModel($model_name);
310
-            $controller->validateModel($related_model_name);
311
-            return $controller->sendResponse(
312
-                $controller->getEntitiesFromRelation(
313
-                    $request->get_param('id'),
314
-                    $main_model->related_settings_for($related_model_name),
315
-                    $request
316
-                )
317
-            );
318
-        } catch (Exception $e) {
319
-            return $controller->sendResponse($e);
320
-        }
321
-    }
322
-
323
-
324
-    /**
325
-     * Gets a collection for the given model and filters
326
-     *
327
-     * @param EEM_Base $model
328
-     * @param WP_REST_Request $request
329
-     * @return array
330
-     * @throws EE_Error
331
-     * @throws InvalidArgumentException
332
-     * @throws InvalidDataTypeException
333
-     * @throws InvalidInterfaceException
334
-     * @throws ReflectionException
335
-     * @throws RestException
336
-     */
337
-    public function getEntitiesFromModel($model, $request)
338
-    {
339
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
340
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
341
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
342
-            throw new RestException(
343
-                sprintf('rest_%s_cannot_list', $model_name_plural),
344
-                sprintf(
345
-                    __('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
346
-                    $model_name_plural,
347
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
348
-                ),
349
-                array('status' => 403)
350
-            );
351
-        }
352
-        if (! $request->get_header('no_rest_headers')) {
353
-            $this->setHeadersFromQueryParams($model, $query_params);
354
-        }
355
-        /** @type array $results */
356
-        $results = $model->get_all_wpdb_results($query_params);
357
-        $nice_results = array();
358
-        foreach ($results as $result) {
359
-            $nice_results[] =  $this->createEntityFromWpdbResult(
360
-                $model,
361
-                $result,
362
-                $request
363
-            );
364
-        }
365
-        return $nice_results;
366
-    }
367
-
368
-
369
-    /**
370
-     * Gets the collection for given relation object
371
-     * The same as Read::get_entities_from_model(), except if the relation
372
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
373
-     * the join-model-object into the results
374
-     *
375
-     * @param array $primary_model_query_params query params for finding the item from which
376
-     *                                                            relations will be based
377
-     * @param \EE_Model_Relation_Base $relation
378
-     * @param WP_REST_Request $request
379
-     * @return array
380
-     * @throws EE_Error
381
-     * @throws InvalidArgumentException
382
-     * @throws InvalidDataTypeException
383
-     * @throws InvalidInterfaceException
384
-     * @throws ReflectionException
385
-     * @throws RestException
386
-     * @throws \EventEspresso\core\exceptions\ModelConfigurationException
387
-     */
388
-    protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
389
-    {
390
-        $context = $this->validateContext($request->get_param('caps'));
391
-        $model = $relation->get_this_model();
392
-        $related_model = $relation->get_other_model();
393
-        if (! isset($primary_model_query_params[0])) {
394
-            $primary_model_query_params[0] = array();
395
-        }
396
-        // check if they can access the 1st model object
397
-        $primary_model_query_params = array(
398
-            0       => $primary_model_query_params[0],
399
-            'limit' => 1,
400
-        );
401
-        if ($model instanceof EEM_Soft_Delete_Base) {
402
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
403
-                $primary_model_query_params
404
-            );
405
-        }
406
-        $restricted_query_params = $primary_model_query_params;
407
-        $restricted_query_params['caps'] = $context;
408
-        $restricted_query_params['limit'] = 1;
409
-        $this->setDebugInfo('main model query params', $restricted_query_params);
410
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
411
-        $primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
412
-        $primary_model_row = null;
413
-        if (is_array($primary_model_rows)) {
414
-            $primary_model_row = reset($primary_model_rows);
415
-        }
416
-        if (! (
417
-            Capabilities::currentUserHasPartialAccessTo($related_model, $context)
418
-            && $primary_model_row
419
-        )
420
-        ) {
421
-            if ($relation instanceof EE_Belongs_To_Relation) {
422
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
423
-            } else {
424
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
425
-                    $related_model->get_this_model_name()
426
-                );
427
-            }
428
-            throw new RestException(
429
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
430
-                sprintf(
431
-                    __(
432
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
433
-                        'event_espresso'
434
-                    ),
435
-                    $related_model_name_maybe_plural,
436
-                    $relation->get_this_model()->get_this_model_name(),
437
-                    implode(
438
-                        ',',
439
-                        array_keys(
440
-                            Capabilities::getMissingPermissions($related_model, $context)
441
-                        )
442
-                    )
443
-                ),
444
-                array('status' => 403)
445
-            );
446
-        }
447
-
448
-        $this->checkPassword(
449
-            $model,
450
-            $primary_model_row,
451
-            $restricted_query_params,
452
-            $request
453
-        );
454
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
455
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
456
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
457
-                              . '.'
458
-                              . $where_condition_key ] = $where_condition_value;
459
-        }
460
-        $query_params['default_where_conditions'] = 'none';
461
-        $query_params['caps'] = $context;
462
-        if (! $request->get_header('no_rest_headers')) {
463
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
464
-        }
465
-        /** @type array $results */
466
-        $results = $relation->get_other_model()->get_all_wpdb_results($query_params);
467
-        $nice_results = array();
468
-        foreach ($results as $result) {
469
-            $nice_result = $this->createEntityFromWpdbResult(
470
-                $relation->get_other_model(),
471
-                $result,
472
-                $request
473
-            );
474
-            if ($relation instanceof \EE_HABTM_Relation) {
475
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
476
-                // if there are conflicts we prefer the properties from the main model
477
-                $join_model_result = $this->createEntityFromWpdbResult(
478
-                    $relation->get_join_model(),
479
-                    $result,
480
-                    $request
481
-                );
482
-                $joined_result = array_merge($nice_result, $join_model_result);
483
-                // but keep the meta stuff from the main model
484
-                if (isset($nice_result['meta'])) {
485
-                    $joined_result['meta'] = $nice_result['meta'];
486
-                }
487
-                $nice_result = $joined_result;
488
-            }
489
-            $nice_results[] = $nice_result;
490
-        }
491
-        if ($relation instanceof EE_Belongs_To_Relation) {
492
-            return array_shift($nice_results);
493
-        } else {
494
-            return $nice_results;
495
-        }
496
-    }
497
-
498
-
499
-    /**
500
-     * Gets the collection for given relation object
501
-     * The same as Read::get_entities_from_model(), except if the relation
502
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
503
-     * the join-model-object into the results
504
-     *
505
-     * @param string                  $id the ID of the thing we are fetching related stuff from
506
-     * @param \EE_Model_Relation_Base $relation
507
-     * @param WP_REST_Request         $request
508
-     * @return array
509
-     * @throws EE_Error
510
-     */
511
-    public function getEntitiesFromRelation($id, $relation, $request)
512
-    {
513
-        if (! $relation->get_this_model()->has_primary_key_field()) {
514
-            throw new EE_Error(
515
-                sprintf(
516
-                    __(
517
-                    // @codingStandardsIgnoreStart
518
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
519
-                        // @codingStandardsIgnoreEnd
520
-                        'event_espresso'
521
-                    ),
522
-                    $relation->get_this_model()->get_this_model_name()
523
-                )
524
-            );
525
-        }
526
-        // can we edit that main item?
527
-        // if not, show nothing but an error
528
-        // otherwise, please proceed
529
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
530
-            array(
531
-                array(
532
-                    $relation->get_this_model()->primary_key_name() => $id,
533
-                ),
534
-            ),
535
-            $relation,
536
-            $request
537
-        );
538
-    }
539
-
540
-
541
-    /**
542
-     * Sets the headers that are based on the model and query params,
543
-     * like the total records. This should only be called on the original request
544
-     * from the client, not on subsequent internal
545
-     *
546
-     * @param EEM_Base $model
547
-     * @param array    $query_params
548
-     * @return void
549
-     */
550
-    protected function setHeadersFromQueryParams($model, $query_params)
551
-    {
552
-        $this->setDebugInfo('model query params', $query_params);
553
-        $this->setDebugInfo(
554
-            'missing caps',
555
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
556
-        );
557
-        // normally the limit to a 2-part array, where the 2nd item is the limit
558
-        if (! isset($query_params['limit'])) {
559
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
560
-        }
561
-        if (is_array($query_params['limit'])) {
562
-            $limit_parts = $query_params['limit'];
563
-        } else {
564
-            $limit_parts = explode(',', $query_params['limit']);
565
-            if (count($limit_parts) == 1) {
566
-                $limit_parts = array(0, $limit_parts[0]);
567
-            }
568
-        }
569
-        // remove the group by and having parts of the query, as those will
570
-        // make the sql query return an array of values, instead of just a single value
571
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
572
-        $count = $model->count($query_params, null, true);
573
-        $pages = $count / $limit_parts[1];
574
-        $this->setResponseHeader('Total', $count, false);
575
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
576
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
577
-    }
578
-
579
-
580
-    /**
581
-     * Changes database results into REST API entities
582
-     *
583
-     * @param EEM_Base $model
584
-     * @param array $db_row like results from $wpdb->get_results()
585
-     * @param WP_REST_Request $rest_request
586
-     * @param string $deprecated no longer used
587
-     * @return array ready for being converted into json for sending to client
588
-     * @throws EE_Error
589
-     * @throws RestException
590
-     * @throws InvalidDataTypeException
591
-     * @throws InvalidInterfaceException
592
-     * @throws InvalidArgumentException
593
-     * @throws ReflectionException
594
-     */
595
-    public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
596
-    {
597
-        if (! $rest_request instanceof WP_REST_Request) {
598
-            // ok so this was called in the old style, where the 3rd arg was
599
-            // $include, and the 4th arg was $context
600
-            // now setup the request just to avoid fatal errors, although we won't be able
601
-            // to truly make use of it because it's kinda devoid of info
602
-            $rest_request = new WP_REST_Request();
603
-            $rest_request->set_param('include', $rest_request);
604
-            $rest_request->set_param('caps', $deprecated);
605
-        }
606
-        if ($rest_request->get_param('caps') == null) {
607
-            $rest_request->set_param('caps', EEM_Base::caps_read);
608
-        }
609
-        $current_user_full_access_to_entity = $model->currentUserCan(
610
-            EEM_Base::caps_read_admin,
611
-            $model->deduce_fields_n_values_from_cols_n_values($db_row)
612
-        );
613
-        $entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
614
-        $entity_array = $this->addExtraFields($model, $db_row, $entity_array);
615
-        $entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
616
-        // when it's a regular read request for a model with a password and the password wasn't provided
617
-        // remove the password protected fields
618
-        $has_protected_fields = false;
619
-        try {
620
-            $this->checkPassword(
621
-                $model,
622
-                $db_row,
623
-                $model->alter_query_params_to_restrict_by_ID(
624
-                    $model->get_index_primary_key_string(
625
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
626
-                    )
627
-                ),
628
-                $rest_request
629
-            );
630
-        } catch (RestPasswordRequiredException $e) {
631
-            if ($model->hasPassword()) {
632
-                // just remove protected fields
633
-                $has_protected_fields = true;
634
-                $entity_array = Capabilities::filterOutPasswordProtectedFields(
635
-                    $entity_array,
636
-                    $model,
637
-                    $this->getModelVersionInfo()
638
-                );
639
-            } else {
640
-                // that's a problem. None of this should be accessible if no password was provided
641
-                throw $e;
642
-            }
643
-        }
644
-
645
-        $entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields);
646
-        $entity_array = apply_filters(
647
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
648
-            $entity_array,
649
-            $model,
650
-            $rest_request->get_param('caps'),
651
-            $rest_request,
652
-            $this
653
-        );
654
-        // add an empty protected property for now. If it's still around after we remove everything the request didn't
655
-        // want, we'll populate it then. k?
656
-        $entity_array['_protected'] = array();
657
-        // remove any properties the request didn't want. This way _protected won't bother mentioning them
658
-        $entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
659
-        $entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields);
660
-        // if they still wanted the _protected property, add it.
661
-        if (isset($entity_array['_protected'])) {
662
-            $entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
663
-        }
664
-        $entity_array = apply_filters(
665
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
666
-            $entity_array,
667
-            $model,
668
-            $rest_request->get_param('caps'),
669
-            $rest_request,
670
-            $this
671
-        );
672
-        if (! $current_user_full_access_to_entity) {
673
-            $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
674
-                $entity_array,
675
-                $model,
676
-                $rest_request->get_param('caps'),
677
-                $this->getModelVersionInfo()
678
-            );
679
-        } else {
680
-            $result_without_inaccessible_fields = $entity_array;
681
-        }
682
-        $this->setDebugInfo(
683
-            'inaccessible fields',
684
-            array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
685
-        );
686
-        return apply_filters(
687
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
688
-            $result_without_inaccessible_fields,
689
-            $model,
690
-            $rest_request->get_param('caps')
691
-        );
692
-    }
693
-
694
-    /**
695
-     * Returns an array describing which fields can be protected, and which actually were removed this request
696
-     * @since 4.9.74.p
697
-     * @param $model
698
-     * @param $results_so_far
699
-     * @param $protected
700
-     * @return array results
701
-     */
702
-    protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
703
-    {
704
-        if (! $model->hasPassword() || ! $protected) {
705
-            return $results_so_far;
706
-        }
707
-        $password_field = $model->getPasswordField();
708
-        $all_protected = array_merge(
709
-            array($password_field->get_name()),
710
-            $password_field->protectedFields()
711
-        );
712
-        $fields_included = array_keys($results_so_far);
713
-        $fields_included = array_intersect(
714
-            $all_protected,
715
-            $fields_included
716
-        );
717
-        foreach ($fields_included as $field_name) {
718
-            $results_so_far['_protected'][] = $field_name ;
719
-        }
720
-        return $results_so_far;
721
-    }
722
-
723
-    /**
724
-     * Creates a REST entity array (JSON object we're going to return in the response, but
725
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
726
-     * from $wpdb->get_row( $sql, ARRAY_A)
727
-     *
728
-     * @param EEM_Base $model
729
-     * @param array    $db_row
730
-     * @return array entity mostly ready for converting to JSON and sending in the response
731
-     */
732
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
733
-    {
734
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
735
-        $result = array_intersect_key(
736
-            $result,
737
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
738
-        );
739
-        // if this is a CPT, we need to set the global $post to it,
740
-        // otherwise shortcodes etc won't work properly while rendering it
741
-        if ($model instanceof \EEM_CPT_Base) {
742
-            $do_chevy_shuffle = true;
743
-        } else {
744
-            $do_chevy_shuffle = false;
745
-        }
746
-        if ($do_chevy_shuffle) {
747
-            global $post;
748
-            $old_post = $post;
749
-            $post = get_post($result[ $model->primary_key_name() ]);
750
-            if (! $post instanceof \WP_Post) {
751
-                // well that's weird, because $result is what we JUST fetched from the database
752
-                throw new RestException(
753
-                    'error_fetching_post_from_database_results',
754
-                    esc_html__(
755
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
756
-                        'event_espresso'
757
-                    )
758
-                );
759
-            }
760
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
761
-            $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
762
-                $model_object_classname,
763
-                $result,
764
-                false,
765
-                false
766
-            );
767
-        }
768
-        foreach ($result as $field_name => $field_value) {
769
-            $field_obj = $model->field_settings_for($field_name);
770
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
771
-                unset($result[ $field_name ]);
772
-            } elseif ($this->isSubclassOfOne(
773
-                $field_obj,
774
-                $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
775
-            )
776
-            ) {
777
-                $result[ $field_name ] = array(
778
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
779
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
780
-                );
781
-            } elseif ($this->isSubclassOfOne(
782
-                $field_obj,
783
-                $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
784
-            )
785
-            ) {
786
-                $result[ $field_name ] = array(
787
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
788
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
789
-                );
790
-            } elseif ($field_obj instanceof \EE_Datetime_Field) {
791
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
792
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
793
-                if (is_null($field_value)) {
794
-                    $field_value = $field_obj->getDefaultDateTimeObj();
795
-                }
796
-                if (is_null($field_value)) {
797
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
798
-                        $field_obj,
799
-                        $field_value,
800
-                        $this->getModelVersionInfo()->requestedVersion()
801
-                    );
802
-                } else {
803
-                    $timezone = $field_value->getTimezone();
804
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
805
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
806
-                        $field_obj,
807
-                        $field_value,
808
-                        $this->getModelVersionInfo()->requestedVersion()
809
-                    );
810
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
811
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
812
-                        $field_obj,
813
-                        $field_value,
814
-                        $this->getModelVersionInfo()->requestedVersion()
815
-                    );
816
-                }
817
-                $result[ $field_name . '_gmt' ] = $gmt_date;
818
-                $result[ $field_name ] = $local_date;
819
-            } else {
820
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
821
-            }
822
-        }
823
-        if ($do_chevy_shuffle) {
824
-            $post = $old_post;
825
-        }
826
-        return $result;
827
-    }
828
-
829
-
830
-    /**
831
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
832
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
833
-     * representation using $field_obj->prepare_for_set_from_db())
834
-     *
835
-     * @param EE_Model_Field_Base $field_obj
836
-     * @param mixed               $value  as it's stored on a model object
837
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
838
-     * @return mixed
839
-     * @throws ObjectDetectedException if $value contains a PHP object
840
-     */
841
-    protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
842
-    {
843
-        $value = $field_obj->prepare_for_set_from_db($value);
844
-        switch ($format) {
845
-            case 'pretty':
846
-                $value = $field_obj->prepare_for_pretty_echoing($value);
847
-                break;
848
-            case 'normal':
849
-            default:
850
-                $value = $field_obj->prepare_for_get($value);
851
-                break;
852
-        }
853
-        return ModelDataTranslator::prepareFieldValuesForJson(
854
-            $field_obj,
855
-            $value,
856
-            $this->getModelVersionInfo()->requestedVersion()
857
-        );
858
-    }
859
-
860
-
861
-    /**
862
-     * Adds a few extra fields to the entity response
863
-     *
864
-     * @param EEM_Base $model
865
-     * @param array    $db_row
866
-     * @param array    $entity_array
867
-     * @return array modified entity
868
-     */
869
-    protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
870
-    {
871
-        if ($model instanceof EEM_CPT_Base) {
872
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
873
-        }
874
-        return $entity_array;
875
-    }
876
-
877
-
878
-    /**
879
-     * Gets links we want to add to the response
880
-     *
881
-     * @global \WP_REST_Server $wp_rest_server
882
-     * @param EEM_Base         $model
883
-     * @param array            $db_row
884
-     * @param array            $entity_array
885
-     * @return array the _links item in the entity
886
-     */
887
-    protected function getEntityLinks($model, $db_row, $entity_array)
888
-    {
889
-        // add basic links
890
-        $links = array();
891
-        if ($model->has_primary_key_field()) {
892
-            $links['self'] = array(
893
-                array(
894
-                    'href' => $this->getVersionedLinkTo(
895
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
896
-                        . '/'
897
-                        . $entity_array[ $model->primary_key_name() ]
898
-                    ),
899
-                ),
900
-            );
901
-        }
902
-        $links['collection'] = array(
903
-            array(
904
-                'href' => $this->getVersionedLinkTo(
905
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
906
-                ),
907
-            ),
908
-        );
909
-        // add links to related models
910
-        if ($model->has_primary_key_field()) {
911
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
912
-                $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
913
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
914
-                    array(
915
-                        'href'   => $this->getVersionedLinkTo(
916
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
917
-                            . '/'
918
-                            . $entity_array[ $model->primary_key_name() ]
919
-                            . '/'
920
-                            . $related_model_part
921
-                        ),
922
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
923
-                    ),
924
-                );
925
-            }
926
-        }
927
-        return $links;
928
-    }
929
-
930
-
931
-    /**
932
-     * Adds the included models indicated in the request to the entity provided
933
-     *
934
-     * @param EEM_Base $model
935
-     * @param WP_REST_Request $rest_request
936
-     * @param array $entity_array
937
-     * @param array $db_row
938
-     * @param boolean $included_items_protected if the original item is password protected, don't include any related models.
939
-     * @return array the modified entity
940
-     * @throws RestException
941
-     */
942
-    protected function includeRequestedModels(
943
-        EEM_Base $model,
944
-        WP_REST_Request $rest_request,
945
-        $entity_array,
946
-        $db_row = array(),
947
-        $included_items_protected = false
948
-    ) {
949
-        // if $db_row not included, hope the entity array has what we need
950
-        if (! $db_row) {
951
-            $db_row = $entity_array;
952
-        }
953
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
954
-        foreach ($relation_settings as $relation_name => $relation_obj) {
955
-            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
956
-                $rest_request->get_param('include'),
957
-                $relation_name
958
-            );
959
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
960
-                $rest_request->get_param('calculate'),
961
-                $relation_name
962
-            );
963
-            // did they specify they wanted to include a related model, or
964
-            // specific fields from a related model?
965
-            // or did they specify to calculate a field from a related model?
966
-            if ($related_fields_to_include || $related_fields_to_calculate) {
967
-                // if so, we should include at least some part of the related model
968
-                $pretend_related_request = new WP_REST_Request();
969
-                $pretend_related_request->set_query_params(
970
-                    array(
971
-                        'caps'      => $rest_request->get_param('caps'),
972
-                        'include'   => $related_fields_to_include,
973
-                        'calculate' => $related_fields_to_calculate,
974
-                        'password' => $rest_request->get_param('password')
975
-                    )
976
-                );
977
-                $pretend_related_request->add_header('no_rest_headers', true);
978
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
979
-                    $model->get_index_primary_key_string(
980
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
981
-                    )
982
-                );
983
-                if (! $included_items_protected) {
984
-                    try {
985
-                        $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
986
-                            $primary_model_query_params,
987
-                            $relation_obj,
988
-                            $pretend_related_request
989
-                        );
990
-                    } catch (RestException $e) {
991
-                        $related_results = null;
992
-                    }
993
-                } else {
994
-                    // they're protected, hide them.
995
-                    $related_results = null;
996
-                    $entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
997
-                }
998
-                if ($related_results instanceof WP_Error || $related_results === null) {
999
-                    $related_results = $relation_obj instanceof EE_Belongs_To_Relation ? null : array();
1000
-                }
1001
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1002
-            }
1003
-        }
1004
-        return $entity_array;
1005
-    }
1006
-
1007
-    /**
1008
-     * If the user has requested only specific properties (including meta properties like _links or _protected)
1009
-     * remove everything else.
1010
-     * @since 4.9.74.p
1011
-     * @param EEM_Base $model
1012
-     * @param WP_REST_Request $rest_request
1013
-     * @param $entity_array
1014
-     * @return array
1015
-     * @throws EE_Error
1016
-     */
1017
-    protected function includeOnlyRequestedProperties(
1018
-        EEM_Base $model,
1019
-        WP_REST_Request $rest_request,
1020
-        $entity_array
1021
-    ) {
1022
-
1023
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1024
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1025
-        // if they passed in * or didn't specify any includes, return everything
1026
-        if (! in_array('*', $includes_for_this_model)
1027
-            && ! empty($includes_for_this_model)
1028
-        ) {
1029
-            if ($model->has_primary_key_field()) {
1030
-                // always include the primary key. ya just gotta know that at least
1031
-                $includes_for_this_model[] = $model->primary_key_name();
1032
-            }
1033
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1034
-                $includes_for_this_model[] = '_calculated_fields';
1035
-            }
1036
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1037
-        }
1038
-        return $entity_array;
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * Returns a new array with all the names of models removed. Eg
1044
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1045
-     *
1046
-     * @param array $arr
1047
-     * @return array
1048
-     */
1049
-    private function removeModelNamesFromArray($arr)
1050
-    {
1051
-        return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
1052
-    }
1053
-
1054
-
1055
-    /**
1056
-     * Gets the calculated fields for the response
1057
-     *
1058
-     * @param EEM_Base        $model
1059
-     * @param array           $wpdb_row
1060
-     * @param WP_REST_Request $rest_request
1061
-     * @param boolean $row_is_protected whether this row is password protected or not
1062
-     * @return \stdClass the _calculations item in the entity
1063
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
1064
-     * did, let's know about it ASAP, so let the exception bubble up)
1065
-     */
1066
-    protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false)
1067
-    {
1068
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1069
-            $rest_request->get_param('calculate'),
1070
-            ''
1071
-        );
1072
-        // note: setting calculate=* doesn't do anything
1073
-        $calculated_fields_to_return = new \stdClass();
1074
-        $protected_fields = array();
1075
-        foreach ($calculated_fields as $field_to_calculate) {
1076
-            try {
1077
-                // it's password protected, so they shouldn't be able to read this. Remove the value
1078
-                $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1079
-                if ($row_is_protected
1080
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1081
-                    && $schema['properties'][ $field_to_calculate ]['protected']) {
1082
-                    $calculated_value = null;
1083
-                    $protected_fields[] = $field_to_calculate;
1084
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1085
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1086
-                            case 'boolean':
1087
-                                $calculated_value = false;
1088
-                                break;
1089
-                            case 'integer':
1090
-                                $calculated_value = 0;
1091
-                                break;
1092
-                            case 'string':
1093
-                                $calculated_value = '';
1094
-                                break;
1095
-                            case 'array':
1096
-                                $calculated_value = array();
1097
-                                break;
1098
-                            case 'object':
1099
-                                $calculated_value = new stdClass();
1100
-                                break;
1101
-                        }
1102
-                    }
1103
-                } else {
1104
-                    $calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1105
-                        null,
1106
-                        $this->fields_calculator->retrieveCalculatedFieldValue(
1107
-                            $model,
1108
-                            $field_to_calculate,
1109
-                            $wpdb_row,
1110
-                            $rest_request,
1111
-                            $this
1112
-                        ),
1113
-                        $this->getModelVersionInfo()->requestedVersion()
1114
-                    );
1115
-                }
1116
-                $calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1117
-            } catch (RestException $e) {
1118
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
1119
-                $this->setResponseHeader(
1120
-                    'Notices-Field-Calculation-Errors['
1121
-                    . $e->getStringCode()
1122
-                    . ']['
1123
-                    . $model->get_this_model_name()
1124
-                    . ']['
1125
-                    . $field_to_calculate
1126
-                    . ']',
1127
-                    $e->getMessage(),
1128
-                    true
1129
-                );
1130
-            }
1131
-        }
1132
-        $calculated_fields_to_return->_protected = $protected_fields;
1133
-        return $calculated_fields_to_return;
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * Gets the full URL to the resource, taking the requested version into account
1139
-     *
1140
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1141
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1142
-     */
1143
-    public function getVersionedLinkTo($link_part_after_version_and_slash)
1144
-    {
1145
-        return rest_url(
1146
-            EED_Core_Rest_Api::get_versioned_route_to(
1147
-                $link_part_after_version_and_slash,
1148
-                $this->getModelVersionInfo()->requestedVersion()
1149
-            )
1150
-        );
1151
-    }
1152
-
1153
-
1154
-    /**
1155
-     * Gets the correct lowercase name for the relation in the API according
1156
-     * to the relation's type
1157
-     *
1158
-     * @param string                  $relation_name
1159
-     * @param \EE_Model_Relation_Base $relation_obj
1160
-     * @return string
1161
-     */
1162
-    public static function getRelatedEntityName($relation_name, $relation_obj)
1163
-    {
1164
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1165
-            return strtolower($relation_name);
1166
-        } else {
1167
-            return EEH_Inflector::pluralize_and_lower($relation_name);
1168
-        }
1169
-    }
1170
-
1171
-
1172
-    /**
1173
-     * Gets the one model object with the specified id for the specified model
1174
-     *
1175
-     * @param EEM_Base        $model
1176
-     * @param WP_REST_Request $request
1177
-     * @return array
1178
-     */
1179
-    public function getEntityFromModel($model, $request)
1180
-    {
1181
-        $context = $this->validateContext($request->get_param('caps'));
1182
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1183
-    }
1184
-
1185
-
1186
-    /**
1187
-     * If a context is provided which isn't valid, maybe it was added in a future
1188
-     * version so just treat it as a default read
1189
-     *
1190
-     * @param string $context
1191
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1192
-     */
1193
-    public function validateContext($context)
1194
-    {
1195
-        if (! $context) {
1196
-            $context = EEM_Base::caps_read;
1197
-        }
1198
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1199
-        if (in_array($context, $valid_contexts)) {
1200
-            return $context;
1201
-        } else {
1202
-            return EEM_Base::caps_read;
1203
-        }
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     * Verifies the passed in value is an allowable default where conditions value.
1209
-     *
1210
-     * @param $default_query_params
1211
-     * @return string
1212
-     */
1213
-    public function validateDefaultQueryParams($default_query_params)
1214
-    {
1215
-        $valid_default_where_conditions_for_api_calls = array(
1216
-            EEM_Base::default_where_conditions_all,
1217
-            EEM_Base::default_where_conditions_minimum_all,
1218
-            EEM_Base::default_where_conditions_minimum_others,
1219
-        );
1220
-        if (! $default_query_params) {
1221
-            $default_query_params = EEM_Base::default_where_conditions_all;
1222
-        }
1223
-        if (in_array(
1224
-            $default_query_params,
1225
-            $valid_default_where_conditions_for_api_calls,
1226
-            true
1227
-        )) {
1228
-            return $default_query_params;
1229
-        } else {
1230
-            return EEM_Base::default_where_conditions_all;
1231
-        }
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     * Translates API filter get parameter into model query params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1237
-     * Note: right now the query parameter keys for fields (and related fields)
1238
-     * can be left as-is, but it's quite possible this will change someday.
1239
-     * Also, this method's contents might be candidate for moving to Model_Data_Translator
1240
-     *
1241
-     * @param EEM_Base $model
1242
-     * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1243
-     * @return array model query params (@see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1244
-     *                                    or FALSE to indicate that absolutely no results should be returned
1245
-     * @throws EE_Error
1246
-     * @throws RestException
1247
-     */
1248
-    public function createModelQueryParams($model, $query_params)
1249
-    {
1250
-        $model_query_params = array();
1251
-        if (isset($query_params['where'])) {
1252
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1253
-                $query_params['where'],
1254
-                $model,
1255
-                $this->getModelVersionInfo()->requestedVersion()
1256
-            );
1257
-        }
1258
-        if (isset($query_params['order_by'])) {
1259
-            $order_by = $query_params['order_by'];
1260
-        } elseif (isset($query_params['orderby'])) {
1261
-            $order_by = $query_params['orderby'];
1262
-        } else {
1263
-            $order_by = null;
1264
-        }
1265
-        if ($order_by !== null) {
1266
-            if (is_array($order_by)) {
1267
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1268
-            } else {
1269
-                // it's a single item
1270
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1271
-            }
1272
-            $model_query_params['order_by'] = $order_by;
1273
-        }
1274
-        if (isset($query_params['group_by'])) {
1275
-            $group_by = $query_params['group_by'];
1276
-        } elseif (isset($query_params['groupby'])) {
1277
-            $group_by = $query_params['groupby'];
1278
-        } else {
1279
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1280
-        }
1281
-        // make sure they're all real names
1282
-        if (is_array($group_by)) {
1283
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1284
-        }
1285
-        if ($group_by !== null) {
1286
-            $model_query_params['group_by'] = $group_by;
1287
-        }
1288
-        if (isset($query_params['having'])) {
1289
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1290
-                $query_params['having'],
1291
-                $model,
1292
-                $this->getModelVersionInfo()->requestedVersion()
1293
-            );
1294
-        }
1295
-        if (isset($query_params['order'])) {
1296
-            $model_query_params['order'] = $query_params['order'];
1297
-        }
1298
-        if (isset($query_params['mine'])) {
1299
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1300
-        }
1301
-        if (isset($query_params['limit'])) {
1302
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1303
-            if (! is_array($query_params['limit'])) {
1304
-                $limit_array = explode(',', (string) $query_params['limit']);
1305
-            } else {
1306
-                $limit_array = $query_params['limit'];
1307
-            }
1308
-            $sanitized_limit = array();
1309
-            foreach ($limit_array as $key => $limit_part) {
1310
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1311
-                    throw new EE_Error(
1312
-                        sprintf(
1313
-                            __(
1314
-                            // @codingStandardsIgnoreStart
1315
-                                '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.',
1316
-                                // @codingStandardsIgnoreEnd
1317
-                                'event_espresso'
1318
-                            ),
1319
-                            wp_json_encode($query_params['limit'])
1320
-                        )
1321
-                    );
1322
-                }
1323
-                $sanitized_limit[] = (int) $limit_part;
1324
-            }
1325
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1326
-        } else {
1327
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1328
-        }
1329
-        if (isset($query_params['caps'])) {
1330
-            $model_query_params['caps'] = $this->validateContext($query_params['caps']);
1331
-        } else {
1332
-            $model_query_params['caps'] = EEM_Base::caps_read;
1333
-        }
1334
-        if (isset($query_params['default_where_conditions'])) {
1335
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1336
-                $query_params['default_where_conditions']
1337
-            );
1338
-        }
1339
-        // if this is a model protected by a password on another model, exclude the password protected
1340
-        // entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1341
-        // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1342
-        if (! $model->hasPassword()
1343
-            && $model->restrictedByRelatedModelPassword()
1344
-            && $model_query_params['caps'] === EEM_Base::caps_read) {
1345
-            if (empty($query_params['password'])) {
1346
-                $model_query_params['exclude_protected'] = true;
1347
-            }
1348
-        }
1349
-
1350
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1351
-    }
1352
-
1353
-
1354
-    /**
1355
-     * Changes the REST-style query params for use in the models
1356
-     *
1357
-     * @deprecated
1358
-     * @param EEM_Base $model
1359
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1360
-     * @return array
1361
-     */
1362
-    public function prepareRestQueryParamsKeyForModels($model, $query_params)
1363
-    {
1364
-        $model_ready_query_params = array();
1365
-        foreach ($query_params as $key => $value) {
1366
-            if (is_array($value)) {
1367
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1368
-            } else {
1369
-                $model_ready_query_params[ $key ] = $value;
1370
-            }
1371
-        }
1372
-        return $model_ready_query_params;
1373
-    }
1374
-
1375
-
1376
-    /**
1377
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1378
-     * @param $model
1379
-     * @param $query_params
1380
-     * @return array
1381
-     */
1382
-    public function prepareRestQueryParamsValuesForModels($model, $query_params)
1383
-    {
1384
-        $model_ready_query_params = array();
1385
-        foreach ($query_params as $key => $value) {
1386
-            if (is_array($value)) {
1387
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1388
-            } else {
1389
-                $model_ready_query_params[ $key ] = $value;
1390
-            }
1391
-        }
1392
-        return $model_ready_query_params;
1393
-    }
1394
-
1395
-
1396
-    /**
1397
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1398
-     * If no prefix is specified, returns items with no period.
1399
-     *
1400
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1401
-     * @param string       $prefix            "Event" or "foobar"
1402
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1403
-     *                                        we only return strings starting with that and a period; if no prefix was
1404
-     *                                        specified we return all items containing NO periods
1405
-     */
1406
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1407
-    {
1408
-        if (is_string($string_to_explode)) {
1409
-            $exploded_contents = explode(',', $string_to_explode);
1410
-        } elseif (is_array($string_to_explode)) {
1411
-            $exploded_contents = $string_to_explode;
1412
-        } else {
1413
-            $exploded_contents = array();
1414
-        }
1415
-        // if the string was empty, we want an empty array
1416
-        $exploded_contents = array_filter($exploded_contents);
1417
-        $contents_with_prefix = array();
1418
-        foreach ($exploded_contents as $item) {
1419
-            $item = trim($item);
1420
-            // if no prefix was provided, so we look for items with no "." in them
1421
-            if (! $prefix) {
1422
-                // does this item have a period?
1423
-                if (strpos($item, '.') === false) {
1424
-                    // if not, then its what we're looking for
1425
-                    $contents_with_prefix[] = $item;
1426
-                }
1427
-            } elseif (strpos($item, $prefix . '.') === 0) {
1428
-                // this item has the prefix and a period, grab it
1429
-                $contents_with_prefix[] = substr(
1430
-                    $item,
1431
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1432
-                );
1433
-            } elseif ($item === $prefix) {
1434
-                // this item is JUST the prefix
1435
-                // so let's grab everything after, which is a blank string
1436
-                $contents_with_prefix[] = '';
1437
-            }
1438
-        }
1439
-        return $contents_with_prefix;
1440
-    }
1441
-
1442
-
1443
-    /**
1444
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1445
-     * Deprecated because its return values were really quite confusing- sometimes it returned
1446
-     * an empty array (when the include string was blank or '*') or sometimes it returned
1447
-     * array('*') (when you provided a model and a model of that kind was found).
1448
-     * Parses the $include_string so we fetch all the field names relating to THIS model
1449
-     * (ie have NO period in them), or for the provided model (ie start with the model
1450
-     * name and then a period).
1451
-     * @param string $include_string @see Read:handle_request_get_all
1452
-     * @param string $model_name
1453
-     * @return array of fields for this model. If $model_name is provided, then
1454
-     *                               the fields for that model, with the model's name removed from each.
1455
-     *                               If $include_string was blank or '*' returns an empty array
1456
-     */
1457
-    public function extractIncludesForThisModel($include_string, $model_name = null)
1458
-    {
1459
-        if (is_array($include_string)) {
1460
-            $include_string = implode(',', $include_string);
1461
-        }
1462
-        if ($include_string === '*' || $include_string === '') {
1463
-            return array();
1464
-        }
1465
-        $includes = explode(',', $include_string);
1466
-        $extracted_fields_to_include = array();
1467
-        if ($model_name) {
1468
-            foreach ($includes as $field_to_include) {
1469
-                $field_to_include = trim($field_to_include);
1470
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1471
-                    // found the model name at the exact start
1472
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1473
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1474
-                } elseif ($field_to_include == $model_name) {
1475
-                    $extracted_fields_to_include[] = '*';
1476
-                }
1477
-            }
1478
-        } else {
1479
-            // look for ones with no period
1480
-            foreach ($includes as $field_to_include) {
1481
-                $field_to_include = trim($field_to_include);
1482
-                if (strpos($field_to_include, '.') === false
1483
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1484
-                ) {
1485
-                    $extracted_fields_to_include[] = $field_to_include;
1486
-                }
1487
-            }
1488
-        }
1489
-        return $extracted_fields_to_include;
1490
-    }
1491
-
1492
-
1493
-    /**
1494
-     * Gets the single item using the model according to the request in the context given, otherwise
1495
-     * returns that it's inaccessible to the current user
1496
-     *
1497
-     * @param EEM_Base $model
1498
-     * @param WP_REST_Request $request
1499
-     * @param null $context
1500
-     * @return array
1501
-     * @throws EE_Error
1502
-     */
1503
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1504
-    {
1505
-        $query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1506
-        if ($model instanceof EEM_Soft_Delete_Base) {
1507
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1508
-        }
1509
-        $restricted_query_params = $query_params;
1510
-        $restricted_query_params['caps'] = $context;
1511
-        $this->setDebugInfo('model query params', $restricted_query_params);
1512
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1513
-        if (! empty($model_rows)) {
1514
-            return $this->createEntityFromWpdbResult(
1515
-                $model,
1516
-                reset($model_rows),
1517
-                $request
1518
-            );
1519
-        } else {
1520
-            // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1521
-            $lowercase_model_name = strtolower($model->get_this_model_name());
1522
-            if ($model->exists($query_params)) {
1523
-                // you got shafted- it existed but we didn't want to tell you!
1524
-                throw new RestException(
1525
-                    'rest_user_cannot_' . $context,
1526
-                    sprintf(
1527
-                        __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1528
-                        $context,
1529
-                        $lowercase_model_name,
1530
-                        Capabilities::getMissingPermissionsString(
1531
-                            $model,
1532
-                            $context
1533
-                        )
1534
-                    ),
1535
-                    array('status' => 403)
1536
-                );
1537
-            } else {
1538
-                // it's not you. It just doesn't exist
1539
-                throw new RestException(
1540
-                    sprintf('rest_%s_invalid_id', $lowercase_model_name),
1541
-                    sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1542
-                    array('status' => 404)
1543
-                );
1544
-            }
1545
-        }
1546
-    }
1547
-
1548
-    /**
1549
-     * Checks that if this content requires a password to be read, that it's been provided and is correct.
1550
-     * @since 4.9.74.p
1551
-     * @param EEM_Base $model
1552
-     * @param $model_row
1553
-     * @param $query_params Adds 'default_where_conditions' => 'minimum' to ensure we don't confuse trashed with
1554
-     *                      password protected.
1555
-     * @param WP_REST_Request $request
1556
-     * @throws EE_Error
1557
-     * @throws InvalidArgumentException
1558
-     * @throws InvalidDataTypeException
1559
-     * @throws InvalidInterfaceException
1560
-     * @throws RestPasswordRequiredException
1561
-     * @throws RestPasswordIncorrectException
1562
-     * @throws \EventEspresso\core\exceptions\ModelConfigurationException
1563
-     * @throws ReflectionException
1564
-     */
1565
-    protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request)
1566
-    {
1567
-        $query_params['default_where_conditions'] = 'minimum';
1568
-        // stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1569
-        // or you don't.
1570
-        $request_caps = $request->get_param('caps');
1571
-        if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1572
-            return;
1573
-        }
1574
-        // if this entity requires a password, they better give it and it better be right!
1575
-        if ($model->hasPassword()
1576
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '') {
1577
-            if (empty($request['password'])) {
1578
-                throw new RestPasswordRequiredException();
1579
-            } elseif (!hash_equals(
1580
-                $model_row[ $model->getPasswordField()->get_qualified_column() ],
1581
-                $request['password']
1582
-            )) {
1583
-                throw new RestPasswordIncorrectException();
1584
-            }
1585
-        } // wait! maybe this content is password protected
1586
-        elseif ($model->restrictedByRelatedModelPassword()
1587
-            && $request->get_param('caps') === EEM_Base::caps_read) {
1588
-            $password_supplied = $request->get_param('password');
1589
-            if (empty($password_supplied)) {
1590
-                $query_params['exclude_protected'] = true;
1591
-                if (!$model->exists($query_params)) {
1592
-                    throw new RestPasswordRequiredException();
1593
-                }
1594
-            } else {
1595
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1596
-                if (!$model->exists($query_params)) {
1597
-                    throw new RestPasswordIncorrectException();
1598
-                }
1599
-            }
1600
-        }
1601
-    }
48
+	/**
49
+	 * @var CalculatedModelFields
50
+	 */
51
+	protected $fields_calculator;
52
+
53
+
54
+	/**
55
+	 * Read constructor.
56
+	 * @param CalculatedModelFields $fields_calculator
57
+	 */
58
+	public function __construct(CalculatedModelFields $fields_calculator)
59
+	{
60
+		parent::__construct();
61
+		$this->fields_calculator = $fields_calculator;
62
+	}
63
+
64
+
65
+	/**
66
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
67
+	 *
68
+	 * @param WP_REST_Request $request
69
+	 * @param string $version
70
+	 * @param string $model_name
71
+	 * @return WP_REST_Response|WP_Error
72
+	 * @throws InvalidArgumentException
73
+	 * @throws InvalidDataTypeException
74
+	 * @throws InvalidInterfaceException
75
+	 */
76
+	public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
77
+	{
78
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
79
+		try {
80
+			$controller->setRequestedVersion($version);
81
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
82
+				return $controller->sendResponse(
83
+					new WP_Error(
84
+						'endpoint_parsing_error',
85
+						sprintf(
86
+							__(
87
+								'There is no model for endpoint %s. Please contact event espresso support',
88
+								'event_espresso'
89
+							),
90
+							$model_name
91
+						)
92
+					)
93
+				);
94
+			}
95
+			return $controller->sendResponse(
96
+				$controller->getEntitiesFromModel(
97
+					$controller->getModelVersionInfo()->loadModel($model_name),
98
+					$request
99
+				)
100
+			);
101
+		} catch (Exception $e) {
102
+			return $controller->sendResponse($e);
103
+		}
104
+	}
105
+
106
+
107
+	/**
108
+	 * Prepares and returns schema for any OPTIONS request.
109
+	 *
110
+	 * @param string $version The API endpoint version being used.
111
+	 * @param string $model_name Something like `Event` or `Registration`
112
+	 * @return array
113
+	 * @throws InvalidArgumentException
114
+	 * @throws InvalidDataTypeException
115
+	 * @throws InvalidInterfaceException
116
+	 */
117
+	public static function handleSchemaRequest($version, $model_name)
118
+	{
119
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
120
+		try {
121
+			$controller->setRequestedVersion($version);
122
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
123
+				return array();
124
+			}
125
+			// get the model for this version
126
+			$model = $controller->getModelVersionInfo()->loadModel($model_name);
127
+			$model_schema = new JsonModelSchema($model, LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields'));
128
+			return $model_schema->getModelSchemaForRelations(
129
+				$controller->getModelVersionInfo()->relationSettings($model),
130
+				$controller->customizeSchemaForRestResponse(
131
+					$model,
132
+					$model_schema->getModelSchemaForFields(
133
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
134
+						$model_schema->getInitialSchemaStructure()
135
+					)
136
+				)
137
+			);
138
+		} catch (Exception $e) {
139
+			return array();
140
+		}
141
+	}
142
+
143
+
144
+	/**
145
+	 * This loops through each field in the given schema for the model and does the following:
146
+	 * - add any extra fields that are REST API specific and related to existing fields.
147
+	 * - transform default values into the correct format for a REST API response.
148
+	 *
149
+	 * @param EEM_Base $model
150
+	 * @param array    $schema
151
+	 * @return array  The final schema.
152
+	 */
153
+	protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
154
+	{
155
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
156
+			$schema = $this->translateDefaultsForRestResponse(
157
+				$field_name,
158
+				$field,
159
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
160
+			);
161
+		}
162
+		return $schema;
163
+	}
164
+
165
+
166
+	/**
167
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
168
+	 * response.
169
+	 *
170
+	 * @param                      $field_name
171
+	 * @param EE_Model_Field_Base  $field
172
+	 * @param array                $schema
173
+	 * @return array
174
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
175
+	 * did, let's know about it ASAP, so let the exception bubble up)
176
+	 */
177
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
178
+	{
179
+		if (isset($schema['properties'][ $field_name ]['default'])) {
180
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
181
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
182
+					if ($default_key === 'raw') {
183
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
184
+							ModelDataTranslator::prepareFieldValueForJson(
185
+								$field,
186
+								$default_value,
187
+								$this->getModelVersionInfo()->requestedVersion()
188
+							);
189
+					}
190
+				}
191
+			} else {
192
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
193
+					$field,
194
+					$schema['properties'][ $field_name ]['default'],
195
+					$this->getModelVersionInfo()->requestedVersion()
196
+				);
197
+			}
198
+		}
199
+		return $schema;
200
+	}
201
+
202
+
203
+	/**
204
+	 * Adds additional fields to the schema
205
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
206
+	 * needs to be added to the schema.
207
+	 *
208
+	 * @param                      $field_name
209
+	 * @param EE_Model_Field_Base  $field
210
+	 * @param array                $schema
211
+	 * @return array
212
+	 */
213
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
214
+	{
215
+		if ($field instanceof EE_Datetime_Field) {
216
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
217
+			// modify the description
218
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
219
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
220
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
221
+			);
222
+		}
223
+		return $schema;
224
+	}
225
+
226
+
227
+	/**
228
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
229
+	 *
230
+	 * @return string
231
+	 */
232
+	protected function getRouteFromRequest()
233
+	{
234
+		if (isset($GLOBALS['wp'])
235
+			&& $GLOBALS['wp'] instanceof \WP
236
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
237
+		) {
238
+			return $GLOBALS['wp']->query_vars['rest_route'];
239
+		} else {
240
+			return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
241
+		}
242
+	}
243
+
244
+
245
+	/**
246
+	 * Gets a single entity related to the model indicated in the path and its id
247
+	 *
248
+	 * @param WP_REST_Request $request
249
+	 * @param string $version
250
+	 * @param string $model_name
251
+	 * @return WP_REST_Response|WP_Error
252
+	 * @throws InvalidDataTypeException
253
+	 * @throws InvalidInterfaceException
254
+	 * @throws InvalidArgumentException
255
+	 */
256
+	public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
257
+	{
258
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
259
+		try {
260
+			$controller->setRequestedVersion($version);
261
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
262
+				return $controller->sendResponse(
263
+					new WP_Error(
264
+						'endpoint_parsing_error',
265
+						sprintf(
266
+							__(
267
+								'There is no model for endpoint %s. Please contact event espresso support',
268
+								'event_espresso'
269
+							),
270
+							$model_name
271
+						)
272
+					)
273
+				);
274
+			}
275
+			return $controller->sendResponse(
276
+				$controller->getEntityFromModel(
277
+					$controller->getModelVersionInfo()->loadModel($model_name),
278
+					$request
279
+				)
280
+			);
281
+		} catch (Exception $e) {
282
+			return $controller->sendResponse($e);
283
+		}
284
+	}
285
+
286
+
287
+	/**
288
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
289
+	 * to the item with the given id
290
+	 *
291
+	 * @param WP_REST_Request $request
292
+	 * @param string $version
293
+	 * @param string $model_name
294
+	 * @param string $related_model_name
295
+	 * @return WP_REST_Response|WP_Error
296
+	 * @throws InvalidDataTypeException
297
+	 * @throws InvalidInterfaceException
298
+	 * @throws InvalidArgumentException
299
+	 */
300
+	public static function handleRequestGetRelated(
301
+		WP_REST_Request $request,
302
+		$version,
303
+		$model_name,
304
+		$related_model_name
305
+	) {
306
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
307
+		try {
308
+			$controller->setRequestedVersion($version);
309
+			$main_model = $controller->validateModel($model_name);
310
+			$controller->validateModel($related_model_name);
311
+			return $controller->sendResponse(
312
+				$controller->getEntitiesFromRelation(
313
+					$request->get_param('id'),
314
+					$main_model->related_settings_for($related_model_name),
315
+					$request
316
+				)
317
+			);
318
+		} catch (Exception $e) {
319
+			return $controller->sendResponse($e);
320
+		}
321
+	}
322
+
323
+
324
+	/**
325
+	 * Gets a collection for the given model and filters
326
+	 *
327
+	 * @param EEM_Base $model
328
+	 * @param WP_REST_Request $request
329
+	 * @return array
330
+	 * @throws EE_Error
331
+	 * @throws InvalidArgumentException
332
+	 * @throws InvalidDataTypeException
333
+	 * @throws InvalidInterfaceException
334
+	 * @throws ReflectionException
335
+	 * @throws RestException
336
+	 */
337
+	public function getEntitiesFromModel($model, $request)
338
+	{
339
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
340
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
341
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
342
+			throw new RestException(
343
+				sprintf('rest_%s_cannot_list', $model_name_plural),
344
+				sprintf(
345
+					__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
346
+					$model_name_plural,
347
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
348
+				),
349
+				array('status' => 403)
350
+			);
351
+		}
352
+		if (! $request->get_header('no_rest_headers')) {
353
+			$this->setHeadersFromQueryParams($model, $query_params);
354
+		}
355
+		/** @type array $results */
356
+		$results = $model->get_all_wpdb_results($query_params);
357
+		$nice_results = array();
358
+		foreach ($results as $result) {
359
+			$nice_results[] =  $this->createEntityFromWpdbResult(
360
+				$model,
361
+				$result,
362
+				$request
363
+			);
364
+		}
365
+		return $nice_results;
366
+	}
367
+
368
+
369
+	/**
370
+	 * Gets the collection for given relation object
371
+	 * The same as Read::get_entities_from_model(), except if the relation
372
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
373
+	 * the join-model-object into the results
374
+	 *
375
+	 * @param array $primary_model_query_params query params for finding the item from which
376
+	 *                                                            relations will be based
377
+	 * @param \EE_Model_Relation_Base $relation
378
+	 * @param WP_REST_Request $request
379
+	 * @return array
380
+	 * @throws EE_Error
381
+	 * @throws InvalidArgumentException
382
+	 * @throws InvalidDataTypeException
383
+	 * @throws InvalidInterfaceException
384
+	 * @throws ReflectionException
385
+	 * @throws RestException
386
+	 * @throws \EventEspresso\core\exceptions\ModelConfigurationException
387
+	 */
388
+	protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
389
+	{
390
+		$context = $this->validateContext($request->get_param('caps'));
391
+		$model = $relation->get_this_model();
392
+		$related_model = $relation->get_other_model();
393
+		if (! isset($primary_model_query_params[0])) {
394
+			$primary_model_query_params[0] = array();
395
+		}
396
+		// check if they can access the 1st model object
397
+		$primary_model_query_params = array(
398
+			0       => $primary_model_query_params[0],
399
+			'limit' => 1,
400
+		);
401
+		if ($model instanceof EEM_Soft_Delete_Base) {
402
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
403
+				$primary_model_query_params
404
+			);
405
+		}
406
+		$restricted_query_params = $primary_model_query_params;
407
+		$restricted_query_params['caps'] = $context;
408
+		$restricted_query_params['limit'] = 1;
409
+		$this->setDebugInfo('main model query params', $restricted_query_params);
410
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
411
+		$primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
412
+		$primary_model_row = null;
413
+		if (is_array($primary_model_rows)) {
414
+			$primary_model_row = reset($primary_model_rows);
415
+		}
416
+		if (! (
417
+			Capabilities::currentUserHasPartialAccessTo($related_model, $context)
418
+			&& $primary_model_row
419
+		)
420
+		) {
421
+			if ($relation instanceof EE_Belongs_To_Relation) {
422
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
423
+			} else {
424
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
425
+					$related_model->get_this_model_name()
426
+				);
427
+			}
428
+			throw new RestException(
429
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
430
+				sprintf(
431
+					__(
432
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
433
+						'event_espresso'
434
+					),
435
+					$related_model_name_maybe_plural,
436
+					$relation->get_this_model()->get_this_model_name(),
437
+					implode(
438
+						',',
439
+						array_keys(
440
+							Capabilities::getMissingPermissions($related_model, $context)
441
+						)
442
+					)
443
+				),
444
+				array('status' => 403)
445
+			);
446
+		}
447
+
448
+		$this->checkPassword(
449
+			$model,
450
+			$primary_model_row,
451
+			$restricted_query_params,
452
+			$request
453
+		);
454
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
455
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
456
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
457
+							  . '.'
458
+							  . $where_condition_key ] = $where_condition_value;
459
+		}
460
+		$query_params['default_where_conditions'] = 'none';
461
+		$query_params['caps'] = $context;
462
+		if (! $request->get_header('no_rest_headers')) {
463
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
464
+		}
465
+		/** @type array $results */
466
+		$results = $relation->get_other_model()->get_all_wpdb_results($query_params);
467
+		$nice_results = array();
468
+		foreach ($results as $result) {
469
+			$nice_result = $this->createEntityFromWpdbResult(
470
+				$relation->get_other_model(),
471
+				$result,
472
+				$request
473
+			);
474
+			if ($relation instanceof \EE_HABTM_Relation) {
475
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
476
+				// if there are conflicts we prefer the properties from the main model
477
+				$join_model_result = $this->createEntityFromWpdbResult(
478
+					$relation->get_join_model(),
479
+					$result,
480
+					$request
481
+				);
482
+				$joined_result = array_merge($nice_result, $join_model_result);
483
+				// but keep the meta stuff from the main model
484
+				if (isset($nice_result['meta'])) {
485
+					$joined_result['meta'] = $nice_result['meta'];
486
+				}
487
+				$nice_result = $joined_result;
488
+			}
489
+			$nice_results[] = $nice_result;
490
+		}
491
+		if ($relation instanceof EE_Belongs_To_Relation) {
492
+			return array_shift($nice_results);
493
+		} else {
494
+			return $nice_results;
495
+		}
496
+	}
497
+
498
+
499
+	/**
500
+	 * Gets the collection for given relation object
501
+	 * The same as Read::get_entities_from_model(), except if the relation
502
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
503
+	 * the join-model-object into the results
504
+	 *
505
+	 * @param string                  $id the ID of the thing we are fetching related stuff from
506
+	 * @param \EE_Model_Relation_Base $relation
507
+	 * @param WP_REST_Request         $request
508
+	 * @return array
509
+	 * @throws EE_Error
510
+	 */
511
+	public function getEntitiesFromRelation($id, $relation, $request)
512
+	{
513
+		if (! $relation->get_this_model()->has_primary_key_field()) {
514
+			throw new EE_Error(
515
+				sprintf(
516
+					__(
517
+					// @codingStandardsIgnoreStart
518
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
519
+						// @codingStandardsIgnoreEnd
520
+						'event_espresso'
521
+					),
522
+					$relation->get_this_model()->get_this_model_name()
523
+				)
524
+			);
525
+		}
526
+		// can we edit that main item?
527
+		// if not, show nothing but an error
528
+		// otherwise, please proceed
529
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
530
+			array(
531
+				array(
532
+					$relation->get_this_model()->primary_key_name() => $id,
533
+				),
534
+			),
535
+			$relation,
536
+			$request
537
+		);
538
+	}
539
+
540
+
541
+	/**
542
+	 * Sets the headers that are based on the model and query params,
543
+	 * like the total records. This should only be called on the original request
544
+	 * from the client, not on subsequent internal
545
+	 *
546
+	 * @param EEM_Base $model
547
+	 * @param array    $query_params
548
+	 * @return void
549
+	 */
550
+	protected function setHeadersFromQueryParams($model, $query_params)
551
+	{
552
+		$this->setDebugInfo('model query params', $query_params);
553
+		$this->setDebugInfo(
554
+			'missing caps',
555
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
556
+		);
557
+		// normally the limit to a 2-part array, where the 2nd item is the limit
558
+		if (! isset($query_params['limit'])) {
559
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
560
+		}
561
+		if (is_array($query_params['limit'])) {
562
+			$limit_parts = $query_params['limit'];
563
+		} else {
564
+			$limit_parts = explode(',', $query_params['limit']);
565
+			if (count($limit_parts) == 1) {
566
+				$limit_parts = array(0, $limit_parts[0]);
567
+			}
568
+		}
569
+		// remove the group by and having parts of the query, as those will
570
+		// make the sql query return an array of values, instead of just a single value
571
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
572
+		$count = $model->count($query_params, null, true);
573
+		$pages = $count / $limit_parts[1];
574
+		$this->setResponseHeader('Total', $count, false);
575
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
576
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
577
+	}
578
+
579
+
580
+	/**
581
+	 * Changes database results into REST API entities
582
+	 *
583
+	 * @param EEM_Base $model
584
+	 * @param array $db_row like results from $wpdb->get_results()
585
+	 * @param WP_REST_Request $rest_request
586
+	 * @param string $deprecated no longer used
587
+	 * @return array ready for being converted into json for sending to client
588
+	 * @throws EE_Error
589
+	 * @throws RestException
590
+	 * @throws InvalidDataTypeException
591
+	 * @throws InvalidInterfaceException
592
+	 * @throws InvalidArgumentException
593
+	 * @throws ReflectionException
594
+	 */
595
+	public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
596
+	{
597
+		if (! $rest_request instanceof WP_REST_Request) {
598
+			// ok so this was called in the old style, where the 3rd arg was
599
+			// $include, and the 4th arg was $context
600
+			// now setup the request just to avoid fatal errors, although we won't be able
601
+			// to truly make use of it because it's kinda devoid of info
602
+			$rest_request = new WP_REST_Request();
603
+			$rest_request->set_param('include', $rest_request);
604
+			$rest_request->set_param('caps', $deprecated);
605
+		}
606
+		if ($rest_request->get_param('caps') == null) {
607
+			$rest_request->set_param('caps', EEM_Base::caps_read);
608
+		}
609
+		$current_user_full_access_to_entity = $model->currentUserCan(
610
+			EEM_Base::caps_read_admin,
611
+			$model->deduce_fields_n_values_from_cols_n_values($db_row)
612
+		);
613
+		$entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
614
+		$entity_array = $this->addExtraFields($model, $db_row, $entity_array);
615
+		$entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
616
+		// when it's a regular read request for a model with a password and the password wasn't provided
617
+		// remove the password protected fields
618
+		$has_protected_fields = false;
619
+		try {
620
+			$this->checkPassword(
621
+				$model,
622
+				$db_row,
623
+				$model->alter_query_params_to_restrict_by_ID(
624
+					$model->get_index_primary_key_string(
625
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
626
+					)
627
+				),
628
+				$rest_request
629
+			);
630
+		} catch (RestPasswordRequiredException $e) {
631
+			if ($model->hasPassword()) {
632
+				// just remove protected fields
633
+				$has_protected_fields = true;
634
+				$entity_array = Capabilities::filterOutPasswordProtectedFields(
635
+					$entity_array,
636
+					$model,
637
+					$this->getModelVersionInfo()
638
+				);
639
+			} else {
640
+				// that's a problem. None of this should be accessible if no password was provided
641
+				throw $e;
642
+			}
643
+		}
644
+
645
+		$entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields);
646
+		$entity_array = apply_filters(
647
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
648
+			$entity_array,
649
+			$model,
650
+			$rest_request->get_param('caps'),
651
+			$rest_request,
652
+			$this
653
+		);
654
+		// add an empty protected property for now. If it's still around after we remove everything the request didn't
655
+		// want, we'll populate it then. k?
656
+		$entity_array['_protected'] = array();
657
+		// remove any properties the request didn't want. This way _protected won't bother mentioning them
658
+		$entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
659
+		$entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields);
660
+		// if they still wanted the _protected property, add it.
661
+		if (isset($entity_array['_protected'])) {
662
+			$entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
663
+		}
664
+		$entity_array = apply_filters(
665
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
666
+			$entity_array,
667
+			$model,
668
+			$rest_request->get_param('caps'),
669
+			$rest_request,
670
+			$this
671
+		);
672
+		if (! $current_user_full_access_to_entity) {
673
+			$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
674
+				$entity_array,
675
+				$model,
676
+				$rest_request->get_param('caps'),
677
+				$this->getModelVersionInfo()
678
+			);
679
+		} else {
680
+			$result_without_inaccessible_fields = $entity_array;
681
+		}
682
+		$this->setDebugInfo(
683
+			'inaccessible fields',
684
+			array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
685
+		);
686
+		return apply_filters(
687
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
688
+			$result_without_inaccessible_fields,
689
+			$model,
690
+			$rest_request->get_param('caps')
691
+		);
692
+	}
693
+
694
+	/**
695
+	 * Returns an array describing which fields can be protected, and which actually were removed this request
696
+	 * @since 4.9.74.p
697
+	 * @param $model
698
+	 * @param $results_so_far
699
+	 * @param $protected
700
+	 * @return array results
701
+	 */
702
+	protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
703
+	{
704
+		if (! $model->hasPassword() || ! $protected) {
705
+			return $results_so_far;
706
+		}
707
+		$password_field = $model->getPasswordField();
708
+		$all_protected = array_merge(
709
+			array($password_field->get_name()),
710
+			$password_field->protectedFields()
711
+		);
712
+		$fields_included = array_keys($results_so_far);
713
+		$fields_included = array_intersect(
714
+			$all_protected,
715
+			$fields_included
716
+		);
717
+		foreach ($fields_included as $field_name) {
718
+			$results_so_far['_protected'][] = $field_name ;
719
+		}
720
+		return $results_so_far;
721
+	}
722
+
723
+	/**
724
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
725
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
726
+	 * from $wpdb->get_row( $sql, ARRAY_A)
727
+	 *
728
+	 * @param EEM_Base $model
729
+	 * @param array    $db_row
730
+	 * @return array entity mostly ready for converting to JSON and sending in the response
731
+	 */
732
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
733
+	{
734
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
735
+		$result = array_intersect_key(
736
+			$result,
737
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
738
+		);
739
+		// if this is a CPT, we need to set the global $post to it,
740
+		// otherwise shortcodes etc won't work properly while rendering it
741
+		if ($model instanceof \EEM_CPT_Base) {
742
+			$do_chevy_shuffle = true;
743
+		} else {
744
+			$do_chevy_shuffle = false;
745
+		}
746
+		if ($do_chevy_shuffle) {
747
+			global $post;
748
+			$old_post = $post;
749
+			$post = get_post($result[ $model->primary_key_name() ]);
750
+			if (! $post instanceof \WP_Post) {
751
+				// well that's weird, because $result is what we JUST fetched from the database
752
+				throw new RestException(
753
+					'error_fetching_post_from_database_results',
754
+					esc_html__(
755
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
756
+						'event_espresso'
757
+					)
758
+				);
759
+			}
760
+			$model_object_classname = 'EE_' . $model->get_this_model_name();
761
+			$post->{$model_object_classname} = \EE_Registry::instance()->load_class(
762
+				$model_object_classname,
763
+				$result,
764
+				false,
765
+				false
766
+			);
767
+		}
768
+		foreach ($result as $field_name => $field_value) {
769
+			$field_obj = $model->field_settings_for($field_name);
770
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
771
+				unset($result[ $field_name ]);
772
+			} elseif ($this->isSubclassOfOne(
773
+				$field_obj,
774
+				$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
775
+			)
776
+			) {
777
+				$result[ $field_name ] = array(
778
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
779
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
780
+				);
781
+			} elseif ($this->isSubclassOfOne(
782
+				$field_obj,
783
+				$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
784
+			)
785
+			) {
786
+				$result[ $field_name ] = array(
787
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
788
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
789
+				);
790
+			} elseif ($field_obj instanceof \EE_Datetime_Field) {
791
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
792
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
793
+				if (is_null($field_value)) {
794
+					$field_value = $field_obj->getDefaultDateTimeObj();
795
+				}
796
+				if (is_null($field_value)) {
797
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
798
+						$field_obj,
799
+						$field_value,
800
+						$this->getModelVersionInfo()->requestedVersion()
801
+					);
802
+				} else {
803
+					$timezone = $field_value->getTimezone();
804
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
805
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
806
+						$field_obj,
807
+						$field_value,
808
+						$this->getModelVersionInfo()->requestedVersion()
809
+					);
810
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
811
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
812
+						$field_obj,
813
+						$field_value,
814
+						$this->getModelVersionInfo()->requestedVersion()
815
+					);
816
+				}
817
+				$result[ $field_name . '_gmt' ] = $gmt_date;
818
+				$result[ $field_name ] = $local_date;
819
+			} else {
820
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
821
+			}
822
+		}
823
+		if ($do_chevy_shuffle) {
824
+			$post = $old_post;
825
+		}
826
+		return $result;
827
+	}
828
+
829
+
830
+	/**
831
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
832
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
833
+	 * representation using $field_obj->prepare_for_set_from_db())
834
+	 *
835
+	 * @param EE_Model_Field_Base $field_obj
836
+	 * @param mixed               $value  as it's stored on a model object
837
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
838
+	 * @return mixed
839
+	 * @throws ObjectDetectedException if $value contains a PHP object
840
+	 */
841
+	protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
842
+	{
843
+		$value = $field_obj->prepare_for_set_from_db($value);
844
+		switch ($format) {
845
+			case 'pretty':
846
+				$value = $field_obj->prepare_for_pretty_echoing($value);
847
+				break;
848
+			case 'normal':
849
+			default:
850
+				$value = $field_obj->prepare_for_get($value);
851
+				break;
852
+		}
853
+		return ModelDataTranslator::prepareFieldValuesForJson(
854
+			$field_obj,
855
+			$value,
856
+			$this->getModelVersionInfo()->requestedVersion()
857
+		);
858
+	}
859
+
860
+
861
+	/**
862
+	 * Adds a few extra fields to the entity response
863
+	 *
864
+	 * @param EEM_Base $model
865
+	 * @param array    $db_row
866
+	 * @param array    $entity_array
867
+	 * @return array modified entity
868
+	 */
869
+	protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
870
+	{
871
+		if ($model instanceof EEM_CPT_Base) {
872
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
873
+		}
874
+		return $entity_array;
875
+	}
876
+
877
+
878
+	/**
879
+	 * Gets links we want to add to the response
880
+	 *
881
+	 * @global \WP_REST_Server $wp_rest_server
882
+	 * @param EEM_Base         $model
883
+	 * @param array            $db_row
884
+	 * @param array            $entity_array
885
+	 * @return array the _links item in the entity
886
+	 */
887
+	protected function getEntityLinks($model, $db_row, $entity_array)
888
+	{
889
+		// add basic links
890
+		$links = array();
891
+		if ($model->has_primary_key_field()) {
892
+			$links['self'] = array(
893
+				array(
894
+					'href' => $this->getVersionedLinkTo(
895
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
896
+						. '/'
897
+						. $entity_array[ $model->primary_key_name() ]
898
+					),
899
+				),
900
+			);
901
+		}
902
+		$links['collection'] = array(
903
+			array(
904
+				'href' => $this->getVersionedLinkTo(
905
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
906
+				),
907
+			),
908
+		);
909
+		// add links to related models
910
+		if ($model->has_primary_key_field()) {
911
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
912
+				$related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
913
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
914
+					array(
915
+						'href'   => $this->getVersionedLinkTo(
916
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
917
+							. '/'
918
+							. $entity_array[ $model->primary_key_name() ]
919
+							. '/'
920
+							. $related_model_part
921
+						),
922
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
923
+					),
924
+				);
925
+			}
926
+		}
927
+		return $links;
928
+	}
929
+
930
+
931
+	/**
932
+	 * Adds the included models indicated in the request to the entity provided
933
+	 *
934
+	 * @param EEM_Base $model
935
+	 * @param WP_REST_Request $rest_request
936
+	 * @param array $entity_array
937
+	 * @param array $db_row
938
+	 * @param boolean $included_items_protected if the original item is password protected, don't include any related models.
939
+	 * @return array the modified entity
940
+	 * @throws RestException
941
+	 */
942
+	protected function includeRequestedModels(
943
+		EEM_Base $model,
944
+		WP_REST_Request $rest_request,
945
+		$entity_array,
946
+		$db_row = array(),
947
+		$included_items_protected = false
948
+	) {
949
+		// if $db_row not included, hope the entity array has what we need
950
+		if (! $db_row) {
951
+			$db_row = $entity_array;
952
+		}
953
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
954
+		foreach ($relation_settings as $relation_name => $relation_obj) {
955
+			$related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
956
+				$rest_request->get_param('include'),
957
+				$relation_name
958
+			);
959
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
960
+				$rest_request->get_param('calculate'),
961
+				$relation_name
962
+			);
963
+			// did they specify they wanted to include a related model, or
964
+			// specific fields from a related model?
965
+			// or did they specify to calculate a field from a related model?
966
+			if ($related_fields_to_include || $related_fields_to_calculate) {
967
+				// if so, we should include at least some part of the related model
968
+				$pretend_related_request = new WP_REST_Request();
969
+				$pretend_related_request->set_query_params(
970
+					array(
971
+						'caps'      => $rest_request->get_param('caps'),
972
+						'include'   => $related_fields_to_include,
973
+						'calculate' => $related_fields_to_calculate,
974
+						'password' => $rest_request->get_param('password')
975
+					)
976
+				);
977
+				$pretend_related_request->add_header('no_rest_headers', true);
978
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
979
+					$model->get_index_primary_key_string(
980
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
981
+					)
982
+				);
983
+				if (! $included_items_protected) {
984
+					try {
985
+						$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
986
+							$primary_model_query_params,
987
+							$relation_obj,
988
+							$pretend_related_request
989
+						);
990
+					} catch (RestException $e) {
991
+						$related_results = null;
992
+					}
993
+				} else {
994
+					// they're protected, hide them.
995
+					$related_results = null;
996
+					$entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
997
+				}
998
+				if ($related_results instanceof WP_Error || $related_results === null) {
999
+					$related_results = $relation_obj instanceof EE_Belongs_To_Relation ? null : array();
1000
+				}
1001
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1002
+			}
1003
+		}
1004
+		return $entity_array;
1005
+	}
1006
+
1007
+	/**
1008
+	 * If the user has requested only specific properties (including meta properties like _links or _protected)
1009
+	 * remove everything else.
1010
+	 * @since 4.9.74.p
1011
+	 * @param EEM_Base $model
1012
+	 * @param WP_REST_Request $rest_request
1013
+	 * @param $entity_array
1014
+	 * @return array
1015
+	 * @throws EE_Error
1016
+	 */
1017
+	protected function includeOnlyRequestedProperties(
1018
+		EEM_Base $model,
1019
+		WP_REST_Request $rest_request,
1020
+		$entity_array
1021
+	) {
1022
+
1023
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1024
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1025
+		// if they passed in * or didn't specify any includes, return everything
1026
+		if (! in_array('*', $includes_for_this_model)
1027
+			&& ! empty($includes_for_this_model)
1028
+		) {
1029
+			if ($model->has_primary_key_field()) {
1030
+				// always include the primary key. ya just gotta know that at least
1031
+				$includes_for_this_model[] = $model->primary_key_name();
1032
+			}
1033
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1034
+				$includes_for_this_model[] = '_calculated_fields';
1035
+			}
1036
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1037
+		}
1038
+		return $entity_array;
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * Returns a new array with all the names of models removed. Eg
1044
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1045
+	 *
1046
+	 * @param array $arr
1047
+	 * @return array
1048
+	 */
1049
+	private function removeModelNamesFromArray($arr)
1050
+	{
1051
+		return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
1052
+	}
1053
+
1054
+
1055
+	/**
1056
+	 * Gets the calculated fields for the response
1057
+	 *
1058
+	 * @param EEM_Base        $model
1059
+	 * @param array           $wpdb_row
1060
+	 * @param WP_REST_Request $rest_request
1061
+	 * @param boolean $row_is_protected whether this row is password protected or not
1062
+	 * @return \stdClass the _calculations item in the entity
1063
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
1064
+	 * did, let's know about it ASAP, so let the exception bubble up)
1065
+	 */
1066
+	protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false)
1067
+	{
1068
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1069
+			$rest_request->get_param('calculate'),
1070
+			''
1071
+		);
1072
+		// note: setting calculate=* doesn't do anything
1073
+		$calculated_fields_to_return = new \stdClass();
1074
+		$protected_fields = array();
1075
+		foreach ($calculated_fields as $field_to_calculate) {
1076
+			try {
1077
+				// it's password protected, so they shouldn't be able to read this. Remove the value
1078
+				$schema = $this->fields_calculator->getJsonSchemaForModel($model);
1079
+				if ($row_is_protected
1080
+					&& isset($schema['properties'][ $field_to_calculate ]['protected'])
1081
+					&& $schema['properties'][ $field_to_calculate ]['protected']) {
1082
+					$calculated_value = null;
1083
+					$protected_fields[] = $field_to_calculate;
1084
+					if ($schema['properties'][ $field_to_calculate ]['type']) {
1085
+						switch ($schema['properties'][ $field_to_calculate ]['type']) {
1086
+							case 'boolean':
1087
+								$calculated_value = false;
1088
+								break;
1089
+							case 'integer':
1090
+								$calculated_value = 0;
1091
+								break;
1092
+							case 'string':
1093
+								$calculated_value = '';
1094
+								break;
1095
+							case 'array':
1096
+								$calculated_value = array();
1097
+								break;
1098
+							case 'object':
1099
+								$calculated_value = new stdClass();
1100
+								break;
1101
+						}
1102
+					}
1103
+				} else {
1104
+					$calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1105
+						null,
1106
+						$this->fields_calculator->retrieveCalculatedFieldValue(
1107
+							$model,
1108
+							$field_to_calculate,
1109
+							$wpdb_row,
1110
+							$rest_request,
1111
+							$this
1112
+						),
1113
+						$this->getModelVersionInfo()->requestedVersion()
1114
+					);
1115
+				}
1116
+				$calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1117
+			} catch (RestException $e) {
1118
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
1119
+				$this->setResponseHeader(
1120
+					'Notices-Field-Calculation-Errors['
1121
+					. $e->getStringCode()
1122
+					. ']['
1123
+					. $model->get_this_model_name()
1124
+					. ']['
1125
+					. $field_to_calculate
1126
+					. ']',
1127
+					$e->getMessage(),
1128
+					true
1129
+				);
1130
+			}
1131
+		}
1132
+		$calculated_fields_to_return->_protected = $protected_fields;
1133
+		return $calculated_fields_to_return;
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * Gets the full URL to the resource, taking the requested version into account
1139
+	 *
1140
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1141
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1142
+	 */
1143
+	public function getVersionedLinkTo($link_part_after_version_and_slash)
1144
+	{
1145
+		return rest_url(
1146
+			EED_Core_Rest_Api::get_versioned_route_to(
1147
+				$link_part_after_version_and_slash,
1148
+				$this->getModelVersionInfo()->requestedVersion()
1149
+			)
1150
+		);
1151
+	}
1152
+
1153
+
1154
+	/**
1155
+	 * Gets the correct lowercase name for the relation in the API according
1156
+	 * to the relation's type
1157
+	 *
1158
+	 * @param string                  $relation_name
1159
+	 * @param \EE_Model_Relation_Base $relation_obj
1160
+	 * @return string
1161
+	 */
1162
+	public static function getRelatedEntityName($relation_name, $relation_obj)
1163
+	{
1164
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1165
+			return strtolower($relation_name);
1166
+		} else {
1167
+			return EEH_Inflector::pluralize_and_lower($relation_name);
1168
+		}
1169
+	}
1170
+
1171
+
1172
+	/**
1173
+	 * Gets the one model object with the specified id for the specified model
1174
+	 *
1175
+	 * @param EEM_Base        $model
1176
+	 * @param WP_REST_Request $request
1177
+	 * @return array
1178
+	 */
1179
+	public function getEntityFromModel($model, $request)
1180
+	{
1181
+		$context = $this->validateContext($request->get_param('caps'));
1182
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1183
+	}
1184
+
1185
+
1186
+	/**
1187
+	 * If a context is provided which isn't valid, maybe it was added in a future
1188
+	 * version so just treat it as a default read
1189
+	 *
1190
+	 * @param string $context
1191
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1192
+	 */
1193
+	public function validateContext($context)
1194
+	{
1195
+		if (! $context) {
1196
+			$context = EEM_Base::caps_read;
1197
+		}
1198
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1199
+		if (in_array($context, $valid_contexts)) {
1200
+			return $context;
1201
+		} else {
1202
+			return EEM_Base::caps_read;
1203
+		}
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 * Verifies the passed in value is an allowable default where conditions value.
1209
+	 *
1210
+	 * @param $default_query_params
1211
+	 * @return string
1212
+	 */
1213
+	public function validateDefaultQueryParams($default_query_params)
1214
+	{
1215
+		$valid_default_where_conditions_for_api_calls = array(
1216
+			EEM_Base::default_where_conditions_all,
1217
+			EEM_Base::default_where_conditions_minimum_all,
1218
+			EEM_Base::default_where_conditions_minimum_others,
1219
+		);
1220
+		if (! $default_query_params) {
1221
+			$default_query_params = EEM_Base::default_where_conditions_all;
1222
+		}
1223
+		if (in_array(
1224
+			$default_query_params,
1225
+			$valid_default_where_conditions_for_api_calls,
1226
+			true
1227
+		)) {
1228
+			return $default_query_params;
1229
+		} else {
1230
+			return EEM_Base::default_where_conditions_all;
1231
+		}
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 * Translates API filter get parameter into model query params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1237
+	 * Note: right now the query parameter keys for fields (and related fields)
1238
+	 * can be left as-is, but it's quite possible this will change someday.
1239
+	 * Also, this method's contents might be candidate for moving to Model_Data_Translator
1240
+	 *
1241
+	 * @param EEM_Base $model
1242
+	 * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1243
+	 * @return array model query params (@see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1244
+	 *                                    or FALSE to indicate that absolutely no results should be returned
1245
+	 * @throws EE_Error
1246
+	 * @throws RestException
1247
+	 */
1248
+	public function createModelQueryParams($model, $query_params)
1249
+	{
1250
+		$model_query_params = array();
1251
+		if (isset($query_params['where'])) {
1252
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1253
+				$query_params['where'],
1254
+				$model,
1255
+				$this->getModelVersionInfo()->requestedVersion()
1256
+			);
1257
+		}
1258
+		if (isset($query_params['order_by'])) {
1259
+			$order_by = $query_params['order_by'];
1260
+		} elseif (isset($query_params['orderby'])) {
1261
+			$order_by = $query_params['orderby'];
1262
+		} else {
1263
+			$order_by = null;
1264
+		}
1265
+		if ($order_by !== null) {
1266
+			if (is_array($order_by)) {
1267
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1268
+			} else {
1269
+				// it's a single item
1270
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1271
+			}
1272
+			$model_query_params['order_by'] = $order_by;
1273
+		}
1274
+		if (isset($query_params['group_by'])) {
1275
+			$group_by = $query_params['group_by'];
1276
+		} elseif (isset($query_params['groupby'])) {
1277
+			$group_by = $query_params['groupby'];
1278
+		} else {
1279
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1280
+		}
1281
+		// make sure they're all real names
1282
+		if (is_array($group_by)) {
1283
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1284
+		}
1285
+		if ($group_by !== null) {
1286
+			$model_query_params['group_by'] = $group_by;
1287
+		}
1288
+		if (isset($query_params['having'])) {
1289
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1290
+				$query_params['having'],
1291
+				$model,
1292
+				$this->getModelVersionInfo()->requestedVersion()
1293
+			);
1294
+		}
1295
+		if (isset($query_params['order'])) {
1296
+			$model_query_params['order'] = $query_params['order'];
1297
+		}
1298
+		if (isset($query_params['mine'])) {
1299
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1300
+		}
1301
+		if (isset($query_params['limit'])) {
1302
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1303
+			if (! is_array($query_params['limit'])) {
1304
+				$limit_array = explode(',', (string) $query_params['limit']);
1305
+			} else {
1306
+				$limit_array = $query_params['limit'];
1307
+			}
1308
+			$sanitized_limit = array();
1309
+			foreach ($limit_array as $key => $limit_part) {
1310
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1311
+					throw new EE_Error(
1312
+						sprintf(
1313
+							__(
1314
+							// @codingStandardsIgnoreStart
1315
+								'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.',
1316
+								// @codingStandardsIgnoreEnd
1317
+								'event_espresso'
1318
+							),
1319
+							wp_json_encode($query_params['limit'])
1320
+						)
1321
+					);
1322
+				}
1323
+				$sanitized_limit[] = (int) $limit_part;
1324
+			}
1325
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1326
+		} else {
1327
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1328
+		}
1329
+		if (isset($query_params['caps'])) {
1330
+			$model_query_params['caps'] = $this->validateContext($query_params['caps']);
1331
+		} else {
1332
+			$model_query_params['caps'] = EEM_Base::caps_read;
1333
+		}
1334
+		if (isset($query_params['default_where_conditions'])) {
1335
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1336
+				$query_params['default_where_conditions']
1337
+			);
1338
+		}
1339
+		// if this is a model protected by a password on another model, exclude the password protected
1340
+		// entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1341
+		// though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1342
+		if (! $model->hasPassword()
1343
+			&& $model->restrictedByRelatedModelPassword()
1344
+			&& $model_query_params['caps'] === EEM_Base::caps_read) {
1345
+			if (empty($query_params['password'])) {
1346
+				$model_query_params['exclude_protected'] = true;
1347
+			}
1348
+		}
1349
+
1350
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1351
+	}
1352
+
1353
+
1354
+	/**
1355
+	 * Changes the REST-style query params for use in the models
1356
+	 *
1357
+	 * @deprecated
1358
+	 * @param EEM_Base $model
1359
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1360
+	 * @return array
1361
+	 */
1362
+	public function prepareRestQueryParamsKeyForModels($model, $query_params)
1363
+	{
1364
+		$model_ready_query_params = array();
1365
+		foreach ($query_params as $key => $value) {
1366
+			if (is_array($value)) {
1367
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1368
+			} else {
1369
+				$model_ready_query_params[ $key ] = $value;
1370
+			}
1371
+		}
1372
+		return $model_ready_query_params;
1373
+	}
1374
+
1375
+
1376
+	/**
1377
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1378
+	 * @param $model
1379
+	 * @param $query_params
1380
+	 * @return array
1381
+	 */
1382
+	public function prepareRestQueryParamsValuesForModels($model, $query_params)
1383
+	{
1384
+		$model_ready_query_params = array();
1385
+		foreach ($query_params as $key => $value) {
1386
+			if (is_array($value)) {
1387
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1388
+			} else {
1389
+				$model_ready_query_params[ $key ] = $value;
1390
+			}
1391
+		}
1392
+		return $model_ready_query_params;
1393
+	}
1394
+
1395
+
1396
+	/**
1397
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1398
+	 * If no prefix is specified, returns items with no period.
1399
+	 *
1400
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1401
+	 * @param string       $prefix            "Event" or "foobar"
1402
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1403
+	 *                                        we only return strings starting with that and a period; if no prefix was
1404
+	 *                                        specified we return all items containing NO periods
1405
+	 */
1406
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1407
+	{
1408
+		if (is_string($string_to_explode)) {
1409
+			$exploded_contents = explode(',', $string_to_explode);
1410
+		} elseif (is_array($string_to_explode)) {
1411
+			$exploded_contents = $string_to_explode;
1412
+		} else {
1413
+			$exploded_contents = array();
1414
+		}
1415
+		// if the string was empty, we want an empty array
1416
+		$exploded_contents = array_filter($exploded_contents);
1417
+		$contents_with_prefix = array();
1418
+		foreach ($exploded_contents as $item) {
1419
+			$item = trim($item);
1420
+			// if no prefix was provided, so we look for items with no "." in them
1421
+			if (! $prefix) {
1422
+				// does this item have a period?
1423
+				if (strpos($item, '.') === false) {
1424
+					// if not, then its what we're looking for
1425
+					$contents_with_prefix[] = $item;
1426
+				}
1427
+			} elseif (strpos($item, $prefix . '.') === 0) {
1428
+				// this item has the prefix and a period, grab it
1429
+				$contents_with_prefix[] = substr(
1430
+					$item,
1431
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1432
+				);
1433
+			} elseif ($item === $prefix) {
1434
+				// this item is JUST the prefix
1435
+				// so let's grab everything after, which is a blank string
1436
+				$contents_with_prefix[] = '';
1437
+			}
1438
+		}
1439
+		return $contents_with_prefix;
1440
+	}
1441
+
1442
+
1443
+	/**
1444
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1445
+	 * Deprecated because its return values were really quite confusing- sometimes it returned
1446
+	 * an empty array (when the include string was blank or '*') or sometimes it returned
1447
+	 * array('*') (when you provided a model and a model of that kind was found).
1448
+	 * Parses the $include_string so we fetch all the field names relating to THIS model
1449
+	 * (ie have NO period in them), or for the provided model (ie start with the model
1450
+	 * name and then a period).
1451
+	 * @param string $include_string @see Read:handle_request_get_all
1452
+	 * @param string $model_name
1453
+	 * @return array of fields for this model. If $model_name is provided, then
1454
+	 *                               the fields for that model, with the model's name removed from each.
1455
+	 *                               If $include_string was blank or '*' returns an empty array
1456
+	 */
1457
+	public function extractIncludesForThisModel($include_string, $model_name = null)
1458
+	{
1459
+		if (is_array($include_string)) {
1460
+			$include_string = implode(',', $include_string);
1461
+		}
1462
+		if ($include_string === '*' || $include_string === '') {
1463
+			return array();
1464
+		}
1465
+		$includes = explode(',', $include_string);
1466
+		$extracted_fields_to_include = array();
1467
+		if ($model_name) {
1468
+			foreach ($includes as $field_to_include) {
1469
+				$field_to_include = trim($field_to_include);
1470
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1471
+					// found the model name at the exact start
1472
+					$field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1473
+					$extracted_fields_to_include[] = $field_sans_model_name;
1474
+				} elseif ($field_to_include == $model_name) {
1475
+					$extracted_fields_to_include[] = '*';
1476
+				}
1477
+			}
1478
+		} else {
1479
+			// look for ones with no period
1480
+			foreach ($includes as $field_to_include) {
1481
+				$field_to_include = trim($field_to_include);
1482
+				if (strpos($field_to_include, '.') === false
1483
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1484
+				) {
1485
+					$extracted_fields_to_include[] = $field_to_include;
1486
+				}
1487
+			}
1488
+		}
1489
+		return $extracted_fields_to_include;
1490
+	}
1491
+
1492
+
1493
+	/**
1494
+	 * Gets the single item using the model according to the request in the context given, otherwise
1495
+	 * returns that it's inaccessible to the current user
1496
+	 *
1497
+	 * @param EEM_Base $model
1498
+	 * @param WP_REST_Request $request
1499
+	 * @param null $context
1500
+	 * @return array
1501
+	 * @throws EE_Error
1502
+	 */
1503
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1504
+	{
1505
+		$query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1506
+		if ($model instanceof EEM_Soft_Delete_Base) {
1507
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1508
+		}
1509
+		$restricted_query_params = $query_params;
1510
+		$restricted_query_params['caps'] = $context;
1511
+		$this->setDebugInfo('model query params', $restricted_query_params);
1512
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1513
+		if (! empty($model_rows)) {
1514
+			return $this->createEntityFromWpdbResult(
1515
+				$model,
1516
+				reset($model_rows),
1517
+				$request
1518
+			);
1519
+		} else {
1520
+			// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1521
+			$lowercase_model_name = strtolower($model->get_this_model_name());
1522
+			if ($model->exists($query_params)) {
1523
+				// you got shafted- it existed but we didn't want to tell you!
1524
+				throw new RestException(
1525
+					'rest_user_cannot_' . $context,
1526
+					sprintf(
1527
+						__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1528
+						$context,
1529
+						$lowercase_model_name,
1530
+						Capabilities::getMissingPermissionsString(
1531
+							$model,
1532
+							$context
1533
+						)
1534
+					),
1535
+					array('status' => 403)
1536
+				);
1537
+			} else {
1538
+				// it's not you. It just doesn't exist
1539
+				throw new RestException(
1540
+					sprintf('rest_%s_invalid_id', $lowercase_model_name),
1541
+					sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1542
+					array('status' => 404)
1543
+				);
1544
+			}
1545
+		}
1546
+	}
1547
+
1548
+	/**
1549
+	 * Checks that if this content requires a password to be read, that it's been provided and is correct.
1550
+	 * @since 4.9.74.p
1551
+	 * @param EEM_Base $model
1552
+	 * @param $model_row
1553
+	 * @param $query_params Adds 'default_where_conditions' => 'minimum' to ensure we don't confuse trashed with
1554
+	 *                      password protected.
1555
+	 * @param WP_REST_Request $request
1556
+	 * @throws EE_Error
1557
+	 * @throws InvalidArgumentException
1558
+	 * @throws InvalidDataTypeException
1559
+	 * @throws InvalidInterfaceException
1560
+	 * @throws RestPasswordRequiredException
1561
+	 * @throws RestPasswordIncorrectException
1562
+	 * @throws \EventEspresso\core\exceptions\ModelConfigurationException
1563
+	 * @throws ReflectionException
1564
+	 */
1565
+	protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request)
1566
+	{
1567
+		$query_params['default_where_conditions'] = 'minimum';
1568
+		// stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1569
+		// or you don't.
1570
+		$request_caps = $request->get_param('caps');
1571
+		if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1572
+			return;
1573
+		}
1574
+		// if this entity requires a password, they better give it and it better be right!
1575
+		if ($model->hasPassword()
1576
+			&& $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '') {
1577
+			if (empty($request['password'])) {
1578
+				throw new RestPasswordRequiredException();
1579
+			} elseif (!hash_equals(
1580
+				$model_row[ $model->getPasswordField()->get_qualified_column() ],
1581
+				$request['password']
1582
+			)) {
1583
+				throw new RestPasswordIncorrectException();
1584
+			}
1585
+		} // wait! maybe this content is password protected
1586
+		elseif ($model->restrictedByRelatedModelPassword()
1587
+			&& $request->get_param('caps') === EEM_Base::caps_read) {
1588
+			$password_supplied = $request->get_param('password');
1589
+			if (empty($password_supplied)) {
1590
+				$query_params['exclude_protected'] = true;
1591
+				if (!$model->exists($query_params)) {
1592
+					throw new RestPasswordRequiredException();
1593
+				}
1594
+			} else {
1595
+				$query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1596
+				if (!$model->exists($query_params)) {
1597
+					throw new RestPasswordIncorrectException();
1598
+				}
1599
+			}
1600
+		}
1601
+	}
1602 1602
 }
Please login to merge, or discard this patch.
Spacing   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -78,7 +78,7 @@  discard block
 block discarded – undo
78 78
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
79 79
         try {
80 80
             $controller->setRequestedVersion($version);
81
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
81
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
82 82
                 return $controller->sendResponse(
83 83
                     new WP_Error(
84 84
                         'endpoint_parsing_error',
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
120 120
         try {
121 121
             $controller->setRequestedVersion($version);
122
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
122
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
123 123
                 return array();
124 124
             }
125 125
             // get the model for this version
@@ -176,11 +176,11 @@  discard block
 block discarded – undo
176 176
      */
177 177
     protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
178 178
     {
179
-        if (isset($schema['properties'][ $field_name ]['default'])) {
180
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
181
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
179
+        if (isset($schema['properties'][$field_name]['default'])) {
180
+            if (is_array($schema['properties'][$field_name]['default'])) {
181
+                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
182 182
                     if ($default_key === 'raw') {
183
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
183
+                        $schema['properties'][$field_name]['default'][$default_key] =
184 184
                             ModelDataTranslator::prepareFieldValueForJson(
185 185
                                 $field,
186 186
                                 $default_value,
@@ -189,9 +189,9 @@  discard block
 block discarded – undo
189 189
                     }
190 190
                 }
191 191
             } else {
192
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
192
+                $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson(
193 193
                     $field,
194
-                    $schema['properties'][ $field_name ]['default'],
194
+                    $schema['properties'][$field_name]['default'],
195 195
                     $this->getModelVersionInfo()->requestedVersion()
196 196
                 );
197 197
             }
@@ -213,9 +213,9 @@  discard block
 block discarded – undo
213 213
     protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
214 214
     {
215 215
         if ($field instanceof EE_Datetime_Field) {
216
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
216
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
217 217
             // modify the description
218
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
218
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
219 219
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
220 220
                 wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
221 221
             );
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
259 259
         try {
260 260
             $controller->setRequestedVersion($version);
261
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
261
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
262 262
                 return $controller->sendResponse(
263 263
                     new WP_Error(
264 264
                         'endpoint_parsing_error',
@@ -337,7 +337,7 @@  discard block
 block discarded – undo
337 337
     public function getEntitiesFromModel($model, $request)
338 338
     {
339 339
         $query_params = $this->createModelQueryParams($model, $request->get_params());
340
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
340
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
341 341
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
342 342
             throw new RestException(
343 343
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -349,14 +349,14 @@  discard block
 block discarded – undo
349 349
                 array('status' => 403)
350 350
             );
351 351
         }
352
-        if (! $request->get_header('no_rest_headers')) {
352
+        if ( ! $request->get_header('no_rest_headers')) {
353 353
             $this->setHeadersFromQueryParams($model, $query_params);
354 354
         }
355 355
         /** @type array $results */
356 356
         $results = $model->get_all_wpdb_results($query_params);
357 357
         $nice_results = array();
358 358
         foreach ($results as $result) {
359
-            $nice_results[] =  $this->createEntityFromWpdbResult(
359
+            $nice_results[] = $this->createEntityFromWpdbResult(
360 360
                 $model,
361 361
                 $result,
362 362
                 $request
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
         $context = $this->validateContext($request->get_param('caps'));
391 391
         $model = $relation->get_this_model();
392 392
         $related_model = $relation->get_other_model();
393
-        if (! isset($primary_model_query_params[0])) {
393
+        if ( ! isset($primary_model_query_params[0])) {
394 394
             $primary_model_query_params[0] = array();
395 395
         }
396 396
         // check if they can access the 1st model object
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
         if (is_array($primary_model_rows)) {
414 414
             $primary_model_row = reset($primary_model_rows);
415 415
         }
416
-        if (! (
416
+        if ( ! (
417 417
             Capabilities::currentUserHasPartialAccessTo($related_model, $context)
418 418
             && $primary_model_row
419 419
         )
@@ -453,13 +453,13 @@  discard block
 block discarded – undo
453 453
         );
454 454
         $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
455 455
         foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
456
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
456
+            $query_params[0][$relation->get_this_model()->get_this_model_name()
457 457
                               . '.'
458
-                              . $where_condition_key ] = $where_condition_value;
458
+                              . $where_condition_key] = $where_condition_value;
459 459
         }
460 460
         $query_params['default_where_conditions'] = 'none';
461 461
         $query_params['caps'] = $context;
462
-        if (! $request->get_header('no_rest_headers')) {
462
+        if ( ! $request->get_header('no_rest_headers')) {
463 463
             $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
464 464
         }
465 465
         /** @type array $results */
@@ -510,7 +510,7 @@  discard block
 block discarded – undo
510 510
      */
511 511
     public function getEntitiesFromRelation($id, $relation, $request)
512 512
     {
513
-        if (! $relation->get_this_model()->has_primary_key_field()) {
513
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
514 514
             throw new EE_Error(
515 515
                 sprintf(
516 516
                     __(
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
             Capabilities::getMissingPermissionsString($model, $query_params['caps'])
556 556
         );
557 557
         // normally the limit to a 2-part array, where the 2nd item is the limit
558
-        if (! isset($query_params['limit'])) {
558
+        if ( ! isset($query_params['limit'])) {
559 559
             $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
560 560
         }
561 561
         if (is_array($query_params['limit'])) {
@@ -594,7 +594,7 @@  discard block
 block discarded – undo
594 594
      */
595 595
     public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
596 596
     {
597
-        if (! $rest_request instanceof WP_REST_Request) {
597
+        if ( ! $rest_request instanceof WP_REST_Request) {
598 598
             // ok so this was called in the old style, where the 3rd arg was
599 599
             // $include, and the 4th arg was $context
600 600
             // now setup the request just to avoid fatal errors, although we won't be able
@@ -669,7 +669,7 @@  discard block
 block discarded – undo
669 669
             $rest_request,
670 670
             $this
671 671
         );
672
-        if (! $current_user_full_access_to_entity) {
672
+        if ( ! $current_user_full_access_to_entity) {
673 673
             $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
674 674
                 $entity_array,
675 675
                 $model,
@@ -701,7 +701,7 @@  discard block
 block discarded – undo
701 701
      */
702 702
     protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
703 703
     {
704
-        if (! $model->hasPassword() || ! $protected) {
704
+        if ( ! $model->hasPassword() || ! $protected) {
705 705
             return $results_so_far;
706 706
         }
707 707
         $password_field = $model->getPasswordField();
@@ -715,7 +715,7 @@  discard block
 block discarded – undo
715 715
             $fields_included
716 716
         );
717 717
         foreach ($fields_included as $field_name) {
718
-            $results_so_far['_protected'][] = $field_name ;
718
+            $results_so_far['_protected'][] = $field_name;
719 719
         }
720 720
         return $results_so_far;
721 721
     }
@@ -746,8 +746,8 @@  discard block
 block discarded – undo
746 746
         if ($do_chevy_shuffle) {
747 747
             global $post;
748 748
             $old_post = $post;
749
-            $post = get_post($result[ $model->primary_key_name() ]);
750
-            if (! $post instanceof \WP_Post) {
749
+            $post = get_post($result[$model->primary_key_name()]);
750
+            if ( ! $post instanceof \WP_Post) {
751 751
                 // well that's weird, because $result is what we JUST fetched from the database
752 752
                 throw new RestException(
753 753
                     'error_fetching_post_from_database_results',
@@ -757,7 +757,7 @@  discard block
 block discarded – undo
757 757
                     )
758 758
                 );
759 759
             }
760
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
760
+            $model_object_classname = 'EE_'.$model->get_this_model_name();
761 761
             $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
762 762
                 $model_object_classname,
763 763
                 $result,
@@ -768,13 +768,13 @@  discard block
 block discarded – undo
768 768
         foreach ($result as $field_name => $field_value) {
769 769
             $field_obj = $model->field_settings_for($field_name);
770 770
             if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
771
-                unset($result[ $field_name ]);
771
+                unset($result[$field_name]);
772 772
             } elseif ($this->isSubclassOfOne(
773 773
                 $field_obj,
774 774
                 $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
775 775
             )
776 776
             ) {
777
-                $result[ $field_name ] = array(
777
+                $result[$field_name] = array(
778 778
                     'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
779 779
                     'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
780 780
                 );
@@ -783,7 +783,7 @@  discard block
 block discarded – undo
783 783
                 $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
784 784
             )
785 785
             ) {
786
-                $result[ $field_name ] = array(
786
+                $result[$field_name] = array(
787 787
                     'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
788 788
                     'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
789 789
                 );
@@ -814,10 +814,10 @@  discard block
 block discarded – undo
814 814
                         $this->getModelVersionInfo()->requestedVersion()
815 815
                     );
816 816
                 }
817
-                $result[ $field_name . '_gmt' ] = $gmt_date;
818
-                $result[ $field_name ] = $local_date;
817
+                $result[$field_name.'_gmt'] = $gmt_date;
818
+                $result[$field_name] = $local_date;
819 819
             } else {
820
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
820
+                $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
821 821
             }
822 822
         }
823 823
         if ($do_chevy_shuffle) {
@@ -869,7 +869,7 @@  discard block
 block discarded – undo
869 869
     protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
870 870
     {
871 871
         if ($model instanceof EEM_CPT_Base) {
872
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
872
+            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
873 873
         }
874 874
         return $entity_array;
875 875
     }
@@ -894,7 +894,7 @@  discard block
 block discarded – undo
894 894
                     'href' => $this->getVersionedLinkTo(
895 895
                         EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
896 896
                         . '/'
897
-                        . $entity_array[ $model->primary_key_name() ]
897
+                        . $entity_array[$model->primary_key_name()]
898 898
                     ),
899 899
                 ),
900 900
             );
@@ -910,12 +910,12 @@  discard block
 block discarded – undo
910 910
         if ($model->has_primary_key_field()) {
911 911
             foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
912 912
                 $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
913
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
913
+                $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = array(
914 914
                     array(
915 915
                         'href'   => $this->getVersionedLinkTo(
916 916
                             EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
917 917
                             . '/'
918
-                            . $entity_array[ $model->primary_key_name() ]
918
+                            . $entity_array[$model->primary_key_name()]
919 919
                             . '/'
920 920
                             . $related_model_part
921 921
                         ),
@@ -947,7 +947,7 @@  discard block
 block discarded – undo
947 947
         $included_items_protected = false
948 948
     ) {
949 949
         // if $db_row not included, hope the entity array has what we need
950
-        if (! $db_row) {
950
+        if ( ! $db_row) {
951 951
             $db_row = $entity_array;
952 952
         }
953 953
         $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
@@ -980,7 +980,7 @@  discard block
 block discarded – undo
980 980
                         $model->deduce_fields_n_values_from_cols_n_values($db_row)
981 981
                     )
982 982
                 );
983
-                if (! $included_items_protected) {
983
+                if ( ! $included_items_protected) {
984 984
                     try {
985 985
                         $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
986 986
                             $primary_model_query_params,
@@ -998,7 +998,7 @@  discard block
 block discarded – undo
998 998
                 if ($related_results instanceof WP_Error || $related_results === null) {
999 999
                     $related_results = $relation_obj instanceof EE_Belongs_To_Relation ? null : array();
1000 1000
                 }
1001
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1001
+                $entity_array[Read::getRelatedEntityName($relation_name, $relation_obj)] = $related_results;
1002 1002
             }
1003 1003
         }
1004 1004
         return $entity_array;
@@ -1023,7 +1023,7 @@  discard block
 block discarded – undo
1023 1023
         $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1024 1024
         $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1025 1025
         // if they passed in * or didn't specify any includes, return everything
1026
-        if (! in_array('*', $includes_for_this_model)
1026
+        if ( ! in_array('*', $includes_for_this_model)
1027 1027
             && ! empty($includes_for_this_model)
1028 1028
         ) {
1029 1029
             if ($model->has_primary_key_field()) {
@@ -1077,12 +1077,12 @@  discard block
 block discarded – undo
1077 1077
                 // it's password protected, so they shouldn't be able to read this. Remove the value
1078 1078
                 $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1079 1079
                 if ($row_is_protected
1080
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1081
-                    && $schema['properties'][ $field_to_calculate ]['protected']) {
1080
+                    && isset($schema['properties'][$field_to_calculate]['protected'])
1081
+                    && $schema['properties'][$field_to_calculate]['protected']) {
1082 1082
                     $calculated_value = null;
1083 1083
                     $protected_fields[] = $field_to_calculate;
1084
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1085
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1084
+                    if ($schema['properties'][$field_to_calculate]['type']) {
1085
+                        switch ($schema['properties'][$field_to_calculate]['type']) {
1086 1086
                             case 'boolean':
1087 1087
                                 $calculated_value = false;
1088 1088
                                 break;
@@ -1192,7 +1192,7 @@  discard block
 block discarded – undo
1192 1192
      */
1193 1193
     public function validateContext($context)
1194 1194
     {
1195
-        if (! $context) {
1195
+        if ( ! $context) {
1196 1196
             $context = EEM_Base::caps_read;
1197 1197
         }
1198 1198
         $valid_contexts = EEM_Base::valid_cap_contexts();
@@ -1217,7 +1217,7 @@  discard block
 block discarded – undo
1217 1217
             EEM_Base::default_where_conditions_minimum_all,
1218 1218
             EEM_Base::default_where_conditions_minimum_others,
1219 1219
         );
1220
-        if (! $default_query_params) {
1220
+        if ( ! $default_query_params) {
1221 1221
             $default_query_params = EEM_Base::default_where_conditions_all;
1222 1222
         }
1223 1223
         if (in_array(
@@ -1300,14 +1300,14 @@  discard block
 block discarded – undo
1300 1300
         }
1301 1301
         if (isset($query_params['limit'])) {
1302 1302
             // limit should be either a string like '23' or '23,43', or an array with two items in it
1303
-            if (! is_array($query_params['limit'])) {
1303
+            if ( ! is_array($query_params['limit'])) {
1304 1304
                 $limit_array = explode(',', (string) $query_params['limit']);
1305 1305
             } else {
1306 1306
                 $limit_array = $query_params['limit'];
1307 1307
             }
1308 1308
             $sanitized_limit = array();
1309 1309
             foreach ($limit_array as $key => $limit_part) {
1310
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1310
+                if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1311 1311
                     throw new EE_Error(
1312 1312
                         sprintf(
1313 1313
                             __(
@@ -1339,7 +1339,7 @@  discard block
 block discarded – undo
1339 1339
         // if this is a model protected by a password on another model, exclude the password protected
1340 1340
         // entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1341 1341
         // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1342
-        if (! $model->hasPassword()
1342
+        if ( ! $model->hasPassword()
1343 1343
             && $model->restrictedByRelatedModelPassword()
1344 1344
             && $model_query_params['caps'] === EEM_Base::caps_read) {
1345 1345
             if (empty($query_params['password'])) {
@@ -1364,9 +1364,9 @@  discard block
 block discarded – undo
1364 1364
         $model_ready_query_params = array();
1365 1365
         foreach ($query_params as $key => $value) {
1366 1366
             if (is_array($value)) {
1367
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1367
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1368 1368
             } else {
1369
-                $model_ready_query_params[ $key ] = $value;
1369
+                $model_ready_query_params[$key] = $value;
1370 1370
             }
1371 1371
         }
1372 1372
         return $model_ready_query_params;
@@ -1384,9 +1384,9 @@  discard block
 block discarded – undo
1384 1384
         $model_ready_query_params = array();
1385 1385
         foreach ($query_params as $key => $value) {
1386 1386
             if (is_array($value)) {
1387
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1387
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1388 1388
             } else {
1389
-                $model_ready_query_params[ $key ] = $value;
1389
+                $model_ready_query_params[$key] = $value;
1390 1390
             }
1391 1391
         }
1392 1392
         return $model_ready_query_params;
@@ -1418,17 +1418,17 @@  discard block
 block discarded – undo
1418 1418
         foreach ($exploded_contents as $item) {
1419 1419
             $item = trim($item);
1420 1420
             // if no prefix was provided, so we look for items with no "." in them
1421
-            if (! $prefix) {
1421
+            if ( ! $prefix) {
1422 1422
                 // does this item have a period?
1423 1423
                 if (strpos($item, '.') === false) {
1424 1424
                     // if not, then its what we're looking for
1425 1425
                     $contents_with_prefix[] = $item;
1426 1426
                 }
1427
-            } elseif (strpos($item, $prefix . '.') === 0) {
1427
+            } elseif (strpos($item, $prefix.'.') === 0) {
1428 1428
                 // this item has the prefix and a period, grab it
1429 1429
                 $contents_with_prefix[] = substr(
1430 1430
                     $item,
1431
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1431
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1432 1432
                 );
1433 1433
             } elseif ($item === $prefix) {
1434 1434
                 // this item is JUST the prefix
@@ -1467,9 +1467,9 @@  discard block
 block discarded – undo
1467 1467
         if ($model_name) {
1468 1468
             foreach ($includes as $field_to_include) {
1469 1469
                 $field_to_include = trim($field_to_include);
1470
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1470
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1471 1471
                     // found the model name at the exact start
1472
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1472
+                    $field_sans_model_name = str_replace($model_name.'.', '', $field_to_include);
1473 1473
                     $extracted_fields_to_include[] = $field_sans_model_name;
1474 1474
                 } elseif ($field_to_include == $model_name) {
1475 1475
                     $extracted_fields_to_include[] = '*';
@@ -1510,7 +1510,7 @@  discard block
 block discarded – undo
1510 1510
         $restricted_query_params['caps'] = $context;
1511 1511
         $this->setDebugInfo('model query params', $restricted_query_params);
1512 1512
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1513
-        if (! empty($model_rows)) {
1513
+        if ( ! empty($model_rows)) {
1514 1514
             return $this->createEntityFromWpdbResult(
1515 1515
                 $model,
1516 1516
                 reset($model_rows),
@@ -1522,7 +1522,7 @@  discard block
 block discarded – undo
1522 1522
             if ($model->exists($query_params)) {
1523 1523
                 // you got shafted- it existed but we didn't want to tell you!
1524 1524
                 throw new RestException(
1525
-                    'rest_user_cannot_' . $context,
1525
+                    'rest_user_cannot_'.$context,
1526 1526
                     sprintf(
1527 1527
                         __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1528 1528
                         $context,
@@ -1573,11 +1573,11 @@  discard block
 block discarded – undo
1573 1573
         }
1574 1574
         // if this entity requires a password, they better give it and it better be right!
1575 1575
         if ($model->hasPassword()
1576
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '') {
1576
+            && $model_row[$model->getPasswordField()->get_qualified_column()] !== '') {
1577 1577
             if (empty($request['password'])) {
1578 1578
                 throw new RestPasswordRequiredException();
1579
-            } elseif (!hash_equals(
1580
-                $model_row[ $model->getPasswordField()->get_qualified_column() ],
1579
+            } elseif ( ! hash_equals(
1580
+                $model_row[$model->getPasswordField()->get_qualified_column()],
1581 1581
                 $request['password']
1582 1582
             )) {
1583 1583
                 throw new RestPasswordIncorrectException();
@@ -1588,12 +1588,12 @@  discard block
 block discarded – undo
1588 1588
             $password_supplied = $request->get_param('password');
1589 1589
             if (empty($password_supplied)) {
1590 1590
                 $query_params['exclude_protected'] = true;
1591
-                if (!$model->exists($query_params)) {
1591
+                if ( ! $model->exists($query_params)) {
1592 1592
                     throw new RestPasswordRequiredException();
1593 1593
                 }
1594 1594
             } else {
1595
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1596
-                if (!$model->exists($query_params)) {
1595
+                $query_params[0][$model->modelChainAndPassword()] = $password_supplied;
1596
+                if ( ! $model->exists($query_params)) {
1597 1597
                     throw new RestPasswordIncorrectException();
1598 1598
                 }
1599 1599
             }
Please login to merge, or discard this patch.
caffeinated/payment_methods/Paypal_Pro/EEG_Paypal_Pro.gateway.php 1 patch
Indentation   +602 added lines, -602 removed lines patch added patch discarded remove patch
@@ -11,606 +11,606 @@
 block discarded – undo
11 11
 class EEG_Paypal_Pro extends EE_Onsite_Gateway
12 12
 {
13 13
 
14
-    /**
15
-     * @var $_paypal_api_username string
16
-     */
17
-    protected $_username = null;
18
-
19
-    /**
20
-     * @var $_password string
21
-     */
22
-    protected $_password = null;
23
-
24
-    /**
25
-     * @var $_signature string
26
-     */
27
-    protected $_signature = null;
28
-
29
-    /**
30
-     * @var $_credit_card_types array with the keys for credit card types accepted on this account
31
-     */
32
-    protected $_credit_card_types    = null;
33
-
34
-    protected $_currencies_supported = array(
35
-        'USD',
36
-        'GBP',
37
-        'CAD',
38
-        'AUD',
39
-        'BRL',
40
-        'CHF',
41
-        'CZK',
42
-        'DKK',
43
-        'EUR',
44
-        'HKD',
45
-        'HUF',
46
-        'ILS',
47
-        'JPY',
48
-        'MXN',
49
-        'MYR',
50
-        'NOK',
51
-        'NZD',
52
-        'PHP',
53
-        'PLN',
54
-        'SEK',
55
-        'SGD',
56
-        'THB',
57
-        'TRY',
58
-        'TWD',
59
-        'RUB',
60
-        'INR',
61
-    );
62
-
63
-
64
-
65
-    /**
66
-     * @param EEI_Payment $payment
67
-     * @param array       $billing_info {
68
-     * @type string $credit_card
69
-     * @type string $credit_card_type
70
-     * @type string $exp_month always 2 characters
71
-     * @type string $exp_year always 4 characters
72
-     * @type string $cvv
73
-     * }
74
-     * @see      parent::do_direct_payment for more info
75
-     * @return EE_Payment|EEI_Payment
76
-     * @throws EE_Error
77
-     */
78
-    public function do_direct_payment($payment, $billing_info = null)
79
-    {
80
-        $transaction = $payment->transaction();
81
-        if (! $transaction instanceof EEI_Transaction) {
82
-            throw new EE_Error(
83
-                esc_html__('No transaction for payment while paying with PayPal Pro.', 'event_espresso')
84
-            );
85
-        }
86
-        $primary_registrant = $transaction->primary_registration();
87
-        if (! $primary_registrant instanceof EEI_Registration) {
88
-            throw new EE_Error(
89
-                esc_html__(
90
-                    'No primary registration on transaction while paying with PayPal Pro.',
91
-                    'event_espresso'
92
-                )
93
-            );
94
-        }
95
-        $attendee = $primary_registrant->attendee();
96
-        if (! $attendee instanceof EEI_Attendee) {
97
-            throw new EE_Error(
98
-                esc_html__(
99
-                    'No attendee on primary registration while paying with PayPal Pro.',
100
-                    'event_espresso'
101
-                )
102
-            );
103
-        }
104
-        $gateway_formatter = $this->_get_gateway_formatter();
105
-        $order_description = substr($gateway_formatter->formatOrderDescription($payment), 0, 127);
106
-        // charge for the full amount. Show itemized list
107
-        if ($this->_money->compare_floats($payment->amount(), $transaction->total(), '==')) {
108
-            $item_num = 1;
109
-            $total_line_item = $transaction->total_line_item();
110
-            $order_items = array();
111
-            foreach ($total_line_item->get_items() as $line_item) {
112
-                // ignore line items with a quantity of 0
113
-                if ($line_item->quantity() == 0) {
114
-                    continue;
115
-                }
116
-                // For percent items, whose unit_price is 0, use the total instead.
117
-                if ($line_item->is_percent()) {
118
-                    $unit_price = $line_item->total();
119
-                    $line_item_quantity = 1;
120
-                } else {
121
-                    $unit_price = $line_item->unit_price();
122
-                    $line_item_quantity = $line_item->quantity();
123
-                }
124
-                $item = array(
125
-                    // Item Name.  127 char max.
126
-                    'l_name'                 => substr(
127
-                        $gateway_formatter->formatLineItemName($line_item, $payment),
128
-                        0,
129
-                        127
130
-                    ),
131
-                    // Item description.  127 char max.
132
-                    'l_desc'                 => substr(
133
-                        $gateway_formatter->formatLineItemDesc($line_item, $payment),
134
-                        0,
135
-                        127
136
-                    ),
137
-                    // Cost of individual item.
138
-                    'l_amt'                  => $unit_price,
139
-                    // Item Number.  127 char max.
140
-                    'l_number'               => $item_num++,
141
-                    // Item quantity.  Must be any positive integer.
142
-                    'l_qty'                  => $line_item_quantity,
143
-                    // Item's sales tax amount.
144
-                    'l_taxamt'               => '',
145
-                    // eBay auction number of item.
146
-                    'l_ebayitemnumber'       => '',
147
-                    // eBay transaction ID of purchased item.
148
-                    'l_ebayitemauctiontxnid' => '',
149
-                    // eBay order ID for the item.
150
-                    'l_ebayitemorderid'      => '',
151
-                );
152
-                // add to array of all items
153
-                array_push($order_items, $item);
154
-            }
155
-            $item_amount = $total_line_item->get_items_total();
156
-            $tax_amount = $total_line_item->get_total_tax();
157
-        } else {
158
-            $order_items = array();
159
-            $item_amount = $payment->amount();
160
-            $tax_amount = 0;
161
-            array_push($order_items, array(
162
-                // Item Name.  127 char max.
163
-                'l_name'   => substr(
164
-                    $gateway_formatter->formatPartialPaymentLineItemName($payment),
165
-                    0,
166
-                    127
167
-                ),
168
-                // Item description.  127 char max.
169
-                'l_desc'   => substr(
170
-                    $gateway_formatter->formatPartialPaymentLineItemDesc($payment),
171
-                    0,
172
-                    127
173
-                ),
174
-                // Cost of individual item.
175
-                'l_amt'    => $payment->amount(),
176
-                // Item Number.  127 char max.
177
-                'l_number' => 1,
178
-                // Item quantity.  Must be any positive integer.
179
-                'l_qty'    => 1,
180
-            ));
181
-        }
182
-        // Populate data arrays with order data.
183
-        $DPFields = array(
184
-            // How you want to obtain payment ?
185
-            // Authorization indicates the payment is a basic auth subject to settlement with Auth & Capture.
186
-            // Sale indicates that this is a final sale for which you are requesting payment.  Default is Sale.
187
-            'paymentaction'    => 'Sale',
188
-            // Required.  IP address of the payer's browser.
189
-            'ipaddress'        => $_SERVER['REMOTE_ADDR'],
190
-            // Flag to determine whether you want the results returned by FMF.  1 or 0.  Default is 0.
191
-            'returnfmfdetails' => '1',
192
-        );
193
-        $CCDetails = array(
194
-            // Required. Type of credit card.  Visa, MasterCard, Discover, Amex, Maestro, Solo.
195
-            // If Maestro or Solo, the currency code must be GBP.
196
-            //  In addition, either start date or issue number must be specified.
197
-            'creditcardtype' => $billing_info['credit_card_type'],
198
-            // Required.  Credit card number.  No spaces or punctuation.
199
-            'acct'           => $billing_info['credit_card'],
200
-            // Required.  Credit card expiration date.  Format is MMYYYY
201
-            'expdate'        => $billing_info['exp_month'] . $billing_info['exp_year'],
202
-            // Requirements determined by your PayPal account settings.  Security digits for credit card.
203
-            'cvv2'           => $billing_info['cvv'],
204
-        );
205
-        $PayerInfo = array(
206
-            // Email address of payer.
207
-            'email'       => $billing_info['email'],
208
-            // Unique PayPal customer ID for payer.
209
-            'payerid'     => '',
210
-            // Status of payer.  Values are verified or unverified
211
-            'payerstatus' => '',
212
-            // Payer's business name.
213
-            'business'    => '',
214
-        );
215
-        $PayerName = array(
216
-            // Payer's salutation.  20 char max.
217
-            'salutation' => '',
218
-            // Payer's first name.  25 char max.
219
-            'firstname'  => substr($billing_info['first_name'], 0, 25),
220
-            // Payer's middle name.  25 char max.
221
-            'middlename' => '',
222
-            // Payer's last name.  25 char max.
223
-            'lastname'   => substr($billing_info['last_name'], 0, 25),
224
-            // Payer's suffix.  12 char max.
225
-            'suffix'     => '',
226
-        );
227
-        $BillingAddress = array(
228
-            // Required.  First street address.
229
-            'street'      => $billing_info['address'],
230
-            // Second street address.
231
-            'street2'     => $billing_info['address2'],
232
-            // Required.  Name of City.
233
-            'city'        => $billing_info['city'],
234
-            // Required. Name of State or Province.
235
-            'state'       => substr($billing_info['state'], 0, 40),
236
-            // Required.  Country code.
237
-            'countrycode' => $billing_info['country'],
238
-            // Required.  Postal code of payer.
239
-            'zip'         => $billing_info['zip'],
240
-        );
241
-        // check if the registration info contains the needed fields for paypal pro
242
-        // (see https://developer.paypal.com/docs/classic/api/merchant/DoDirectPayment_API_Operation_NVP/)
243
-        if ($attendee->address() && $attendee->city() && $attendee->country_ID()) {
244
-            $use_registration_address_info = true;
245
-        } else {
246
-            $use_registration_address_info = false;
247
-        }
248
-        // so if the attendee has enough data to fill out PayPal Pro's shipping info, use it.
249
-        // If not, use the billing info again
250
-        $ShippingAddress = array(
251
-            'shiptoname'     => substr($use_registration_address_info
252
-                ? $attendee->full_name()
253
-                : $billing_info['first_name'] . ' ' . $billing_info['last_name'], 0, 32),
254
-            'shiptostreet'   => substr($use_registration_address_info
255
-                ? $attendee->address()
256
-                : $billing_info['address'], 0, 100),
257
-            'shiptostreet2'  => substr($use_registration_address_info
258
-                ? $attendee->address2() : $billing_info['address2'], 0, 100),
259
-            'shiptocity'     => substr($use_registration_address_info
260
-                ? $attendee->city()
261
-                : $billing_info['city'], 0, 40),
262
-            'state'          => substr($use_registration_address_info
263
-                ? $attendee->state_name()
264
-                : $billing_info['state'], 0, 40),
265
-            'shiptocountry'  => $use_registration_address_info
266
-                ? $attendee->country_ID()
267
-                : $billing_info['country'],
268
-            'shiptozip'      => substr($use_registration_address_info
269
-                ? $attendee->zip()
270
-                : $billing_info['zip'], 0, 20),
271
-            'shiptophonenum' => substr($use_registration_address_info
272
-                ? $attendee->phone()
273
-                : $billing_info['phone'], 0, 20),
274
-        );
275
-        $PaymentDetails = array(
276
-            // Required.  Total amount of order, including shipping, handling, and tax.
277
-            'amt'          => $gateway_formatter->formatCurrency($payment->amount()),
278
-            // Required.  Three-letter currency code.  Default is USD.
279
-            'currencycode' => $payment->currency_code(),
280
-            // Required if you include itemized cart details. (L_AMTn, etc.)
281
-            // Subtotal of items not including S&H, or tax.
282
-            'itemamt'      => $gateway_formatter->formatCurrency($item_amount),//
283
-            // Total shipping costs for the order.  If you specify shippingamt, you must also specify itemamt.
284
-            'shippingamt'  => '',
285
-            // Total handling costs for the order.  If you specify handlingamt, you must also specify itemamt.
286
-            'handlingamt'  => '',
287
-            // Required if you specify itemized cart tax details.
288
-            // Sum of tax for all items on the order.  Total sales tax.
289
-            'taxamt'       => $gateway_formatter->formatCurrency($tax_amount),
290
-            // Description of the order the customer is purchasing.  127 char max.
291
-            'desc'         => $order_description,
292
-            // Free-form field for your own use.  256 char max.
293
-            'custom'       => $primary_registrant ? $primary_registrant->ID() : '',
294
-            // Your own invoice or tracking number
295
-            'invnum'       => wp_generate_password(12, false),// $transaction->ID(),
296
-            // URL for receiving Instant Payment Notifications.  This overrides what your profile is set to use.
297
-            'notifyurl'    => '',
298
-            'buttonsource' => 'EventEspresso_SP',// EE will blow up if you change this
299
-        );
300
-        // Wrap all data arrays into a single, "master" array which will be passed into the class function.
301
-        $PayPalRequestData = array(
302
-            'DPFields'        => $DPFields,
303
-            'CCDetails'       => $CCDetails,
304
-            'PayerInfo'       => $PayerInfo,
305
-            'PayerName'       => $PayerName,
306
-            'BillingAddress'  => $BillingAddress,
307
-            'ShippingAddress' => $ShippingAddress,
308
-            'PaymentDetails'  => $PaymentDetails,
309
-            'OrderItems'      => $order_items,
310
-        );
311
-        $this->_log_clean_request($PayPalRequestData, $payment);
312
-        try {
313
-            $PayPalResult = $this->prep_and_curl_request($PayPalRequestData);
314
-            // remove PCI-sensitive data so it doesn't get stored
315
-            $PayPalResult = $this->_log_clean_response($PayPalResult, $payment);
316
-            if (isset($PayPalResult['L_ERRORCODE0']) && $PayPalResult['L_ERRORCODE0'] === '10002') {
317
-                $message = esc_html__('PayPal did not accept your API username, password, or signature. Please double-check these credentials and if debug mode is on.', 'event_espresso');
318
-            } elseif (isset($PayPalResult['L_LONGMESSAGE0'])) {
319
-                $message = $PayPalResult['L_LONGMESSAGE0'];
320
-            } else {
321
-                $message = $PayPalResult['ACK'];
322
-            }
323
-            if (empty($PayPalResult['RAWRESPONSE'])) {
324
-                $payment->set_status($this->_pay_model->failed_status());
325
-                $payment->set_gateway_response(__('No response received from Paypal Pro', 'event_espresso'));
326
-                $payment->set_details($PayPalResult);
327
-            } else {
328
-                if ($this->_APICallSuccessful($PayPalResult)) {
329
-                    $payment->set_status($this->_pay_model->approved_status());
330
-                } else {
331
-                    $payment->set_status($this->_pay_model->declined_status());
332
-                }
333
-                // make sure we interpret the AMT as a float, not an international string
334
-                // (where periods are thousand separators)
335
-                $payment->set_amount(isset($PayPalResult['AMT']) ? floatval($PayPalResult['AMT']) : 0);
336
-                $payment->set_gateway_response($message);
337
-                $payment->set_txn_id_chq_nmbr(isset($PayPalResult['TRANSACTIONID'])
338
-                    ? $PayPalResult['TRANSACTIONID']
339
-                    : null);
340
-                $primary_registration_code = $primary_registrant instanceof EE_Registration
341
-                    ? $primary_registrant->reg_code()
342
-                    : '';
343
-                $payment->set_extra_accntng($primary_registration_code);
344
-                $payment->set_details($PayPalResult);
345
-            }
346
-        } catch (Exception $e) {
347
-            $payment->set_status($this->_pay_model->failed_status());
348
-            $payment->set_gateway_response($e->getMessage());
349
-        }
350
-        // $payment->set_status( $this->_pay_model->declined_status() );
351
-        // $payment->set_gateway_response( '' );
352
-        return $payment;
353
-    }
354
-
355
-
356
-
357
-    /**
358
-     * CLeans out sensitive CC data and then logs it, and returns the cleaned request
359
-     *
360
-     * @param array       $request
361
-     * @param EEI_Payment $payment
362
-     * @return void
363
-     */
364
-    private function _log_clean_request($request, $payment)
365
-    {
366
-        $cleaned_request_data = $request;
367
-        unset($cleaned_request_data['CCDetails']['acct']);
368
-        unset($cleaned_request_data['CCDetails']['cvv2']);
369
-        unset($cleaned_request_data['CCDetails']['expdate']);
370
-        $this->log(array('Paypal Request' => $cleaned_request_data), $payment);
371
-    }
372
-
373
-
374
-
375
-    /**
376
-     * Cleans the response, logs it, and returns it
377
-     *
378
-     * @param array       $response
379
-     * @param EEI_Payment $payment
380
-     * @return array cleaned
381
-     */
382
-    private function _log_clean_response($response, $payment)
383
-    {
384
-        unset($response['REQUESTDATA']['CREDITCARDTYPE']);
385
-        unset($response['REQUESTDATA']['ACCT']);
386
-        unset($response['REQUESTDATA']['EXPDATE']);
387
-        unset($response['REQUESTDATA']['CVV2']);
388
-        unset($response['RAWREQUEST']);
389
-        $this->log(array('Paypal Response' => $response), $payment);
390
-        return $response;
391
-    }
392
-
393
-
394
-
395
-    /**
396
-     * @param $DataArray
397
-     * @return array
398
-     */
399
-    private function prep_and_curl_request($DataArray)
400
-    {
401
-        // Create empty holders for each portion of the NVP string
402
-        $DPFieldsNVP = '&METHOD=DoDirectPayment&BUTTONSOURCE=AngellEYE_PHP_Class_DDP';
403
-        $CCDetailsNVP = '';
404
-        $PayerInfoNVP = '';
405
-        $PayerNameNVP = '';
406
-        $BillingAddressNVP = '';
407
-        $ShippingAddressNVP = '';
408
-        $PaymentDetailsNVP = '';
409
-        $OrderItemsNVP = '';
410
-        $Secure3DNVP = '';
411
-        // DP Fields
412
-        $DPFields = isset($DataArray['DPFields']) ? $DataArray['DPFields'] : array();
413
-        foreach ($DPFields as $DPFieldsVar => $DPFieldsVal) {
414
-            $DPFieldsNVP .= '&' . strtoupper($DPFieldsVar) . '=' . urlencode($DPFieldsVal);
415
-        }
416
-        // CC Details Fields
417
-        $CCDetails = isset($DataArray['CCDetails']) ? $DataArray['CCDetails'] : array();
418
-        foreach ($CCDetails as $CCDetailsVar => $CCDetailsVal) {
419
-            $CCDetailsNVP .= '&' . strtoupper($CCDetailsVar) . '=' . urlencode($CCDetailsVal);
420
-        }
421
-        // PayerInfo Type Fields
422
-        $PayerInfo = isset($DataArray['PayerInfo']) ? $DataArray['PayerInfo'] : array();
423
-        foreach ($PayerInfo as $PayerInfoVar => $PayerInfoVal) {
424
-            $PayerInfoNVP .= '&' . strtoupper($PayerInfoVar) . '=' . urlencode($PayerInfoVal);
425
-        }
426
-        // Payer Name Fields
427
-        $PayerName = isset($DataArray['PayerName']) ? $DataArray['PayerName'] : array();
428
-        foreach ($PayerName as $PayerNameVar => $PayerNameVal) {
429
-            $PayerNameNVP .= '&' . strtoupper($PayerNameVar) . '=' . urlencode($PayerNameVal);
430
-        }
431
-        // Address Fields (Billing)
432
-        $BillingAddress = isset($DataArray['BillingAddress']) ? $DataArray['BillingAddress'] : array();
433
-        foreach ($BillingAddress as $BillingAddressVar => $BillingAddressVal) {
434
-            $BillingAddressNVP .= '&' . strtoupper($BillingAddressVar) . '=' . urlencode($BillingAddressVal);
435
-        }
436
-        // Payment Details Type Fields
437
-        $PaymentDetails = isset($DataArray['PaymentDetails']) ? $DataArray['PaymentDetails'] : array();
438
-        foreach ($PaymentDetails as $PaymentDetailsVar => $PaymentDetailsVal) {
439
-            $PaymentDetailsNVP .= '&' . strtoupper($PaymentDetailsVar) . '=' . urlencode($PaymentDetailsVal);
440
-        }
441
-        // Payment Details Item Type Fields
442
-        $OrderItems = isset($DataArray['OrderItems']) ? $DataArray['OrderItems'] : array();
443
-        $n = 0;
444
-        foreach ($OrderItems as $OrderItemsVar => $OrderItemsVal) {
445
-            $CurrentItem = $OrderItems[ $OrderItemsVar ];
446
-            foreach ($CurrentItem as $CurrentItemVar => $CurrentItemVal) {
447
-                $OrderItemsNVP .= '&' . strtoupper($CurrentItemVar) . $n . '=' . urlencode($CurrentItemVal);
448
-            }
449
-            $n++;
450
-        }
451
-        // Ship To Address Fields
452
-        $ShippingAddress = isset($DataArray['ShippingAddress']) ? $DataArray['ShippingAddress'] : array();
453
-        foreach ($ShippingAddress as $ShippingAddressVar => $ShippingAddressVal) {
454
-            $ShippingAddressNVP .= '&' . strtoupper($ShippingAddressVar) . '=' . urlencode($ShippingAddressVal);
455
-        }
456
-        // 3D Secure Fields
457
-        $Secure3D = isset($DataArray['Secure3D']) ? $DataArray['Secure3D'] : array();
458
-        foreach ($Secure3D as $Secure3DVar => $Secure3DVal) {
459
-            $Secure3DNVP .= '&' . strtoupper($Secure3DVar) . '=' . urlencode($Secure3DVal);
460
-        }
461
-        // Now that we have each chunk we need to go ahead and append them all together for our entire NVP string
462
-        $NVPRequest = 'USER='
463
-                      . $this->_username
464
-                      . '&PWD='
465
-                      . $this->_password
466
-                      . '&VERSION=64.0'
467
-                      . '&SIGNATURE='
468
-                      . $this->_signature
469
-                      . $DPFieldsNVP
470
-                      . $CCDetailsNVP
471
-                      . $PayerInfoNVP
472
-                      . $PayerNameNVP
473
-                      . $BillingAddressNVP
474
-                      . $PaymentDetailsNVP
475
-                      . $OrderItemsNVP
476
-                      . $ShippingAddressNVP
477
-                      . $Secure3DNVP;
478
-        $NVPResponse = $this->_CURLRequest($NVPRequest);
479
-        $NVPRequestArray = $this->_NVPToArray($NVPRequest);
480
-        $NVPResponseArray = $this->_NVPToArray($NVPResponse);
481
-        $Errors = $this->_GetErrors($NVPResponseArray);
482
-        $NVPResponseArray['ERRORS'] = $Errors;
483
-        $NVPResponseArray['REQUESTDATA'] = $NVPRequestArray;
484
-        $NVPResponseArray['RAWREQUEST'] = $NVPRequest;
485
-        $NVPResponseArray['RAWRESPONSE'] = $NVPResponse;
486
-        return $NVPResponseArray;
487
-    }
488
-
489
-
490
-
491
-    /**
492
-     * @param $Request
493
-     * @return mixed
494
-     */
495
-    private function _CURLRequest($Request)
496
-    {
497
-        $EndPointURL = $this->_debug_mode ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp';
498
-        $curl = curl_init();
499
-        curl_setopt($curl, CURLOPT_VERBOSE, apply_filters('FHEE__EEG_Paypal_Pro__CurlRequest__CURLOPT_VERBOSE', true));
500
-        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
501
-        curl_setopt($curl, CURLOPT_TIMEOUT, 60);
502
-        curl_setopt($curl, CURLOPT_URL, $EndPointURL);
503
-        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
504
-        curl_setopt($curl, CURLOPT_POSTFIELDS, $Request);
505
-        curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
506
-        // execute the curl POST
507
-        $Response = curl_exec($curl);
508
-        curl_close($curl);
509
-        return $Response;
510
-    }
511
-
512
-
513
-
514
-    /**
515
-     * @param $NVPString
516
-     * @return array
517
-     */
518
-    private function _NVPToArray($NVPString)
519
-    {
520
-        // prepare responses into array
521
-        $proArray = array();
522
-        while (strlen($NVPString)) {
523
-            // name
524
-            $keypos = strpos($NVPString, '=');
525
-            $keyval = substr($NVPString, 0, $keypos);
526
-            // value
527
-            $valuepos = strpos($NVPString, '&') ? strpos($NVPString, '&') : strlen($NVPString);
528
-            $valval = substr($NVPString, $keypos + 1, $valuepos - $keypos - 1);
529
-            // decoding the response
530
-            $proArray[ $keyval ] = urldecode($valval);
531
-            $NVPString = substr($NVPString, $valuepos + 1, strlen($NVPString));
532
-        }
533
-        return $proArray;
534
-    }
535
-
536
-
537
-
538
-    /**
539
-     * @param array $PayPalResult
540
-     * @return bool
541
-     */
542
-    private function _APICallSuccessful($PayPalResult)
543
-    {
544
-        $approved = false;
545
-        // check main response message from PayPal
546
-        if (isset($PayPalResult['ACK']) && ! empty($PayPalResult['ACK'])) {
547
-            $ack = strtoupper($PayPalResult['ACK']);
548
-            $approved = ($ack == 'SUCCESS' || $ack == 'SUCCESSWITHWARNING' || $ack == 'PARTIALSUCCESS') ? true : false;
549
-        }
550
-        return $approved;
551
-    }
552
-
553
-
554
-
555
-    /**
556
-     * @param $DataArray
557
-     * @return array
558
-     */
559
-    private function _GetErrors($DataArray)
560
-    {
561
-        $Errors = array();
562
-        $n = 0;
563
-        while (isset($DataArray[ 'L_ERRORCODE' . $n . '' ])) {
564
-            $LErrorCode = isset($DataArray[ 'L_ERRORCODE' . $n . '' ]) ? $DataArray[ 'L_ERRORCODE' . $n . '' ] : '';
565
-            $LShortMessage = isset($DataArray[ 'L_SHORTMESSAGE' . $n . '' ])
566
-                ? $DataArray[ 'L_SHORTMESSAGE' . $n . '' ]
567
-                : '';
568
-            $LLongMessage = isset($DataArray[ 'L_LONGMESSAGE' . $n . '' ])
569
-                ? $DataArray[ 'L_LONGMESSAGE' . $n . '' ]
570
-                : '';
571
-            $LSeverityCode = isset($DataArray[ 'L_SEVERITYCODE' . $n . '' ])
572
-                ? $DataArray[ 'L_SEVERITYCODE' . $n . '' ]
573
-                : '';
574
-            $CurrentItem = array(
575
-                'L_ERRORCODE'    => $LErrorCode,
576
-                'L_SHORTMESSAGE' => $LShortMessage,
577
-                'L_LONGMESSAGE'  => $LLongMessage,
578
-                'L_SEVERITYCODE' => $LSeverityCode,
579
-            );
580
-            array_push($Errors, $CurrentItem);
581
-            $n++;
582
-        }
583
-        return $Errors;
584
-    }
585
-
586
-
587
-
588
-    /**
589
-     *        nothing to see here...  move along....
590
-     *
591
-     * @access protected
592
-     * @param $Errors
593
-     * @return string
594
-     */
595
-    private function _DisplayErrors($Errors)
596
-    {
597
-        $error = '';
598
-        foreach ($Errors as $ErrorVar => $ErrorVal) {
599
-            $CurrentError = $Errors[ $ErrorVar ];
600
-            foreach ($CurrentError as $CurrentErrorVar => $CurrentErrorVal) {
601
-                $CurrentVarName = '';
602
-                if ($CurrentErrorVar == 'L_ERRORCODE') {
603
-                    $CurrentVarName = 'Error Code';
604
-                } elseif ($CurrentErrorVar == 'L_SHORTMESSAGE') {
605
-                    $CurrentVarName = 'Short Message';
606
-                } elseif ($CurrentErrorVar == 'L_LONGMESSAGE') {
607
-                    $CurrentVarName = 'Long Message';
608
-                } elseif ($CurrentErrorVar == 'L_SEVERITYCODE') {
609
-                    $CurrentVarName = 'Severity Code';
610
-                }
611
-                $error .= '<br />' . $CurrentVarName . ': ' . $CurrentErrorVal;
612
-            }
613
-        }
614
-        return $error;
615
-    }
14
+	/**
15
+	 * @var $_paypal_api_username string
16
+	 */
17
+	protected $_username = null;
18
+
19
+	/**
20
+	 * @var $_password string
21
+	 */
22
+	protected $_password = null;
23
+
24
+	/**
25
+	 * @var $_signature string
26
+	 */
27
+	protected $_signature = null;
28
+
29
+	/**
30
+	 * @var $_credit_card_types array with the keys for credit card types accepted on this account
31
+	 */
32
+	protected $_credit_card_types    = null;
33
+
34
+	protected $_currencies_supported = array(
35
+		'USD',
36
+		'GBP',
37
+		'CAD',
38
+		'AUD',
39
+		'BRL',
40
+		'CHF',
41
+		'CZK',
42
+		'DKK',
43
+		'EUR',
44
+		'HKD',
45
+		'HUF',
46
+		'ILS',
47
+		'JPY',
48
+		'MXN',
49
+		'MYR',
50
+		'NOK',
51
+		'NZD',
52
+		'PHP',
53
+		'PLN',
54
+		'SEK',
55
+		'SGD',
56
+		'THB',
57
+		'TRY',
58
+		'TWD',
59
+		'RUB',
60
+		'INR',
61
+	);
62
+
63
+
64
+
65
+	/**
66
+	 * @param EEI_Payment $payment
67
+	 * @param array       $billing_info {
68
+	 * @type string $credit_card
69
+	 * @type string $credit_card_type
70
+	 * @type string $exp_month always 2 characters
71
+	 * @type string $exp_year always 4 characters
72
+	 * @type string $cvv
73
+	 * }
74
+	 * @see      parent::do_direct_payment for more info
75
+	 * @return EE_Payment|EEI_Payment
76
+	 * @throws EE_Error
77
+	 */
78
+	public function do_direct_payment($payment, $billing_info = null)
79
+	{
80
+		$transaction = $payment->transaction();
81
+		if (! $transaction instanceof EEI_Transaction) {
82
+			throw new EE_Error(
83
+				esc_html__('No transaction for payment while paying with PayPal Pro.', 'event_espresso')
84
+			);
85
+		}
86
+		$primary_registrant = $transaction->primary_registration();
87
+		if (! $primary_registrant instanceof EEI_Registration) {
88
+			throw new EE_Error(
89
+				esc_html__(
90
+					'No primary registration on transaction while paying with PayPal Pro.',
91
+					'event_espresso'
92
+				)
93
+			);
94
+		}
95
+		$attendee = $primary_registrant->attendee();
96
+		if (! $attendee instanceof EEI_Attendee) {
97
+			throw new EE_Error(
98
+				esc_html__(
99
+					'No attendee on primary registration while paying with PayPal Pro.',
100
+					'event_espresso'
101
+				)
102
+			);
103
+		}
104
+		$gateway_formatter = $this->_get_gateway_formatter();
105
+		$order_description = substr($gateway_formatter->formatOrderDescription($payment), 0, 127);
106
+		// charge for the full amount. Show itemized list
107
+		if ($this->_money->compare_floats($payment->amount(), $transaction->total(), '==')) {
108
+			$item_num = 1;
109
+			$total_line_item = $transaction->total_line_item();
110
+			$order_items = array();
111
+			foreach ($total_line_item->get_items() as $line_item) {
112
+				// ignore line items with a quantity of 0
113
+				if ($line_item->quantity() == 0) {
114
+					continue;
115
+				}
116
+				// For percent items, whose unit_price is 0, use the total instead.
117
+				if ($line_item->is_percent()) {
118
+					$unit_price = $line_item->total();
119
+					$line_item_quantity = 1;
120
+				} else {
121
+					$unit_price = $line_item->unit_price();
122
+					$line_item_quantity = $line_item->quantity();
123
+				}
124
+				$item = array(
125
+					// Item Name.  127 char max.
126
+					'l_name'                 => substr(
127
+						$gateway_formatter->formatLineItemName($line_item, $payment),
128
+						0,
129
+						127
130
+					),
131
+					// Item description.  127 char max.
132
+					'l_desc'                 => substr(
133
+						$gateway_formatter->formatLineItemDesc($line_item, $payment),
134
+						0,
135
+						127
136
+					),
137
+					// Cost of individual item.
138
+					'l_amt'                  => $unit_price,
139
+					// Item Number.  127 char max.
140
+					'l_number'               => $item_num++,
141
+					// Item quantity.  Must be any positive integer.
142
+					'l_qty'                  => $line_item_quantity,
143
+					// Item's sales tax amount.
144
+					'l_taxamt'               => '',
145
+					// eBay auction number of item.
146
+					'l_ebayitemnumber'       => '',
147
+					// eBay transaction ID of purchased item.
148
+					'l_ebayitemauctiontxnid' => '',
149
+					// eBay order ID for the item.
150
+					'l_ebayitemorderid'      => '',
151
+				);
152
+				// add to array of all items
153
+				array_push($order_items, $item);
154
+			}
155
+			$item_amount = $total_line_item->get_items_total();
156
+			$tax_amount = $total_line_item->get_total_tax();
157
+		} else {
158
+			$order_items = array();
159
+			$item_amount = $payment->amount();
160
+			$tax_amount = 0;
161
+			array_push($order_items, array(
162
+				// Item Name.  127 char max.
163
+				'l_name'   => substr(
164
+					$gateway_formatter->formatPartialPaymentLineItemName($payment),
165
+					0,
166
+					127
167
+				),
168
+				// Item description.  127 char max.
169
+				'l_desc'   => substr(
170
+					$gateway_formatter->formatPartialPaymentLineItemDesc($payment),
171
+					0,
172
+					127
173
+				),
174
+				// Cost of individual item.
175
+				'l_amt'    => $payment->amount(),
176
+				// Item Number.  127 char max.
177
+				'l_number' => 1,
178
+				// Item quantity.  Must be any positive integer.
179
+				'l_qty'    => 1,
180
+			));
181
+		}
182
+		// Populate data arrays with order data.
183
+		$DPFields = array(
184
+			// How you want to obtain payment ?
185
+			// Authorization indicates the payment is a basic auth subject to settlement with Auth & Capture.
186
+			// Sale indicates that this is a final sale for which you are requesting payment.  Default is Sale.
187
+			'paymentaction'    => 'Sale',
188
+			// Required.  IP address of the payer's browser.
189
+			'ipaddress'        => $_SERVER['REMOTE_ADDR'],
190
+			// Flag to determine whether you want the results returned by FMF.  1 or 0.  Default is 0.
191
+			'returnfmfdetails' => '1',
192
+		);
193
+		$CCDetails = array(
194
+			// Required. Type of credit card.  Visa, MasterCard, Discover, Amex, Maestro, Solo.
195
+			// If Maestro or Solo, the currency code must be GBP.
196
+			//  In addition, either start date or issue number must be specified.
197
+			'creditcardtype' => $billing_info['credit_card_type'],
198
+			// Required.  Credit card number.  No spaces or punctuation.
199
+			'acct'           => $billing_info['credit_card'],
200
+			// Required.  Credit card expiration date.  Format is MMYYYY
201
+			'expdate'        => $billing_info['exp_month'] . $billing_info['exp_year'],
202
+			// Requirements determined by your PayPal account settings.  Security digits for credit card.
203
+			'cvv2'           => $billing_info['cvv'],
204
+		);
205
+		$PayerInfo = array(
206
+			// Email address of payer.
207
+			'email'       => $billing_info['email'],
208
+			// Unique PayPal customer ID for payer.
209
+			'payerid'     => '',
210
+			// Status of payer.  Values are verified or unverified
211
+			'payerstatus' => '',
212
+			// Payer's business name.
213
+			'business'    => '',
214
+		);
215
+		$PayerName = array(
216
+			// Payer's salutation.  20 char max.
217
+			'salutation' => '',
218
+			// Payer's first name.  25 char max.
219
+			'firstname'  => substr($billing_info['first_name'], 0, 25),
220
+			// Payer's middle name.  25 char max.
221
+			'middlename' => '',
222
+			// Payer's last name.  25 char max.
223
+			'lastname'   => substr($billing_info['last_name'], 0, 25),
224
+			// Payer's suffix.  12 char max.
225
+			'suffix'     => '',
226
+		);
227
+		$BillingAddress = array(
228
+			// Required.  First street address.
229
+			'street'      => $billing_info['address'],
230
+			// Second street address.
231
+			'street2'     => $billing_info['address2'],
232
+			// Required.  Name of City.
233
+			'city'        => $billing_info['city'],
234
+			// Required. Name of State or Province.
235
+			'state'       => substr($billing_info['state'], 0, 40),
236
+			// Required.  Country code.
237
+			'countrycode' => $billing_info['country'],
238
+			// Required.  Postal code of payer.
239
+			'zip'         => $billing_info['zip'],
240
+		);
241
+		// check if the registration info contains the needed fields for paypal pro
242
+		// (see https://developer.paypal.com/docs/classic/api/merchant/DoDirectPayment_API_Operation_NVP/)
243
+		if ($attendee->address() && $attendee->city() && $attendee->country_ID()) {
244
+			$use_registration_address_info = true;
245
+		} else {
246
+			$use_registration_address_info = false;
247
+		}
248
+		// so if the attendee has enough data to fill out PayPal Pro's shipping info, use it.
249
+		// If not, use the billing info again
250
+		$ShippingAddress = array(
251
+			'shiptoname'     => substr($use_registration_address_info
252
+				? $attendee->full_name()
253
+				: $billing_info['first_name'] . ' ' . $billing_info['last_name'], 0, 32),
254
+			'shiptostreet'   => substr($use_registration_address_info
255
+				? $attendee->address()
256
+				: $billing_info['address'], 0, 100),
257
+			'shiptostreet2'  => substr($use_registration_address_info
258
+				? $attendee->address2() : $billing_info['address2'], 0, 100),
259
+			'shiptocity'     => substr($use_registration_address_info
260
+				? $attendee->city()
261
+				: $billing_info['city'], 0, 40),
262
+			'state'          => substr($use_registration_address_info
263
+				? $attendee->state_name()
264
+				: $billing_info['state'], 0, 40),
265
+			'shiptocountry'  => $use_registration_address_info
266
+				? $attendee->country_ID()
267
+				: $billing_info['country'],
268
+			'shiptozip'      => substr($use_registration_address_info
269
+				? $attendee->zip()
270
+				: $billing_info['zip'], 0, 20),
271
+			'shiptophonenum' => substr($use_registration_address_info
272
+				? $attendee->phone()
273
+				: $billing_info['phone'], 0, 20),
274
+		);
275
+		$PaymentDetails = array(
276
+			// Required.  Total amount of order, including shipping, handling, and tax.
277
+			'amt'          => $gateway_formatter->formatCurrency($payment->amount()),
278
+			// Required.  Three-letter currency code.  Default is USD.
279
+			'currencycode' => $payment->currency_code(),
280
+			// Required if you include itemized cart details. (L_AMTn, etc.)
281
+			// Subtotal of items not including S&H, or tax.
282
+			'itemamt'      => $gateway_formatter->formatCurrency($item_amount),//
283
+			// Total shipping costs for the order.  If you specify shippingamt, you must also specify itemamt.
284
+			'shippingamt'  => '',
285
+			// Total handling costs for the order.  If you specify handlingamt, you must also specify itemamt.
286
+			'handlingamt'  => '',
287
+			// Required if you specify itemized cart tax details.
288
+			// Sum of tax for all items on the order.  Total sales tax.
289
+			'taxamt'       => $gateway_formatter->formatCurrency($tax_amount),
290
+			// Description of the order the customer is purchasing.  127 char max.
291
+			'desc'         => $order_description,
292
+			// Free-form field for your own use.  256 char max.
293
+			'custom'       => $primary_registrant ? $primary_registrant->ID() : '',
294
+			// Your own invoice or tracking number
295
+			'invnum'       => wp_generate_password(12, false),// $transaction->ID(),
296
+			// URL for receiving Instant Payment Notifications.  This overrides what your profile is set to use.
297
+			'notifyurl'    => '',
298
+			'buttonsource' => 'EventEspresso_SP',// EE will blow up if you change this
299
+		);
300
+		// Wrap all data arrays into a single, "master" array which will be passed into the class function.
301
+		$PayPalRequestData = array(
302
+			'DPFields'        => $DPFields,
303
+			'CCDetails'       => $CCDetails,
304
+			'PayerInfo'       => $PayerInfo,
305
+			'PayerName'       => $PayerName,
306
+			'BillingAddress'  => $BillingAddress,
307
+			'ShippingAddress' => $ShippingAddress,
308
+			'PaymentDetails'  => $PaymentDetails,
309
+			'OrderItems'      => $order_items,
310
+		);
311
+		$this->_log_clean_request($PayPalRequestData, $payment);
312
+		try {
313
+			$PayPalResult = $this->prep_and_curl_request($PayPalRequestData);
314
+			// remove PCI-sensitive data so it doesn't get stored
315
+			$PayPalResult = $this->_log_clean_response($PayPalResult, $payment);
316
+			if (isset($PayPalResult['L_ERRORCODE0']) && $PayPalResult['L_ERRORCODE0'] === '10002') {
317
+				$message = esc_html__('PayPal did not accept your API username, password, or signature. Please double-check these credentials and if debug mode is on.', 'event_espresso');
318
+			} elseif (isset($PayPalResult['L_LONGMESSAGE0'])) {
319
+				$message = $PayPalResult['L_LONGMESSAGE0'];
320
+			} else {
321
+				$message = $PayPalResult['ACK'];
322
+			}
323
+			if (empty($PayPalResult['RAWRESPONSE'])) {
324
+				$payment->set_status($this->_pay_model->failed_status());
325
+				$payment->set_gateway_response(__('No response received from Paypal Pro', 'event_espresso'));
326
+				$payment->set_details($PayPalResult);
327
+			} else {
328
+				if ($this->_APICallSuccessful($PayPalResult)) {
329
+					$payment->set_status($this->_pay_model->approved_status());
330
+				} else {
331
+					$payment->set_status($this->_pay_model->declined_status());
332
+				}
333
+				// make sure we interpret the AMT as a float, not an international string
334
+				// (where periods are thousand separators)
335
+				$payment->set_amount(isset($PayPalResult['AMT']) ? floatval($PayPalResult['AMT']) : 0);
336
+				$payment->set_gateway_response($message);
337
+				$payment->set_txn_id_chq_nmbr(isset($PayPalResult['TRANSACTIONID'])
338
+					? $PayPalResult['TRANSACTIONID']
339
+					: null);
340
+				$primary_registration_code = $primary_registrant instanceof EE_Registration
341
+					? $primary_registrant->reg_code()
342
+					: '';
343
+				$payment->set_extra_accntng($primary_registration_code);
344
+				$payment->set_details($PayPalResult);
345
+			}
346
+		} catch (Exception $e) {
347
+			$payment->set_status($this->_pay_model->failed_status());
348
+			$payment->set_gateway_response($e->getMessage());
349
+		}
350
+		// $payment->set_status( $this->_pay_model->declined_status() );
351
+		// $payment->set_gateway_response( '' );
352
+		return $payment;
353
+	}
354
+
355
+
356
+
357
+	/**
358
+	 * CLeans out sensitive CC data and then logs it, and returns the cleaned request
359
+	 *
360
+	 * @param array       $request
361
+	 * @param EEI_Payment $payment
362
+	 * @return void
363
+	 */
364
+	private function _log_clean_request($request, $payment)
365
+	{
366
+		$cleaned_request_data = $request;
367
+		unset($cleaned_request_data['CCDetails']['acct']);
368
+		unset($cleaned_request_data['CCDetails']['cvv2']);
369
+		unset($cleaned_request_data['CCDetails']['expdate']);
370
+		$this->log(array('Paypal Request' => $cleaned_request_data), $payment);
371
+	}
372
+
373
+
374
+
375
+	/**
376
+	 * Cleans the response, logs it, and returns it
377
+	 *
378
+	 * @param array       $response
379
+	 * @param EEI_Payment $payment
380
+	 * @return array cleaned
381
+	 */
382
+	private function _log_clean_response($response, $payment)
383
+	{
384
+		unset($response['REQUESTDATA']['CREDITCARDTYPE']);
385
+		unset($response['REQUESTDATA']['ACCT']);
386
+		unset($response['REQUESTDATA']['EXPDATE']);
387
+		unset($response['REQUESTDATA']['CVV2']);
388
+		unset($response['RAWREQUEST']);
389
+		$this->log(array('Paypal Response' => $response), $payment);
390
+		return $response;
391
+	}
392
+
393
+
394
+
395
+	/**
396
+	 * @param $DataArray
397
+	 * @return array
398
+	 */
399
+	private function prep_and_curl_request($DataArray)
400
+	{
401
+		// Create empty holders for each portion of the NVP string
402
+		$DPFieldsNVP = '&METHOD=DoDirectPayment&BUTTONSOURCE=AngellEYE_PHP_Class_DDP';
403
+		$CCDetailsNVP = '';
404
+		$PayerInfoNVP = '';
405
+		$PayerNameNVP = '';
406
+		$BillingAddressNVP = '';
407
+		$ShippingAddressNVP = '';
408
+		$PaymentDetailsNVP = '';
409
+		$OrderItemsNVP = '';
410
+		$Secure3DNVP = '';
411
+		// DP Fields
412
+		$DPFields = isset($DataArray['DPFields']) ? $DataArray['DPFields'] : array();
413
+		foreach ($DPFields as $DPFieldsVar => $DPFieldsVal) {
414
+			$DPFieldsNVP .= '&' . strtoupper($DPFieldsVar) . '=' . urlencode($DPFieldsVal);
415
+		}
416
+		// CC Details Fields
417
+		$CCDetails = isset($DataArray['CCDetails']) ? $DataArray['CCDetails'] : array();
418
+		foreach ($CCDetails as $CCDetailsVar => $CCDetailsVal) {
419
+			$CCDetailsNVP .= '&' . strtoupper($CCDetailsVar) . '=' . urlencode($CCDetailsVal);
420
+		}
421
+		// PayerInfo Type Fields
422
+		$PayerInfo = isset($DataArray['PayerInfo']) ? $DataArray['PayerInfo'] : array();
423
+		foreach ($PayerInfo as $PayerInfoVar => $PayerInfoVal) {
424
+			$PayerInfoNVP .= '&' . strtoupper($PayerInfoVar) . '=' . urlencode($PayerInfoVal);
425
+		}
426
+		// Payer Name Fields
427
+		$PayerName = isset($DataArray['PayerName']) ? $DataArray['PayerName'] : array();
428
+		foreach ($PayerName as $PayerNameVar => $PayerNameVal) {
429
+			$PayerNameNVP .= '&' . strtoupper($PayerNameVar) . '=' . urlencode($PayerNameVal);
430
+		}
431
+		// Address Fields (Billing)
432
+		$BillingAddress = isset($DataArray['BillingAddress']) ? $DataArray['BillingAddress'] : array();
433
+		foreach ($BillingAddress as $BillingAddressVar => $BillingAddressVal) {
434
+			$BillingAddressNVP .= '&' . strtoupper($BillingAddressVar) . '=' . urlencode($BillingAddressVal);
435
+		}
436
+		// Payment Details Type Fields
437
+		$PaymentDetails = isset($DataArray['PaymentDetails']) ? $DataArray['PaymentDetails'] : array();
438
+		foreach ($PaymentDetails as $PaymentDetailsVar => $PaymentDetailsVal) {
439
+			$PaymentDetailsNVP .= '&' . strtoupper($PaymentDetailsVar) . '=' . urlencode($PaymentDetailsVal);
440
+		}
441
+		// Payment Details Item Type Fields
442
+		$OrderItems = isset($DataArray['OrderItems']) ? $DataArray['OrderItems'] : array();
443
+		$n = 0;
444
+		foreach ($OrderItems as $OrderItemsVar => $OrderItemsVal) {
445
+			$CurrentItem = $OrderItems[ $OrderItemsVar ];
446
+			foreach ($CurrentItem as $CurrentItemVar => $CurrentItemVal) {
447
+				$OrderItemsNVP .= '&' . strtoupper($CurrentItemVar) . $n . '=' . urlencode($CurrentItemVal);
448
+			}
449
+			$n++;
450
+		}
451
+		// Ship To Address Fields
452
+		$ShippingAddress = isset($DataArray['ShippingAddress']) ? $DataArray['ShippingAddress'] : array();
453
+		foreach ($ShippingAddress as $ShippingAddressVar => $ShippingAddressVal) {
454
+			$ShippingAddressNVP .= '&' . strtoupper($ShippingAddressVar) . '=' . urlencode($ShippingAddressVal);
455
+		}
456
+		// 3D Secure Fields
457
+		$Secure3D = isset($DataArray['Secure3D']) ? $DataArray['Secure3D'] : array();
458
+		foreach ($Secure3D as $Secure3DVar => $Secure3DVal) {
459
+			$Secure3DNVP .= '&' . strtoupper($Secure3DVar) . '=' . urlencode($Secure3DVal);
460
+		}
461
+		// Now that we have each chunk we need to go ahead and append them all together for our entire NVP string
462
+		$NVPRequest = 'USER='
463
+					  . $this->_username
464
+					  . '&PWD='
465
+					  . $this->_password
466
+					  . '&VERSION=64.0'
467
+					  . '&SIGNATURE='
468
+					  . $this->_signature
469
+					  . $DPFieldsNVP
470
+					  . $CCDetailsNVP
471
+					  . $PayerInfoNVP
472
+					  . $PayerNameNVP
473
+					  . $BillingAddressNVP
474
+					  . $PaymentDetailsNVP
475
+					  . $OrderItemsNVP
476
+					  . $ShippingAddressNVP
477
+					  . $Secure3DNVP;
478
+		$NVPResponse = $this->_CURLRequest($NVPRequest);
479
+		$NVPRequestArray = $this->_NVPToArray($NVPRequest);
480
+		$NVPResponseArray = $this->_NVPToArray($NVPResponse);
481
+		$Errors = $this->_GetErrors($NVPResponseArray);
482
+		$NVPResponseArray['ERRORS'] = $Errors;
483
+		$NVPResponseArray['REQUESTDATA'] = $NVPRequestArray;
484
+		$NVPResponseArray['RAWREQUEST'] = $NVPRequest;
485
+		$NVPResponseArray['RAWRESPONSE'] = $NVPResponse;
486
+		return $NVPResponseArray;
487
+	}
488
+
489
+
490
+
491
+	/**
492
+	 * @param $Request
493
+	 * @return mixed
494
+	 */
495
+	private function _CURLRequest($Request)
496
+	{
497
+		$EndPointURL = $this->_debug_mode ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp';
498
+		$curl = curl_init();
499
+		curl_setopt($curl, CURLOPT_VERBOSE, apply_filters('FHEE__EEG_Paypal_Pro__CurlRequest__CURLOPT_VERBOSE', true));
500
+		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
501
+		curl_setopt($curl, CURLOPT_TIMEOUT, 60);
502
+		curl_setopt($curl, CURLOPT_URL, $EndPointURL);
503
+		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
504
+		curl_setopt($curl, CURLOPT_POSTFIELDS, $Request);
505
+		curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
506
+		// execute the curl POST
507
+		$Response = curl_exec($curl);
508
+		curl_close($curl);
509
+		return $Response;
510
+	}
511
+
512
+
513
+
514
+	/**
515
+	 * @param $NVPString
516
+	 * @return array
517
+	 */
518
+	private function _NVPToArray($NVPString)
519
+	{
520
+		// prepare responses into array
521
+		$proArray = array();
522
+		while (strlen($NVPString)) {
523
+			// name
524
+			$keypos = strpos($NVPString, '=');
525
+			$keyval = substr($NVPString, 0, $keypos);
526
+			// value
527
+			$valuepos = strpos($NVPString, '&') ? strpos($NVPString, '&') : strlen($NVPString);
528
+			$valval = substr($NVPString, $keypos + 1, $valuepos - $keypos - 1);
529
+			// decoding the response
530
+			$proArray[ $keyval ] = urldecode($valval);
531
+			$NVPString = substr($NVPString, $valuepos + 1, strlen($NVPString));
532
+		}
533
+		return $proArray;
534
+	}
535
+
536
+
537
+
538
+	/**
539
+	 * @param array $PayPalResult
540
+	 * @return bool
541
+	 */
542
+	private function _APICallSuccessful($PayPalResult)
543
+	{
544
+		$approved = false;
545
+		// check main response message from PayPal
546
+		if (isset($PayPalResult['ACK']) && ! empty($PayPalResult['ACK'])) {
547
+			$ack = strtoupper($PayPalResult['ACK']);
548
+			$approved = ($ack == 'SUCCESS' || $ack == 'SUCCESSWITHWARNING' || $ack == 'PARTIALSUCCESS') ? true : false;
549
+		}
550
+		return $approved;
551
+	}
552
+
553
+
554
+
555
+	/**
556
+	 * @param $DataArray
557
+	 * @return array
558
+	 */
559
+	private function _GetErrors($DataArray)
560
+	{
561
+		$Errors = array();
562
+		$n = 0;
563
+		while (isset($DataArray[ 'L_ERRORCODE' . $n . '' ])) {
564
+			$LErrorCode = isset($DataArray[ 'L_ERRORCODE' . $n . '' ]) ? $DataArray[ 'L_ERRORCODE' . $n . '' ] : '';
565
+			$LShortMessage = isset($DataArray[ 'L_SHORTMESSAGE' . $n . '' ])
566
+				? $DataArray[ 'L_SHORTMESSAGE' . $n . '' ]
567
+				: '';
568
+			$LLongMessage = isset($DataArray[ 'L_LONGMESSAGE' . $n . '' ])
569
+				? $DataArray[ 'L_LONGMESSAGE' . $n . '' ]
570
+				: '';
571
+			$LSeverityCode = isset($DataArray[ 'L_SEVERITYCODE' . $n . '' ])
572
+				? $DataArray[ 'L_SEVERITYCODE' . $n . '' ]
573
+				: '';
574
+			$CurrentItem = array(
575
+				'L_ERRORCODE'    => $LErrorCode,
576
+				'L_SHORTMESSAGE' => $LShortMessage,
577
+				'L_LONGMESSAGE'  => $LLongMessage,
578
+				'L_SEVERITYCODE' => $LSeverityCode,
579
+			);
580
+			array_push($Errors, $CurrentItem);
581
+			$n++;
582
+		}
583
+		return $Errors;
584
+	}
585
+
586
+
587
+
588
+	/**
589
+	 *        nothing to see here...  move along....
590
+	 *
591
+	 * @access protected
592
+	 * @param $Errors
593
+	 * @return string
594
+	 */
595
+	private function _DisplayErrors($Errors)
596
+	{
597
+		$error = '';
598
+		foreach ($Errors as $ErrorVar => $ErrorVal) {
599
+			$CurrentError = $Errors[ $ErrorVar ];
600
+			foreach ($CurrentError as $CurrentErrorVar => $CurrentErrorVal) {
601
+				$CurrentVarName = '';
602
+				if ($CurrentErrorVar == 'L_ERRORCODE') {
603
+					$CurrentVarName = 'Error Code';
604
+				} elseif ($CurrentErrorVar == 'L_SHORTMESSAGE') {
605
+					$CurrentVarName = 'Short Message';
606
+				} elseif ($CurrentErrorVar == 'L_LONGMESSAGE') {
607
+					$CurrentVarName = 'Long Message';
608
+				} elseif ($CurrentErrorVar == 'L_SEVERITYCODE') {
609
+					$CurrentVarName = 'Severity Code';
610
+				}
611
+				$error .= '<br />' . $CurrentVarName . ': ' . $CurrentErrorVal;
612
+			}
613
+		}
614
+		return $error;
615
+	}
616 616
 }
Please login to merge, or discard this patch.
public/template_tags.php 1 patch
Spacing   +289 added lines, -289 removed lines patch added patch discarded remove patch
@@ -14,12 +14,12 @@  discard block
 block discarded – undo
14 14
  * @param int | \EE_Event $event
15 15
  * @return bool
16 16
  */
17
-function is_espresso_event( $event = NULL ) {
18
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
17
+function is_espresso_event($event = NULL) {
18
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
19 19
 		// extract EE_Event object from passed param regardless of what it is (within reason of course)
20
-		$event = EEH_Event_View::get_event( $event );
20
+		$event = EEH_Event_View::get_event($event);
21 21
 		// do we have a valid event ?
22
-		return $event instanceof EE_Event  ? TRUE : FALSE;
22
+		return $event instanceof EE_Event ? TRUE : FALSE;
23 23
 	}
24 24
 	return FALSE;
25 25
 }
@@ -31,7 +31,7 @@  discard block
 block discarded – undo
31 31
  * @return bool
32 32
  */
33 33
 function is_espresso_event_single() {
34
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
34
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
35 35
 		global $wp_query;
36 36
 		// return conditionals set by CPTs
37 37
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_event_single : FALSE;
@@ -46,7 +46,7 @@  discard block
 block discarded – undo
46 46
  * @return bool
47 47
  */
48 48
 function is_espresso_event_archive() {
49
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
49
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
50 50
 		global $wp_query;
51 51
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_event_archive : FALSE;
52 52
 	}
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
  * @return bool
61 61
  */
62 62
 function is_espresso_event_taxonomy() {
63
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
63
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
64 64
 		global $wp_query;
65 65
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_event_taxonomy : FALSE;
66 66
 	}
@@ -74,10 +74,10 @@  discard block
 block discarded – undo
74 74
  * @param int | \EE_Venue $venue
75 75
  * @return bool
76 76
  */
77
-function is_espresso_venue( $venue = NULL ) {
78
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
77
+function is_espresso_venue($venue = NULL) {
78
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
79 79
 		// extract EE_Venue object from passed param regardless of what it is (within reason of course)
80
-		$venue = EEH_Venue_View::get_venue( $venue, FALSE );
80
+		$venue = EEH_Venue_View::get_venue($venue, FALSE);
81 81
 		// do we have a valid event ?
82 82
 		return $venue instanceof EE_Venue ? TRUE : FALSE;
83 83
 	}
@@ -91,7 +91,7 @@  discard block
 block discarded – undo
91 91
  * @return bool
92 92
  */
93 93
 function is_espresso_venue_single() {
94
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
94
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
95 95
 		global $wp_query;
96 96
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_venue_single : FALSE;
97 97
 	}
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
  * @return bool
106 106
  */
107 107
 function is_espresso_venue_archive() {
108
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
108
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
109 109
 		global $wp_query;
110 110
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_venue_archive : FALSE;
111 111
 	}
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
  * @return bool
120 120
  */
121 121
 function is_espresso_venue_taxonomy() {
122
-	if ( can_use_espresso_conditionals( __FUNCTION__ )) {
122
+	if (can_use_espresso_conditionals(__FUNCTION__)) {
123 123
 		global $wp_query;
124 124
 		return $wp_query instanceof WP_Query ? $wp_query->is_espresso_venue_taxonomy : FALSE;
125 125
 	}
@@ -133,12 +133,12 @@  discard block
 block discarded – undo
133 133
  * @param $conditional_tag
134 134
  * @return bool
135 135
  */
136
-function can_use_espresso_conditionals( $conditional_tag ) {
137
-	if ( ! did_action( 'AHEE__EE_System__initialize' )) {
136
+function can_use_espresso_conditionals($conditional_tag) {
137
+	if ( ! did_action('AHEE__EE_System__initialize')) {
138 138
 		EE_Error::doing_it_wrong(
139 139
 			__FUNCTION__,
140 140
 			sprintf(
141
-				__( 'The "%s" conditional tag can not be used until after the "init" hook has run, but works best when used within a theme\'s template files.','event_espresso'),
141
+				__('The "%s" conditional tag can not be used until after the "init" hook has run, but works best when used within a theme\'s template files.', 'event_espresso'),
142 142
 				$conditional_tag
143 143
 			),
144 144
 			'4.4.0'
@@ -153,13 +153,13 @@  discard block
 block discarded – undo
153 153
 
154 154
 /*************************** Event Queries ***************************/
155 155
 
156
-if ( ! function_exists( 'espresso_get_events' )) {
156
+if ( ! function_exists('espresso_get_events')) {
157 157
 	/**
158 158
 	 * 	espresso_get_events
159 159
 	 * @param array $params
160 160
 	 * @return array
161 161
 	 */
162
-	function espresso_get_events( $params = array() ) {
162
+	function espresso_get_events($params = array()) {
163 163
 		//set default params
164 164
 		$default_espresso_events_params = array(
165 165
 			'limit' => 10,
@@ -170,18 +170,18 @@  discard block
 block discarded – undo
170 170
 			'sort' => 'ASC'
171 171
 		);
172 172
 		// allow the defaults to be filtered
173
-		$default_espresso_events_params = apply_filters( 'espresso_get_events__default_espresso_events_params', $default_espresso_events_params );
173
+		$default_espresso_events_params = apply_filters('espresso_get_events__default_espresso_events_params', $default_espresso_events_params);
174 174
 		// grab params and merge with defaults, then extract
175
-		$params = array_merge( $default_espresso_events_params, $params );
175
+		$params = array_merge($default_espresso_events_params, $params);
176 176
 		// run the query
177
-		$events_query = new EventEspresso\core\domain\services\wp_queries\EventListQuery( $params );
177
+		$events_query = new EventEspresso\core\domain\services\wp_queries\EventListQuery($params);
178 178
 		// assign results to a variable so we can return it
179 179
 		$events = $events_query->have_posts() ? $events_query->posts : array();
180 180
 		// but first reset the query and postdata
181 181
 		wp_reset_query();
182 182
 		wp_reset_postdata();
183 183
 		EED_Events_Archive::remove_all_events_archive_filters();
184
-		unset( $events_query );
184
+		unset($events_query);
185 185
 		return $events;
186 186
 	}
187 187
 }
@@ -195,33 +195,33 @@  discard block
 block discarded – undo
195 195
  * espresso_load_ticket_selector
196 196
  */
197 197
 function espresso_load_ticket_selector() {
198
-	EE_Registry::instance()->load_file( EE_MODULES . 'ticket_selector', 'EED_Ticket_Selector', 'module' );
198
+	EE_Registry::instance()->load_file(EE_MODULES.'ticket_selector', 'EED_Ticket_Selector', 'module');
199 199
 }
200 200
 
201
-if ( ! function_exists( 'espresso_ticket_selector' )) {
201
+if ( ! function_exists('espresso_ticket_selector')) {
202 202
 	/**
203 203
 	 * espresso_ticket_selector
204 204
 	 * @param null $event
205 205
 	 */
206
-	function espresso_ticket_selector( $event = NULL ) {
207
-		if (  ! apply_filters( 'FHEE_disable_espresso_ticket_selector', FALSE ) ) {
206
+	function espresso_ticket_selector($event = NULL) {
207
+		if ( ! apply_filters('FHEE_disable_espresso_ticket_selector', FALSE)) {
208 208
 			espresso_load_ticket_selector();
209 209
             \EED_Ticket_Selector::set_definitions();
210
-			echo EED_Ticket_Selector::display_ticket_selector( $event );
210
+			echo EED_Ticket_Selector::display_ticket_selector($event);
211 211
 		}
212 212
 	}
213 213
 }
214 214
 
215 215
 
216
-	if ( ! function_exists( 'espresso_view_details_btn' )) {
216
+	if ( ! function_exists('espresso_view_details_btn')) {
217 217
 	/**
218 218
 	 * espresso_view_details_btn
219 219
 	 * @param null $event
220 220
 	 */
221
-	function espresso_view_details_btn( $event = NULL ) {
222
-		if (  ! apply_filters( 'FHEE_disable_espresso_view_details_btn', FALSE ) ) {
221
+	function espresso_view_details_btn($event = NULL) {
222
+		if ( ! apply_filters('FHEE_disable_espresso_view_details_btn', FALSE)) {
223 223
 			espresso_load_ticket_selector();
224
-			echo EED_Ticket_Selector::display_ticket_selector( $event, TRUE );
224
+			echo EED_Ticket_Selector::display_ticket_selector($event, TRUE);
225 225
 		}
226 226
 	}
227 227
 }
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
 
232 232
 /*************************** EEH_Event_View ***************************/
233 233
 
234
-if ( ! function_exists( 'espresso_load_event_list_assets' )) {
234
+if ( ! function_exists('espresso_load_event_list_assets')) {
235 235
 	/**
236 236
 	 * espresso_load_event_list_assets
237 237
 	 * ensures that event list styles and scripts are loaded
@@ -240,13 +240,13 @@  discard block
 block discarded – undo
240 240
 	 */
241 241
 	function espresso_load_event_list_assets() {
242 242
 		$event_list = EED_Events_Archive::instance();
243
-		add_action( 'AHEE__EE_System__initialize_last', array( $event_list, 'load_event_list_assets' ), 10 );
244
-		add_filter( 'FHEE_enable_default_espresso_css', '__return_true' );
243
+		add_action('AHEE__EE_System__initialize_last', array($event_list, 'load_event_list_assets'), 10);
244
+		add_filter('FHEE_enable_default_espresso_css', '__return_true');
245 245
 	}
246 246
 }
247 247
 
248 248
 
249
-if ( ! function_exists( 'espresso_event_reg_button' )) {
249
+if ( ! function_exists('espresso_event_reg_button')) {
250 250
 	/**
251 251
 	 * espresso_event_reg_button
252 252
 	 * returns the "Register Now" button if event is active,
@@ -258,9 +258,9 @@  discard block
 block discarded – undo
258 258
 	 * @param bool $EVT_ID
259 259
 	 * @return string
260 260
 	 */
261
-	function espresso_event_reg_button( $btn_text_if_active = NULL, $btn_text_if_inactive = FALSE, $EVT_ID = FALSE ) {
262
-		$event_status = EEH_Event_View::event_active_status( $EVT_ID );
263
-		switch ( $event_status ) {
261
+	function espresso_event_reg_button($btn_text_if_active = NULL, $btn_text_if_inactive = FALSE, $EVT_ID = FALSE) {
262
+		$event_status = EEH_Event_View::event_active_status($EVT_ID);
263
+		switch ($event_status) {
264 264
 			case EE_Datetime::sold_out :
265 265
 				$btn_text = __('Sold Out', 'event_espresso');
266 266
 				$class = 'ee-pink';
@@ -276,10 +276,10 @@  discard block
 block discarded – undo
276 276
 			case EE_Datetime::upcoming :
277 277
 			case EE_Datetime::active :
278 278
 			default :
279
-				$btn_text =! empty( $btn_text_if_active ) ? $btn_text_if_active : __( 'Register Now', 'event_espresso' );
279
+				$btn_text = ! empty($btn_text_if_active) ? $btn_text_if_active : __('Register Now', 'event_espresso');
280 280
 				$class = 'ee-green';
281 281
 		}
282
-		if ( $event_status < 1 && ! empty( $btn_text_if_inactive )) {
282
+		if ($event_status < 1 && ! empty($btn_text_if_inactive)) {
283 283
 			$btn_text = $btn_text_if_inactive;
284 284
 			$class = 'ee-grey';
285 285
 		}
@@ -293,7 +293,7 @@  discard block
 block discarded – undo
293 293
 
294 294
 
295 295
 
296
-if ( ! function_exists( 'espresso_display_ticket_selector' )) {
296
+if ( ! function_exists('espresso_display_ticket_selector')) {
297 297
 	/**
298 298
 	 * espresso_display_ticket_selector
299 299
 	 * whether or not to display the Ticket Selector for an event
@@ -301,14 +301,14 @@  discard block
 block discarded – undo
301 301
 	 * @param bool $EVT_ID
302 302
 	 * @return boolean
303 303
 	 */
304
-	function espresso_display_ticket_selector( $EVT_ID = FALSE ) {
305
-		return EEH_Event_View::display_ticket_selector( $EVT_ID );
304
+	function espresso_display_ticket_selector($EVT_ID = FALSE) {
305
+		return EEH_Event_View::display_ticket_selector($EVT_ID);
306 306
 	}
307 307
 }
308 308
 
309 309
 
310 310
 
311
-if ( ! function_exists( 'espresso_event_status_banner' )) {
311
+if ( ! function_exists('espresso_event_status_banner')) {
312 312
 	/**
313 313
 	 * espresso_event_status
314 314
 	 * returns a banner showing the event status if it is sold out, expired, or inactive
@@ -316,13 +316,13 @@  discard block
 block discarded – undo
316 316
 	 * @param bool $EVT_ID
317 317
 	 * @return string
318 318
 	 */
319
-	function espresso_event_status_banner( $EVT_ID = FALSE ) {
320
-		return EEH_Event_View::event_status( $EVT_ID );
319
+	function espresso_event_status_banner($EVT_ID = FALSE) {
320
+		return EEH_Event_View::event_status($EVT_ID);
321 321
 	}
322 322
 }
323 323
 
324 324
 
325
-if ( ! function_exists( 'espresso_event_status' )) {
325
+if ( ! function_exists('espresso_event_status')) {
326 326
 	/**
327 327
 	 * espresso_event_status
328 328
 	 * returns the event status if it is sold out, expired, or inactive
@@ -331,13 +331,13 @@  discard block
 block discarded – undo
331 331
 	 * @param bool $echo
332 332
 	 * @return string
333 333
 	 */
334
-	function espresso_event_status( $EVT_ID = 0, $echo = TRUE ) {
335
-		return EEH_Event_View::event_active_status( $EVT_ID, $echo );
334
+	function espresso_event_status($EVT_ID = 0, $echo = TRUE) {
335
+		return EEH_Event_View::event_active_status($EVT_ID, $echo);
336 336
 	}
337 337
 }
338 338
 
339 339
 
340
-if ( ! function_exists( 'espresso_event_categories' )) {
340
+if ( ! function_exists('espresso_event_categories')) {
341 341
 	/**
342 342
 	 * espresso_event_categories
343 343
 	 * returns the terms associated with an event
@@ -347,17 +347,17 @@  discard block
 block discarded – undo
347 347
 	 * @param bool $echo
348 348
 	 * @return string
349 349
 	 */
350
-	function espresso_event_categories( $EVT_ID = 0, $hide_uncategorized = TRUE, $echo = TRUE ) {
351
-		if ( $echo ) {
352
-			echo EEH_Event_View::event_categories( $EVT_ID, $hide_uncategorized );
350
+	function espresso_event_categories($EVT_ID = 0, $hide_uncategorized = TRUE, $echo = TRUE) {
351
+		if ($echo) {
352
+			echo EEH_Event_View::event_categories($EVT_ID, $hide_uncategorized);
353 353
 			return '';
354 354
 		}
355
-		return EEH_Event_View::event_categories( $EVT_ID, $hide_uncategorized );
355
+		return EEH_Event_View::event_categories($EVT_ID, $hide_uncategorized);
356 356
 	}
357 357
 }
358 358
 
359 359
 
360
-if ( ! function_exists( 'espresso_event_tickets_available' )) {
360
+if ( ! function_exists('espresso_event_tickets_available')) {
361 361
 	/**
362 362
 	 * espresso_event_tickets_available
363 363
 	 * returns the ticket types available for purchase for an event
@@ -367,26 +367,26 @@  discard block
 block discarded – undo
367 367
 	 * @param bool $format
368 368
 	 * @return string
369 369
 	 */
370
-	function espresso_event_tickets_available( $EVT_ID = 0, $echo = TRUE, $format = TRUE ) {
371
-		$tickets = EEH_Event_View::event_tickets_available( $EVT_ID );
372
-		if ( is_array( $tickets ) && ! empty( $tickets )) {
370
+	function espresso_event_tickets_available($EVT_ID = 0, $echo = TRUE, $format = TRUE) {
371
+		$tickets = EEH_Event_View::event_tickets_available($EVT_ID);
372
+		if (is_array($tickets) && ! empty($tickets)) {
373 373
 			// if formatting then $html will be a string, else it will be an array of ticket objects
374
-			$html = $format ? '<ul id="ee-event-tickets-ul-' . $EVT_ID . '" class="ee-event-tickets-ul">' : array();
375
-			foreach ( $tickets as $ticket ) {
376
-				if ( $ticket instanceof EE_Ticket ) {
377
-					if ( $format ) {
378
-						$html .= '<li id="ee-event-tickets-li-' . $ticket->ID() . '" class="ee-event-tickets-li">';
379
-						$html .= $ticket->name() . ' ' . EEH_Template::format_currency( $ticket->get_ticket_total_with_taxes() );
374
+			$html = $format ? '<ul id="ee-event-tickets-ul-'.$EVT_ID.'" class="ee-event-tickets-ul">' : array();
375
+			foreach ($tickets as $ticket) {
376
+				if ($ticket instanceof EE_Ticket) {
377
+					if ($format) {
378
+						$html .= '<li id="ee-event-tickets-li-'.$ticket->ID().'" class="ee-event-tickets-li">';
379
+						$html .= $ticket->name().' '.EEH_Template::format_currency($ticket->get_ticket_total_with_taxes());
380 380
 						$html .= '</li>';
381 381
 					} else {
382 382
 						$html[] = $ticket;
383 383
 					}
384 384
 				}
385 385
 			}
386
-			if ( $format ) {
386
+			if ($format) {
387 387
 				$html .= '</ul>';
388 388
 			}
389
-			if ( $echo && $format ) {
389
+			if ($echo && $format) {
390 390
 				echo $html;
391 391
 				return '';
392 392
 			}
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
 	}
397 397
 }
398 398
 
399
-if ( ! function_exists( 'espresso_event_date_obj' )) {
399
+if ( ! function_exists('espresso_event_date_obj')) {
400 400
 	/**
401 401
 	 * espresso_event_date_obj
402 402
 	 * returns the primary date object for an event
@@ -404,13 +404,13 @@  discard block
 block discarded – undo
404 404
 	 * @param bool $EVT_ID
405 405
 	 * @return object
406 406
 	 */
407
-	function espresso_event_date_obj( $EVT_ID = FALSE ) {
408
-		return EEH_Event_View::get_primary_date_obj( $EVT_ID );
407
+	function espresso_event_date_obj($EVT_ID = FALSE) {
408
+		return EEH_Event_View::get_primary_date_obj($EVT_ID);
409 409
 	}
410 410
 }
411 411
 
412 412
 
413
-if ( ! function_exists( 'espresso_event_date' )) {
413
+if ( ! function_exists('espresso_event_date')) {
414 414
 	/**
415 415
 	 * espresso_event_date
416 416
 	 * returns the primary date for an event
@@ -421,22 +421,22 @@  discard block
 block discarded – undo
421 421
 	 * @param bool $echo
422 422
 	 * @return string
423 423
 	 */
424
-	function espresso_event_date( $date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE ) {
425
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
426
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
427
-		$date_format = apply_filters( 'FHEE__espresso_event_date__date_format', $date_format );
428
-		$time_format = apply_filters( 'FHEE__espresso_event_date__time_format', $time_format );
429
-		if($echo){
430
-			echo EEH_Event_View::the_event_date( $date_format, $time_format, $EVT_ID );
424
+	function espresso_event_date($date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE) {
425
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
426
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
427
+		$date_format = apply_filters('FHEE__espresso_event_date__date_format', $date_format);
428
+		$time_format = apply_filters('FHEE__espresso_event_date__time_format', $time_format);
429
+		if ($echo) {
430
+			echo EEH_Event_View::the_event_date($date_format, $time_format, $EVT_ID);
431 431
 			return '';
432 432
 		}
433
-		return EEH_Event_View::the_event_date( $date_format, $time_format, $EVT_ID );
433
+		return EEH_Event_View::the_event_date($date_format, $time_format, $EVT_ID);
434 434
 
435 435
 	}
436 436
 }
437 437
 
438 438
 
439
-if ( ! function_exists( 'espresso_list_of_event_dates' )) {
439
+if ( ! function_exists('espresso_list_of_event_dates')) {
440 440
 	/**
441 441
 	 * espresso_list_of_event_dates
442 442
 	 * returns a unordered list of dates for an event
@@ -451,40 +451,40 @@  discard block
 block discarded – undo
451 451
 	 * @param null   $limit
452 452
 	 * @return string
453 453
 	 */
454
-	function espresso_list_of_event_dates( $EVT_ID = 0, $date_format = '', $time_format = '', $echo = TRUE, $show_expired = NULL, $format = TRUE, $add_breaks = TRUE, $limit = NULL ) {
455
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
456
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
457
-		$date_format = apply_filters( 'FHEE__espresso_list_of_event_dates__date_format', $date_format );
458
-		$time_format = apply_filters( 'FHEE__espresso_list_of_event_dates__time_format', $time_format );
459
-		$datetimes = EEH_Event_View::get_all_date_obj( $EVT_ID, $show_expired, FALSE, $limit );
460
-		if ( ! $format ) {
461
-			return apply_filters( 'FHEE__espresso_list_of_event_dates__datetimes', $datetimes );
454
+	function espresso_list_of_event_dates($EVT_ID = 0, $date_format = '', $time_format = '', $echo = TRUE, $show_expired = NULL, $format = TRUE, $add_breaks = TRUE, $limit = NULL) {
455
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
456
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
457
+		$date_format = apply_filters('FHEE__espresso_list_of_event_dates__date_format', $date_format);
458
+		$time_format = apply_filters('FHEE__espresso_list_of_event_dates__time_format', $time_format);
459
+		$datetimes = EEH_Event_View::get_all_date_obj($EVT_ID, $show_expired, FALSE, $limit);
460
+		if ( ! $format) {
461
+			return apply_filters('FHEE__espresso_list_of_event_dates__datetimes', $datetimes);
462 462
 		}
463 463
 		//d( $datetimes );
464
-		if ( is_array( $datetimes ) && ! empty( $datetimes )) {
464
+		if (is_array($datetimes) && ! empty($datetimes)) {
465 465
 			global $post;
466
-			$html = $format ? '<ul id="ee-event-datetimes-ul-' . $post->ID . '" class="ee-event-datetimes-ul ee-clearfix">' : '';
467
-			foreach ( $datetimes as $datetime ) {
468
-				if ( $datetime instanceof EE_Datetime ) {
469
-					$html .= '<li id="ee-event-datetimes-li-' . $datetime->ID();
470
-					$html .= '" class="ee-event-datetimes-li ee-event-datetimes-li-' . $datetime->get_active_status() . '">';
466
+			$html = $format ? '<ul id="ee-event-datetimes-ul-'.$post->ID.'" class="ee-event-datetimes-ul ee-clearfix">' : '';
467
+			foreach ($datetimes as $datetime) {
468
+				if ($datetime instanceof EE_Datetime) {
469
+					$html .= '<li id="ee-event-datetimes-li-'.$datetime->ID();
470
+					$html .= '" class="ee-event-datetimes-li ee-event-datetimes-li-'.$datetime->get_active_status().'">';
471 471
 					$datetime_name = $datetime->name();
472
-					$html .= ! empty( $datetime_name ) ? '<strong>' . $datetime_name . '</strong>' : '';
473
-					$html .= ! empty( $datetime_name )  && $add_breaks ? '<br />' : '';
474
-					$html .= '<span class="dashicons dashicons-calendar"></span><span class="ee-event-datetimes-li-daterange">' . $datetime->date_range( $date_format ) . '</span><br/>';
475
-					$html .= '<span class="dashicons dashicons-clock"></span><span class="ee-event-datetimes-li-timerange">' . $datetime->time_range( $time_format ) . '</span>';
472
+					$html .= ! empty($datetime_name) ? '<strong>'.$datetime_name.'</strong>' : '';
473
+					$html .= ! empty($datetime_name) && $add_breaks ? '<br />' : '';
474
+					$html .= '<span class="dashicons dashicons-calendar"></span><span class="ee-event-datetimes-li-daterange">'.$datetime->date_range($date_format).'</span><br/>';
475
+					$html .= '<span class="dashicons dashicons-clock"></span><span class="ee-event-datetimes-li-timerange">'.$datetime->time_range($time_format).'</span>';
476 476
 					$datetime_description = $datetime->description();
477
-					$html .= ! empty( $datetime_description )  && $add_breaks ? '<br />' : '';
478
-					$html .= ! empty( $datetime_description ) ? ' - ' . $datetime_description : '';
479
-					$html = apply_filters( 'FHEE__espresso_list_of_event_dates__datetime_html', $html, $datetime );
477
+					$html .= ! empty($datetime_description) && $add_breaks ? '<br />' : '';
478
+					$html .= ! empty($datetime_description) ? ' - '.$datetime_description : '';
479
+					$html = apply_filters('FHEE__espresso_list_of_event_dates__datetime_html', $html, $datetime);
480 480
 					$html .= '</li>';
481 481
 				}
482 482
 			}
483 483
 			$html .= $format ? '</ul>' : '';
484 484
 		} else {
485
-			$html = $format ?  '<p><span class="dashicons dashicons-marker pink-text"></span>' . __( 'There are no upcoming dates for this event.', 'event_espresso' ) . '</p><br/>' : '';
485
+			$html = $format ? '<p><span class="dashicons dashicons-marker pink-text"></span>'.__('There are no upcoming dates for this event.', 'event_espresso').'</p><br/>' : '';
486 486
 		}
487
-		if ( $echo ) {
487
+		if ($echo) {
488 488
 			echo $html;
489 489
 			return '';
490 490
 		}
@@ -493,7 +493,7 @@  discard block
 block discarded – undo
493 493
 }
494 494
 
495 495
 
496
-if ( ! function_exists( 'espresso_event_end_date' )) {
496
+if ( ! function_exists('espresso_event_end_date')) {
497 497
 	/**
498 498
 	 * espresso_event_end_date
499 499
 	 * returns the last date for an event
@@ -504,20 +504,20 @@  discard block
 block discarded – undo
504 504
 	 * @param bool   $echo
505 505
 	 * @return string
506 506
 	 */
507
-	function espresso_event_end_date( $date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE ) {
508
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
509
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
510
-		$date_format = apply_filters( 'FHEE__espresso_event_end_date__date_format', $date_format );
511
-		$time_format = apply_filters( 'FHEE__espresso_event_end_date__time_format', $time_format );
512
-		if($echo){
513
-			echo EEH_Event_View::the_event_end_date( $date_format, $time_format, $EVT_ID );
507
+	function espresso_event_end_date($date_format = '', $time_format = '', $EVT_ID = FALSE, $echo = TRUE) {
508
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
509
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
510
+		$date_format = apply_filters('FHEE__espresso_event_end_date__date_format', $date_format);
511
+		$time_format = apply_filters('FHEE__espresso_event_end_date__time_format', $time_format);
512
+		if ($echo) {
513
+			echo EEH_Event_View::the_event_end_date($date_format, $time_format, $EVT_ID);
514 514
 			return '';
515 515
 		}
516
-		return EEH_Event_View::the_event_end_date( $date_format, $time_format, $EVT_ID );
516
+		return EEH_Event_View::the_event_end_date($date_format, $time_format, $EVT_ID);
517 517
 	}
518 518
 }
519 519
 
520
-if ( ! function_exists( 'espresso_event_date_range' )) {
520
+if ( ! function_exists('espresso_event_date_range')) {
521 521
 	/**
522 522
 	 * espresso_event_date_range
523 523
 	 * returns the first and last chronologically ordered dates for an event (if different)
@@ -530,31 +530,31 @@  discard block
 block discarded – undo
530 530
 	 * @param bool   $echo
531 531
 	 * @return string
532 532
 	 */
533
-	function espresso_event_date_range( $date_format = '', $time_format = '', $single_date_format = '', $single_time_format = '', $EVT_ID = FALSE, $echo = TRUE ) {
533
+	function espresso_event_date_range($date_format = '', $time_format = '', $single_date_format = '', $single_time_format = '', $EVT_ID = FALSE, $echo = TRUE) {
534 534
 		// set and filter date and time formats when a range is returned
535
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
536
-		$date_format = apply_filters( 'FHEE__espresso_event_date_range__date_format', $date_format );
535
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
536
+		$date_format = apply_filters('FHEE__espresso_event_date_range__date_format', $date_format);
537 537
 		// get the start and end date with NO time portion
538
-		$the_event_date = EEH_Event_View::the_earliest_event_date( $date_format, '', $EVT_ID );
539
-		$the_event_end_date = EEH_Event_View::the_latest_event_date( $date_format, '', $EVT_ID );
538
+		$the_event_date = EEH_Event_View::the_earliest_event_date($date_format, '', $EVT_ID);
539
+		$the_event_end_date = EEH_Event_View::the_latest_event_date($date_format, '', $EVT_ID);
540 540
 		// now we can determine if date range spans more than one day
541
-		if ( $the_event_date != $the_event_end_date ) {
542
-			$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
543
-			$time_format = apply_filters( 'FHEE__espresso_event_date_range__time_format', $time_format );
541
+		if ($the_event_date != $the_event_end_date) {
542
+			$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
543
+			$time_format = apply_filters('FHEE__espresso_event_date_range__time_format', $time_format);
544 544
 			$html = sprintf(
545
-				__( '%1$s - %2$s', 'event_espresso' ),
546
-				EEH_Event_View::the_earliest_event_date( $date_format, $time_format, $EVT_ID ),
547
-				EEH_Event_View::the_latest_event_date( $date_format, $time_format, $EVT_ID )
545
+				__('%1$s - %2$s', 'event_espresso'),
546
+				EEH_Event_View::the_earliest_event_date($date_format, $time_format, $EVT_ID),
547
+				EEH_Event_View::the_latest_event_date($date_format, $time_format, $EVT_ID)
548 548
 			);
549 549
 		} else {
550 550
 			// set and filter date and time formats when only a single datetime is returned
551
-			$single_date_format = ! empty( $single_date_format ) ? $single_date_format : get_option( 'date_format' );
552
-			$single_time_format = ! empty( $single_time_format ) ? $single_time_format : get_option( 'time_format' );
553
-			$single_date_format = apply_filters( 'FHEE__espresso_event_date_range__single_date_format', $single_date_format );
554
-			$single_time_format = apply_filters( 'FHEE__espresso_event_date_range__single_time_format', $single_time_format );
555
-			$html = EEH_Event_View::the_earliest_event_date( $single_date_format, $single_time_format, $EVT_ID );
551
+			$single_date_format = ! empty($single_date_format) ? $single_date_format : get_option('date_format');
552
+			$single_time_format = ! empty($single_time_format) ? $single_time_format : get_option('time_format');
553
+			$single_date_format = apply_filters('FHEE__espresso_event_date_range__single_date_format', $single_date_format);
554
+			$single_time_format = apply_filters('FHEE__espresso_event_date_range__single_time_format', $single_time_format);
555
+			$html = EEH_Event_View::the_earliest_event_date($single_date_format, $single_time_format, $EVT_ID);
556 556
 		}
557
-		if ( $echo ) {
557
+		if ($echo) {
558 558
 			echo $html;
559 559
 			return '';
560 560
 		}
@@ -562,7 +562,7 @@  discard block
 block discarded – undo
562 562
 	}
563 563
 }
564 564
 
565
-if ( ! function_exists( 'espresso_next_upcoming_datetime_obj' )) {
565
+if ( ! function_exists('espresso_next_upcoming_datetime_obj')) {
566 566
 	/**
567 567
 	 * espresso_next_upcoming_datetime_obj
568 568
 	 * returns the next upcoming datetime object for an event
@@ -570,12 +570,12 @@  discard block
 block discarded – undo
570 570
 	 * @param int $EVT_ID
571 571
 	 * @return EE_Datetime|null
572 572
 	 */
573
-	function espresso_next_upcoming_datetime_obj( $EVT_ID = 0 ) {
574
-		return EEH_Event_View::get_next_upcoming_date_obj( $EVT_ID );
573
+	function espresso_next_upcoming_datetime_obj($EVT_ID = 0) {
574
+		return EEH_Event_View::get_next_upcoming_date_obj($EVT_ID);
575 575
 	}
576 576
 }
577 577
 
578
-if ( ! function_exists( 'espresso_next_upcoming_datetime' ) ) {
578
+if ( ! function_exists('espresso_next_upcoming_datetime')) {
579 579
 	/**
580 580
 	 * espresso_next_upcoming_datetime
581 581
 	 * returns the start date and time for the next upcoming event.
@@ -586,30 +586,30 @@  discard block
 block discarded – undo
586 586
 	 * @param bool $echo
587 587
 	 * @return string
588 588
 	 */
589
-	function espresso_next_upcoming_datetime( $date_format = '', $time_format = '', $EVT_ID = 0, $echo = true ) {
589
+	function espresso_next_upcoming_datetime($date_format = '', $time_format = '', $EVT_ID = 0, $echo = true) {
590 590
 
591
-		$date_format = ! empty( $date_format ) ? $date_format : get_option( 'date_format' );
592
-		$date_format = apply_filters( 'FHEE__espresso_next_upcoming_datetime__date_format', $date_format );
591
+		$date_format = ! empty($date_format) ? $date_format : get_option('date_format');
592
+		$date_format = apply_filters('FHEE__espresso_next_upcoming_datetime__date_format', $date_format);
593 593
 
594
-		$time_format = ! empty( $time_format ) ? $time_format : get_option( 'time_format' );
595
-		$time_format = apply_filters( 'FHEE__espresso_next_upcoming_datetime__time_format', $time_format );
594
+		$time_format = ! empty($time_format) ? $time_format : get_option('time_format');
595
+		$time_format = apply_filters('FHEE__espresso_next_upcoming_datetime__time_format', $time_format);
596 596
 
597
-		$datetime_format = trim( $date_format . ' ' . $time_format);
597
+		$datetime_format = trim($date_format.' '.$time_format);
598 598
 
599
-		$datetime = espresso_next_upcoming_datetime_obj( $EVT_ID );
599
+		$datetime = espresso_next_upcoming_datetime_obj($EVT_ID);
600 600
 
601
-		if( ! $datetime instanceof EE_Datetime ) {
601
+		if ( ! $datetime instanceof EE_Datetime) {
602 602
 			return '';
603 603
 		}
604
-		if ( $echo ){
605
-			echo $datetime->get_i18n_datetime( 'DTT_EVT_start', $datetime_format );
604
+		if ($echo) {
605
+			echo $datetime->get_i18n_datetime('DTT_EVT_start', $datetime_format);
606 606
 			return '';
607 607
 		}
608
-		return $datetime->get_i18n_datetime( 'DTT_EVT_start', $datetime_format );
608
+		return $datetime->get_i18n_datetime('DTT_EVT_start', $datetime_format);
609 609
 	}
610 610
 }
611 611
 
612
-if ( ! function_exists( 'espresso_event_date_as_calendar_page' )) {
612
+if ( ! function_exists('espresso_event_date_as_calendar_page')) {
613 613
 	/**
614 614
 	 * espresso_event_date_as_calendar_page
615 615
 	 * returns the primary date for an event, stylized to appear as the page of a calendar
@@ -617,15 +617,15 @@  discard block
 block discarded – undo
617 617
 	 * @param bool $EVT_ID
618 618
 	 * @return string
619 619
 	 */
620
-	function espresso_event_date_as_calendar_page( $EVT_ID = FALSE ) {
621
-		EEH_Event_View::event_date_as_calendar_page( $EVT_ID );
620
+	function espresso_event_date_as_calendar_page($EVT_ID = FALSE) {
621
+		EEH_Event_View::event_date_as_calendar_page($EVT_ID);
622 622
 	}
623 623
 }
624 624
 
625 625
 
626 626
 
627 627
 
628
-if ( ! function_exists( 'espresso_event_link_url' )) {
628
+if ( ! function_exists('espresso_event_link_url')) {
629 629
 	/**
630 630
 	 * espresso_event_link_url
631 631
 	 *
@@ -633,18 +633,18 @@  discard block
 block discarded – undo
633 633
 	 * @param bool $echo
634 634
 	 * @return string
635 635
 	 */
636
-	function espresso_event_link_url( $EVT_ID = 0, $echo = TRUE ) {
637
-		if ( $echo ) {
638
-			echo EEH_Event_View::event_link_url( $EVT_ID );
636
+	function espresso_event_link_url($EVT_ID = 0, $echo = TRUE) {
637
+		if ($echo) {
638
+			echo EEH_Event_View::event_link_url($EVT_ID);
639 639
 			return '';
640 640
 		}
641
-		return EEH_Event_View::event_link_url( $EVT_ID );
641
+		return EEH_Event_View::event_link_url($EVT_ID);
642 642
 	}
643 643
 }
644 644
 
645 645
 
646 646
 
647
-if ( ! function_exists( 'espresso_event_has_content_or_excerpt' )) {
647
+if ( ! function_exists('espresso_event_has_content_or_excerpt')) {
648 648
 	/**
649 649
 	 *    espresso_event_has_content_or_excerpt
650 650
 	 *
@@ -652,15 +652,15 @@  discard block
 block discarded – undo
652 652
 	 * @param bool $EVT_ID
653 653
 	 * @return    boolean
654 654
 	 */
655
-	function espresso_event_has_content_or_excerpt( $EVT_ID = FALSE ) {
656
-		return EEH_Event_View::event_has_content_or_excerpt( $EVT_ID );
655
+	function espresso_event_has_content_or_excerpt($EVT_ID = FALSE) {
656
+		return EEH_Event_View::event_has_content_or_excerpt($EVT_ID);
657 657
 	}
658 658
 }
659 659
 
660 660
 
661 661
 
662 662
 
663
-if ( ! function_exists( 'espresso_event_content_or_excerpt' )) {
663
+if ( ! function_exists('espresso_event_content_or_excerpt')) {
664 664
 	/**
665 665
 	 * espresso_event_content_or_excerpt
666 666
 	 *
@@ -669,18 +669,18 @@  discard block
 block discarded – undo
669 669
 	 * @param bool $echo
670 670
 	 * @return string
671 671
 	 */
672
-	function espresso_event_content_or_excerpt( $num_words = 55, $more = NULL, $echo = TRUE ) {
673
-		if ( $echo ) {
674
-			echo EEH_Event_View::event_content_or_excerpt( $num_words, $more );
672
+	function espresso_event_content_or_excerpt($num_words = 55, $more = NULL, $echo = TRUE) {
673
+		if ($echo) {
674
+			echo EEH_Event_View::event_content_or_excerpt($num_words, $more);
675 675
 			return '';
676 676
 		}
677
-		return EEH_Event_View::event_content_or_excerpt( $num_words, $more );
677
+		return EEH_Event_View::event_content_or_excerpt($num_words, $more);
678 678
 	}
679 679
 }
680 680
 
681 681
 
682 682
 
683
-if ( ! function_exists( 'espresso_event_phone' )) {
683
+if ( ! function_exists('espresso_event_phone')) {
684 684
 	/**
685 685
 	 * espresso_event_phone
686 686
 	 *
@@ -688,18 +688,18 @@  discard block
 block discarded – undo
688 688
 	 * @param bool $echo
689 689
 	 * @return string
690 690
 	 */
691
-	function espresso_event_phone( $EVT_ID = 0, $echo = TRUE ) {
692
-		if ( $echo ) {
693
-			echo EEH_Event_View::event_phone( $EVT_ID );
691
+	function espresso_event_phone($EVT_ID = 0, $echo = TRUE) {
692
+		if ($echo) {
693
+			echo EEH_Event_View::event_phone($EVT_ID);
694 694
 			return '';
695 695
 		}
696
-		return EEH_Event_View::event_phone( $EVT_ID );
696
+		return EEH_Event_View::event_phone($EVT_ID);
697 697
 	}
698 698
 }
699 699
 
700 700
 
701 701
 
702
-if ( ! function_exists( 'espresso_edit_event_link' )) {
702
+if ( ! function_exists('espresso_edit_event_link')) {
703 703
 	/**
704 704
 	 * espresso_edit_event_link
705 705
 	 * returns a link to edit an event
@@ -708,39 +708,39 @@  discard block
 block discarded – undo
708 708
 	 * @param bool $echo
709 709
 	 * @return string
710 710
 	 */
711
-	function espresso_edit_event_link( $EVT_ID = 0, $echo = TRUE ) {
712
-		if ( $echo ) {
713
-			echo EEH_Event_View::edit_event_link( $EVT_ID );
711
+	function espresso_edit_event_link($EVT_ID = 0, $echo = TRUE) {
712
+		if ($echo) {
713
+			echo EEH_Event_View::edit_event_link($EVT_ID);
714 714
 			return '';
715 715
 		}
716
-		return EEH_Event_View::edit_event_link( $EVT_ID );
716
+		return EEH_Event_View::edit_event_link($EVT_ID);
717 717
 	}
718 718
 }
719 719
 
720 720
 
721
-if ( ! function_exists( 'espresso_organization_name' )) {
721
+if ( ! function_exists('espresso_organization_name')) {
722 722
 	/**
723 723
 	 * espresso_organization_name
724 724
 	 * @param bool $echo
725 725
 	 * @return string
726 726
 	 */
727 727
 	function espresso_organization_name($echo = TRUE) {
728
-		if($echo){
729
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'name' );
728
+		if ($echo) {
729
+			echo EE_Registry::instance()->CFG->organization->get_pretty('name');
730 730
 			return '';
731 731
 		}
732
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'name' );
732
+		return EE_Registry::instance()->CFG->organization->get_pretty('name');
733 733
 	}
734 734
 }
735 735
 
736
-if ( ! function_exists( 'espresso_organization_address' )) {
736
+if ( ! function_exists('espresso_organization_address')) {
737 737
 	/**
738 738
 	 * espresso_organization_address
739 739
 	 * @param string $type
740 740
 	 * @return string
741 741
 	 */
742
-	function espresso_organization_address( $type = 'inline' ) {
743
-		if ( EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config ) {
742
+	function espresso_organization_address($type = 'inline') {
743
+		if (EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config) {
744 744
 			$address = new EventEspresso\core\domain\entities\GenericAddress(
745 745
 				EE_Registry::instance()->CFG->organization->address_1,
746 746
 				EE_Registry::instance()->CFG->organization->address_2,
@@ -749,129 +749,129 @@  discard block
 block discarded – undo
749 749
 				EE_Registry::instance()->CFG->organization->zip,
750 750
 				EE_Registry::instance()->CFG->organization->CNT_ISO
751 751
 			);
752
-			return EEH_Address::format( $address, $type );
752
+			return EEH_Address::format($address, $type);
753 753
 		}
754 754
 		return '';
755 755
 	}
756 756
 }
757 757
 
758
-if ( ! function_exists( 'espresso_organization_email' )) {
758
+if ( ! function_exists('espresso_organization_email')) {
759 759
 	/**
760 760
 	 * espresso_organization_email
761 761
 	 * @param bool $echo
762 762
 	 * @return string
763 763
 	 */
764
-	function espresso_organization_email( $echo = TRUE ) {
765
-		if($echo){
766
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'email' );
764
+	function espresso_organization_email($echo = TRUE) {
765
+		if ($echo) {
766
+			echo EE_Registry::instance()->CFG->organization->get_pretty('email');
767 767
 			return '';
768 768
 		}
769
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'email' );
769
+		return EE_Registry::instance()->CFG->organization->get_pretty('email');
770 770
 	}
771 771
 }
772 772
 
773
-if ( ! function_exists( 'espresso_organization_logo_url' )) {
773
+if ( ! function_exists('espresso_organization_logo_url')) {
774 774
 	/**
775 775
 	 * espresso_organization_logo_url
776 776
 	 * @param bool $echo
777 777
 	 * @return string
778 778
 	 */
779
-	function espresso_organization_logo_url( $echo = TRUE ) {
780
-		if($echo){
781
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'logo_url' );
779
+	function espresso_organization_logo_url($echo = TRUE) {
780
+		if ($echo) {
781
+			echo EE_Registry::instance()->CFG->organization->get_pretty('logo_url');
782 782
 			return '';
783 783
 		}
784
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'logo_url' );
784
+		return EE_Registry::instance()->CFG->organization->get_pretty('logo_url');
785 785
 	}
786 786
 }
787 787
 
788
-if ( ! function_exists( 'espresso_organization_facebook' )) {
788
+if ( ! function_exists('espresso_organization_facebook')) {
789 789
 	/**
790 790
 	 * espresso_organization_facebook
791 791
 	 * @param bool $echo
792 792
 	 * @return string
793 793
 	 */
794
-	function espresso_organization_facebook( $echo = TRUE ) {
795
-		if($echo){
796
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'facebook' );
794
+	function espresso_organization_facebook($echo = TRUE) {
795
+		if ($echo) {
796
+			echo EE_Registry::instance()->CFG->organization->get_pretty('facebook');
797 797
 			return '';
798 798
 		}
799
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'facebook' );
799
+		return EE_Registry::instance()->CFG->organization->get_pretty('facebook');
800 800
 	}
801 801
 }
802 802
 
803
-if ( ! function_exists( 'espresso_organization_twitter' )) {
803
+if ( ! function_exists('espresso_organization_twitter')) {
804 804
 	/**
805 805
 	 * espresso_organization_twitter
806 806
 	 * @param bool $echo
807 807
 	 * @return string
808 808
 	 */
809
-	function espresso_organization_twitter( $echo = TRUE ) {
810
-		if($echo){
811
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'twitter' );
809
+	function espresso_organization_twitter($echo = TRUE) {
810
+		if ($echo) {
811
+			echo EE_Registry::instance()->CFG->organization->get_pretty('twitter');
812 812
 			return '';
813 813
 		}
814
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'twitter' );
814
+		return EE_Registry::instance()->CFG->organization->get_pretty('twitter');
815 815
 	}
816 816
 }
817 817
 
818
-if ( ! function_exists( 'espresso_organization_linkedin' )) {
818
+if ( ! function_exists('espresso_organization_linkedin')) {
819 819
 	/**
820 820
 	 * espresso_organization_linkedin
821 821
 	 * @param bool $echo
822 822
 	 * @return string
823 823
 	 */
824
-	function espresso_organization_linkedin( $echo = TRUE ) {
825
-		if($echo){
826
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'linkedin' );
824
+	function espresso_organization_linkedin($echo = TRUE) {
825
+		if ($echo) {
826
+			echo EE_Registry::instance()->CFG->organization->get_pretty('linkedin');
827 827
 			return '';
828 828
 		}
829
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'linkedin' );
829
+		return EE_Registry::instance()->CFG->organization->get_pretty('linkedin');
830 830
 	}
831 831
 }
832 832
 
833
-if ( ! function_exists( 'espresso_organization_pinterest' )) {
833
+if ( ! function_exists('espresso_organization_pinterest')) {
834 834
 	/**
835 835
 	 * espresso_organization_pinterest
836 836
 	 * @param bool $echo
837 837
 	 * @return string
838 838
 	 */
839
-	function espresso_organization_pinterest( $echo = TRUE ) {
840
-		if($echo){
841
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'pinterest' );
839
+	function espresso_organization_pinterest($echo = TRUE) {
840
+		if ($echo) {
841
+			echo EE_Registry::instance()->CFG->organization->get_pretty('pinterest');
842 842
 			return '';
843 843
 		}
844
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'pinterest' );
844
+		return EE_Registry::instance()->CFG->organization->get_pretty('pinterest');
845 845
 	}
846 846
 }
847 847
 
848
-if ( ! function_exists( 'espresso_organization_google' )) {
848
+if ( ! function_exists('espresso_organization_google')) {
849 849
 	/**
850 850
 	 * espresso_organization_google
851 851
 	 * @param bool $echo
852 852
 	 * @return string
853 853
 	 */
854
-	function espresso_organization_google( $echo = TRUE ) {
855
-		if($echo){
856
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'google' );
854
+	function espresso_organization_google($echo = TRUE) {
855
+		if ($echo) {
856
+			echo EE_Registry::instance()->CFG->organization->get_pretty('google');
857 857
 			return '';
858 858
 		}
859
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'google' );
859
+		return EE_Registry::instance()->CFG->organization->get_pretty('google');
860 860
 	}
861 861
 }
862 862
 
863
-if ( ! function_exists( 'espresso_organization_instagram' )) {
863
+if ( ! function_exists('espresso_organization_instagram')) {
864 864
 	/**
865 865
 	 * espresso_organization_instagram
866 866
 	 * @param bool $echo
867 867
 	 * @return string
868 868
 	 */
869
-	function espresso_organization_instagram( $echo = TRUE ) {
870
-		if($echo){
871
-			echo EE_Registry::instance()->CFG->organization->get_pretty( 'instagram' );
869
+	function espresso_organization_instagram($echo = TRUE) {
870
+		if ($echo) {
871
+			echo EE_Registry::instance()->CFG->organization->get_pretty('instagram');
872 872
 			return '';
873 873
 		}
874
-		return EE_Registry::instance()->CFG->organization->get_pretty( 'instagram' );
874
+		return EE_Registry::instance()->CFG->organization->get_pretty('instagram');
875 875
 	}
876 876
 }
877 877
 
@@ -881,7 +881,7 @@  discard block
 block discarded – undo
881 881
 
882 882
 
883 883
 
884
-if ( ! function_exists( 'espresso_event_venues' )) {
884
+if ( ! function_exists('espresso_event_venues')) {
885 885
 	/**
886 886
 	 * espresso_event_venues
887 887
 	 *
@@ -895,7 +895,7 @@  discard block
 block discarded – undo
895 895
 
896 896
 
897 897
 
898
-if ( ! function_exists( 'espresso_venue_id' )) {
898
+if ( ! function_exists('espresso_venue_id')) {
899 899
 	/**
900 900
 	 *    espresso_venue_name
901 901
 	 *
@@ -903,15 +903,15 @@  discard block
 block discarded – undo
903 903
 	 * @param     int $EVT_ID
904 904
 	 * @return    string
905 905
 	 */
906
-	function espresso_venue_id( $EVT_ID = 0 ) {
907
-		$venue = EEH_Venue_View::get_venue( $EVT_ID );
906
+	function espresso_venue_id($EVT_ID = 0) {
907
+		$venue = EEH_Venue_View::get_venue($EVT_ID);
908 908
 		return $venue instanceof EE_Venue ? $venue->ID() : 0;
909 909
 	}
910 910
 }
911 911
 
912 912
 
913 913
 
914
-if ( ! function_exists( 'espresso_is_venue_private' ) ) {
914
+if ( ! function_exists('espresso_is_venue_private')) {
915 915
 	/**
916 916
 	 * Return whether a venue is private or not.
917 917
 	 * @see EEH_Venue_View::get_venue() for more info on expected return results.
@@ -920,45 +920,45 @@  discard block
 block discarded – undo
920 920
 	 *
921 921
 	 * @return bool | null
922 922
 	 */
923
-	function espresso_is_venue_private( $VNU_ID = 0 ) {
924
-		return EEH_Venue_View::is_venue_private( $VNU_ID );
923
+	function espresso_is_venue_private($VNU_ID = 0) {
924
+		return EEH_Venue_View::is_venue_private($VNU_ID);
925 925
 	}
926 926
 }
927 927
 
928 928
 
929 929
 
930
-if ( ! function_exists( 'espresso_venue_is_password_protected' ) ) {
930
+if ( ! function_exists('espresso_venue_is_password_protected')) {
931 931
 	/**
932 932
 	 * returns true or false if a venue is password protected or not
933 933
 	 *
934 934
 	 * @param int     $VNU_ID optional, the venue id to check.
935 935
 	 * @return string
936 936
 	 */
937
-	function espresso_venue_is_password_protected( $VNU_ID = 0 ) {
938
-		EE_Registry::instance()->load_helper( 'Venue_View' );
939
-		return EEH_Venue_View::is_venue_password_protected( $VNU_ID );
937
+	function espresso_venue_is_password_protected($VNU_ID = 0) {
938
+		EE_Registry::instance()->load_helper('Venue_View');
939
+		return EEH_Venue_View::is_venue_password_protected($VNU_ID);
940 940
 	}
941 941
 }
942 942
 
943 943
 
944 944
 
945
-if ( ! function_exists( 'espresso_password_protected_venue_form' ) ) {
945
+if ( ! function_exists('espresso_password_protected_venue_form')) {
946 946
 	/**
947 947
 	 * Returns a password form if venue is password protected.
948 948
 	 *
949 949
 	 * @param int     $VNU_ID optional, the venue id to check.
950 950
 	 * @return string
951 951
 	 */
952
-	function espresso_password_protected_venue_form( $VNU_ID = 0 ) {
953
-		EE_Registry::instance()->load_helper( 'Venue_View' );
954
-		return EEH_Venue_View::password_protected_venue_form( $VNU_ID );
952
+	function espresso_password_protected_venue_form($VNU_ID = 0) {
953
+		EE_Registry::instance()->load_helper('Venue_View');
954
+		return EEH_Venue_View::password_protected_venue_form($VNU_ID);
955 955
 	}
956 956
 }
957 957
 
958 958
 
959 959
 
960 960
 
961
-if ( ! function_exists( 'espresso_venue_name' )) {
961
+if ( ! function_exists('espresso_venue_name')) {
962 962
 	/**
963 963
 	 *    espresso_venue_name
964 964
 	 *
@@ -968,19 +968,19 @@  discard block
 block discarded – undo
968 968
 	 * @param bool   $echo
969 969
 	 * @return    string
970 970
 	 */
971
-	function espresso_venue_name( $VNU_ID = 0, $link_to = 'details', $echo = TRUE ) {
972
-		if($echo){
973
-			echo EEH_Venue_View::venue_name( $link_to, $VNU_ID );
971
+	function espresso_venue_name($VNU_ID = 0, $link_to = 'details', $echo = TRUE) {
972
+		if ($echo) {
973
+			echo EEH_Venue_View::venue_name($link_to, $VNU_ID);
974 974
 			return '';
975 975
 		}
976
-		return EEH_Venue_View::venue_name( $link_to, $VNU_ID );
976
+		return EEH_Venue_View::venue_name($link_to, $VNU_ID);
977 977
 	}
978 978
 }
979 979
 
980 980
 
981 981
 
982 982
 
983
-if ( ! function_exists( 'espresso_venue_link' )) {
983
+if ( ! function_exists('espresso_venue_link')) {
984 984
 	/**
985 985
 	 * 	espresso_venue_link
986 986
 	 *
@@ -989,14 +989,14 @@  discard block
 block discarded – undo
989 989
 	 *  @param 	string 	$text
990 990
 	 *  @return 	string
991 991
 	 */
992
-	function espresso_venue_link( $VNU_ID = 0, $text = '' ) {
993
-		return EEH_Venue_View::venue_details_link( $VNU_ID, $text );
992
+	function espresso_venue_link($VNU_ID = 0, $text = '') {
993
+		return EEH_Venue_View::venue_details_link($VNU_ID, $text);
994 994
 	}
995 995
 }
996 996
 
997 997
 
998 998
 
999
-if ( ! function_exists( 'espresso_venue_description' )) {
999
+if ( ! function_exists('espresso_venue_description')) {
1000 1000
 	/**
1001 1001
 	 *    espresso_venue_description
1002 1002
 	 *
@@ -1005,17 +1005,17 @@  discard block
 block discarded – undo
1005 1005
 	 * @param bool $echo
1006 1006
 	 * @return    string
1007 1007
 	 */
1008
-	function espresso_venue_description( $VNU_ID = FALSE, $echo = TRUE ) {
1009
-		if($echo){
1010
-			echo EEH_Venue_View::venue_description( $VNU_ID );
1008
+	function espresso_venue_description($VNU_ID = FALSE, $echo = TRUE) {
1009
+		if ($echo) {
1010
+			echo EEH_Venue_View::venue_description($VNU_ID);
1011 1011
 			return '';
1012 1012
 		}
1013
-		return EEH_Venue_View::venue_description( $VNU_ID );
1013
+		return EEH_Venue_View::venue_description($VNU_ID);
1014 1014
 	}
1015 1015
 }
1016 1016
 
1017 1017
 
1018
-if ( ! function_exists( 'espresso_venue_excerpt' )) {
1018
+if ( ! function_exists('espresso_venue_excerpt')) {
1019 1019
 	/**
1020 1020
 	 *    espresso_venue_excerpt
1021 1021
 	 *
@@ -1024,18 +1024,18 @@  discard block
 block discarded – undo
1024 1024
 	 * @param bool $echo
1025 1025
 	 * @return    string
1026 1026
 	 */
1027
-	function espresso_venue_excerpt( $VNU_ID = 0,  $echo = TRUE ) {
1028
-		if ( $echo ) {
1029
-			echo EEH_Venue_View::venue_excerpt( $VNU_ID );
1027
+	function espresso_venue_excerpt($VNU_ID = 0, $echo = TRUE) {
1028
+		if ($echo) {
1029
+			echo EEH_Venue_View::venue_excerpt($VNU_ID);
1030 1030
 			return '';
1031 1031
 		}
1032
-		return EEH_Venue_View::venue_excerpt( $VNU_ID );
1032
+		return EEH_Venue_View::venue_excerpt($VNU_ID);
1033 1033
 	}
1034 1034
 }
1035 1035
 
1036 1036
 
1037 1037
 
1038
-if ( ! function_exists( 'espresso_venue_categories' )) {
1038
+if ( ! function_exists('espresso_venue_categories')) {
1039 1039
 	/**
1040 1040
 	 * espresso_venue_categories
1041 1041
 	 * returns the terms associated with a venue
@@ -1045,17 +1045,17 @@  discard block
 block discarded – undo
1045 1045
 	 * @param bool $echo
1046 1046
 	 * @return string
1047 1047
 	 */
1048
-	function espresso_venue_categories( $VNU_ID = 0, $hide_uncategorized = TRUE,  $echo = TRUE ) {
1049
-		if ( $echo ) {
1050
-			echo EEH_Venue_View::venue_categories( $VNU_ID, $hide_uncategorized );
1048
+	function espresso_venue_categories($VNU_ID = 0, $hide_uncategorized = TRUE, $echo = TRUE) {
1049
+		if ($echo) {
1050
+			echo EEH_Venue_View::venue_categories($VNU_ID, $hide_uncategorized);
1051 1051
 			return '';
1052 1052
 		}
1053
-		return EEH_Venue_View::venue_categories( $VNU_ID, $hide_uncategorized );
1053
+		return EEH_Venue_View::venue_categories($VNU_ID, $hide_uncategorized);
1054 1054
 	}
1055 1055
 }
1056 1056
 
1057 1057
 
1058
-if ( ! function_exists( 'espresso_venue_address' )) {
1058
+if ( ! function_exists('espresso_venue_address')) {
1059 1059
 	/**
1060 1060
 	 * espresso_venue_address
1061 1061
 	 * returns a formatted block of html  for displaying a venue's address
@@ -1065,17 +1065,17 @@  discard block
 block discarded – undo
1065 1065
 	 * @param bool   $echo
1066 1066
 	 * @return string
1067 1067
 	 */
1068
-	function espresso_venue_address( $type = 'multiline', $VNU_ID = 0, $echo = TRUE ) {
1069
-		if ( $echo ) {
1070
-			echo EEH_Venue_View::venue_address( $type, $VNU_ID );
1068
+	function espresso_venue_address($type = 'multiline', $VNU_ID = 0, $echo = TRUE) {
1069
+		if ($echo) {
1070
+			echo EEH_Venue_View::venue_address($type, $VNU_ID);
1071 1071
 			return '';
1072 1072
 		}
1073
-		return EEH_Venue_View::venue_address( $type, $VNU_ID );
1073
+		return EEH_Venue_View::venue_address($type, $VNU_ID);
1074 1074
 	}
1075 1075
 }
1076 1076
 
1077 1077
 
1078
-if ( ! function_exists( 'espresso_venue_raw_address' )) {
1078
+if ( ! function_exists('espresso_venue_raw_address')) {
1079 1079
 	/**
1080 1080
 	 * espresso_venue_address
1081 1081
 	 * returns an UN-formatted string containing a venue's address
@@ -1085,17 +1085,17 @@  discard block
 block discarded – undo
1085 1085
 	 * @param bool     $echo
1086 1086
 	 * @return string
1087 1087
 	 */
1088
-	function espresso_venue_raw_address( $type = 'multiline', $VNU_ID = 0, $echo = TRUE ) {
1089
-		if ( $echo ) {
1090
-			echo EEH_Venue_View::venue_address( $type, $VNU_ID, FALSE, FALSE );
1088
+	function espresso_venue_raw_address($type = 'multiline', $VNU_ID = 0, $echo = TRUE) {
1089
+		if ($echo) {
1090
+			echo EEH_Venue_View::venue_address($type, $VNU_ID, FALSE, FALSE);
1091 1091
 			return '';
1092 1092
 		}
1093
-		return EEH_Venue_View::venue_address( $type, $VNU_ID, FALSE, FALSE );
1093
+		return EEH_Venue_View::venue_address($type, $VNU_ID, FALSE, FALSE);
1094 1094
 	}
1095 1095
 }
1096 1096
 
1097 1097
 
1098
-if ( ! function_exists( 'espresso_venue_has_address' )) {
1098
+if ( ! function_exists('espresso_venue_has_address')) {
1099 1099
 	/**
1100 1100
 	 * espresso_venue_has_address
1101 1101
 	 * returns TRUE or FALSE if a Venue has address information
@@ -1103,13 +1103,13 @@  discard block
 block discarded – undo
1103 1103
 	 * @param int $VNU_ID
1104 1104
 	 * @return bool
1105 1105
 	 */
1106
-	function espresso_venue_has_address( $VNU_ID = 0 ) {
1107
-		return EEH_Venue_View::venue_has_address( $VNU_ID );
1106
+	function espresso_venue_has_address($VNU_ID = 0) {
1107
+		return EEH_Venue_View::venue_has_address($VNU_ID);
1108 1108
 	}
1109 1109
 }
1110 1110
 
1111 1111
 
1112
-if ( ! function_exists( 'espresso_venue_gmap' )) {
1112
+if ( ! function_exists('espresso_venue_gmap')) {
1113 1113
 	/**
1114 1114
 	 * espresso_venue_gmap
1115 1115
 	 * returns a google map for the venue address
@@ -1120,17 +1120,17 @@  discard block
 block discarded – undo
1120 1120
 	 * @param bool     $echo
1121 1121
 	 * @return string
1122 1122
 	 */
1123
-	function espresso_venue_gmap( $VNU_ID = 0, $map_ID = FALSE, $gmap = array(), $echo = TRUE  ) {
1124
-		if ( $echo ) {
1125
-			echo EEH_Venue_View::venue_gmap( $VNU_ID, $map_ID, $gmap );
1123
+	function espresso_venue_gmap($VNU_ID = 0, $map_ID = FALSE, $gmap = array(), $echo = TRUE) {
1124
+		if ($echo) {
1125
+			echo EEH_Venue_View::venue_gmap($VNU_ID, $map_ID, $gmap);
1126 1126
 			return '';
1127 1127
 		}
1128
-		return EEH_Venue_View::venue_gmap( $VNU_ID, $map_ID, $gmap );
1128
+		return EEH_Venue_View::venue_gmap($VNU_ID, $map_ID, $gmap);
1129 1129
 	}
1130 1130
 }
1131 1131
 
1132 1132
 
1133
-if ( ! function_exists( 'espresso_venue_phone' )) {
1133
+if ( ! function_exists('espresso_venue_phone')) {
1134 1134
 	/**
1135 1135
 	 * espresso_venue_phone
1136 1136
 	 *
@@ -1138,18 +1138,18 @@  discard block
 block discarded – undo
1138 1138
 	 * @param bool $echo
1139 1139
 	 * @return string
1140 1140
 	 */
1141
-	function espresso_venue_phone( $VNU_ID = 0, $echo = TRUE ) {
1142
-		if ( $echo ) {
1143
-			echo EEH_Venue_View::venue_phone( $VNU_ID );
1141
+	function espresso_venue_phone($VNU_ID = 0, $echo = TRUE) {
1142
+		if ($echo) {
1143
+			echo EEH_Venue_View::venue_phone($VNU_ID);
1144 1144
 			return '';
1145 1145
 		}
1146
-		return EEH_Venue_View::venue_phone( $VNU_ID );
1146
+		return EEH_Venue_View::venue_phone($VNU_ID);
1147 1147
 	}
1148 1148
 }
1149 1149
 
1150 1150
 
1151 1151
 
1152
-if ( ! function_exists( 'espresso_venue_website' )) {
1152
+if ( ! function_exists('espresso_venue_website')) {
1153 1153
 	/**
1154 1154
 	 * espresso_venue_website
1155 1155
 	 *
@@ -1157,18 +1157,18 @@  discard block
 block discarded – undo
1157 1157
 	 * @param bool $echo
1158 1158
 	 * @return string
1159 1159
 	 */
1160
-	function espresso_venue_website( $VNU_ID = 0, $echo = TRUE ) {
1161
-		if ( $echo ) {
1162
-			echo EEH_Venue_View::venue_website_link( $VNU_ID );
1160
+	function espresso_venue_website($VNU_ID = 0, $echo = TRUE) {
1161
+		if ($echo) {
1162
+			echo EEH_Venue_View::venue_website_link($VNU_ID);
1163 1163
 			return '';
1164 1164
 		}
1165
-		return EEH_Venue_View::venue_website_link( $VNU_ID );
1165
+		return EEH_Venue_View::venue_website_link($VNU_ID);
1166 1166
 	}
1167 1167
 }
1168 1168
 
1169 1169
 
1170 1170
 
1171
-if ( ! function_exists( 'espresso_edit_venue_link' )) {
1171
+if ( ! function_exists('espresso_edit_venue_link')) {
1172 1172
 	/**
1173 1173
 	 * espresso_edit_venue_link
1174 1174
 	 *
@@ -1176,12 +1176,12 @@  discard block
 block discarded – undo
1176 1176
 	 * @param bool $echo
1177 1177
 	 * @return string
1178 1178
 	 */
1179
-	function espresso_edit_venue_link( $VNU_ID = 0, $echo = TRUE ) {
1180
-		if($echo){
1181
-			echo EEH_Venue_View::edit_venue_link( $VNU_ID );
1179
+	function espresso_edit_venue_link($VNU_ID = 0, $echo = TRUE) {
1180
+		if ($echo) {
1181
+			echo EEH_Venue_View::edit_venue_link($VNU_ID);
1182 1182
 			return '';
1183 1183
 		}
1184
-		return EEH_Venue_View::edit_venue_link( $VNU_ID );
1184
+		return EEH_Venue_View::edit_venue_link($VNU_ID);
1185 1185
 	}
1186 1186
 }
1187 1187
 
Please login to merge, or discard this patch.
core/helpers/EEH_Event_View.helper.php 1 patch
Indentation   +569 added lines, -569 removed lines patch added patch discarded remove patch
@@ -11,578 +11,578 @@
 block discarded – undo
11 11
 class EEH_Event_View extends EEH_Base
12 12
 {
13 13
 
14
-    /**
15
-     * @var EE_Event $_event
16
-     */
17
-    private static $_event = null;
18
-
19
-
20
-
21
-    /**
22
-     * get_event
23
-     * attempts to retrieve an EE_Event object any way it can
24
-     *
25
-     * @param int|WP_Post $EVT_ID
26
-     * @return EE_Event|null
27
-     * @throws \EE_Error
28
-     */
29
-    public static function get_event($EVT_ID = 0)
30
-    {
31
-        // international newspaper?
32
-        global $post;
33
-        $EVT_ID = $EVT_ID instanceof WP_Post && $EVT_ID->post_type === 'espresso_events'
34
-            ? $EVT_ID->ID
35
-            : absint($EVT_ID);
36
-        // do we already have the Event  you are looking for?
37
-        if (EEH_Event_View::$_event instanceof EE_Event && $EVT_ID && EEH_Event_View::$_event->ID() === $EVT_ID) {
38
-            return EEH_Event_View::$_event;
39
-        }
40
-        // reset property so that the new event is cached.
41
-        EEH_Event_View::$_event = null;
42
-        if (! $EVT_ID && $post instanceof EE_Event) {
43
-            EEH_Event_View::$_event = $post;
44
-            return EEH_Event_View::$_event;
45
-        }
46
-        // if the post type is for an event and it has a cached event and we don't have a different incoming $EVT_ID
47
-        // then let's just use that cached event on the $post object.
48
-        if ($post instanceof WP_Post
49
-            && $post->post_type === 'espresso_events'
50
-            && isset($post->EE_Event)
51
-            && (
52
-                $EVT_ID === 0
53
-                || $EVT_ID === $post->ID
54
-            )
55
-        ) {
56
-            EEH_Event_View::$_event = $post->EE_Event;
57
-            return EEH_Event_View::$_event;
58
-        }
59
-        // If the event we have isn't an event but we do have an EVT_ID, let's try getting the event using the ID.
60
-        if (! EEH_Event_View::$_event instanceof EE_Event && $EVT_ID) {
61
-            EEH_Event_View::$_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
62
-        }
63
-        return EEH_Event_View::$_event;
64
-    }
65
-
66
-
67
-
68
-    /**
69
-     *    display_ticket_selector
70
-     *
71
-     * @access    public
72
-     * @param    int $EVT_ID
73
-     * @return    boolean
74
-     */
75
-    public static function display_ticket_selector($EVT_ID = 0)
76
-    {
77
-        $event = EEH_Event_View::get_event($EVT_ID);
78
-        return $event instanceof EE_Event ? $event->display_ticket_selector() : false;
79
-    }
80
-
81
-
82
-
83
-    /**
84
-     *    event_status
85
-     *
86
-     * @access    public
87
-     * @param    int $EVT_ID
88
-     * @return    string
89
-     */
90
-    public static function event_status($EVT_ID = 0)
91
-    {
92
-        $event = EEH_Event_View::get_event($EVT_ID);
93
-        return $event instanceof EE_Event ? $event->pretty_active_status(false) : '';
94
-    }
95
-
96
-
97
-
98
-    /**
99
-     *  event_active_status
100
-     *
101
-     *  @access     public
102
-     * @param    int $EVT_ID
103
-     *  @return     string
104
-     */
105
-    public static function event_active_status($EVT_ID = 0, $echo = true)
106
-    {
107
-        $event = EEH_Event_View::get_event($EVT_ID);
108
-        return $event instanceof EE_Event ? $event->pretty_active_status($echo) : 'inactive';
109
-    }
110
-
111
-
112
-
113
-    /**
114
-     *  event_has_content_or_excerpt
115
-     *
116
-     *  @access     public
117
-     * @param    int $EVT_ID
118
-     *  @return     string
119
-     */
120
-    public static function event_has_content_or_excerpt($EVT_ID = 0)
121
-    {
122
-        $event = EEH_Event_View::get_event($EVT_ID);
123
-        $has_content_or_excerpt = false;
124
-        if ($event instanceof EE_Event) {
125
-            $has_content_or_excerpt = $event->description() != '' || $event->short_description(null, null, true) != '' ? true : false;
126
-        }
127
-        if (is_archive() && ! ( espresso_display_full_description_in_event_list() || espresso_display_excerpt_in_event_list() )) {
128
-            $has_content_or_excerpt = false;
129
-        }
130
-        return $has_content_or_excerpt;
131
-    }
132
-
133
-
134
-
135
-    /**
136
-     *    event_active_status
137
-     *
138
-     * @access    public
139
-     * @param null $num_words
140
-     * @param null $more
141
-     * @return    string
142
-     */
143
-    public static function event_content_or_excerpt($num_words = null, $more = null)
144
-    {
145
-        global $post;
146
-        ob_start();
147
-        if (( is_single() ) || ( is_archive() && espresso_display_full_description_in_event_list() )) {
148
-            // admin has chosen "full description"
149
-            // for the "Event Espresso - Events > Templates > Display Description" option
150
-            the_content();
151
-        } elseif (( is_archive() && espresso_display_excerpt_in_event_list() )) {
152
-            if (has_excerpt($post->ID)) {
153
-                // admin has chosen "excerpt (short desc)"
154
-                // for the "Event Espresso - Events > Templates > Display Description" option
155
-                // AND an excerpt actually exists
156
-                the_excerpt();
157
-            } else {
158
-                // admin has chosen "excerpt (short desc)"
159
-                // for the "Event Espresso - Events > Templates > Display Description" option
160
-                // but NO excerpt actually exists, so we need to create one
161
-                if (! empty($num_words)) {
162
-                    if (empty($more)) {
163
-                        $more_link_text = __('(more&hellip;)', 'event_espresso');
164
-                        $more = ' <a href="' . get_permalink() . '"';
165
-                        $more .= ' class="more-link"';
166
-                        $more .= \EED_Events_Archive::link_target();
167
-                        $more .= '>' . $more_link_text . '</a>';
168
-                        $more = apply_filters('the_content_more_link', $more, $more_link_text);
169
-                    }
170
-                    $content = str_replace('NOMORELINK', '', get_the_content('NOMORELINK'));
171
-
172
-                    $content =  wp_trim_words($content, $num_words, ' ') . $more;
173
-                } else {
174
-                    $content =  get_the_content();
175
-                }
176
-                global $allowedtags;
177
-                // make sure links are allowed
178
-                $allowedtags['a'] = isset($allowedtags['a'])
179
-                    ? $allowedtags['a']
180
-                    : array();
181
-                // as well as target attribute
182
-                $allowedtags['a']['target'] = isset($allowedtags['a']['target'])
183
-                    ? $allowedtags['a']['target']
184
-                    : false;
185
-                // but get previous value so we can reset it
186
-                $prev_value = $allowedtags['a']['target'];
187
-                $allowedtags['a']['target'] = true;
188
-                $content = wp_kses($content, $allowedtags);
189
-                $content = strip_shortcodes($content);
190
-                echo apply_filters('the_content', $content);
191
-                $allowedtags['a']['target'] = $prev_value;
192
-            }
193
-        } else {
194
-            // admin has chosen "none"
195
-            // for the "Event Espresso - Events > Templates > Display Description" option
196
-            echo apply_filters('the_content', '');
197
-        }
198
-        return ob_get_clean();
199
-    }
200
-
201
-
202
-
203
-    /**
204
-     *  event_tickets_available
205
-     *
206
-     *  @access     public
207
-     * @param    int $EVT_ID
208
-     *  @return     EE_Ticket[]
209
-     */
210
-    public static function event_tickets_available($EVT_ID = 0)
211
-    {
212
-        $event = EEH_Event_View::get_event($EVT_ID);
213
-        $tickets_available_for_purchase = array();
214
-        if ($event instanceof EE_Event) {
215
-            $datetimes = EEH_Event_View::get_all_date_obj($EVT_ID, false);
216
-            foreach ($datetimes as $datetime) {
217
-                $tickets_available_for_purchase = array_merge($tickets_available_for_purchase, $datetime->ticket_types_available_for_purchase());
218
-            }
219
-        }
220
-        return $tickets_available_for_purchase;
221
-    }
222
-
223
-
224
-
225
-    /**
226
-     *    the_event_date
227
-     *
228
-     * @access    public
229
-     * @param    int $EVT_ID
230
-     * @param     bool   $hide_uncategorized
231
-     * @return    string
232
-     */
233
-    public static function event_categories($EVT_ID = 0, $hide_uncategorized = true)
234
-    {
235
-        $category_links = array();
236
-        $event = EEH_Event_View::get_event($EVT_ID);
237
-        if ($event instanceof EE_Event) {
238
-            $event_categories = get_the_terms($event->ID(), 'espresso_event_categories');
239
-            if ($event_categories) {
240
-                // loop thru terms and create links
241
-                foreach ($event_categories as $term) {
242
-                    $url = get_term_link($term, 'espresso_venue_categories');
243
-                    if (! is_wp_error($url) && (( $hide_uncategorized && strtolower($term->name) != __('uncategorized', 'event_espresso')) || ! $hide_uncategorized )) {
244
-                        $category_links[] = '<a href="' . esc_url($url)
245
-                                            . '" rel="tag"'
246
-                                            . \EED_Events_Archive::link_target()
247
-                                            .'>'
248
-                                            . $term->name
249
-                                            . '</a>';
250
-                    }
251
-                }
252
-            }
253
-        }
254
-        return implode(', ', $category_links);
255
-    }
256
-
257
-
258
-
259
-    /**
260
-     *    the_event_date - first date by date order
261
-     *
262
-     * @access    public
263
-     * @param string $dt_frmt
264
-     * @param string $tm_frmt
265
-     * @param int    $EVT_ID
266
-     * @return    string
267
-     */
268
-    public static function the_event_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
269
-    {
270
-        $datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
271
-        $format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
272
-        return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_start', $format) :  '';
273
-    }
274
-
275
-
276
-
277
-    /**
278
-     *    the_event_end_date - last date by date order
279
-     *
280
-     * @access    public
281
-     * @param string $dt_frmt
282
-     * @param string $tm_frmt
283
-     * @param int    $EVT_ID
284
-     * @return    string
285
-     */
286
-    public static function the_event_end_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
287
-    {
288
-        $datetime = EEH_Event_View::get_last_date_obj($EVT_ID);
289
-        $format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
290
-        return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
291
-    }
292
-
293
-
294
-
295
-    /**
296
-     *    the_earliest_event_date - first date chronologically
297
-     *
298
-     * @access    public
299
-     * @param string $dt_frmt
300
-     * @param string $tm_frmt
301
-     * @param int    $EVT_ID
302
-     * @return    string
303
-     */
304
-    public static function the_earliest_event_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
305
-    {
306
-        $datetime = EEH_Event_View::get_earliest_date_obj($EVT_ID);
307
-        $format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
308
-        return $datetime instanceof EE_Datetime ?  $datetime->get_i18n_datetime('DTT_EVT_start', $format) : '';
309
-    }
310
-
311
-
312
-
313
-    /**
314
-     *    the_latest_event_date - latest date chronologically
315
-     *
316
-     * @access    public
317
-     * @param string $dt_frmt
318
-     * @param string $tm_frmt
319
-     * @param int    $EVT_ID
320
-     * @return    string
321
-     */
322
-    public static function the_latest_event_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
323
-    {
324
-        $datetime = EEH_Event_View::get_latest_date_obj($EVT_ID);
325
-        $format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
326
-        return $datetime instanceof EE_Datetime ?  $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
327
-    }
328
-
329
-
330
-
331
-    /**
332
-     *    event_date_as_calendar_page
333
-     *
334
-     * @access    public
335
-     * @param int $EVT_ID
336
-     * @return    string
337
-     */
338
-    public static function event_date_as_calendar_page($EVT_ID = 0)
339
-    {
340
-        $datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
341
-        if ($datetime instanceof EE_Datetime) {
342
-    ?>
14
+	/**
15
+	 * @var EE_Event $_event
16
+	 */
17
+	private static $_event = null;
18
+
19
+
20
+
21
+	/**
22
+	 * get_event
23
+	 * attempts to retrieve an EE_Event object any way it can
24
+	 *
25
+	 * @param int|WP_Post $EVT_ID
26
+	 * @return EE_Event|null
27
+	 * @throws \EE_Error
28
+	 */
29
+	public static function get_event($EVT_ID = 0)
30
+	{
31
+		// international newspaper?
32
+		global $post;
33
+		$EVT_ID = $EVT_ID instanceof WP_Post && $EVT_ID->post_type === 'espresso_events'
34
+			? $EVT_ID->ID
35
+			: absint($EVT_ID);
36
+		// do we already have the Event  you are looking for?
37
+		if (EEH_Event_View::$_event instanceof EE_Event && $EVT_ID && EEH_Event_View::$_event->ID() === $EVT_ID) {
38
+			return EEH_Event_View::$_event;
39
+		}
40
+		// reset property so that the new event is cached.
41
+		EEH_Event_View::$_event = null;
42
+		if (! $EVT_ID && $post instanceof EE_Event) {
43
+			EEH_Event_View::$_event = $post;
44
+			return EEH_Event_View::$_event;
45
+		}
46
+		// if the post type is for an event and it has a cached event and we don't have a different incoming $EVT_ID
47
+		// then let's just use that cached event on the $post object.
48
+		if ($post instanceof WP_Post
49
+			&& $post->post_type === 'espresso_events'
50
+			&& isset($post->EE_Event)
51
+			&& (
52
+				$EVT_ID === 0
53
+				|| $EVT_ID === $post->ID
54
+			)
55
+		) {
56
+			EEH_Event_View::$_event = $post->EE_Event;
57
+			return EEH_Event_View::$_event;
58
+		}
59
+		// If the event we have isn't an event but we do have an EVT_ID, let's try getting the event using the ID.
60
+		if (! EEH_Event_View::$_event instanceof EE_Event && $EVT_ID) {
61
+			EEH_Event_View::$_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
62
+		}
63
+		return EEH_Event_View::$_event;
64
+	}
65
+
66
+
67
+
68
+	/**
69
+	 *    display_ticket_selector
70
+	 *
71
+	 * @access    public
72
+	 * @param    int $EVT_ID
73
+	 * @return    boolean
74
+	 */
75
+	public static function display_ticket_selector($EVT_ID = 0)
76
+	{
77
+		$event = EEH_Event_View::get_event($EVT_ID);
78
+		return $event instanceof EE_Event ? $event->display_ticket_selector() : false;
79
+	}
80
+
81
+
82
+
83
+	/**
84
+	 *    event_status
85
+	 *
86
+	 * @access    public
87
+	 * @param    int $EVT_ID
88
+	 * @return    string
89
+	 */
90
+	public static function event_status($EVT_ID = 0)
91
+	{
92
+		$event = EEH_Event_View::get_event($EVT_ID);
93
+		return $event instanceof EE_Event ? $event->pretty_active_status(false) : '';
94
+	}
95
+
96
+
97
+
98
+	/**
99
+	 *  event_active_status
100
+	 *
101
+	 *  @access     public
102
+	 * @param    int $EVT_ID
103
+	 *  @return     string
104
+	 */
105
+	public static function event_active_status($EVT_ID = 0, $echo = true)
106
+	{
107
+		$event = EEH_Event_View::get_event($EVT_ID);
108
+		return $event instanceof EE_Event ? $event->pretty_active_status($echo) : 'inactive';
109
+	}
110
+
111
+
112
+
113
+	/**
114
+	 *  event_has_content_or_excerpt
115
+	 *
116
+	 *  @access     public
117
+	 * @param    int $EVT_ID
118
+	 *  @return     string
119
+	 */
120
+	public static function event_has_content_or_excerpt($EVT_ID = 0)
121
+	{
122
+		$event = EEH_Event_View::get_event($EVT_ID);
123
+		$has_content_or_excerpt = false;
124
+		if ($event instanceof EE_Event) {
125
+			$has_content_or_excerpt = $event->description() != '' || $event->short_description(null, null, true) != '' ? true : false;
126
+		}
127
+		if (is_archive() && ! ( espresso_display_full_description_in_event_list() || espresso_display_excerpt_in_event_list() )) {
128
+			$has_content_or_excerpt = false;
129
+		}
130
+		return $has_content_or_excerpt;
131
+	}
132
+
133
+
134
+
135
+	/**
136
+	 *    event_active_status
137
+	 *
138
+	 * @access    public
139
+	 * @param null $num_words
140
+	 * @param null $more
141
+	 * @return    string
142
+	 */
143
+	public static function event_content_or_excerpt($num_words = null, $more = null)
144
+	{
145
+		global $post;
146
+		ob_start();
147
+		if (( is_single() ) || ( is_archive() && espresso_display_full_description_in_event_list() )) {
148
+			// admin has chosen "full description"
149
+			// for the "Event Espresso - Events > Templates > Display Description" option
150
+			the_content();
151
+		} elseif (( is_archive() && espresso_display_excerpt_in_event_list() )) {
152
+			if (has_excerpt($post->ID)) {
153
+				// admin has chosen "excerpt (short desc)"
154
+				// for the "Event Espresso - Events > Templates > Display Description" option
155
+				// AND an excerpt actually exists
156
+				the_excerpt();
157
+			} else {
158
+				// admin has chosen "excerpt (short desc)"
159
+				// for the "Event Espresso - Events > Templates > Display Description" option
160
+				// but NO excerpt actually exists, so we need to create one
161
+				if (! empty($num_words)) {
162
+					if (empty($more)) {
163
+						$more_link_text = __('(more&hellip;)', 'event_espresso');
164
+						$more = ' <a href="' . get_permalink() . '"';
165
+						$more .= ' class="more-link"';
166
+						$more .= \EED_Events_Archive::link_target();
167
+						$more .= '>' . $more_link_text . '</a>';
168
+						$more = apply_filters('the_content_more_link', $more, $more_link_text);
169
+					}
170
+					$content = str_replace('NOMORELINK', '', get_the_content('NOMORELINK'));
171
+
172
+					$content =  wp_trim_words($content, $num_words, ' ') . $more;
173
+				} else {
174
+					$content =  get_the_content();
175
+				}
176
+				global $allowedtags;
177
+				// make sure links are allowed
178
+				$allowedtags['a'] = isset($allowedtags['a'])
179
+					? $allowedtags['a']
180
+					: array();
181
+				// as well as target attribute
182
+				$allowedtags['a']['target'] = isset($allowedtags['a']['target'])
183
+					? $allowedtags['a']['target']
184
+					: false;
185
+				// but get previous value so we can reset it
186
+				$prev_value = $allowedtags['a']['target'];
187
+				$allowedtags['a']['target'] = true;
188
+				$content = wp_kses($content, $allowedtags);
189
+				$content = strip_shortcodes($content);
190
+				echo apply_filters('the_content', $content);
191
+				$allowedtags['a']['target'] = $prev_value;
192
+			}
193
+		} else {
194
+			// admin has chosen "none"
195
+			// for the "Event Espresso - Events > Templates > Display Description" option
196
+			echo apply_filters('the_content', '');
197
+		}
198
+		return ob_get_clean();
199
+	}
200
+
201
+
202
+
203
+	/**
204
+	 *  event_tickets_available
205
+	 *
206
+	 *  @access     public
207
+	 * @param    int $EVT_ID
208
+	 *  @return     EE_Ticket[]
209
+	 */
210
+	public static function event_tickets_available($EVT_ID = 0)
211
+	{
212
+		$event = EEH_Event_View::get_event($EVT_ID);
213
+		$tickets_available_for_purchase = array();
214
+		if ($event instanceof EE_Event) {
215
+			$datetimes = EEH_Event_View::get_all_date_obj($EVT_ID, false);
216
+			foreach ($datetimes as $datetime) {
217
+				$tickets_available_for_purchase = array_merge($tickets_available_for_purchase, $datetime->ticket_types_available_for_purchase());
218
+			}
219
+		}
220
+		return $tickets_available_for_purchase;
221
+	}
222
+
223
+
224
+
225
+	/**
226
+	 *    the_event_date
227
+	 *
228
+	 * @access    public
229
+	 * @param    int $EVT_ID
230
+	 * @param     bool   $hide_uncategorized
231
+	 * @return    string
232
+	 */
233
+	public static function event_categories($EVT_ID = 0, $hide_uncategorized = true)
234
+	{
235
+		$category_links = array();
236
+		$event = EEH_Event_View::get_event($EVT_ID);
237
+		if ($event instanceof EE_Event) {
238
+			$event_categories = get_the_terms($event->ID(), 'espresso_event_categories');
239
+			if ($event_categories) {
240
+				// loop thru terms and create links
241
+				foreach ($event_categories as $term) {
242
+					$url = get_term_link($term, 'espresso_venue_categories');
243
+					if (! is_wp_error($url) && (( $hide_uncategorized && strtolower($term->name) != __('uncategorized', 'event_espresso')) || ! $hide_uncategorized )) {
244
+						$category_links[] = '<a href="' . esc_url($url)
245
+											. '" rel="tag"'
246
+											. \EED_Events_Archive::link_target()
247
+											.'>'
248
+											. $term->name
249
+											. '</a>';
250
+					}
251
+				}
252
+			}
253
+		}
254
+		return implode(', ', $category_links);
255
+	}
256
+
257
+
258
+
259
+	/**
260
+	 *    the_event_date - first date by date order
261
+	 *
262
+	 * @access    public
263
+	 * @param string $dt_frmt
264
+	 * @param string $tm_frmt
265
+	 * @param int    $EVT_ID
266
+	 * @return    string
267
+	 */
268
+	public static function the_event_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
269
+	{
270
+		$datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
271
+		$format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
272
+		return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_start', $format) :  '';
273
+	}
274
+
275
+
276
+
277
+	/**
278
+	 *    the_event_end_date - last date by date order
279
+	 *
280
+	 * @access    public
281
+	 * @param string $dt_frmt
282
+	 * @param string $tm_frmt
283
+	 * @param int    $EVT_ID
284
+	 * @return    string
285
+	 */
286
+	public static function the_event_end_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
287
+	{
288
+		$datetime = EEH_Event_View::get_last_date_obj($EVT_ID);
289
+		$format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
290
+		return $datetime instanceof EE_Datetime ? $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
291
+	}
292
+
293
+
294
+
295
+	/**
296
+	 *    the_earliest_event_date - first date chronologically
297
+	 *
298
+	 * @access    public
299
+	 * @param string $dt_frmt
300
+	 * @param string $tm_frmt
301
+	 * @param int    $EVT_ID
302
+	 * @return    string
303
+	 */
304
+	public static function the_earliest_event_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
305
+	{
306
+		$datetime = EEH_Event_View::get_earliest_date_obj($EVT_ID);
307
+		$format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
308
+		return $datetime instanceof EE_Datetime ?  $datetime->get_i18n_datetime('DTT_EVT_start', $format) : '';
309
+	}
310
+
311
+
312
+
313
+	/**
314
+	 *    the_latest_event_date - latest date chronologically
315
+	 *
316
+	 * @access    public
317
+	 * @param string $dt_frmt
318
+	 * @param string $tm_frmt
319
+	 * @param int    $EVT_ID
320
+	 * @return    string
321
+	 */
322
+	public static function the_latest_event_date($dt_frmt = 'D M jS', $tm_frmt = 'g:i a', $EVT_ID = 0)
323
+	{
324
+		$datetime = EEH_Event_View::get_latest_date_obj($EVT_ID);
325
+		$format = ! empty($dt_frmt) && ! empty($tm_frmt) ? $dt_frmt . ' ' . $tm_frmt : $dt_frmt . $tm_frmt;
326
+		return $datetime instanceof EE_Datetime ?  $datetime->get_i18n_datetime('DTT_EVT_end', $format) : '';
327
+	}
328
+
329
+
330
+
331
+	/**
332
+	 *    event_date_as_calendar_page
333
+	 *
334
+	 * @access    public
335
+	 * @param int $EVT_ID
336
+	 * @return    string
337
+	 */
338
+	public static function event_date_as_calendar_page($EVT_ID = 0)
339
+	{
340
+		$datetime = EEH_Event_View::get_primary_date_obj($EVT_ID);
341
+		if ($datetime instanceof EE_Datetime) {
342
+	?>
343 343
         <div class="event-date-calendar-page-dv">
344 344
             <div class="event-date-calendar-page-month-dv"><?php echo $datetime->get_i18n_datetime('DTT_EVT_start', 'M');?></div>
345 345
             <div class="event-date-calendar-page-day-dv"><?php echo $datetime->start_date('d');?></div>
346 346
         </div>
347 347
     <?php
348
-        }
349
-    }
350
-
351
-
352
-
353
-    /**
354
-     *    get_primary_date_obj - orders date by DTT_order
355
-     *
356
-     * @access    public
357
-     * @param int $EVT_ID
358
-     * @return    string
359
-     */
360
-    public static function get_primary_date_obj($EVT_ID = 0)
361
-    {
362
-        $event = EEH_Event_View::get_event($EVT_ID);
363
-        if ($event instanceof EE_Event) {
364
-            $datetimes = $event->get_many_related(
365
-                'Datetime',
366
-                array(
367
-                    'limit' => 1,
368
-                    'order_by' => array( 'DTT_order' => 'ASC' )
369
-                )
370
-            );
371
-            return reset($datetimes);
372
-        } else {
373
-             return false;
374
-        }
375
-    }
376
-
377
-
378
-
379
-    /**
380
-     *    get_last_date_obj - orders date by DTT_order
381
-     *
382
-     * @access    public
383
-     * @param int $EVT_ID
384
-     * @return    string
385
-     */
386
-    public static function get_last_date_obj($EVT_ID = 0)
387
-    {
388
-        $event = EEH_Event_View::get_event($EVT_ID);
389
-        if ($event instanceof EE_Event) {
390
-            $datetimes = $event->get_many_related(
391
-                'Datetime',
392
-                array(
393
-                    'limit' => 1,
394
-                    'order_by' => array( 'DTT_order' => 'DESC' )
395
-                )
396
-            );
397
-            return end($datetimes);
398
-        } else {
399
-            return false;
400
-        }
401
-    }
402
-
403
-
404
-
405
-    /**
406
-     *    get_earliest_date_obj - orders date chronologically
407
-     *
408
-     * @access    public
409
-     * @param int $EVT_ID
410
-     * @return    string
411
-     */
412
-    public static function get_earliest_date_obj($EVT_ID = 0)
413
-    {
414
-        $event = EEH_Event_View::get_event($EVT_ID);
415
-        if ($event instanceof EE_Event) {
416
-            $datetimes = $event->get_many_related(
417
-                'Datetime',
418
-                array(
419
-                    'limit' => 1,
420
-                    'order_by' => array( 'DTT_EVT_start' => 'ASC' )
421
-                )
422
-            );
423
-            return reset($datetimes);
424
-        } else {
425
-             return false;
426
-        }
427
-    }
428
-
429
-
430
-
431
-    /**
432
-     *    get_latest_date_obj - orders date chronologically
433
-     *
434
-     * @access    public
435
-     * @param int $EVT_ID
436
-     * @return    string
437
-     */
438
-    public static function get_latest_date_obj($EVT_ID = 0)
439
-    {
440
-        $event = EEH_Event_View::get_event($EVT_ID);
441
-        if ($event instanceof EE_Event) {
442
-            $datetimes = $event->get_many_related(
443
-                'Datetime',
444
-                array(
445
-                    'limit' => 1,
446
-                    'order_by' => array( 'DTT_EVT_start' => 'DESC' )
447
-                )
448
-            );
449
-            return end($datetimes);
450
-        } else {
451
-            return false;
452
-        }
453
-    }
454
-
455
-    /**
456
-     *    get_next_upcoming_date_obj - return the next upcoming datetime
457
-     *
458
-     * @access    public
459
-     * @param int $EVT_ID
460
-     * @return    EE_Datetime|null
461
-     */
462
-    public static function get_next_upcoming_date_obj($EVT_ID = 0)
463
-    {
464
-        $datetime = EEM_Datetime::instance()->get_one(
465
-            array(
466
-                array(
467
-                    'Event.EVT_ID' => $EVT_ID,
468
-                    'DTT_EVT_start' => array('>=', current_time('mysql', true))
469
-                ),
470
-                'order_by' => array('DTT_EVT_start' => 'asc')
471
-            )
472
-        );
473
-        return $datetime instanceof EE_Datetime ? $datetime : null;
474
-    }
475
-
476
-    /**
477
-     *    get_all_date_obj
478
-     *
479
-     * @access    public
480
-     * @param int $EVT_ID
481
-     * @param null $include_expired
482
-     * @param bool $include_deleted
483
-     * @param null $limit
484
-     * @return EE_Datetime[]
485
-     */
486
-    public static function get_all_date_obj($EVT_ID = 0, $include_expired = null, $include_deleted = false, $limit = null)
487
-    {
488
-        $event = EEH_Event_View::get_event($EVT_ID);
489
-        if ($include_expired === null) {
490
-            if ($event instanceof EE_Event && $event->is_expired()) {
491
-                $include_expired = true;
492
-            } else {
493
-                $include_expired = false;
494
-            }
495
-        }
496
-
497
-        if ($event instanceof EE_Event) {
498
-            return $event->datetimes_ordered($include_expired, $include_deleted, $limit);
499
-        } else {
500
-             return array();
501
-        }
502
-    }
503
-
504
-
505
-
506
-    /**
507
-     *    event_link_url
508
-     *
509
-     * @access    public
510
-     * @param int $EVT_ID
511
-     * @return    string
512
-     */
513
-    public static function event_link_url($EVT_ID = 0)
514
-    {
515
-        $event = EEH_Event_View::get_event($EVT_ID);
516
-        if ($event instanceof EE_Event) {
517
-            $url = $event->external_url() !== null && $event->external_url() !== '' ? $event->external_url() : get_permalink($event->ID());
518
-            return preg_match("~^(?:f|ht)tps?://~i", $url) ? $url : 'http://' . $url;
519
-        }
520
-        return null;
521
-    }
522
-
523
-
524
-
525
-    /**
526
-     *    event_phone
527
-     *
528
-     * @access    public
529
-     * @param int $EVT_ID
530
-     * @return    string
531
-     */
532
-    public static function event_phone($EVT_ID = 0)
533
-    {
534
-        $event = EEH_Event_View::get_event($EVT_ID);
535
-        if ($event instanceof EE_Event) {
536
-            return EEH_Schema::telephone($event->phone());
537
-        }
538
-        return null;
539
-    }
540
-
541
-
542
-
543
-    /**
544
-     *    edit_event_link
545
-     *
546
-     * @access    public
547
-     * @param int    $EVT_ID
548
-     * @param string $link
549
-     * @param string $before
550
-     * @param string $after
551
-     * @return    string
552
-     */
553
-    public static function edit_event_link($EVT_ID = 0, $link = '', $before = '', $after = '')
554
-    {
555
-        $event = EEH_Event_View::get_event($EVT_ID);
556
-        if ($event instanceof EE_Event) {
557
-            // can the user edit this post ?
558
-            if (current_user_can('edit_post', $event->ID())) {
559
-                // set link text
560
-                $link_text = ! empty($link) ? $link : __('edit this event', 'event_espresso');
561
-                // generate nonce
562
-                $nonce = wp_create_nonce('edit_nonce');
563
-                // generate url to event editor for this event
564
-                $url = add_query_arg(array( 'page' => 'espresso_events', 'action' => 'edit', 'post' => $event->ID(), 'edit_nonce' => $nonce ), admin_url());
565
-                // get edit CPT text
566
-                $post_type_obj = get_post_type_object('espresso_events');
567
-                // build final link html
568
-                $link = '<a class="post-edit-link" href="' . $url . '" ';
569
-                $link .= ' title="' . esc_attr($post_type_obj->labels->edit_item) . '"';
570
-                $link .= \EED_Events_Archive::link_target();
571
-                $link .='>' . $link_text . '</a>';
572
-                // put it all together
573
-                return $before . apply_filters('edit_post_link', $link, $event->ID()) . $after;
574
-            }
575
-        }
576
-        return '';
577
-    }
578
-
579
-
580
-
581
-    /**
582
-     * @return string
583
-     */
584
-    public static function event_archive_url()
585
-    {
586
-        return get_post_type_archive_link('espresso_events');
587
-    }
348
+		}
349
+	}
350
+
351
+
352
+
353
+	/**
354
+	 *    get_primary_date_obj - orders date by DTT_order
355
+	 *
356
+	 * @access    public
357
+	 * @param int $EVT_ID
358
+	 * @return    string
359
+	 */
360
+	public static function get_primary_date_obj($EVT_ID = 0)
361
+	{
362
+		$event = EEH_Event_View::get_event($EVT_ID);
363
+		if ($event instanceof EE_Event) {
364
+			$datetimes = $event->get_many_related(
365
+				'Datetime',
366
+				array(
367
+					'limit' => 1,
368
+					'order_by' => array( 'DTT_order' => 'ASC' )
369
+				)
370
+			);
371
+			return reset($datetimes);
372
+		} else {
373
+			 return false;
374
+		}
375
+	}
376
+
377
+
378
+
379
+	/**
380
+	 *    get_last_date_obj - orders date by DTT_order
381
+	 *
382
+	 * @access    public
383
+	 * @param int $EVT_ID
384
+	 * @return    string
385
+	 */
386
+	public static function get_last_date_obj($EVT_ID = 0)
387
+	{
388
+		$event = EEH_Event_View::get_event($EVT_ID);
389
+		if ($event instanceof EE_Event) {
390
+			$datetimes = $event->get_many_related(
391
+				'Datetime',
392
+				array(
393
+					'limit' => 1,
394
+					'order_by' => array( 'DTT_order' => 'DESC' )
395
+				)
396
+			);
397
+			return end($datetimes);
398
+		} else {
399
+			return false;
400
+		}
401
+	}
402
+
403
+
404
+
405
+	/**
406
+	 *    get_earliest_date_obj - orders date chronologically
407
+	 *
408
+	 * @access    public
409
+	 * @param int $EVT_ID
410
+	 * @return    string
411
+	 */
412
+	public static function get_earliest_date_obj($EVT_ID = 0)
413
+	{
414
+		$event = EEH_Event_View::get_event($EVT_ID);
415
+		if ($event instanceof EE_Event) {
416
+			$datetimes = $event->get_many_related(
417
+				'Datetime',
418
+				array(
419
+					'limit' => 1,
420
+					'order_by' => array( 'DTT_EVT_start' => 'ASC' )
421
+				)
422
+			);
423
+			return reset($datetimes);
424
+		} else {
425
+			 return false;
426
+		}
427
+	}
428
+
429
+
430
+
431
+	/**
432
+	 *    get_latest_date_obj - orders date chronologically
433
+	 *
434
+	 * @access    public
435
+	 * @param int $EVT_ID
436
+	 * @return    string
437
+	 */
438
+	public static function get_latest_date_obj($EVT_ID = 0)
439
+	{
440
+		$event = EEH_Event_View::get_event($EVT_ID);
441
+		if ($event instanceof EE_Event) {
442
+			$datetimes = $event->get_many_related(
443
+				'Datetime',
444
+				array(
445
+					'limit' => 1,
446
+					'order_by' => array( 'DTT_EVT_start' => 'DESC' )
447
+				)
448
+			);
449
+			return end($datetimes);
450
+		} else {
451
+			return false;
452
+		}
453
+	}
454
+
455
+	/**
456
+	 *    get_next_upcoming_date_obj - return the next upcoming datetime
457
+	 *
458
+	 * @access    public
459
+	 * @param int $EVT_ID
460
+	 * @return    EE_Datetime|null
461
+	 */
462
+	public static function get_next_upcoming_date_obj($EVT_ID = 0)
463
+	{
464
+		$datetime = EEM_Datetime::instance()->get_one(
465
+			array(
466
+				array(
467
+					'Event.EVT_ID' => $EVT_ID,
468
+					'DTT_EVT_start' => array('>=', current_time('mysql', true))
469
+				),
470
+				'order_by' => array('DTT_EVT_start' => 'asc')
471
+			)
472
+		);
473
+		return $datetime instanceof EE_Datetime ? $datetime : null;
474
+	}
475
+
476
+	/**
477
+	 *    get_all_date_obj
478
+	 *
479
+	 * @access    public
480
+	 * @param int $EVT_ID
481
+	 * @param null $include_expired
482
+	 * @param bool $include_deleted
483
+	 * @param null $limit
484
+	 * @return EE_Datetime[]
485
+	 */
486
+	public static function get_all_date_obj($EVT_ID = 0, $include_expired = null, $include_deleted = false, $limit = null)
487
+	{
488
+		$event = EEH_Event_View::get_event($EVT_ID);
489
+		if ($include_expired === null) {
490
+			if ($event instanceof EE_Event && $event->is_expired()) {
491
+				$include_expired = true;
492
+			} else {
493
+				$include_expired = false;
494
+			}
495
+		}
496
+
497
+		if ($event instanceof EE_Event) {
498
+			return $event->datetimes_ordered($include_expired, $include_deleted, $limit);
499
+		} else {
500
+			 return array();
501
+		}
502
+	}
503
+
504
+
505
+
506
+	/**
507
+	 *    event_link_url
508
+	 *
509
+	 * @access    public
510
+	 * @param int $EVT_ID
511
+	 * @return    string
512
+	 */
513
+	public static function event_link_url($EVT_ID = 0)
514
+	{
515
+		$event = EEH_Event_View::get_event($EVT_ID);
516
+		if ($event instanceof EE_Event) {
517
+			$url = $event->external_url() !== null && $event->external_url() !== '' ? $event->external_url() : get_permalink($event->ID());
518
+			return preg_match("~^(?:f|ht)tps?://~i", $url) ? $url : 'http://' . $url;
519
+		}
520
+		return null;
521
+	}
522
+
523
+
524
+
525
+	/**
526
+	 *    event_phone
527
+	 *
528
+	 * @access    public
529
+	 * @param int $EVT_ID
530
+	 * @return    string
531
+	 */
532
+	public static function event_phone($EVT_ID = 0)
533
+	{
534
+		$event = EEH_Event_View::get_event($EVT_ID);
535
+		if ($event instanceof EE_Event) {
536
+			return EEH_Schema::telephone($event->phone());
537
+		}
538
+		return null;
539
+	}
540
+
541
+
542
+
543
+	/**
544
+	 *    edit_event_link
545
+	 *
546
+	 * @access    public
547
+	 * @param int    $EVT_ID
548
+	 * @param string $link
549
+	 * @param string $before
550
+	 * @param string $after
551
+	 * @return    string
552
+	 */
553
+	public static function edit_event_link($EVT_ID = 0, $link = '', $before = '', $after = '')
554
+	{
555
+		$event = EEH_Event_View::get_event($EVT_ID);
556
+		if ($event instanceof EE_Event) {
557
+			// can the user edit this post ?
558
+			if (current_user_can('edit_post', $event->ID())) {
559
+				// set link text
560
+				$link_text = ! empty($link) ? $link : __('edit this event', 'event_espresso');
561
+				// generate nonce
562
+				$nonce = wp_create_nonce('edit_nonce');
563
+				// generate url to event editor for this event
564
+				$url = add_query_arg(array( 'page' => 'espresso_events', 'action' => 'edit', 'post' => $event->ID(), 'edit_nonce' => $nonce ), admin_url());
565
+				// get edit CPT text
566
+				$post_type_obj = get_post_type_object('espresso_events');
567
+				// build final link html
568
+				$link = '<a class="post-edit-link" href="' . $url . '" ';
569
+				$link .= ' title="' . esc_attr($post_type_obj->labels->edit_item) . '"';
570
+				$link .= \EED_Events_Archive::link_target();
571
+				$link .='>' . $link_text . '</a>';
572
+				// put it all together
573
+				return $before . apply_filters('edit_post_link', $link, $event->ID()) . $after;
574
+			}
575
+		}
576
+		return '';
577
+	}
578
+
579
+
580
+
581
+	/**
582
+	 * @return string
583
+	 */
584
+	public static function event_archive_url()
585
+	{
586
+		return get_post_type_archive_link('espresso_events');
587
+	}
588 588
 }
Please login to merge, or discard this patch.
admin_pages/messages/Messages_Template_List_Table.class.php 2 patches
Indentation   +350 added lines, -350 removed lines patch added patch discarded remove patch
@@ -13,354 +13,354 @@
 block discarded – undo
13 13
 {
14 14
 
15 15
 
16
-    /**
17
-     * @return Messages_Admin_Page
18
-     */
19
-    public function get_admin_page()
20
-    {
21
-        return $this->_admin_page;
22
-    }
23
-
24
-
25
-    /**
26
-     * Setup data object
27
-     */
28
-    protected function _setup_data()
29
-    {
30
-        $this->_data = $this->get_admin_page()->get_message_templates(
31
-            $this->_per_page,
32
-            $this->_view,
33
-            false
34
-        );
35
-        $this->_all_data_count = $this->get_admin_page()->get_message_templates(
36
-            $this->_per_page,
37
-            $this->_view,
38
-            true,
39
-            true
40
-        );
41
-    }
42
-
43
-
44
-    /**
45
-     * Set internal properties
46
-     */
47
-    protected function _set_properties()
48
-    {
49
-        $this->_wp_list_args = array(
50
-            'singular' => esc_html__('Message Template Group', 'event_espresso'),
51
-            'plural'   => esc_html__('Message Template', 'event_espresso'),
52
-            'ajax'     => true, // for now,
53
-            'screen'   => $this->get_admin_page()->get_current_screen()->id,
54
-        );
55
-        $this->_columns = array(
56
-            // 'cb' => '<input type="checkbox" />', //no deleting default (global) templates!
57
-            'message_type' => esc_html__('Message Type', 'event_espresso'),
58
-            'messenger'    => esc_html__('Messenger', 'event_espresso'),
59
-            'description'  => esc_html__('Description', 'event_espresso'),
60
-        );
61
-
62
-        $this->_sortable_columns = array(
63
-            'messenger' => array('MTP_messenger' => true),
64
-        );
65
-
66
-        $this->_hidden_columns = array();
67
-    }
68
-
69
-
70
-    /**
71
-     * Overriding the single_row method from parent to verify whether the $item has an accessible
72
-     * message_type or messenger object before generating the row.
73
-     *
74
-     * @param EE_Message_Template_Group $item
75
-     * @return string
76
-     * @throws EE_Error
77
-     */
78
-    public function single_row($item)
79
-    {
80
-        $message_type = $item->message_type_obj();
81
-        $messenger = $item->messenger_obj();
82
-
83
-        if (! $message_type instanceof EE_message_type || ! $messenger instanceof EE_messenger) {
84
-            echo '';
85
-            return;
86
-        }
87
-
88
-        parent::single_row($item);
89
-    }
90
-
91
-
92
-    /**
93
-     * @return array
94
-     * @throws EE_Error
95
-     */
96
-    protected function _get_table_filters()
97
-    {
98
-        $filters = array();
99
-
100
-        // get select inputs
101
-        $select_inputs = array(
102
-            $this->_get_messengers_dropdown_filter(),
103
-            $this->_get_message_types_dropdown_filter(),
104
-        );
105
-
106
-        // set filters to select inputs if they aren't empty
107
-        foreach ($select_inputs as $select_input) {
108
-            if ($select_input) {
109
-                $filters[] = $select_input;
110
-            }
111
-        }
112
-        return $filters;
113
-    }
114
-
115
-    /**
116
-     * We're just removing the search box for message templates, not needed.
117
-     *
118
-     * @param string $text
119
-     * @param string $input_id
120
-     * @return string ;
121
-     */
122
-    public function search_box($text, $input_id)
123
-    {
124
-        return '';
125
-    }
126
-
127
-
128
-    /**
129
-     * Add counts to the _views property
130
-     */
131
-    protected function _add_view_counts()
132
-    {
133
-        foreach ($this->_views as $view => $args) {
134
-            $this->_views[ $view ]['count'] = $this->get_admin_page()->get_message_templates(
135
-                $this->_per_page,
136
-                $view,
137
-                true,
138
-                true
139
-            );
140
-        }
141
-    }
142
-
143
-
144
-    /**
145
-     * @param EE_Message_Template_Group $item
146
-     * @return string
147
-     */
148
-    public function column_cb($item)
149
-    {
150
-        return '';
151
-    }
152
-
153
-
154
-    /**
155
-     * @param EE_Message_Template_Group $item
156
-     * @return string
157
-     * @throws EE_Error
158
-     */
159
-    public function column_description($item)
160
-    {
161
-        return '<p>' . $item->message_type_obj()->description . '</p>';
162
-    }
163
-
164
-
165
-    /**
166
-     * @param EE_Message_Template_Group $item
167
-     * @return string
168
-     * @throws EE_Error
169
-     */
170
-    public function column_messenger($item)
171
-    {
172
-        // Return the name contents
173
-        return sprintf(
174
-            '%1$s <span style="color:silver">(id:%2$s)</span><br />%3$s%4$s',
175
-            /* $1%s */
176
-            ucwords($item->messenger_obj()->label['singular']),
177
-            /* $2%s */
178
-            $item->GRP_ID(),
179
-            /* %4$s */
180
-            $this->_get_context_links($item),
181
-            $this->row_actions($this->_get_actions_for_messenger_column($item))
182
-        );
183
-    }
184
-
185
-    /**
186
-     * column_message_type
187
-     *
188
-     * @param  EE_Message_Template_Group $item message info for the row
189
-     * @return string message_type name
190
-     * @throws EE_Error
191
-     */
192
-    public function column_message_type($item)
193
-    {
194
-        return ucwords($item->message_type_obj()->label['singular']);
195
-    }
196
-
197
-
198
-    /**
199
-     * Generate dropdown filter select input for messengers
200
-     *
201
-     * @param bool $global
202
-     * @return string
203
-     * @throws EE_Error
204
-     */
205
-    protected function _get_messengers_dropdown_filter($global = true)
206
-    {
207
-        $messenger_options = array();
208
-        $active_message_template_groups_grouped_by_messenger = EEM_Message_Template_Group::instance()->get_all(
209
-            array(
210
-                array(
211
-                    'MTP_is_active' => true,
212
-                    'MTP_is_global' => $global,
213
-                ),
214
-                'group_by' => 'MTP_messenger',
215
-            )
216
-        );
217
-
218
-        foreach ($active_message_template_groups_grouped_by_messenger as $active_message_template_group) {
219
-            if ($active_message_template_group instanceof EE_Message_Template_Group) {
220
-                $messenger = $active_message_template_group->messenger_obj();
221
-                $messenger_label = $messenger instanceof EE_messenger
222
-                    ? $messenger->label['singular']
223
-                    : $active_message_template_group->messenger();
224
-                $messenger_options[ $active_message_template_group->messenger() ] = ucwords($messenger_label);
225
-            }
226
-        }
227
-        return $this->get_admin_page()->get_messengers_select_input($messenger_options);
228
-    }
229
-
230
-
231
-    /**
232
-     * Generate dropdown filter select input for message types
233
-     *
234
-     * @param bool $global
235
-     * @return string
236
-     * @throws EE_Error
237
-     */
238
-    protected function _get_message_types_dropdown_filter($global = true)
239
-    {
240
-        $message_type_options = array();
241
-        $active_message_template_groups_grouped_by_message_type = EEM_Message_Template_Group::instance()->get_all(
242
-            array(
243
-                array(
244
-                    'MTP_is_active' => true,
245
-                    'MTP_is_global' => true,
246
-                ),
247
-                'group_by' => 'MTP_message_type',
248
-            )
249
-        );
250
-
251
-        foreach ($active_message_template_groups_grouped_by_message_type as $active_message_template_group) {
252
-            if ($active_message_template_group instanceof EE_Message_Template_Group) {
253
-                $message_type = $active_message_template_group->message_type_obj();
254
-                $message_type_label = $message_type instanceof EE_message_type
255
-                    ? $message_type->label['singular']
256
-                    : $active_message_template_group->message_type();
257
-                $message_type_options[ $active_message_template_group->message_type() ] = ucwords($message_type_label);
258
-            }
259
-        }
260
-        return $this->get_admin_page()->get_message_types_select_input($message_type_options);
261
-    }
262
-
263
-
264
-    /**
265
-     * Return the edit url for the message template group.
266
-     *
267
-     * @param EE_Message_Template_Group $item
268
-     * @return string
269
-     * @throws EE_Error
270
-     */
271
-    protected function _get_edit_url(EE_Message_Template_Group $item)
272
-    {
273
-        $edit_url = '';
274
-        // edit link but only if item isn't trashed.
275
-        if (! $item->get('MTP_deleted')
276
-            && EE_Registry::instance()->CAP->current_user_can(
277
-                'ee_edit_message',
278
-                'espresso_messages_edit_message_template',
279
-                $item->ID()
280
-            )) {
281
-            $edit_url = EE_Admin_Page::add_query_args_and_nonce(
282
-                array(
283
-                    'action' => 'edit_message_template',
284
-                    'id'     => $item->GRP_ID(),
285
-                ),
286
-                EE_MSG_ADMIN_URL
287
-            );
288
-        }
289
-        return $edit_url;
290
-    }
291
-
292
-
293
-    /**
294
-     * Get the context link string for the messenger column.
295
-     *
296
-     * @param EE_Message_Template_Group $item
297
-     * @return string
298
-     * @throws EE_Error
299
-     */
300
-    protected function _get_context_links(EE_Message_Template_Group $item)
301
-    {
302
-        // first check if we even show the context links or not.
303
-        if (! EE_Registry::instance()->CAP->current_user_can(
304
-            'ee_edit_message',
305
-            'espresso_messages_edit_message_template',
306
-            $item->ID()
307
-        )
308
-            || $item->get('MTP_deleted')
309
-        ) {
310
-            return '';
311
-        }
312
-        // we want to display the contexts in here so we need to set them up
313
-        $c_label = $item->context_label();
314
-        $c_configs = $item->contexts_config();
315
-        $ctxt = array();
316
-        $context_templates = $item->context_templates();
317
-        foreach ($context_templates as $context => $template_fields) {
318
-            $mtp_to = ! empty($context_templates[ $context ]['to'])
319
-                      && $context_templates[ $context ]['to'] instanceof EE_Message_Template
320
-                ? $context_templates[ $context ]['to']->get('MTP_content')
321
-                : null;
322
-            $inactive_class = (
323
-                                  empty($mtp_to)
324
-                                  && ! empty($context_templates[ $context ]['to'])
325
-                              )
326
-                              || ! $item->is_context_active($context)
327
-                ? ' mtp-inactive'
328
-                : '';
329
-            $context_title = sprintf(
330
-                /* translators: Placeholder represents the context label. Example "Edit Event Admin" */
331
-                esc_html__('Edit %1$s', 'event_espresso'),
332
-                ucwords($c_configs[ $context ]['label'])
333
-            );
334
-            $edit_link = EE_Admin_Page::add_query_args_and_nonce(
335
-                array(
336
-                    'action'  => 'edit_message_template',
337
-                    'id'      => $item->GRP_ID(),
338
-                    'context' => $context,
339
-                ),
340
-                EE_MSG_ADMIN_URL
341
-            );
342
-            $ctxt[] = '<a'
343
-                      . ' href="' . $edit_link . '"'
344
-                      . ' class="' . $item->message_type() . '-' . $context . '-edit-link' . $inactive_class . '"'
345
-                      . ' title="' . esc_attr__('Edit Context', 'event_espresso') . '">'
346
-                      . $context_title
347
-                      . '</a>';
348
-        }
349
-
350
-        return sprintf('<strong>%s:</strong> ', ucwords($c_label['plural'])) . implode(' | ', $ctxt);
351
-    }
352
-
353
-
354
-    /**
355
-     * Returns the actions for the messenger column.
356
-     *
357
-     * Note: Children classes may override this so do not remove it.
358
-     *
359
-     * @param EE_Message_Template_Group $item
360
-     * @return array
361
-     */
362
-    protected function _get_actions_for_messenger_column(EE_Message_Template_Group $item)
363
-    {
364
-        return [];
365
-    }
16
+	/**
17
+	 * @return Messages_Admin_Page
18
+	 */
19
+	public function get_admin_page()
20
+	{
21
+		return $this->_admin_page;
22
+	}
23
+
24
+
25
+	/**
26
+	 * Setup data object
27
+	 */
28
+	protected function _setup_data()
29
+	{
30
+		$this->_data = $this->get_admin_page()->get_message_templates(
31
+			$this->_per_page,
32
+			$this->_view,
33
+			false
34
+		);
35
+		$this->_all_data_count = $this->get_admin_page()->get_message_templates(
36
+			$this->_per_page,
37
+			$this->_view,
38
+			true,
39
+			true
40
+		);
41
+	}
42
+
43
+
44
+	/**
45
+	 * Set internal properties
46
+	 */
47
+	protected function _set_properties()
48
+	{
49
+		$this->_wp_list_args = array(
50
+			'singular' => esc_html__('Message Template Group', 'event_espresso'),
51
+			'plural'   => esc_html__('Message Template', 'event_espresso'),
52
+			'ajax'     => true, // for now,
53
+			'screen'   => $this->get_admin_page()->get_current_screen()->id,
54
+		);
55
+		$this->_columns = array(
56
+			// 'cb' => '<input type="checkbox" />', //no deleting default (global) templates!
57
+			'message_type' => esc_html__('Message Type', 'event_espresso'),
58
+			'messenger'    => esc_html__('Messenger', 'event_espresso'),
59
+			'description'  => esc_html__('Description', 'event_espresso'),
60
+		);
61
+
62
+		$this->_sortable_columns = array(
63
+			'messenger' => array('MTP_messenger' => true),
64
+		);
65
+
66
+		$this->_hidden_columns = array();
67
+	}
68
+
69
+
70
+	/**
71
+	 * Overriding the single_row method from parent to verify whether the $item has an accessible
72
+	 * message_type or messenger object before generating the row.
73
+	 *
74
+	 * @param EE_Message_Template_Group $item
75
+	 * @return string
76
+	 * @throws EE_Error
77
+	 */
78
+	public function single_row($item)
79
+	{
80
+		$message_type = $item->message_type_obj();
81
+		$messenger = $item->messenger_obj();
82
+
83
+		if (! $message_type instanceof EE_message_type || ! $messenger instanceof EE_messenger) {
84
+			echo '';
85
+			return;
86
+		}
87
+
88
+		parent::single_row($item);
89
+	}
90
+
91
+
92
+	/**
93
+	 * @return array
94
+	 * @throws EE_Error
95
+	 */
96
+	protected function _get_table_filters()
97
+	{
98
+		$filters = array();
99
+
100
+		// get select inputs
101
+		$select_inputs = array(
102
+			$this->_get_messengers_dropdown_filter(),
103
+			$this->_get_message_types_dropdown_filter(),
104
+		);
105
+
106
+		// set filters to select inputs if they aren't empty
107
+		foreach ($select_inputs as $select_input) {
108
+			if ($select_input) {
109
+				$filters[] = $select_input;
110
+			}
111
+		}
112
+		return $filters;
113
+	}
114
+
115
+	/**
116
+	 * We're just removing the search box for message templates, not needed.
117
+	 *
118
+	 * @param string $text
119
+	 * @param string $input_id
120
+	 * @return string ;
121
+	 */
122
+	public function search_box($text, $input_id)
123
+	{
124
+		return '';
125
+	}
126
+
127
+
128
+	/**
129
+	 * Add counts to the _views property
130
+	 */
131
+	protected function _add_view_counts()
132
+	{
133
+		foreach ($this->_views as $view => $args) {
134
+			$this->_views[ $view ]['count'] = $this->get_admin_page()->get_message_templates(
135
+				$this->_per_page,
136
+				$view,
137
+				true,
138
+				true
139
+			);
140
+		}
141
+	}
142
+
143
+
144
+	/**
145
+	 * @param EE_Message_Template_Group $item
146
+	 * @return string
147
+	 */
148
+	public function column_cb($item)
149
+	{
150
+		return '';
151
+	}
152
+
153
+
154
+	/**
155
+	 * @param EE_Message_Template_Group $item
156
+	 * @return string
157
+	 * @throws EE_Error
158
+	 */
159
+	public function column_description($item)
160
+	{
161
+		return '<p>' . $item->message_type_obj()->description . '</p>';
162
+	}
163
+
164
+
165
+	/**
166
+	 * @param EE_Message_Template_Group $item
167
+	 * @return string
168
+	 * @throws EE_Error
169
+	 */
170
+	public function column_messenger($item)
171
+	{
172
+		// Return the name contents
173
+		return sprintf(
174
+			'%1$s <span style="color:silver">(id:%2$s)</span><br />%3$s%4$s',
175
+			/* $1%s */
176
+			ucwords($item->messenger_obj()->label['singular']),
177
+			/* $2%s */
178
+			$item->GRP_ID(),
179
+			/* %4$s */
180
+			$this->_get_context_links($item),
181
+			$this->row_actions($this->_get_actions_for_messenger_column($item))
182
+		);
183
+	}
184
+
185
+	/**
186
+	 * column_message_type
187
+	 *
188
+	 * @param  EE_Message_Template_Group $item message info for the row
189
+	 * @return string message_type name
190
+	 * @throws EE_Error
191
+	 */
192
+	public function column_message_type($item)
193
+	{
194
+		return ucwords($item->message_type_obj()->label['singular']);
195
+	}
196
+
197
+
198
+	/**
199
+	 * Generate dropdown filter select input for messengers
200
+	 *
201
+	 * @param bool $global
202
+	 * @return string
203
+	 * @throws EE_Error
204
+	 */
205
+	protected function _get_messengers_dropdown_filter($global = true)
206
+	{
207
+		$messenger_options = array();
208
+		$active_message_template_groups_grouped_by_messenger = EEM_Message_Template_Group::instance()->get_all(
209
+			array(
210
+				array(
211
+					'MTP_is_active' => true,
212
+					'MTP_is_global' => $global,
213
+				),
214
+				'group_by' => 'MTP_messenger',
215
+			)
216
+		);
217
+
218
+		foreach ($active_message_template_groups_grouped_by_messenger as $active_message_template_group) {
219
+			if ($active_message_template_group instanceof EE_Message_Template_Group) {
220
+				$messenger = $active_message_template_group->messenger_obj();
221
+				$messenger_label = $messenger instanceof EE_messenger
222
+					? $messenger->label['singular']
223
+					: $active_message_template_group->messenger();
224
+				$messenger_options[ $active_message_template_group->messenger() ] = ucwords($messenger_label);
225
+			}
226
+		}
227
+		return $this->get_admin_page()->get_messengers_select_input($messenger_options);
228
+	}
229
+
230
+
231
+	/**
232
+	 * Generate dropdown filter select input for message types
233
+	 *
234
+	 * @param bool $global
235
+	 * @return string
236
+	 * @throws EE_Error
237
+	 */
238
+	protected function _get_message_types_dropdown_filter($global = true)
239
+	{
240
+		$message_type_options = array();
241
+		$active_message_template_groups_grouped_by_message_type = EEM_Message_Template_Group::instance()->get_all(
242
+			array(
243
+				array(
244
+					'MTP_is_active' => true,
245
+					'MTP_is_global' => true,
246
+				),
247
+				'group_by' => 'MTP_message_type',
248
+			)
249
+		);
250
+
251
+		foreach ($active_message_template_groups_grouped_by_message_type as $active_message_template_group) {
252
+			if ($active_message_template_group instanceof EE_Message_Template_Group) {
253
+				$message_type = $active_message_template_group->message_type_obj();
254
+				$message_type_label = $message_type instanceof EE_message_type
255
+					? $message_type->label['singular']
256
+					: $active_message_template_group->message_type();
257
+				$message_type_options[ $active_message_template_group->message_type() ] = ucwords($message_type_label);
258
+			}
259
+		}
260
+		return $this->get_admin_page()->get_message_types_select_input($message_type_options);
261
+	}
262
+
263
+
264
+	/**
265
+	 * Return the edit url for the message template group.
266
+	 *
267
+	 * @param EE_Message_Template_Group $item
268
+	 * @return string
269
+	 * @throws EE_Error
270
+	 */
271
+	protected function _get_edit_url(EE_Message_Template_Group $item)
272
+	{
273
+		$edit_url = '';
274
+		// edit link but only if item isn't trashed.
275
+		if (! $item->get('MTP_deleted')
276
+			&& EE_Registry::instance()->CAP->current_user_can(
277
+				'ee_edit_message',
278
+				'espresso_messages_edit_message_template',
279
+				$item->ID()
280
+			)) {
281
+			$edit_url = EE_Admin_Page::add_query_args_and_nonce(
282
+				array(
283
+					'action' => 'edit_message_template',
284
+					'id'     => $item->GRP_ID(),
285
+				),
286
+				EE_MSG_ADMIN_URL
287
+			);
288
+		}
289
+		return $edit_url;
290
+	}
291
+
292
+
293
+	/**
294
+	 * Get the context link string for the messenger column.
295
+	 *
296
+	 * @param EE_Message_Template_Group $item
297
+	 * @return string
298
+	 * @throws EE_Error
299
+	 */
300
+	protected function _get_context_links(EE_Message_Template_Group $item)
301
+	{
302
+		// first check if we even show the context links or not.
303
+		if (! EE_Registry::instance()->CAP->current_user_can(
304
+			'ee_edit_message',
305
+			'espresso_messages_edit_message_template',
306
+			$item->ID()
307
+		)
308
+			|| $item->get('MTP_deleted')
309
+		) {
310
+			return '';
311
+		}
312
+		// we want to display the contexts in here so we need to set them up
313
+		$c_label = $item->context_label();
314
+		$c_configs = $item->contexts_config();
315
+		$ctxt = array();
316
+		$context_templates = $item->context_templates();
317
+		foreach ($context_templates as $context => $template_fields) {
318
+			$mtp_to = ! empty($context_templates[ $context ]['to'])
319
+					  && $context_templates[ $context ]['to'] instanceof EE_Message_Template
320
+				? $context_templates[ $context ]['to']->get('MTP_content')
321
+				: null;
322
+			$inactive_class = (
323
+								  empty($mtp_to)
324
+								  && ! empty($context_templates[ $context ]['to'])
325
+							  )
326
+							  || ! $item->is_context_active($context)
327
+				? ' mtp-inactive'
328
+				: '';
329
+			$context_title = sprintf(
330
+				/* translators: Placeholder represents the context label. Example "Edit Event Admin" */
331
+				esc_html__('Edit %1$s', 'event_espresso'),
332
+				ucwords($c_configs[ $context ]['label'])
333
+			);
334
+			$edit_link = EE_Admin_Page::add_query_args_and_nonce(
335
+				array(
336
+					'action'  => 'edit_message_template',
337
+					'id'      => $item->GRP_ID(),
338
+					'context' => $context,
339
+				),
340
+				EE_MSG_ADMIN_URL
341
+			);
342
+			$ctxt[] = '<a'
343
+					  . ' href="' . $edit_link . '"'
344
+					  . ' class="' . $item->message_type() . '-' . $context . '-edit-link' . $inactive_class . '"'
345
+					  . ' title="' . esc_attr__('Edit Context', 'event_espresso') . '">'
346
+					  . $context_title
347
+					  . '</a>';
348
+		}
349
+
350
+		return sprintf('<strong>%s:</strong> ', ucwords($c_label['plural'])) . implode(' | ', $ctxt);
351
+	}
352
+
353
+
354
+	/**
355
+	 * Returns the actions for the messenger column.
356
+	 *
357
+	 * Note: Children classes may override this so do not remove it.
358
+	 *
359
+	 * @param EE_Message_Template_Group $item
360
+	 * @return array
361
+	 */
362
+	protected function _get_actions_for_messenger_column(EE_Message_Template_Group $item)
363
+	{
364
+		return [];
365
+	}
366 366
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
         $message_type = $item->message_type_obj();
81 81
         $messenger = $item->messenger_obj();
82 82
 
83
-        if (! $message_type instanceof EE_message_type || ! $messenger instanceof EE_messenger) {
83
+        if ( ! $message_type instanceof EE_message_type || ! $messenger instanceof EE_messenger) {
84 84
             echo '';
85 85
             return;
86 86
         }
@@ -131,7 +131,7 @@  discard block
 block discarded – undo
131 131
     protected function _add_view_counts()
132 132
     {
133 133
         foreach ($this->_views as $view => $args) {
134
-            $this->_views[ $view ]['count'] = $this->get_admin_page()->get_message_templates(
134
+            $this->_views[$view]['count'] = $this->get_admin_page()->get_message_templates(
135 135
                 $this->_per_page,
136 136
                 $view,
137 137
                 true,
@@ -158,7 +158,7 @@  discard block
 block discarded – undo
158 158
      */
159 159
     public function column_description($item)
160 160
     {
161
-        return '<p>' . $item->message_type_obj()->description . '</p>';
161
+        return '<p>'.$item->message_type_obj()->description.'</p>';
162 162
     }
163 163
 
164 164
 
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
                 $messenger_label = $messenger instanceof EE_messenger
222 222
                     ? $messenger->label['singular']
223 223
                     : $active_message_template_group->messenger();
224
-                $messenger_options[ $active_message_template_group->messenger() ] = ucwords($messenger_label);
224
+                $messenger_options[$active_message_template_group->messenger()] = ucwords($messenger_label);
225 225
             }
226 226
         }
227 227
         return $this->get_admin_page()->get_messengers_select_input($messenger_options);
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
                 $message_type_label = $message_type instanceof EE_message_type
255 255
                     ? $message_type->label['singular']
256 256
                     : $active_message_template_group->message_type();
257
-                $message_type_options[ $active_message_template_group->message_type() ] = ucwords($message_type_label);
257
+                $message_type_options[$active_message_template_group->message_type()] = ucwords($message_type_label);
258 258
             }
259 259
         }
260 260
         return $this->get_admin_page()->get_message_types_select_input($message_type_options);
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
     {
273 273
         $edit_url = '';
274 274
         // edit link but only if item isn't trashed.
275
-        if (! $item->get('MTP_deleted')
275
+        if ( ! $item->get('MTP_deleted')
276 276
             && EE_Registry::instance()->CAP->current_user_can(
277 277
                 'ee_edit_message',
278 278
                 'espresso_messages_edit_message_template',
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
     protected function _get_context_links(EE_Message_Template_Group $item)
301 301
     {
302 302
         // first check if we even show the context links or not.
303
-        if (! EE_Registry::instance()->CAP->current_user_can(
303
+        if ( ! EE_Registry::instance()->CAP->current_user_can(
304 304
             'ee_edit_message',
305 305
             'espresso_messages_edit_message_template',
306 306
             $item->ID()
@@ -315,13 +315,13 @@  discard block
 block discarded – undo
315 315
         $ctxt = array();
316 316
         $context_templates = $item->context_templates();
317 317
         foreach ($context_templates as $context => $template_fields) {
318
-            $mtp_to = ! empty($context_templates[ $context ]['to'])
319
-                      && $context_templates[ $context ]['to'] instanceof EE_Message_Template
320
-                ? $context_templates[ $context ]['to']->get('MTP_content')
318
+            $mtp_to = ! empty($context_templates[$context]['to'])
319
+                      && $context_templates[$context]['to'] instanceof EE_Message_Template
320
+                ? $context_templates[$context]['to']->get('MTP_content')
321 321
                 : null;
322 322
             $inactive_class = (
323 323
                                   empty($mtp_to)
324
-                                  && ! empty($context_templates[ $context ]['to'])
324
+                                  && ! empty($context_templates[$context]['to'])
325 325
                               )
326 326
                               || ! $item->is_context_active($context)
327 327
                 ? ' mtp-inactive'
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
             $context_title = sprintf(
330 330
                 /* translators: Placeholder represents the context label. Example "Edit Event Admin" */
331 331
                 esc_html__('Edit %1$s', 'event_espresso'),
332
-                ucwords($c_configs[ $context ]['label'])
332
+                ucwords($c_configs[$context]['label'])
333 333
             );
334 334
             $edit_link = EE_Admin_Page::add_query_args_and_nonce(
335 335
                 array(
@@ -340,14 +340,14 @@  discard block
 block discarded – undo
340 340
                 EE_MSG_ADMIN_URL
341 341
             );
342 342
             $ctxt[] = '<a'
343
-                      . ' href="' . $edit_link . '"'
344
-                      . ' class="' . $item->message_type() . '-' . $context . '-edit-link' . $inactive_class . '"'
345
-                      . ' title="' . esc_attr__('Edit Context', 'event_espresso') . '">'
343
+                      . ' href="'.$edit_link.'"'
344
+                      . ' class="'.$item->message_type().'-'.$context.'-edit-link'.$inactive_class.'"'
345
+                      . ' title="'.esc_attr__('Edit Context', 'event_espresso').'">'
346 346
                       . $context_title
347 347
                       . '</a>';
348 348
         }
349 349
 
350
-        return sprintf('<strong>%s:</strong> ', ucwords($c_label['plural'])) . implode(' | ', $ctxt);
350
+        return sprintf('<strong>%s:</strong> ', ucwords($c_label['plural'])).implode(' | ', $ctxt);
351 351
     }
352 352
 
353 353
 
Please login to merge, or discard this patch.
core/domain/entities/editor/blocks/EventAttendees.php 1 patch
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -21,172 +21,172 @@
 block discarded – undo
21 21
 class EventAttendees extends Block
22 22
 {
23 23
 
24
-    const BLOCK_TYPE = 'event-attendees';
24
+	const BLOCK_TYPE = 'event-attendees';
25 25
 
26
-    /**
27
-     * @var EventAttendeesBlockRenderer $renderer
28
-     */
29
-    protected $renderer;
26
+	/**
27
+	 * @var EventAttendeesBlockRenderer $renderer
28
+	 */
29
+	protected $renderer;
30 30
 
31 31
 
32
-    /**
33
-     * EventAttendees constructor.
34
-     *
35
-     * @param CoreBlocksAssetManager      $block_asset_manager
36
-     * @param RequestInterface            $request
37
-     * @param EventAttendeesBlockRenderer $renderer
38
-     */
39
-    public function __construct(
40
-        CoreBlocksAssetManager $block_asset_manager,
41
-        RequestInterface $request,
42
-        EventAttendeesBlockRenderer $renderer
43
-    ) {
44
-        parent::__construct($block_asset_manager, $request);
45
-        $this->renderer= $renderer;
46
-    }
32
+	/**
33
+	 * EventAttendees constructor.
34
+	 *
35
+	 * @param CoreBlocksAssetManager      $block_asset_manager
36
+	 * @param RequestInterface            $request
37
+	 * @param EventAttendeesBlockRenderer $renderer
38
+	 */
39
+	public function __construct(
40
+		CoreBlocksAssetManager $block_asset_manager,
41
+		RequestInterface $request,
42
+		EventAttendeesBlockRenderer $renderer
43
+	) {
44
+		parent::__construct($block_asset_manager, $request);
45
+		$this->renderer= $renderer;
46
+	}
47 47
 
48 48
 
49
-    /**
50
-     * Perform any early setup required by the block
51
-     * including setting the block type and supported post types
52
-     *
53
-     * @return void
54
-     */
55
-    public function initialize()
56
-    {
57
-        $this->setBlockType(self::BLOCK_TYPE);
58
-        $this->setSupportedRoutes(
59
-            array(
60
-                'EventEspresso\core\domain\entities\route_match\specifications\admin\EspressoStandardPostTypeEditor',
61
-                'EventEspresso\core\domain\entities\route_match\specifications\admin\WordPressPostTypeEditor',
62
-                'EventEspresso\core\domain\entities\route_match\specifications\frontend\EspressoBlockRenderer',
63
-                'EventEspresso\core\domain\entities\route_match\specifications\frontend\AnyFrontendRequest'
64
-            )
65
-        );
66
-        $EVT_ID = $this->request->getRequestParam('page') === 'espresso_events'
67
-            ? $this->request->getRequestParam('post', 0)
68
-            : 0;
69
-        $this->setAttributes(
70
-            array(
71
-                'eventId'           => array(
72
-                    'type'    => 'number',
73
-                    'default' => $EVT_ID,
74
-                ),
75
-                'datetimeId'        => array(
76
-                    'type'    => 'number',
77
-                    'default' => 0,
78
-                ),
79
-                'ticketId'          => array(
80
-                    'type'    => 'number',
81
-                    'default' => 0,
82
-                ),
83
-                'status'            => array(
84
-                    'type'    => 'string',
85
-                    'default' => EEM_Registration::status_id_approved,
86
-                ),
87
-                'limit'             => array(
88
-                    'type'    => 'number',
89
-                    'default' => 100,
90
-                ),
91
-                'order' => array(
92
-                    'type' => 'string',
93
-                    'default' => 'ASC'
94
-                ),
95
-                'orderBy' => array(
96
-                    'type' => 'string',
97
-                    'default' => 'lastThenFirstName',
98
-                ),
99
-                'showGravatar'      => array(
100
-                    'type'    => 'boolean',
101
-                    'default' => false,
102
-                ),
103
-                'avatarClass' => array(
104
-                    'type' => 'string',
105
-                    'default' => 'contact',
106
-                ),
107
-                'avatarSize' => array(
108
-                    'type' => 'number',
109
-                    'default' => 24,
110
-                ),
111
-                'displayOnArchives' => array(
112
-                    'type'    => 'boolean',
113
-                    'default' => false,
114
-                ),
115
-            )
116
-        );
117
-        $this->setDynamic();
118
-    }
49
+	/**
50
+	 * Perform any early setup required by the block
51
+	 * including setting the block type and supported post types
52
+	 *
53
+	 * @return void
54
+	 */
55
+	public function initialize()
56
+	{
57
+		$this->setBlockType(self::BLOCK_TYPE);
58
+		$this->setSupportedRoutes(
59
+			array(
60
+				'EventEspresso\core\domain\entities\route_match\specifications\admin\EspressoStandardPostTypeEditor',
61
+				'EventEspresso\core\domain\entities\route_match\specifications\admin\WordPressPostTypeEditor',
62
+				'EventEspresso\core\domain\entities\route_match\specifications\frontend\EspressoBlockRenderer',
63
+				'EventEspresso\core\domain\entities\route_match\specifications\frontend\AnyFrontendRequest'
64
+			)
65
+		);
66
+		$EVT_ID = $this->request->getRequestParam('page') === 'espresso_events'
67
+			? $this->request->getRequestParam('post', 0)
68
+			: 0;
69
+		$this->setAttributes(
70
+			array(
71
+				'eventId'           => array(
72
+					'type'    => 'number',
73
+					'default' => $EVT_ID,
74
+				),
75
+				'datetimeId'        => array(
76
+					'type'    => 'number',
77
+					'default' => 0,
78
+				),
79
+				'ticketId'          => array(
80
+					'type'    => 'number',
81
+					'default' => 0,
82
+				),
83
+				'status'            => array(
84
+					'type'    => 'string',
85
+					'default' => EEM_Registration::status_id_approved,
86
+				),
87
+				'limit'             => array(
88
+					'type'    => 'number',
89
+					'default' => 100,
90
+				),
91
+				'order' => array(
92
+					'type' => 'string',
93
+					'default' => 'ASC'
94
+				),
95
+				'orderBy' => array(
96
+					'type' => 'string',
97
+					'default' => 'lastThenFirstName',
98
+				),
99
+				'showGravatar'      => array(
100
+					'type'    => 'boolean',
101
+					'default' => false,
102
+				),
103
+				'avatarClass' => array(
104
+					'type' => 'string',
105
+					'default' => 'contact',
106
+				),
107
+				'avatarSize' => array(
108
+					'type' => 'number',
109
+					'default' => 24,
110
+				),
111
+				'displayOnArchives' => array(
112
+					'type'    => 'boolean',
113
+					'default' => false,
114
+				),
115
+			)
116
+		);
117
+		$this->setDynamic();
118
+	}
119 119
 
120 120
 
121
-    /**
122
-     * Returns an array where the key corresponds to the incoming attribute name from the WP block
123
-     * and the value corresponds to the attribute name for the existing EspressoEventAttendees shortcode
124
-     *
125
-     * @since 4.9.71.p
126
-     * @return array
127
-     */
128
-    private function getAttributesMap()
129
-    {
130
-        return array(
131
-            'eventId'           => 'absint',
132
-            'datetimeId'        => 'absint',
133
-            'ticketId'          => 'absint',
134
-            'status'            => 'sanitize_text_field',
135
-            'limit'             => 'intval',
136
-            'showGravatar'      => 'bool',
137
-            'avatarClass'       => 'sanitize_text_field',
138
-            'avatarSize'        => 'absint',
139
-            'displayOnArchives' => 'bool',
140
-            'order' => 'sanitize_text_field',
141
-            'orderBy' => 'sanitize_text_field',
142
-        );
143
-    }
121
+	/**
122
+	 * Returns an array where the key corresponds to the incoming attribute name from the WP block
123
+	 * and the value corresponds to the attribute name for the existing EspressoEventAttendees shortcode
124
+	 *
125
+	 * @since 4.9.71.p
126
+	 * @return array
127
+	 */
128
+	private function getAttributesMap()
129
+	{
130
+		return array(
131
+			'eventId'           => 'absint',
132
+			'datetimeId'        => 'absint',
133
+			'ticketId'          => 'absint',
134
+			'status'            => 'sanitize_text_field',
135
+			'limit'             => 'intval',
136
+			'showGravatar'      => 'bool',
137
+			'avatarClass'       => 'sanitize_text_field',
138
+			'avatarSize'        => 'absint',
139
+			'displayOnArchives' => 'bool',
140
+			'order' => 'sanitize_text_field',
141
+			'orderBy' => 'sanitize_text_field',
142
+		);
143
+	}
144 144
 
145 145
 
146
-    /**
147
-     * Sanitizes attributes.
148
-     *
149
-     * @param array $attributes
150
-     * @return array
151
-     */
152
-    private function sanitizeAttributes(array $attributes)
153
-    {
154
-        $sanitized_attributes = array();
155
-        foreach ($attributes as $attribute => $value) {
156
-            $convert = $this->getAttributesMap();
157
-            if (isset($convert[ $attribute ])) {
158
-                $sanitize = $convert[ $attribute ];
159
-                if ($sanitize === 'bool') {
160
-                    $sanitized_attributes[ $attribute ] = filter_var(
161
-                        $value,
162
-                        FILTER_VALIDATE_BOOLEAN
163
-                    );
164
-                } else {
165
-                    $sanitized_attributes[ $attribute ] = $sanitize($value);
166
-                }
167
-                // don't pass along attributes with a 0 value
168
-                if ($sanitized_attributes[ $attribute ] === 0) {
169
-                    unset($sanitized_attributes[ $attribute ]);
170
-                }
171
-            }
172
-        }
173
-        return $attributes;
174
-    }
146
+	/**
147
+	 * Sanitizes attributes.
148
+	 *
149
+	 * @param array $attributes
150
+	 * @return array
151
+	 */
152
+	private function sanitizeAttributes(array $attributes)
153
+	{
154
+		$sanitized_attributes = array();
155
+		foreach ($attributes as $attribute => $value) {
156
+			$convert = $this->getAttributesMap();
157
+			if (isset($convert[ $attribute ])) {
158
+				$sanitize = $convert[ $attribute ];
159
+				if ($sanitize === 'bool') {
160
+					$sanitized_attributes[ $attribute ] = filter_var(
161
+						$value,
162
+						FILTER_VALIDATE_BOOLEAN
163
+					);
164
+				} else {
165
+					$sanitized_attributes[ $attribute ] = $sanitize($value);
166
+				}
167
+				// don't pass along attributes with a 0 value
168
+				if ($sanitized_attributes[ $attribute ] === 0) {
169
+					unset($sanitized_attributes[ $attribute ]);
170
+				}
171
+			}
172
+		}
173
+		return $attributes;
174
+	}
175 175
 
176 176
 
177
-    /**
178
-     * Returns the rendered HTML for the block
179
-     *
180
-     * @param array $attributes
181
-     * @return string
182
-     * @throws DomainException
183
-     * @throws EE_Error
184
-     */
185
-    public function renderBlock(array $attributes = array())
186
-    {
187
-        $attributes = $this->sanitizeAttributes($attributes);
188
-        return (is_archive() || is_front_page() || is_home()) && ! $attributes['displayOnArchives']
189
-            ? ''
190
-            : $this->renderer->render($attributes);
191
-    }
177
+	/**
178
+	 * Returns the rendered HTML for the block
179
+	 *
180
+	 * @param array $attributes
181
+	 * @return string
182
+	 * @throws DomainException
183
+	 * @throws EE_Error
184
+	 */
185
+	public function renderBlock(array $attributes = array())
186
+	{
187
+		$attributes = $this->sanitizeAttributes($attributes);
188
+		return (is_archive() || is_front_page() || is_home()) && ! $attributes['displayOnArchives']
189
+			? ''
190
+			: $this->renderer->render($attributes);
191
+	}
192 192
 }
Please login to merge, or discard this patch.