Completed
Branch master (d65695)
by
unknown
04:25
created
core/CPTs/EE_CPT_Strategy.core.php 2 patches
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
         if (is_array($this->_CPTs)) {
129 129
             foreach ($this->_CPTs as $CPT_type => $CPT) {
130 130
                 if (isset($CPT['plural_slug'])) {
131
-                    $_CPT_endpoints [ (string) $CPT['plural_slug'] ] = $CPT_type;
131
+                    $_CPT_endpoints [(string) $CPT['plural_slug']] = $CPT_type;
132 132
                 }
133 133
             }
134 134
         }
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
     public function pre_get_posts($WP_Query)
152 152
     {
153 153
         // check that post-type is set
154
-        if (! $WP_Query instanceof WP_Query) {
154
+        if ( ! $WP_Query instanceof WP_Query) {
155 155
             return;
156 156
         }
157 157
         // add our conditionals
@@ -195,7 +195,7 @@  discard block
 block discarded – undo
195 195
             $terms = EEM_Term::instance()->get_all_CPT_post_tags();
196 196
             foreach ($terms as $term) {
197 197
                 if ($term instanceof EE_Term) {
198
-                    $this->_CPT_terms[ $term->slug() ] = $term;
198
+                    $this->_CPT_terms[$term->slug()] = $term;
199 199
                 }
200 200
             }
201 201
         }
@@ -260,7 +260,7 @@  discard block
 block discarded – undo
260 260
             // loop thru our taxonomies
261 261
             foreach ($this->_CPT_taxonomies as $CPT_taxonomy => $CPT_taxonomy_details) {
262 262
                 // check if one of our taxonomies is set as a query var
263
-                if (isset($WP_Query->query[ $CPT_taxonomy ])) {
263
+                if (isset($WP_Query->query[$CPT_taxonomy])) {
264 264
                     // but which CPT does that correspond to??? hmmm... guess we gotta go looping
265 265
                     foreach ($this->_CPTs as $post_type => $CPT) {
266 266
                         // verify our CPT has args, is public and has taxonomies set
@@ -284,7 +284,7 @@  discard block
 block discarded – undo
284 284
                                     break;
285 285
                                 default:
286 286
                                     do_action(
287
-                                        'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_' . $post_type . '_post_type',
287
+                                        'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_'.$post_type.'_post_type',
288 288
                                         $WP_Query,
289 289
                                         $this
290 290
                                     );
@@ -309,11 +309,11 @@  discard block
 block discarded – undo
309 309
             // loop thru post_types as array
310 310
             foreach ((array) $WP_Query->query_vars['post_type'] as $post_type) {
311 311
                 // is current query for an EE CPT ?
312
-                if (isset($this->_CPTs[ $post_type ])) {
312
+                if (isset($this->_CPTs[$post_type])) {
313 313
                     // is EE on or off ?
314 314
                     if (EE_Maintenance_Mode::instance()->level()) {
315 315
                         // reroute CPT template view to maintenance_mode.template.php
316
-                        if (! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) {
316
+                        if ( ! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) {
317 317
                             add_filter('template_include', array('EE_Maintenance_Mode', 'template_include'), 99999);
318 318
                         }
319 319
                         if (has_filter('the_content', array(EE_Maintenance_Mode::instance(), 'the_content'))) {
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
             'EventEspresso\core\CPTs\CptQueryModifier',
342 342
             array(
343 343
                 $post_type,
344
-                $this->_CPTs[ $post_type ],
344
+                $this->_CPTs[$post_type],
345 345
                 $WP_Query,
346 346
             )
347 347
         );
Please login to merge, or discard this patch.
Indentation   +445 added lines, -445 removed lines patch added patch discarded remove patch
@@ -15,449 +15,449 @@
 block discarded – undo
15 15
  */
16 16
 class EE_CPT_Strategy extends EE_Base
17 17
 {
18
-    /**
19
-     * @var EE_CPT_Strategy $_instance
20
-     */
21
-    private static $_instance;
22
-
23
-    /**
24
-     * the current page, if it utilizes CPTs
25
-     *
26
-     * @var array $CPT
27
-     */
28
-    protected $CPT;
29
-
30
-    /**
31
-     * return value from CustomPostTypeDefinitions::getDefinitions()
32
-     *
33
-     * @var array $_CPTs
34
-     */
35
-    protected $_CPTs = array();
36
-
37
-    /**
38
-     * @var array $_CPT_taxonomies
39
-     */
40
-    protected $_CPT_taxonomies = array();
41
-
42
-    /**
43
-     * @var array $_CPT_terms
44
-     */
45
-    protected $_CPT_terms = array();
46
-
47
-    /**
48
-     * @var array $_CPT_endpoints
49
-     */
50
-    protected $_CPT_endpoints = array();
51
-
52
-    /**
53
-     * @var EEM_Base $CPT_model
54
-     */
55
-    protected $CPT_model;
56
-
57
-    /**
58
-     * @var EventEspresso\Core\CPTs\CptQueryModifier $query_modifier
59
-     */
60
-    protected $query_modifier;
61
-
62
-
63
-    /**
64
-     * @singleton method used to instantiate class object
65
-     * @param CustomPostTypeDefinitions|null $custom_post_types
66
-     * @param CustomTaxonomyDefinitions|null $taxonomies
67
-     * @return EE_CPT_Strategy
68
-     */
69
-    public static function instance(
70
-        CustomPostTypeDefinitions $custom_post_types = null,
71
-        CustomTaxonomyDefinitions $taxonomies = null
72
-    ) {
73
-        // check if class object is instantiated
74
-        if (
75
-            ! self::$_instance instanceof EE_CPT_Strategy
76
-            && $custom_post_types instanceof CustomPostTypeDefinitions
77
-            && $taxonomies instanceof CustomTaxonomyDefinitions
78
-        ) {
79
-            self::$_instance = new self($custom_post_types, $taxonomies);
80
-        }
81
-        return self::$_instance;
82
-    }
83
-
84
-
85
-    /**
86
-     * @param CustomPostTypeDefinitions $custom_post_types
87
-     * @param CustomTaxonomyDefinitions $taxonomies
88
-     */
89
-    protected function __construct(
90
-        CustomPostTypeDefinitions $custom_post_types,
91
-        CustomTaxonomyDefinitions $taxonomies
92
-    ) {
93
-        // get CPT data
94
-        $this->_CPTs = $custom_post_types->getDefinitions();
95
-        $this->_CPT_endpoints = $this->_set_CPT_endpoints();
96
-        $this->_CPT_taxonomies = $taxonomies->getCustomTaxonomyDefinitions();
97
-        add_action('pre_get_posts', array($this, 'pre_get_posts'), 5);
98
-    }
99
-
100
-
101
-    /**
102
-     * @return array
103
-     */
104
-    public function get_CPT_endpoints()
105
-    {
106
-        return $this->_CPT_endpoints;
107
-    }
108
-
109
-
110
-    /**
111
-     * @return array
112
-     */
113
-    public function get_CPT_taxonomies()
114
-    {
115
-        return $this->_CPT_taxonomies;
116
-    }
117
-
118
-
119
-    /**
120
-     * add CPT "slugs" to array of default espresso "pages"
121
-     *
122
-     * @return array
123
-     */
124
-    private function _set_CPT_endpoints()
125
-    {
126
-        $_CPT_endpoints = array();
127
-        if (is_array($this->_CPTs)) {
128
-            foreach ($this->_CPTs as $CPT_type => $CPT) {
129
-                if (isset($CPT['plural_slug'])) {
130
-                    $_CPT_endpoints [ (string) $CPT['plural_slug'] ] = $CPT_type;
131
-                }
132
-            }
133
-        }
134
-        return $_CPT_endpoints;
135
-    }
136
-
137
-
138
-    /**
139
-     * If this query (not just "main" queries (ie, for WP's infamous "loop")) is for an EE CPT, then we want to
140
-     * supercharge the get_posts query to add our EE stuff (like joining to our tables, selecting extra columns, and
141
-     * adding EE objects to the post to facilitate further querying of related data etc)
142
-     *
143
-     * @param WP_Query $WP_Query
144
-     * @return void
145
-     * @throws \EE_Error
146
-     * @throws \InvalidArgumentException
147
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
148
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
149
-     */
150
-    public function pre_get_posts($WP_Query)
151
-    {
152
-        // check that post-type is set
153
-        if (! $WP_Query instanceof WP_Query) {
154
-            return;
155
-        }
156
-        // add our conditionals
157
-        $this->_set_EE_tags_on_WP_Query($WP_Query);
158
-        // check for terms
159
-        $this->_set_post_type_for_terms($WP_Query);
160
-        // make sure paging is always set
161
-        $this->_set_paging($WP_Query);
162
-        // is a taxonomy set ?
163
-        $this->_set_CPT_taxonomies_on_WP_Query($WP_Query);
164
-        // loop thru post_types if set
165
-        $this->_process_WP_Query_post_types($WP_Query);
166
-    }
167
-
168
-
169
-    /**
170
-     * @param WP_Query $WP_Query
171
-     * @return void
172
-     */
173
-    private function _set_EE_tags_on_WP_Query(WP_Query $WP_Query)
174
-    {
175
-        $WP_Query->is_espresso_event_single = false;
176
-        $WP_Query->is_espresso_event_archive = false;
177
-        $WP_Query->is_espresso_event_taxonomy = false;
178
-        $WP_Query->is_espresso_venue_single = false;
179
-        $WP_Query->is_espresso_venue_archive = false;
180
-        $WP_Query->is_espresso_venue_taxonomy = false;
181
-    }
182
-
183
-
184
-    /**
185
-     * @return void
186
-     * @throws EE_Error
187
-     * @throws InvalidArgumentException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidInterfaceException
190
-     */
191
-    private function _set_CPT_terms()
192
-    {
193
-        if (empty($this->_CPT_terms)) {
194
-            $terms = EEM_Term::instance()->get_all_CPT_post_tags();
195
-            foreach ($terms as $term) {
196
-                if ($term instanceof EE_Term) {
197
-                    $this->_CPT_terms[ $term->slug() ] = $term;
198
-                }
199
-            }
200
-        }
201
-    }
202
-
203
-
204
-    /**
205
-     * @param WP_Query $WP_Query
206
-     * @return void
207
-     * @throws EE_Error
208
-     * @throws InvalidArgumentException
209
-     * @throws InvalidDataTypeException
210
-     * @throws InvalidInterfaceException
211
-     */
212
-    private function _set_post_type_for_terms(WP_Query $WP_Query)
213
-    {
214
-        // is a tag set ?
215
-        if (isset($WP_Query->query['tag'])) {
216
-            // get term for tag
217
-            $term = EEM_Term::instance()->get_post_tag_for_event_or_venue($WP_Query->query['tag']);
218
-            // verify the term
219
-            if ($term instanceof EE_Term) {
220
-                $term->post_type = array_merge(array('post', 'page'), (array) $term->post_type);
221
-                $term->post_type = apply_filters(
222
-                    'FHEE__EE_CPT_Strategy___set_post_type_for_terms__term_post_type',
223
-                    $term->post_type,
224
-                    $term
225
-                );
226
-                // if a post type is already set
227
-                if (isset($WP_Query->query_vars['post_type'])) {
228
-                    // add to existing array
229
-                    $term->post_type = array_merge((array) $WP_Query->query_vars['post_type'], $term->post_type);
230
-                }
231
-                // just set post_type to our CPT
232
-                $WP_Query->set('post_type', array_unique($term->post_type));
233
-            }
234
-        }
235
-    }
236
-
237
-
238
-    /**
239
-     * @param WP_Query $WP_Query
240
-     * @return void
241
-     */
242
-    public function _set_paging($WP_Query)
243
-    {
244
-        if ($WP_Query->is_main_query() && apply_filters('FHEE__EE_CPT_Strategy___set_paging', true)) {
245
-            $page = get_query_var('page') ? get_query_var('page') : null;
246
-            $paged = get_query_var('paged') ? get_query_var('paged') : $page;
247
-            $WP_Query->set('paged', $paged);
248
-        }
249
-    }
250
-
251
-
252
-    /**
253
-     * @param \WP_Query $WP_Query
254
-     */
255
-    protected function _set_CPT_taxonomies_on_WP_Query(WP_Query $WP_Query)
256
-    {
257
-        // is a taxonomy set ?
258
-        if ($WP_Query->is_tax) {
259
-            // loop thru our taxonomies
260
-            foreach ($this->_CPT_taxonomies as $CPT_taxonomy => $CPT_taxonomy_details) {
261
-                // check if one of our taxonomies is set as a query var
262
-                if (isset($WP_Query->query[ $CPT_taxonomy ])) {
263
-                    // but which CPT does that correspond to??? hmmm... guess we gotta go looping
264
-                    foreach ($this->_CPTs as $post_type => $CPT) {
265
-                        // verify our CPT has args, is public and has taxonomies set
266
-                        if (
267
-                            isset($CPT['args']['public'])
268
-                            && $CPT['args']['public']
269
-                            && ! empty($CPT['args']['taxonomies'])
270
-                            && in_array($CPT_taxonomy, $CPT['args']['taxonomies'], true)
271
-                        ) {
272
-                            // if so, then add this CPT post_type to the current query's array of post_types'
273
-                            $WP_Query->query_vars['post_type'] = isset($WP_Query->query_vars['post_type'])
274
-                                ? (array) $WP_Query->query_vars['post_type']
275
-                                : array();
276
-                            $WP_Query->query_vars['post_type'][] = $post_type;
277
-                            switch ($post_type) {
278
-                                case 'espresso_events':
279
-                                    $WP_Query->is_espresso_event_taxonomy = true;
280
-                                    break;
281
-                                case 'espresso_venues':
282
-                                    $WP_Query->is_espresso_venue_taxonomy = true;
283
-                                    break;
284
-                                default:
285
-                                    do_action(
286
-                                        'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_' . $post_type . '_post_type',
287
-                                        $WP_Query,
288
-                                        $this
289
-                                    );
290
-                            }
291
-                        }
292
-                    }
293
-                }
294
-            }
295
-        }
296
-    }
297
-
298
-
299
-    /**
300
-     * @param \WP_Query $WP_Query
301
-     * @throws InvalidArgumentException
302
-     * @throws InvalidDataTypeException
303
-     * @throws InvalidInterfaceException
304
-     */
305
-    protected function _process_WP_Query_post_types(WP_Query $WP_Query)
306
-    {
307
-        if (isset($WP_Query->query_vars['post_type'])) {
308
-            // loop thru post_types as array
309
-            foreach ((array) $WP_Query->query_vars['post_type'] as $post_type) {
310
-                // is current query for an EE CPT ?
311
-                if (isset($this->_CPTs[ $post_type ])) {
312
-                    // is EE on or off ?
313
-                    if (EE_Maintenance_Mode::instance()->level()) {
314
-                        // reroute CPT template view to maintenance_mode.template.php
315
-                        if (! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) {
316
-                            add_filter('template_include', array('EE_Maintenance_Mode', 'template_include'), 99999);
317
-                        }
318
-                        if (has_filter('the_content', array(EE_Maintenance_Mode::instance(), 'the_content'))) {
319
-                            add_filter('the_content', array($this, 'inject_EE_shortcode_placeholder'), 1);
320
-                        }
321
-                        return;
322
-                    }
323
-                    $this->_generate_CptQueryModifier($WP_Query, $post_type);
324
-                }
325
-            }
326
-        }
327
-    }
328
-
329
-
330
-    /**
331
-     * @param \WP_Query $WP_Query
332
-     * @param string    $post_type
333
-     * @throws InvalidArgumentException
334
-     * @throws InvalidDataTypeException
335
-     * @throws InvalidInterfaceException
336
-     */
337
-    protected function _generate_CptQueryModifier(WP_Query $WP_Query, $post_type)
338
-    {
339
-        $this->query_modifier = LoaderFactory::getLoader()->getShared(
340
-            'EventEspresso\core\CPTs\CptQueryModifier',
341
-            array(
342
-                $post_type,
343
-                $this->_CPTs[ $post_type ],
344
-                $WP_Query,
345
-            )
346
-        );
347
-        $this->_CPT_taxonomies = $this->query_modifier->taxonomies();
348
-    }
349
-
350
-
351
-    /**
352
-     * inject_EE_shortcode_placeholder
353
-     * in order to display the M-Mode notice on our CPT routes,
354
-     * we need to first inject what looks like one of our shortcodes,
355
-     * so that it can be replaced with the actual M-Mode notice
356
-     *
357
-     * @return string
358
-     */
359
-    public function inject_EE_shortcode_placeholder()
360
-    {
361
-        return '[ESPRESSO_';
362
-    }
363
-
364
-
365
-    /**
366
-     * @deprecated
367
-     * @since  4.8.41
368
-     * @return void
369
-     */
370
-    public function _possibly_set_ee_request_var()
371
-    {
372
-        $this->query_modifier->setRequestVarsIfCpt();
373
-    }
374
-
375
-
376
-    /**
377
-     * @deprecated
378
-     * @since  4.8.41
379
-     * @param  $SQL
380
-     * @return string
381
-     */
382
-    public function posts_fields($SQL)
383
-    {
384
-        if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
385
-            return $this->query_modifier->postsFields($SQL);
386
-        }
387
-        return $SQL;
388
-    }
389
-
390
-
391
-    /**
392
-     * @deprecated
393
-     * @since  4.8.41
394
-     * @param  $SQL
395
-     * @return string
396
-     */
397
-    public function posts_join($SQL)
398
-    {
399
-        if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
400
-            return $this->query_modifier->postsJoin($SQL);
401
-        }
402
-        return $SQL;
403
-    }
404
-
405
-
406
-    /**
407
-     * @deprecated
408
-     * @since  4.8.41
409
-     * @param  \WP_Post[] $posts
410
-     * @return \WP_Post[]
411
-     */
412
-    public function the_posts($posts)
413
-    {
414
-        if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
415
-            $this->query_modifier->thePosts($posts);
416
-        }
417
-        return $posts;
418
-    }
419
-
420
-
421
-    /**
422
-     * @deprecated
423
-     * @since  4.8.41
424
-     * @param $url
425
-     * @param $ID
426
-     * @return string
427
-     */
428
-    public function get_edit_post_link($url, $ID)
429
-    {
430
-        if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
431
-            return $this->query_modifier->getEditPostLink($url, $ID);
432
-        }
433
-        return '';
434
-    }
435
-
436
-
437
-    /**
438
-     * @deprecated
439
-     * @since  4.8.41
440
-     * @param null $WP_Query
441
-     */
442
-    protected function _do_template_filters($WP_Query = null)
443
-    {
444
-        if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
445
-            $this->query_modifier->addTemplateFilters();
446
-        }
447
-    }
448
-
449
-
450
-    /**
451
-     * @deprecated
452
-     * @since  4.8.41
453
-     * @param string $current_template Existing default template path derived for this page call.
454
-     * @return string the path to the full template file.
455
-     */
456
-    public function single_cpt_template($current_template)
457
-    {
458
-        if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
459
-            return $this->query_modifier->singleCptTemplate($current_template);
460
-        }
461
-        return $current_template;
462
-    }
18
+	/**
19
+	 * @var EE_CPT_Strategy $_instance
20
+	 */
21
+	private static $_instance;
22
+
23
+	/**
24
+	 * the current page, if it utilizes CPTs
25
+	 *
26
+	 * @var array $CPT
27
+	 */
28
+	protected $CPT;
29
+
30
+	/**
31
+	 * return value from CustomPostTypeDefinitions::getDefinitions()
32
+	 *
33
+	 * @var array $_CPTs
34
+	 */
35
+	protected $_CPTs = array();
36
+
37
+	/**
38
+	 * @var array $_CPT_taxonomies
39
+	 */
40
+	protected $_CPT_taxonomies = array();
41
+
42
+	/**
43
+	 * @var array $_CPT_terms
44
+	 */
45
+	protected $_CPT_terms = array();
46
+
47
+	/**
48
+	 * @var array $_CPT_endpoints
49
+	 */
50
+	protected $_CPT_endpoints = array();
51
+
52
+	/**
53
+	 * @var EEM_Base $CPT_model
54
+	 */
55
+	protected $CPT_model;
56
+
57
+	/**
58
+	 * @var EventEspresso\Core\CPTs\CptQueryModifier $query_modifier
59
+	 */
60
+	protected $query_modifier;
61
+
62
+
63
+	/**
64
+	 * @singleton method used to instantiate class object
65
+	 * @param CustomPostTypeDefinitions|null $custom_post_types
66
+	 * @param CustomTaxonomyDefinitions|null $taxonomies
67
+	 * @return EE_CPT_Strategy
68
+	 */
69
+	public static function instance(
70
+		CustomPostTypeDefinitions $custom_post_types = null,
71
+		CustomTaxonomyDefinitions $taxonomies = null
72
+	) {
73
+		// check if class object is instantiated
74
+		if (
75
+			! self::$_instance instanceof EE_CPT_Strategy
76
+			&& $custom_post_types instanceof CustomPostTypeDefinitions
77
+			&& $taxonomies instanceof CustomTaxonomyDefinitions
78
+		) {
79
+			self::$_instance = new self($custom_post_types, $taxonomies);
80
+		}
81
+		return self::$_instance;
82
+	}
83
+
84
+
85
+	/**
86
+	 * @param CustomPostTypeDefinitions $custom_post_types
87
+	 * @param CustomTaxonomyDefinitions $taxonomies
88
+	 */
89
+	protected function __construct(
90
+		CustomPostTypeDefinitions $custom_post_types,
91
+		CustomTaxonomyDefinitions $taxonomies
92
+	) {
93
+		// get CPT data
94
+		$this->_CPTs = $custom_post_types->getDefinitions();
95
+		$this->_CPT_endpoints = $this->_set_CPT_endpoints();
96
+		$this->_CPT_taxonomies = $taxonomies->getCustomTaxonomyDefinitions();
97
+		add_action('pre_get_posts', array($this, 'pre_get_posts'), 5);
98
+	}
99
+
100
+
101
+	/**
102
+	 * @return array
103
+	 */
104
+	public function get_CPT_endpoints()
105
+	{
106
+		return $this->_CPT_endpoints;
107
+	}
108
+
109
+
110
+	/**
111
+	 * @return array
112
+	 */
113
+	public function get_CPT_taxonomies()
114
+	{
115
+		return $this->_CPT_taxonomies;
116
+	}
117
+
118
+
119
+	/**
120
+	 * add CPT "slugs" to array of default espresso "pages"
121
+	 *
122
+	 * @return array
123
+	 */
124
+	private function _set_CPT_endpoints()
125
+	{
126
+		$_CPT_endpoints = array();
127
+		if (is_array($this->_CPTs)) {
128
+			foreach ($this->_CPTs as $CPT_type => $CPT) {
129
+				if (isset($CPT['plural_slug'])) {
130
+					$_CPT_endpoints [ (string) $CPT['plural_slug'] ] = $CPT_type;
131
+				}
132
+			}
133
+		}
134
+		return $_CPT_endpoints;
135
+	}
136
+
137
+
138
+	/**
139
+	 * If this query (not just "main" queries (ie, for WP's infamous "loop")) is for an EE CPT, then we want to
140
+	 * supercharge the get_posts query to add our EE stuff (like joining to our tables, selecting extra columns, and
141
+	 * adding EE objects to the post to facilitate further querying of related data etc)
142
+	 *
143
+	 * @param WP_Query $WP_Query
144
+	 * @return void
145
+	 * @throws \EE_Error
146
+	 * @throws \InvalidArgumentException
147
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
148
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
149
+	 */
150
+	public function pre_get_posts($WP_Query)
151
+	{
152
+		// check that post-type is set
153
+		if (! $WP_Query instanceof WP_Query) {
154
+			return;
155
+		}
156
+		// add our conditionals
157
+		$this->_set_EE_tags_on_WP_Query($WP_Query);
158
+		// check for terms
159
+		$this->_set_post_type_for_terms($WP_Query);
160
+		// make sure paging is always set
161
+		$this->_set_paging($WP_Query);
162
+		// is a taxonomy set ?
163
+		$this->_set_CPT_taxonomies_on_WP_Query($WP_Query);
164
+		// loop thru post_types if set
165
+		$this->_process_WP_Query_post_types($WP_Query);
166
+	}
167
+
168
+
169
+	/**
170
+	 * @param WP_Query $WP_Query
171
+	 * @return void
172
+	 */
173
+	private function _set_EE_tags_on_WP_Query(WP_Query $WP_Query)
174
+	{
175
+		$WP_Query->is_espresso_event_single = false;
176
+		$WP_Query->is_espresso_event_archive = false;
177
+		$WP_Query->is_espresso_event_taxonomy = false;
178
+		$WP_Query->is_espresso_venue_single = false;
179
+		$WP_Query->is_espresso_venue_archive = false;
180
+		$WP_Query->is_espresso_venue_taxonomy = false;
181
+	}
182
+
183
+
184
+	/**
185
+	 * @return void
186
+	 * @throws EE_Error
187
+	 * @throws InvalidArgumentException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidInterfaceException
190
+	 */
191
+	private function _set_CPT_terms()
192
+	{
193
+		if (empty($this->_CPT_terms)) {
194
+			$terms = EEM_Term::instance()->get_all_CPT_post_tags();
195
+			foreach ($terms as $term) {
196
+				if ($term instanceof EE_Term) {
197
+					$this->_CPT_terms[ $term->slug() ] = $term;
198
+				}
199
+			}
200
+		}
201
+	}
202
+
203
+
204
+	/**
205
+	 * @param WP_Query $WP_Query
206
+	 * @return void
207
+	 * @throws EE_Error
208
+	 * @throws InvalidArgumentException
209
+	 * @throws InvalidDataTypeException
210
+	 * @throws InvalidInterfaceException
211
+	 */
212
+	private function _set_post_type_for_terms(WP_Query $WP_Query)
213
+	{
214
+		// is a tag set ?
215
+		if (isset($WP_Query->query['tag'])) {
216
+			// get term for tag
217
+			$term = EEM_Term::instance()->get_post_tag_for_event_or_venue($WP_Query->query['tag']);
218
+			// verify the term
219
+			if ($term instanceof EE_Term) {
220
+				$term->post_type = array_merge(array('post', 'page'), (array) $term->post_type);
221
+				$term->post_type = apply_filters(
222
+					'FHEE__EE_CPT_Strategy___set_post_type_for_terms__term_post_type',
223
+					$term->post_type,
224
+					$term
225
+				);
226
+				// if a post type is already set
227
+				if (isset($WP_Query->query_vars['post_type'])) {
228
+					// add to existing array
229
+					$term->post_type = array_merge((array) $WP_Query->query_vars['post_type'], $term->post_type);
230
+				}
231
+				// just set post_type to our CPT
232
+				$WP_Query->set('post_type', array_unique($term->post_type));
233
+			}
234
+		}
235
+	}
236
+
237
+
238
+	/**
239
+	 * @param WP_Query $WP_Query
240
+	 * @return void
241
+	 */
242
+	public function _set_paging($WP_Query)
243
+	{
244
+		if ($WP_Query->is_main_query() && apply_filters('FHEE__EE_CPT_Strategy___set_paging', true)) {
245
+			$page = get_query_var('page') ? get_query_var('page') : null;
246
+			$paged = get_query_var('paged') ? get_query_var('paged') : $page;
247
+			$WP_Query->set('paged', $paged);
248
+		}
249
+	}
250
+
251
+
252
+	/**
253
+	 * @param \WP_Query $WP_Query
254
+	 */
255
+	protected function _set_CPT_taxonomies_on_WP_Query(WP_Query $WP_Query)
256
+	{
257
+		// is a taxonomy set ?
258
+		if ($WP_Query->is_tax) {
259
+			// loop thru our taxonomies
260
+			foreach ($this->_CPT_taxonomies as $CPT_taxonomy => $CPT_taxonomy_details) {
261
+				// check if one of our taxonomies is set as a query var
262
+				if (isset($WP_Query->query[ $CPT_taxonomy ])) {
263
+					// but which CPT does that correspond to??? hmmm... guess we gotta go looping
264
+					foreach ($this->_CPTs as $post_type => $CPT) {
265
+						// verify our CPT has args, is public and has taxonomies set
266
+						if (
267
+							isset($CPT['args']['public'])
268
+							&& $CPT['args']['public']
269
+							&& ! empty($CPT['args']['taxonomies'])
270
+							&& in_array($CPT_taxonomy, $CPT['args']['taxonomies'], true)
271
+						) {
272
+							// if so, then add this CPT post_type to the current query's array of post_types'
273
+							$WP_Query->query_vars['post_type'] = isset($WP_Query->query_vars['post_type'])
274
+								? (array) $WP_Query->query_vars['post_type']
275
+								: array();
276
+							$WP_Query->query_vars['post_type'][] = $post_type;
277
+							switch ($post_type) {
278
+								case 'espresso_events':
279
+									$WP_Query->is_espresso_event_taxonomy = true;
280
+									break;
281
+								case 'espresso_venues':
282
+									$WP_Query->is_espresso_venue_taxonomy = true;
283
+									break;
284
+								default:
285
+									do_action(
286
+										'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_' . $post_type . '_post_type',
287
+										$WP_Query,
288
+										$this
289
+									);
290
+							}
291
+						}
292
+					}
293
+				}
294
+			}
295
+		}
296
+	}
297
+
298
+
299
+	/**
300
+	 * @param \WP_Query $WP_Query
301
+	 * @throws InvalidArgumentException
302
+	 * @throws InvalidDataTypeException
303
+	 * @throws InvalidInterfaceException
304
+	 */
305
+	protected function _process_WP_Query_post_types(WP_Query $WP_Query)
306
+	{
307
+		if (isset($WP_Query->query_vars['post_type'])) {
308
+			// loop thru post_types as array
309
+			foreach ((array) $WP_Query->query_vars['post_type'] as $post_type) {
310
+				// is current query for an EE CPT ?
311
+				if (isset($this->_CPTs[ $post_type ])) {
312
+					// is EE on or off ?
313
+					if (EE_Maintenance_Mode::instance()->level()) {
314
+						// reroute CPT template view to maintenance_mode.template.php
315
+						if (! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) {
316
+							add_filter('template_include', array('EE_Maintenance_Mode', 'template_include'), 99999);
317
+						}
318
+						if (has_filter('the_content', array(EE_Maintenance_Mode::instance(), 'the_content'))) {
319
+							add_filter('the_content', array($this, 'inject_EE_shortcode_placeholder'), 1);
320
+						}
321
+						return;
322
+					}
323
+					$this->_generate_CptQueryModifier($WP_Query, $post_type);
324
+				}
325
+			}
326
+		}
327
+	}
328
+
329
+
330
+	/**
331
+	 * @param \WP_Query $WP_Query
332
+	 * @param string    $post_type
333
+	 * @throws InvalidArgumentException
334
+	 * @throws InvalidDataTypeException
335
+	 * @throws InvalidInterfaceException
336
+	 */
337
+	protected function _generate_CptQueryModifier(WP_Query $WP_Query, $post_type)
338
+	{
339
+		$this->query_modifier = LoaderFactory::getLoader()->getShared(
340
+			'EventEspresso\core\CPTs\CptQueryModifier',
341
+			array(
342
+				$post_type,
343
+				$this->_CPTs[ $post_type ],
344
+				$WP_Query,
345
+			)
346
+		);
347
+		$this->_CPT_taxonomies = $this->query_modifier->taxonomies();
348
+	}
349
+
350
+
351
+	/**
352
+	 * inject_EE_shortcode_placeholder
353
+	 * in order to display the M-Mode notice on our CPT routes,
354
+	 * we need to first inject what looks like one of our shortcodes,
355
+	 * so that it can be replaced with the actual M-Mode notice
356
+	 *
357
+	 * @return string
358
+	 */
359
+	public function inject_EE_shortcode_placeholder()
360
+	{
361
+		return '[ESPRESSO_';
362
+	}
363
+
364
+
365
+	/**
366
+	 * @deprecated
367
+	 * @since  4.8.41
368
+	 * @return void
369
+	 */
370
+	public function _possibly_set_ee_request_var()
371
+	{
372
+		$this->query_modifier->setRequestVarsIfCpt();
373
+	}
374
+
375
+
376
+	/**
377
+	 * @deprecated
378
+	 * @since  4.8.41
379
+	 * @param  $SQL
380
+	 * @return string
381
+	 */
382
+	public function posts_fields($SQL)
383
+	{
384
+		if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
385
+			return $this->query_modifier->postsFields($SQL);
386
+		}
387
+		return $SQL;
388
+	}
389
+
390
+
391
+	/**
392
+	 * @deprecated
393
+	 * @since  4.8.41
394
+	 * @param  $SQL
395
+	 * @return string
396
+	 */
397
+	public function posts_join($SQL)
398
+	{
399
+		if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
400
+			return $this->query_modifier->postsJoin($SQL);
401
+		}
402
+		return $SQL;
403
+	}
404
+
405
+
406
+	/**
407
+	 * @deprecated
408
+	 * @since  4.8.41
409
+	 * @param  \WP_Post[] $posts
410
+	 * @return \WP_Post[]
411
+	 */
412
+	public function the_posts($posts)
413
+	{
414
+		if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
415
+			$this->query_modifier->thePosts($posts);
416
+		}
417
+		return $posts;
418
+	}
419
+
420
+
421
+	/**
422
+	 * @deprecated
423
+	 * @since  4.8.41
424
+	 * @param $url
425
+	 * @param $ID
426
+	 * @return string
427
+	 */
428
+	public function get_edit_post_link($url, $ID)
429
+	{
430
+		if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
431
+			return $this->query_modifier->getEditPostLink($url, $ID);
432
+		}
433
+		return '';
434
+	}
435
+
436
+
437
+	/**
438
+	 * @deprecated
439
+	 * @since  4.8.41
440
+	 * @param null $WP_Query
441
+	 */
442
+	protected function _do_template_filters($WP_Query = null)
443
+	{
444
+		if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
445
+			$this->query_modifier->addTemplateFilters();
446
+		}
447
+	}
448
+
449
+
450
+	/**
451
+	 * @deprecated
452
+	 * @since  4.8.41
453
+	 * @param string $current_template Existing default template path derived for this page call.
454
+	 * @return string the path to the full template file.
455
+	 */
456
+	public function single_cpt_template($current_template)
457
+	{
458
+		if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) {
459
+			return $this->query_modifier->singleCptTemplate($current_template);
460
+		}
461
+		return $current_template;
462
+	}
463 463
 }
Please login to merge, or discard this patch.
core/CPTs/EE_CPT_Event_Strategy.core.php 2 patches
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -122,13 +122,13 @@  discard block
 block discarded – undo
122 122
             )
123 123
         ) {
124 124
             // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement
125
-            $SQL .= ', ' . EEM_Datetime::instance()->table() . '.* ';
125
+            $SQL .= ', '.EEM_Datetime::instance()->table().'.* ';
126 126
             if ($wp_query->is_espresso_event_archive || $wp_query->is_espresso_event_taxonomy) {
127 127
                 // because we only want to retrieve the next upcoming datetime for each event:
128 128
                 // add something like:
129 129
                 // ", MIN( wp_esp_datetime.DTT_EVT_start ) as event_start_date "
130 130
                 // to WP Query SELECT statement
131
-                $SQL .= ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
131
+                $SQL .= ', MIN( '.EEM_Datetime::instance()->table().'.DTT_EVT_start ) as event_start_date ';
132 132
             }
133 133
         }
134 134
         return $SQL;
@@ -158,9 +158,9 @@  discard block
 block discarded – undo
158 158
             // adds something like:
159 159
             // " LEFT JOIN wp_esp_datetime ON ( wp_esp_datetime.EVT_ID = wp_posts.ID ) "
160 160
             // to WP Query JOIN statement
161
-            $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . EEM_Event::instance()->table()
162
-                    . '.ID = ' . EEM_Datetime::instance()->table() . '.'
163
-                    . EEM_Event::instance()->primary_key_name() . ' ) ';
161
+            $SQL .= ' INNER JOIN '.EEM_Datetime::instance()->table().' ON ( '.EEM_Event::instance()->table()
162
+                    . '.ID = '.EEM_Datetime::instance()->table().'.'
163
+                    . EEM_Event::instance()->primary_key_name().' ) ';
164 164
         }
165 165
         return $SQL;
166 166
     }
@@ -190,8 +190,8 @@  discard block
 block discarded – undo
190 190
                 || ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events)
191 191
                 || ! EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events
192 192
             ) {
193
-                $SQL .= ' AND ' . EEM_Datetime::instance()->table() . ".DTT_EVT_end > '"
194
-                        . current_time('mysql', true) . "' ";
193
+                $SQL .= ' AND '.EEM_Datetime::instance()->table().".DTT_EVT_end > '"
194
+                        . current_time('mysql', true)."' ";
195 195
             }
196 196
         }
197 197
         return $SQL;
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
             // but we want to only show each event only once
240 240
             // (whereas if we didn't group them by the post's ID, then we would end up with many repeats)
241 241
             global $wpdb;
242
-            $SQL = $wpdb->posts . '.ID ';
242
+            $SQL = $wpdb->posts.'.ID ';
243 243
         }
244 244
         return $SQL;
245 245
     }
Please login to merge, or discard this patch.
Indentation   +240 added lines, -240 removed lines patch added patch discarded remove patch
@@ -9,244 +9,244 @@
 block discarded – undo
9 9
  */
10 10
 class EE_CPT_Event_Strategy
11 11
 {
12
-    /**
13
-     * the current page, if it utilizes CPTs
14
-     *
15
-     * @var object $CPT
16
-     */
17
-    protected $CPT;
18
-
19
-
20
-    /**
21
-     * @param array|WP_Query|null $wp_query
22
-     * @param array         $CPT
23
-     */
24
-    public function __construct($wp_query, array $CPT = [])
25
-    {
26
-        if ($wp_query instanceof WP_Query) {
27
-            $WP_Query  = $wp_query;
28
-            $this->CPT = $CPT;
29
-        } else {
30
-            $WP_Query  = $wp_query['WP_Query'] ?? null;
31
-            $this->CPT = $wp_query['CPT'] ?? null;
32
-        }
33
-        // !!!!!!!!!!  IMPORTANT !!!!!!!!!!!!
34
-        // here's the list of available filters in the WP_Query object
35
-        // 'posts_where'
36
-        // 'posts_where_paged'
37
-        // 'posts_groupby'
38
-        // 'posts_join_paged'
39
-        // 'posts_orderby'
40
-        // 'posts_distinct'
41
-        // 'post_limits'
42
-        // 'posts_fields'
43
-        // 'posts_join'
44
-        $this->_add_filters();
45
-        if ($WP_Query instanceof WP_Query) {
46
-            $WP_Query->is_espresso_event_single   = is_singular()
47
-                                                    && isset($WP_Query->query->post_type)
48
-                                                    && $WP_Query->query->post_type === 'espresso_events';
49
-            $WP_Query->is_espresso_event_archive  = is_post_type_archive('espresso_events');
50
-            $WP_Query->is_espresso_event_taxonomy = is_tax('espresso_event_categories');
51
-        }
52
-    }
53
-
54
-
55
-    /**
56
-     * When an instance of this class is created, we add our filters
57
-     * (which will get removed in case the next call to get_posts ISN'T
58
-     * for event CPTs)
59
-     */
60
-    protected function _add_filters()
61
-    {
62
-        add_filter('posts_fields', [$this, 'posts_fields'], 1, 2);
63
-        add_filter('posts_join', [$this, 'posts_join'], 1, 2);
64
-        add_filter('posts_where', [$this, 'posts_where'], 10, 2);
65
-        // add_filter( 'the_posts', array( $this, 'the_posts' ), 1, 2 );
66
-        add_filter('posts_orderby', [$this, 'posts_orderby'], 1, 2);
67
-        add_filter('posts_groupby', [$this, 'posts_groupby'], 1, 2);
68
-        add_action('posts_selection', [$this, 'remove_filters']);
69
-    }
70
-
71
-
72
-    /**
73
-     * public access to _remove_filters()
74
-     *
75
-     * @since 4.9.63.p
76
-     */
77
-    public function remove_filters()
78
-    {
79
-        $this->_remove_filters();
80
-    }
81
-
82
-
83
-    /**
84
-     * Should eb called when the last filter or hook is fired for this CPT strategy.
85
-     * This is to avoid applying this CPT strategy for other posts or CPTs (eg,
86
-     * we don't want to join to the datetime table when querying for venues, do we!?)
87
-     */
88
-    protected function _remove_filters()
89
-    {
90
-        remove_filter('posts_fields', [$this, 'posts_fields'], 1);
91
-        remove_filter('posts_join', [$this, 'posts_join'], 1);
92
-        remove_filter('posts_where', [$this, 'posts_where']);
93
-        // remove_filter( 'the_posts', array( $this, 'the_posts' ), 1 );
94
-        remove_filter('posts_orderby', [$this, 'posts_orderby'], 1);
95
-        remove_filter('posts_groupby', [$this, 'posts_groupby'], 1);
96
-        remove_action('posts_selection', [$this, 'remove_filters']);
97
-    }
98
-
99
-
100
-    /**
101
-     * @param string        $SQL
102
-     * @param WP_Query|null $wp_query
103
-     * @return    string
104
-     * @throws EE_Error
105
-     */
106
-    public function posts_fields(string $SQL, ?WP_Query $wp_query): string
107
-    {
108
-        if (
109
-            $wp_query instanceof WP_Query
110
-            && (
111
-                $wp_query->is_espresso_event_single
112
-                || $wp_query->is_espresso_event_archive
113
-                || $wp_query->is_espresso_event_taxonomy
114
-            )
115
-        ) {
116
-            // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement
117
-            $SQL .= ', ' . EEM_Datetime::instance()->table() . '.* ';
118
-            if ($wp_query->is_espresso_event_archive || $wp_query->is_espresso_event_taxonomy) {
119
-                // because we only want to retrieve the next upcoming datetime for each event:
120
-                // add something like:
121
-                // ", MIN( wp_esp_datetime.DTT_EVT_start ) as event_start_date "
122
-                // to WP Query SELECT statement
123
-                $SQL .= ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
124
-            }
125
-        }
126
-        return $SQL;
127
-    }
128
-
129
-
130
-    /**
131
-     * @param string        $SQL
132
-     * @param WP_Query|null $wp_query
133
-     * @return string
134
-     * @throws EE_Error
135
-     */
136
-    public function posts_join(string $SQL, ?WP_Query $wp_query): string
137
-    {
138
-        if (
139
-            $wp_query instanceof WP_Query
140
-            && (
141
-                $wp_query->is_espresso_event_single
142
-                || $wp_query->is_espresso_event_archive
143
-                || $wp_query->is_espresso_event_taxonomy
144
-            )
145
-        ) {
146
-            // adds something like:
147
-            // " LEFT JOIN wp_esp_datetime ON ( wp_esp_datetime.EVT_ID = wp_posts.ID ) "
148
-            // to WP Query JOIN statement
149
-            $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . EEM_Event::instance()->table()
150
-                    . '.ID = ' . EEM_Datetime::instance()->table() . '.'
151
-                    . EEM_Event::instance()->primary_key_name() . ' ) ';
152
-        }
153
-        return $SQL;
154
-    }
155
-
156
-
157
-    /**
158
-     * @param string        $SQL
159
-     * @param WP_Query|null $wp_query
160
-     * @return string
161
-     * @throws EE_Error
162
-     */
163
-    public function posts_where(string $SQL, ?WP_Query $wp_query): string
164
-    {
165
-        if (
166
-            $wp_query instanceof WP_Query
167
-            && (
168
-                $wp_query->is_espresso_event_archive
169
-                || $wp_query->is_espresso_event_taxonomy
170
-            )
171
-        ) {
172
-            if (
173
-                ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive)
174
-                || ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events)
175
-                || ! EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events
176
-            ) {
177
-                $SQL .= ' AND ' . EEM_Datetime::instance()->table() . ".DTT_EVT_end > '"
178
-                        . current_time('mysql', true) . "' ";
179
-            }
180
-        }
181
-        return $SQL;
182
-    }
183
-
184
-
185
-    /**
186
-     * @param string        $SQL
187
-     * @param WP_Query|null $wp_query
188
-     * @return string
189
-     */
190
-    public function posts_orderby(string $SQL, ?WP_Query $wp_query): string
191
-    {
192
-        if (
193
-            $wp_query instanceof WP_Query
194
-            && (
195
-                $wp_query->is_espresso_event_archive
196
-                || $wp_query->is_espresso_event_taxonomy
197
-            )
198
-        ) {
199
-            $SQL = ' event_start_date ASC ';
200
-        }
201
-        return $SQL;
202
-    }
203
-
204
-
205
-    /**
206
-     * @param string        $SQL
207
-     * @param WP_Query|null $wp_query
208
-     * @return string
209
-     */
210
-    public function posts_groupby(string $SQL, ?WP_Query $wp_query): string
211
-    {
212
-        if (
213
-            $wp_query instanceof WP_Query
214
-            && (
215
-                $wp_query->is_espresso_event_archive
216
-                || $wp_query->is_espresso_event_taxonomy
217
-            )
218
-        ) {
219
-            // TODO: add event list option for displaying ALL datetimes in event list or only primary datetime (default)
220
-            // we're joining to the datetimes table, where there can be MANY datetimes for a single event,
221
-            // but we want to only show each event only once
222
-            // (whereas if we didn't group them by the post's ID, then we would end up with many repeats)
223
-            global $wpdb;
224
-            $SQL = $wpdb->posts . '.ID ';
225
-        }
226
-        return $SQL;
227
-    }
228
-
229
-
230
-    /**
231
-     * @param array         $posts
232
-     * @param WP_Query|null $wp_query
233
-     * @return array
234
-     */
235
-    public function the_posts(array $posts, ?WP_Query $wp_query): array
236
-    {
237
-        return $posts;
238
-    }
239
-
240
-
241
-    /**
242
-     * @param mixed           $meta_value
243
-     * @param int|string      $post_id
244
-     * @param int|string      $meta_key
245
-     * @param bool|int|string $single
246
-     * @return mixed
247
-     */
248
-    public function get_EE_post_type_metadata($meta_value, $post_id, $meta_key, $single)
249
-    {
250
-        return $meta_value;
251
-    }
12
+	/**
13
+	 * the current page, if it utilizes CPTs
14
+	 *
15
+	 * @var object $CPT
16
+	 */
17
+	protected $CPT;
18
+
19
+
20
+	/**
21
+	 * @param array|WP_Query|null $wp_query
22
+	 * @param array         $CPT
23
+	 */
24
+	public function __construct($wp_query, array $CPT = [])
25
+	{
26
+		if ($wp_query instanceof WP_Query) {
27
+			$WP_Query  = $wp_query;
28
+			$this->CPT = $CPT;
29
+		} else {
30
+			$WP_Query  = $wp_query['WP_Query'] ?? null;
31
+			$this->CPT = $wp_query['CPT'] ?? null;
32
+		}
33
+		// !!!!!!!!!!  IMPORTANT !!!!!!!!!!!!
34
+		// here's the list of available filters in the WP_Query object
35
+		// 'posts_where'
36
+		// 'posts_where_paged'
37
+		// 'posts_groupby'
38
+		// 'posts_join_paged'
39
+		// 'posts_orderby'
40
+		// 'posts_distinct'
41
+		// 'post_limits'
42
+		// 'posts_fields'
43
+		// 'posts_join'
44
+		$this->_add_filters();
45
+		if ($WP_Query instanceof WP_Query) {
46
+			$WP_Query->is_espresso_event_single   = is_singular()
47
+													&& isset($WP_Query->query->post_type)
48
+													&& $WP_Query->query->post_type === 'espresso_events';
49
+			$WP_Query->is_espresso_event_archive  = is_post_type_archive('espresso_events');
50
+			$WP_Query->is_espresso_event_taxonomy = is_tax('espresso_event_categories');
51
+		}
52
+	}
53
+
54
+
55
+	/**
56
+	 * When an instance of this class is created, we add our filters
57
+	 * (which will get removed in case the next call to get_posts ISN'T
58
+	 * for event CPTs)
59
+	 */
60
+	protected function _add_filters()
61
+	{
62
+		add_filter('posts_fields', [$this, 'posts_fields'], 1, 2);
63
+		add_filter('posts_join', [$this, 'posts_join'], 1, 2);
64
+		add_filter('posts_where', [$this, 'posts_where'], 10, 2);
65
+		// add_filter( 'the_posts', array( $this, 'the_posts' ), 1, 2 );
66
+		add_filter('posts_orderby', [$this, 'posts_orderby'], 1, 2);
67
+		add_filter('posts_groupby', [$this, 'posts_groupby'], 1, 2);
68
+		add_action('posts_selection', [$this, 'remove_filters']);
69
+	}
70
+
71
+
72
+	/**
73
+	 * public access to _remove_filters()
74
+	 *
75
+	 * @since 4.9.63.p
76
+	 */
77
+	public function remove_filters()
78
+	{
79
+		$this->_remove_filters();
80
+	}
81
+
82
+
83
+	/**
84
+	 * Should eb called when the last filter or hook is fired for this CPT strategy.
85
+	 * This is to avoid applying this CPT strategy for other posts or CPTs (eg,
86
+	 * we don't want to join to the datetime table when querying for venues, do we!?)
87
+	 */
88
+	protected function _remove_filters()
89
+	{
90
+		remove_filter('posts_fields', [$this, 'posts_fields'], 1);
91
+		remove_filter('posts_join', [$this, 'posts_join'], 1);
92
+		remove_filter('posts_where', [$this, 'posts_where']);
93
+		// remove_filter( 'the_posts', array( $this, 'the_posts' ), 1 );
94
+		remove_filter('posts_orderby', [$this, 'posts_orderby'], 1);
95
+		remove_filter('posts_groupby', [$this, 'posts_groupby'], 1);
96
+		remove_action('posts_selection', [$this, 'remove_filters']);
97
+	}
98
+
99
+
100
+	/**
101
+	 * @param string        $SQL
102
+	 * @param WP_Query|null $wp_query
103
+	 * @return    string
104
+	 * @throws EE_Error
105
+	 */
106
+	public function posts_fields(string $SQL, ?WP_Query $wp_query): string
107
+	{
108
+		if (
109
+			$wp_query instanceof WP_Query
110
+			&& (
111
+				$wp_query->is_espresso_event_single
112
+				|| $wp_query->is_espresso_event_archive
113
+				|| $wp_query->is_espresso_event_taxonomy
114
+			)
115
+		) {
116
+			// adds something like ", wp_esp_datetime.* " to WP Query SELECT statement
117
+			$SQL .= ', ' . EEM_Datetime::instance()->table() . '.* ';
118
+			if ($wp_query->is_espresso_event_archive || $wp_query->is_espresso_event_taxonomy) {
119
+				// because we only want to retrieve the next upcoming datetime for each event:
120
+				// add something like:
121
+				// ", MIN( wp_esp_datetime.DTT_EVT_start ) as event_start_date "
122
+				// to WP Query SELECT statement
123
+				$SQL .= ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date ';
124
+			}
125
+		}
126
+		return $SQL;
127
+	}
128
+
129
+
130
+	/**
131
+	 * @param string        $SQL
132
+	 * @param WP_Query|null $wp_query
133
+	 * @return string
134
+	 * @throws EE_Error
135
+	 */
136
+	public function posts_join(string $SQL, ?WP_Query $wp_query): string
137
+	{
138
+		if (
139
+			$wp_query instanceof WP_Query
140
+			&& (
141
+				$wp_query->is_espresso_event_single
142
+				|| $wp_query->is_espresso_event_archive
143
+				|| $wp_query->is_espresso_event_taxonomy
144
+			)
145
+		) {
146
+			// adds something like:
147
+			// " LEFT JOIN wp_esp_datetime ON ( wp_esp_datetime.EVT_ID = wp_posts.ID ) "
148
+			// to WP Query JOIN statement
149
+			$SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . EEM_Event::instance()->table()
150
+					. '.ID = ' . EEM_Datetime::instance()->table() . '.'
151
+					. EEM_Event::instance()->primary_key_name() . ' ) ';
152
+		}
153
+		return $SQL;
154
+	}
155
+
156
+
157
+	/**
158
+	 * @param string        $SQL
159
+	 * @param WP_Query|null $wp_query
160
+	 * @return string
161
+	 * @throws EE_Error
162
+	 */
163
+	public function posts_where(string $SQL, ?WP_Query $wp_query): string
164
+	{
165
+		if (
166
+			$wp_query instanceof WP_Query
167
+			&& (
168
+				$wp_query->is_espresso_event_archive
169
+				|| $wp_query->is_espresso_event_taxonomy
170
+			)
171
+		) {
172
+			if (
173
+				! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive)
174
+				|| ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events)
175
+				|| ! EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events
176
+			) {
177
+				$SQL .= ' AND ' . EEM_Datetime::instance()->table() . ".DTT_EVT_end > '"
178
+						. current_time('mysql', true) . "' ";
179
+			}
180
+		}
181
+		return $SQL;
182
+	}
183
+
184
+
185
+	/**
186
+	 * @param string        $SQL
187
+	 * @param WP_Query|null $wp_query
188
+	 * @return string
189
+	 */
190
+	public function posts_orderby(string $SQL, ?WP_Query $wp_query): string
191
+	{
192
+		if (
193
+			$wp_query instanceof WP_Query
194
+			&& (
195
+				$wp_query->is_espresso_event_archive
196
+				|| $wp_query->is_espresso_event_taxonomy
197
+			)
198
+		) {
199
+			$SQL = ' event_start_date ASC ';
200
+		}
201
+		return $SQL;
202
+	}
203
+
204
+
205
+	/**
206
+	 * @param string        $SQL
207
+	 * @param WP_Query|null $wp_query
208
+	 * @return string
209
+	 */
210
+	public function posts_groupby(string $SQL, ?WP_Query $wp_query): string
211
+	{
212
+		if (
213
+			$wp_query instanceof WP_Query
214
+			&& (
215
+				$wp_query->is_espresso_event_archive
216
+				|| $wp_query->is_espresso_event_taxonomy
217
+			)
218
+		) {
219
+			// TODO: add event list option for displaying ALL datetimes in event list or only primary datetime (default)
220
+			// we're joining to the datetimes table, where there can be MANY datetimes for a single event,
221
+			// but we want to only show each event only once
222
+			// (whereas if we didn't group them by the post's ID, then we would end up with many repeats)
223
+			global $wpdb;
224
+			$SQL = $wpdb->posts . '.ID ';
225
+		}
226
+		return $SQL;
227
+	}
228
+
229
+
230
+	/**
231
+	 * @param array         $posts
232
+	 * @param WP_Query|null $wp_query
233
+	 * @return array
234
+	 */
235
+	public function the_posts(array $posts, ?WP_Query $wp_query): array
236
+	{
237
+		return $posts;
238
+	}
239
+
240
+
241
+	/**
242
+	 * @param mixed           $meta_value
243
+	 * @param int|string      $post_id
244
+	 * @param int|string      $meta_key
245
+	 * @param bool|int|string $single
246
+	 * @return mixed
247
+	 */
248
+	public function get_EE_post_type_metadata($meta_value, $post_id, $meta_key, $single)
249
+	{
250
+		return $meta_value;
251
+	}
252 252
 }
Please login to merge, or discard this patch.
core/services/address/CountrySubRegionDao.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
         $data = [];
81 81
         if (empty($this->countries)) {
82 82
             $this->data_version = $this->getCountrySubRegionDataVersion();
83
-            $data = $this->retrieveJsonData(self::REPO_URL . 'countries.json');
83
+            $data = $this->retrieveJsonData(self::REPO_URL.'countries.json');
84 84
         }
85 85
         if (empty($data)) {
86 86
             EE_Error::add_error(
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
      */
145 145
     private function processCountryData($CNT_ISO, $countries = array())
146 146
     {
147
-        if (! empty($countries)) {
147
+        if ( ! empty($countries)) {
148 148
             foreach ($countries as $key => $country) {
149 149
                 if (
150 150
                     $country instanceof stdClass
@@ -153,7 +153,7 @@  discard block
 block discarded – undo
153 153
                     && ! empty($country->filename)
154 154
                 ) {
155 155
                     $country->sub_regions = $this->retrieveJsonData(
156
-                        self::REPO_URL . 'countries/' . $country->filename . '.json'
156
+                        self::REPO_URL.'countries/'.$country->filename.'.json'
157 157
                     );
158 158
                     return $this->saveSubRegionData($country, $country->sub_regions);
159 159
                 }
@@ -215,7 +215,7 @@  discard block
 block discarded – undo
215 215
             foreach ($sub_regions as $sub_region) {
216 216
                 // remove country code from sub region code
217 217
                 $abbrev = str_replace(
218
-                    $country->code . '-',
218
+                    $country->code.'-',
219 219
                     '',
220 220
                     sanitize_text_field($sub_region->code)
221 221
                 );
Please login to merge, or discard this patch.
Indentation   +227 added lines, -227 removed lines patch added patch discarded remove patch
@@ -25,252 +25,252 @@
 block discarded – undo
25 25
  */
26 26
 class CountrySubRegionDao
27 27
 {
28
-    const REPO_URL = 'https://raw.githubusercontent.com/eventespresso/countries-and-subregions/master/';
28
+	const REPO_URL = 'https://raw.githubusercontent.com/eventespresso/countries-and-subregions/master/';
29 29
 
30
-    const OPTION_NAME_COUNTRY_DATA_VERSION = 'espresso-country-sub-region-data-version';
30
+	const OPTION_NAME_COUNTRY_DATA_VERSION = 'espresso-country-sub-region-data-version';
31 31
 
32
-    /**
33
-     * @var EEM_State $state_model
34
-     */
35
-    private $state_model;
32
+	/**
33
+	 * @var EEM_State $state_model
34
+	 */
35
+	private $state_model;
36 36
 
37
-    /**
38
-     * @var JsonValidator $json_validator
39
-     */
40
-    private $json_validator;
37
+	/**
38
+	 * @var JsonValidator $json_validator
39
+	 */
40
+	private $json_validator;
41 41
 
42
-    /**
43
-     * @var string $data_version
44
-     */
45
-    private $data_version;
42
+	/**
43
+	 * @var string $data_version
44
+	 */
45
+	private $data_version;
46 46
 
47
-    /**
48
-     * @var array $countries
49
-     */
50
-    private $countries = array();
47
+	/**
48
+	 * @var array $countries
49
+	 */
50
+	private $countries = array();
51 51
 
52 52
 
53
-    /**
54
-     * CountrySubRegionDao constructor.
55
-     *
56
-     * @param EEM_State     $state_model
57
-     * @param JsonValidator $json_validator
58
-     */
59
-    public function __construct(EEM_State $state_model, JsonValidator $json_validator)
60
-    {
61
-        $this->state_model = $state_model;
62
-        $this->json_validator = $json_validator;
63
-    }
53
+	/**
54
+	 * CountrySubRegionDao constructor.
55
+	 *
56
+	 * @param EEM_State     $state_model
57
+	 * @param JsonValidator $json_validator
58
+	 */
59
+	public function __construct(EEM_State $state_model, JsonValidator $json_validator)
60
+	{
61
+		$this->state_model = $state_model;
62
+		$this->json_validator = $json_validator;
63
+	}
64 64
 
65 65
 
66
-    /**
67
-     * @param EE_Country $country_object
68
-     * @return bool
69
-     * @throws EE_Error
70
-     * @throws InvalidArgumentException
71
-     * @throws InvalidDataTypeException
72
-     * @throws InvalidInterfaceException
73
-     * @throws ReflectionException
74
-     */
75
-    public function saveCountrySubRegions(EE_Country $country_object)
76
-    {
77
-        $CNT_ISO = $country_object->ID();
78
-        $has_sub_regions = $this->state_model->count(array(array('Country.CNT_ISO' => $CNT_ISO)));
79
-        $data = [];
80
-        if (empty($this->countries)) {
81
-            $this->data_version = $this->getCountrySubRegionDataVersion();
82
-            $data = $this->retrieveJsonData(self::REPO_URL . 'countries.json');
83
-        }
84
-        if (empty($data)) {
85
-            EE_Error::add_error(
86
-                'Country Subregion Data could not be retrieved',
87
-                __FILE__,
88
-                __METHOD__,
89
-                __LINE__
90
-            );
91
-        }
92
-        if (
93
-            ! $has_sub_regions
94
-            || (isset($data->version) && version_compare($data->version, $this->data_version))
95
-        ) {
96
-            if (
97
-                isset($data->countries)
98
-                && $this->processCountryData($CNT_ISO, $data->countries) > 0
99
-            ) {
100
-                $this->countries = $data->countries;
101
-                $this->updateCountrySubRegionDataVersion($data->version);
102
-                return true;
103
-            }
104
-        }
105
-        return false;
106
-    }
66
+	/**
67
+	 * @param EE_Country $country_object
68
+	 * @return bool
69
+	 * @throws EE_Error
70
+	 * @throws InvalidArgumentException
71
+	 * @throws InvalidDataTypeException
72
+	 * @throws InvalidInterfaceException
73
+	 * @throws ReflectionException
74
+	 */
75
+	public function saveCountrySubRegions(EE_Country $country_object)
76
+	{
77
+		$CNT_ISO = $country_object->ID();
78
+		$has_sub_regions = $this->state_model->count(array(array('Country.CNT_ISO' => $CNT_ISO)));
79
+		$data = [];
80
+		if (empty($this->countries)) {
81
+			$this->data_version = $this->getCountrySubRegionDataVersion();
82
+			$data = $this->retrieveJsonData(self::REPO_URL . 'countries.json');
83
+		}
84
+		if (empty($data)) {
85
+			EE_Error::add_error(
86
+				'Country Subregion Data could not be retrieved',
87
+				__FILE__,
88
+				__METHOD__,
89
+				__LINE__
90
+			);
91
+		}
92
+		if (
93
+			! $has_sub_regions
94
+			|| (isset($data->version) && version_compare($data->version, $this->data_version))
95
+		) {
96
+			if (
97
+				isset($data->countries)
98
+				&& $this->processCountryData($CNT_ISO, $data->countries) > 0
99
+			) {
100
+				$this->countries = $data->countries;
101
+				$this->updateCountrySubRegionDataVersion($data->version);
102
+				return true;
103
+			}
104
+		}
105
+		return false;
106
+	}
107 107
 
108 108
 
109
-    /**
110
-     * @since 4.9.70.p
111
-     * @return string
112
-     */
113
-    private function getCountrySubRegionDataVersion()
114
-    {
115
-        return get_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, null);
116
-    }
109
+	/**
110
+	 * @since 4.9.70.p
111
+	 * @return string
112
+	 */
113
+	private function getCountrySubRegionDataVersion()
114
+	{
115
+		return get_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, null);
116
+	}
117 117
 
118 118
 
119
-    /**
120
-     * @param string $version
121
-     */
122
-    private function updateCountrySubRegionDataVersion($version = '')
123
-    {
124
-        // add version option if it has never been added before, or update existing
125
-        if ($this->data_version === null) {
126
-            add_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version, '', false);
127
-        } else {
128
-            update_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version);
129
-        }
130
-    }
119
+	/**
120
+	 * @param string $version
121
+	 */
122
+	private function updateCountrySubRegionDataVersion($version = '')
123
+	{
124
+		// add version option if it has never been added before, or update existing
125
+		if ($this->data_version === null) {
126
+			add_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version, '', false);
127
+		} else {
128
+			update_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version);
129
+		}
130
+	}
131 131
 
132 132
 
133
-    /**
134
-     * @param string $CNT_ISO
135
-     * @param array  $countries
136
-     * @return int
137
-     * @throws EE_Error
138
-     * @throws InvalidArgumentException
139
-     * @throws InvalidDataTypeException
140
-     * @throws InvalidInterfaceException
141
-     * @throws ReflectionException
142
-     * @since 4.9.70.p
143
-     */
144
-    private function processCountryData($CNT_ISO, $countries = array())
145
-    {
146
-        if (! empty($countries)) {
147
-            foreach ($countries as $key => $country) {
148
-                if (
149
-                    $country instanceof stdClass
150
-                    && $country->code === $CNT_ISO
151
-                    && empty($country->sub_regions)
152
-                    && ! empty($country->filename)
153
-                ) {
154
-                    $country->sub_regions = $this->retrieveJsonData(
155
-                        self::REPO_URL . 'countries/' . $country->filename . '.json'
156
-                    );
157
-                    return $this->saveSubRegionData($country, $country->sub_regions);
158
-                }
159
-            }
160
-        }
161
-        return 0;
162
-    }
133
+	/**
134
+	 * @param string $CNT_ISO
135
+	 * @param array  $countries
136
+	 * @return int
137
+	 * @throws EE_Error
138
+	 * @throws InvalidArgumentException
139
+	 * @throws InvalidDataTypeException
140
+	 * @throws InvalidInterfaceException
141
+	 * @throws ReflectionException
142
+	 * @since 4.9.70.p
143
+	 */
144
+	private function processCountryData($CNT_ISO, $countries = array())
145
+	{
146
+		if (! empty($countries)) {
147
+			foreach ($countries as $key => $country) {
148
+				if (
149
+					$country instanceof stdClass
150
+					&& $country->code === $CNT_ISO
151
+					&& empty($country->sub_regions)
152
+					&& ! empty($country->filename)
153
+				) {
154
+					$country->sub_regions = $this->retrieveJsonData(
155
+						self::REPO_URL . 'countries/' . $country->filename . '.json'
156
+					);
157
+					return $this->saveSubRegionData($country, $country->sub_regions);
158
+				}
159
+			}
160
+		}
161
+		return 0;
162
+	}
163 163
 
164 164
 
165
-    /**
166
-     * @param string $url
167
-     * @return array
168
-     */
169
-    private function retrieveJsonData($url)
170
-    {
171
-        if (empty($url)) {
172
-            EE_Error::add_error(
173
-                'No URL was provided!',
174
-                __FILE__,
175
-                __METHOD__,
176
-                __LINE__
177
-            );
178
-            return array();
179
-        }
180
-        $request = wp_safe_remote_get($url);
181
-        if ($request instanceof WP_Error) {
182
-            EE_Error::add_error(
183
-                $request->get_error_message(),
184
-                __FILE__,
185
-                __METHOD__,
186
-                __LINE__
187
-            );
188
-            return array();
189
-        }
190
-        $body = wp_remote_retrieve_body($request);
191
-        $json = json_decode($body);
192
-        if ($this->json_validator->isValid(__FILE__, __METHOD__, __LINE__)) {
193
-            return $json;
194
-        }
195
-        return array();
196
-    }
165
+	/**
166
+	 * @param string $url
167
+	 * @return array
168
+	 */
169
+	private function retrieveJsonData($url)
170
+	{
171
+		if (empty($url)) {
172
+			EE_Error::add_error(
173
+				'No URL was provided!',
174
+				__FILE__,
175
+				__METHOD__,
176
+				__LINE__
177
+			);
178
+			return array();
179
+		}
180
+		$request = wp_safe_remote_get($url);
181
+		if ($request instanceof WP_Error) {
182
+			EE_Error::add_error(
183
+				$request->get_error_message(),
184
+				__FILE__,
185
+				__METHOD__,
186
+				__LINE__
187
+			);
188
+			return array();
189
+		}
190
+		$body = wp_remote_retrieve_body($request);
191
+		$json = json_decode($body);
192
+		if ($this->json_validator->isValid(__FILE__, __METHOD__, __LINE__)) {
193
+			return $json;
194
+		}
195
+		return array();
196
+	}
197 197
 
198 198
 
199
-    /**
200
-     * @param stdClass $country
201
-     * @param array    $sub_regions
202
-     * @return int
203
-     * @throws EE_Error
204
-     * @throws InvalidArgumentException
205
-     * @throws InvalidDataTypeException
206
-     * @throws InvalidInterfaceException
207
-     * @throws ReflectionException
208
-     */
209
-    private function saveSubRegionData(stdClass $country, $sub_regions = array())
210
-    {
211
-        $results = 0;
212
-        if (is_array($sub_regions)) {
213
-            $existing_sub_regions = $this->getExistingStateAbbreviations($country->code);
214
-            foreach ($sub_regions as $sub_region) {
215
-                // remove country code from sub region code
216
-                $abbrev = str_replace(
217
-                    $country->code . '-',
218
-                    '',
219
-                    sanitize_text_field($sub_region->code)
220
-                );
221
-                // but NOT if sub region code results in only a number
222
-                if (absint($abbrev) !== 0) {
223
-                    $abbrev = sanitize_text_field($sub_region->code);
224
-                }
225
-                if (
226
-                    ! in_array($abbrev, $existing_sub_regions, true)
227
-                    && $this->state_model->insert(
228
-                        [
229
-                            // STA_ID CNT_ISO STA_abbrev STA_name STA_active
230
-                            'CNT_ISO'    => $country->code,
231
-                            'STA_abbrev' => $abbrev,
232
-                            'STA_name'   => sanitize_text_field($sub_region->name),
233
-                            'STA_active' => 1,
234
-                        ]
235
-                    )
236
-                ) {
237
-                    $results++;
238
-                }
239
-            }
240
-        }
241
-        return $results;
242
-    }
199
+	/**
200
+	 * @param stdClass $country
201
+	 * @param array    $sub_regions
202
+	 * @return int
203
+	 * @throws EE_Error
204
+	 * @throws InvalidArgumentException
205
+	 * @throws InvalidDataTypeException
206
+	 * @throws InvalidInterfaceException
207
+	 * @throws ReflectionException
208
+	 */
209
+	private function saveSubRegionData(stdClass $country, $sub_regions = array())
210
+	{
211
+		$results = 0;
212
+		if (is_array($sub_regions)) {
213
+			$existing_sub_regions = $this->getExistingStateAbbreviations($country->code);
214
+			foreach ($sub_regions as $sub_region) {
215
+				// remove country code from sub region code
216
+				$abbrev = str_replace(
217
+					$country->code . '-',
218
+					'',
219
+					sanitize_text_field($sub_region->code)
220
+				);
221
+				// but NOT if sub region code results in only a number
222
+				if (absint($abbrev) !== 0) {
223
+					$abbrev = sanitize_text_field($sub_region->code);
224
+				}
225
+				if (
226
+					! in_array($abbrev, $existing_sub_regions, true)
227
+					&& $this->state_model->insert(
228
+						[
229
+							// STA_ID CNT_ISO STA_abbrev STA_name STA_active
230
+							'CNT_ISO'    => $country->code,
231
+							'STA_abbrev' => $abbrev,
232
+							'STA_name'   => sanitize_text_field($sub_region->name),
233
+							'STA_active' => 1,
234
+						]
235
+					)
236
+				) {
237
+					$results++;
238
+				}
239
+			}
240
+		}
241
+		return $results;
242
+	}
243 243
 
244 244
 
245
-    /**
246
-     * @param string $CNT_ISO
247
-     * @since 4.9.76.p
248
-     * @return array
249
-     * @throws EE_Error
250
-     * @throws InvalidArgumentException
251
-     * @throws InvalidDataTypeException
252
-     * @throws InvalidInterfaceException
253
-     * @throws ReflectionException
254
-     */
255
-    private function getExistingStateAbbreviations($CNT_ISO)
256
-    {
257
-        $existing_sub_region_IDs = [];
258
-        $existing_sub_regions = $this->state_model->get_all(array(
259
-            array(
260
-                'Country.CNT_ISO' => array(
261
-                    'IN',
262
-                    [$CNT_ISO]
263
-                )
264
-            ),
265
-            'order_by' => array('Country.CNT_name' => 'ASC', 'STA_name' => 'ASC')
266
-        ));
267
-        if (is_array($existing_sub_regions)) {
268
-            foreach ($existing_sub_regions as $existing_sub_region) {
269
-                if ($existing_sub_region instanceof EE_State) {
270
-                    $existing_sub_region_IDs[] = $existing_sub_region->abbrev();
271
-                }
272
-            }
273
-        }
274
-        return $existing_sub_region_IDs;
275
-    }
245
+	/**
246
+	 * @param string $CNT_ISO
247
+	 * @since 4.9.76.p
248
+	 * @return array
249
+	 * @throws EE_Error
250
+	 * @throws InvalidArgumentException
251
+	 * @throws InvalidDataTypeException
252
+	 * @throws InvalidInterfaceException
253
+	 * @throws ReflectionException
254
+	 */
255
+	private function getExistingStateAbbreviations($CNT_ISO)
256
+	{
257
+		$existing_sub_region_IDs = [];
258
+		$existing_sub_regions = $this->state_model->get_all(array(
259
+			array(
260
+				'Country.CNT_ISO' => array(
261
+					'IN',
262
+					[$CNT_ISO]
263
+				)
264
+			),
265
+			'order_by' => array('Country.CNT_name' => 'ASC', 'STA_name' => 'ASC')
266
+		));
267
+		if (is_array($existing_sub_regions)) {
268
+			foreach ($existing_sub_regions as $existing_sub_region) {
269
+				if ($existing_sub_region instanceof EE_State) {
270
+					$existing_sub_region_IDs[] = $existing_sub_region->abbrev();
271
+				}
272
+			}
273
+		}
274
+		return $existing_sub_region_IDs;
275
+	}
276 276
 }
Please login to merge, or discard this patch.
core/services/payment_methods/forms/PayPalSettingsForm.php 1 patch
Indentation   +191 added lines, -191 removed lines patch added patch discarded remove patch
@@ -20,202 +20,202 @@
 block discarded – undo
20 20
  */
21 21
 class PayPalSettingsForm extends EE_Payment_Method_Form
22 22
 {
23
-    /**
24
-     * @var string of HTML being the help tab link
25
-     */
26
-    protected $helpTabLink;
23
+	/**
24
+	 * @var string of HTML being the help tab link
25
+	 */
26
+	protected $helpTabLink;
27 27
 
28
-    public function __construct(array $options_array = array(), $help_tab_link = '')
29
-    {
30
-        $this->helpTabLink = $help_tab_link;
31
-        $options_array = array_replace_recursive(
32
-            array(
33
-                'extra_meta_inputs' => array(
34
-                    'api_username' => new EE_Text_Input(
35
-                        array(
36
-                            'html_label_text' => sprintf(
37
-                                // translators: %s link to help doc
38
-                                esc_html__('API Username %s', 'event_espresso'),
39
-                                $help_tab_link
40
-                            ),
41
-                            'required'        => true,
42
-                        )
43
-                    ),
44
-                    'api_password' => new EE_Text_Input(
45
-                        array(
46
-                            'html_label_text' => sprintf(
47
-                                // translators: %s link to help doc
48
-                                esc_html__('API Password %s', 'event_espresso'),
49
-                                $help_tab_link
50
-                            ),
51
-                            'required'        => true,
52
-                        )
53
-                    ),
54
-                    'api_signature' => new EE_Text_Input(
55
-                        array(
56
-                            'html_label_text' => sprintf(
57
-                                // translators: %s link to help doc
58
-                                esc_html__('API Signature %s', 'event_espresso'),
59
-                                $help_tab_link
60
-                            ),
61
-                            'required'        => true,
62
-                        )
63
-                    ),
64
-                )
65
-            ),
66
-            $options_array
67
-        );
68
-        parent::__construct($options_array);
69
-    }
28
+	public function __construct(array $options_array = array(), $help_tab_link = '')
29
+	{
30
+		$this->helpTabLink = $help_tab_link;
31
+		$options_array = array_replace_recursive(
32
+			array(
33
+				'extra_meta_inputs' => array(
34
+					'api_username' => new EE_Text_Input(
35
+						array(
36
+							'html_label_text' => sprintf(
37
+								// translators: %s link to help doc
38
+								esc_html__('API Username %s', 'event_espresso'),
39
+								$help_tab_link
40
+							),
41
+							'required'        => true,
42
+						)
43
+					),
44
+					'api_password' => new EE_Text_Input(
45
+						array(
46
+							'html_label_text' => sprintf(
47
+								// translators: %s link to help doc
48
+								esc_html__('API Password %s', 'event_espresso'),
49
+								$help_tab_link
50
+							),
51
+							'required'        => true,
52
+						)
53
+					),
54
+					'api_signature' => new EE_Text_Input(
55
+						array(
56
+							'html_label_text' => sprintf(
57
+								// translators: %s link to help doc
58
+								esc_html__('API Signature %s', 'event_espresso'),
59
+								$help_tab_link
60
+							),
61
+							'required'        => true,
62
+						)
63
+					),
64
+				)
65
+			),
66
+			$options_array
67
+		);
68
+		parent::__construct($options_array);
69
+	}
70 70
 
71
-    /**
72
-     * Tests the the PayPal API credentials work ok
73
-     * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string
74
-     * @throws EE_Error
75
-     */
76
-    protected function checkForCredentialsErrors()
77
-    {
78
-        $request_params = array(
79
-            'METHOD'    => 'GetBalance',
80
-            'VERSION'   => '204.0',
81
-            'USER'      => $this->get_input_value('api_username'),
82
-            'PWD'       => $this->get_input_value('api_password'),
83
-            'SIGNATURE' => $this->get_input_value('api_signature'),
84
-        );
85
-        $gateway_url = $this->get_input_value('PMD_debug_mode')
86
-            ? 'https://api-3t.sandbox.paypal.com/nvp'
87
-            : 'https://api-3t.paypal.com/nvp';
88
-        // Request Customer Details.
89
-        $response = wp_remote_post(
90
-            $gateway_url,
91
-            array(
92
-                'method'      => 'POST',
93
-                'timeout'     => 45,
94
-                'httpversion' => '1.1',
95
-                'cookies'     => array(),
96
-                'headers'     => array(),
97
-                'body'        => http_build_query($request_params, '', '&'),
98
-            )
99
-        );
100
-        if (is_wp_error($response) || empty($response['body'])) {
101
-            // If we got here then there was an error in this request.
102
-            // maybe is turned off. We don't know the credentials are invalid
103
-            EE_Error::add_error(
104
-                sprintf(
105
-                    // translators: %1$s Error message received from PayPal
106
-                    esc_html__(
107
-                        // @codingStandardsIgnoreStart
108
-                        'Your PayPal credentials could not be verified. The following error occurred while communicating with PayPal: %1$s',
109
-                        // @codingStandardsIgnoreEnd
110
-                        'event_espresso'
111
-                    ),
112
-                    $response->get_error_message()
113
-                ),
114
-                __FILE__,
115
-                __FUNCTION__,
116
-                __LINE__
117
-            );
118
-        }
119
-        $response_args = array();
120
-        parse_str(urldecode($response['body']), $response_args);
71
+	/**
72
+	 * Tests the the PayPal API credentials work ok
73
+	 * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string
74
+	 * @throws EE_Error
75
+	 */
76
+	protected function checkForCredentialsErrors()
77
+	{
78
+		$request_params = array(
79
+			'METHOD'    => 'GetBalance',
80
+			'VERSION'   => '204.0',
81
+			'USER'      => $this->get_input_value('api_username'),
82
+			'PWD'       => $this->get_input_value('api_password'),
83
+			'SIGNATURE' => $this->get_input_value('api_signature'),
84
+		);
85
+		$gateway_url = $this->get_input_value('PMD_debug_mode')
86
+			? 'https://api-3t.sandbox.paypal.com/nvp'
87
+			: 'https://api-3t.paypal.com/nvp';
88
+		// Request Customer Details.
89
+		$response = wp_remote_post(
90
+			$gateway_url,
91
+			array(
92
+				'method'      => 'POST',
93
+				'timeout'     => 45,
94
+				'httpversion' => '1.1',
95
+				'cookies'     => array(),
96
+				'headers'     => array(),
97
+				'body'        => http_build_query($request_params, '', '&'),
98
+			)
99
+		);
100
+		if (is_wp_error($response) || empty($response['body'])) {
101
+			// If we got here then there was an error in this request.
102
+			// maybe is turned off. We don't know the credentials are invalid
103
+			EE_Error::add_error(
104
+				sprintf(
105
+					// translators: %1$s Error message received from PayPal
106
+					esc_html__(
107
+						// @codingStandardsIgnoreStart
108
+						'Your PayPal credentials could not be verified. The following error occurred while communicating with PayPal: %1$s',
109
+						// @codingStandardsIgnoreEnd
110
+						'event_espresso'
111
+					),
112
+					$response->get_error_message()
113
+				),
114
+				__FILE__,
115
+				__FUNCTION__,
116
+				__LINE__
117
+			);
118
+		}
119
+		$response_args = array();
120
+		parse_str(urldecode($response['body']), $response_args);
121 121
 
122
-        if (empty($response_args['ACK'])) {
123
-            EE_Error::add_error(
124
-                esc_html__(
125
-                    'Your PayPal credentials could not be verified. Part of their response was missing.',
126
-                    'event_espresso'
127
-                ),
128
-                __FILE__,
129
-                __FUNCTION__,
130
-                __LINE__
131
-            );
132
-        }
133
-        if (
134
-            in_array(
135
-                $response_args['ACK'],
136
-                array(
137
-                'Success',
138
-                'SuccessWithWarning'
139
-                ),
140
-                true
141
-            )
142
-        ) {
143
-            return '';
144
-        } else {
145
-            return sprintf(
146
-                // translators: %1$s: PayPal response message, %2$s: PayPal response code
147
-                esc_html__(
148
-                    // @codingStandardsIgnoreStart
149
-                    'Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.',
150
-                    // @codingStandardsIgnoreEnd
151
-                    'event_espresso'
152
-                ),
153
-                isset($response_args['L_LONGMESSAGE0'])
154
-                    ? $response_args['L_LONGMESSAGE0']
155
-                    : esc_html__('No error message received from PayPal', 'event_espresso'),
156
-                isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0
157
-            );
158
-        }
159
-    }
122
+		if (empty($response_args['ACK'])) {
123
+			EE_Error::add_error(
124
+				esc_html__(
125
+					'Your PayPal credentials could not be verified. Part of their response was missing.',
126
+					'event_espresso'
127
+				),
128
+				__FILE__,
129
+				__FUNCTION__,
130
+				__LINE__
131
+			);
132
+		}
133
+		if (
134
+			in_array(
135
+				$response_args['ACK'],
136
+				array(
137
+				'Success',
138
+				'SuccessWithWarning'
139
+				),
140
+				true
141
+			)
142
+		) {
143
+			return '';
144
+		} else {
145
+			return sprintf(
146
+				// translators: %1$s: PayPal response message, %2$s: PayPal response code
147
+				esc_html__(
148
+					// @codingStandardsIgnoreStart
149
+					'Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.',
150
+					// @codingStandardsIgnoreEnd
151
+					'event_espresso'
152
+				),
153
+				isset($response_args['L_LONGMESSAGE0'])
154
+					? $response_args['L_LONGMESSAGE0']
155
+					: esc_html__('No error message received from PayPal', 'event_espresso'),
156
+				isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0
157
+			);
158
+		}
159
+	}
160 160
 
161
-    /**
162
-     * Gets the HTML to show the link to the help tab
163
-     * @return string
164
-     */
165
-    protected function helpTabLink()
166
-    {
167
-        return $this->helpTabLink;
168
-    }
161
+	/**
162
+	 * Gets the HTML to show the link to the help tab
163
+	 * @return string
164
+	 */
165
+	protected function helpTabLink()
166
+	{
167
+		return $this->helpTabLink;
168
+	}
169 169
 
170
-    /**
171
-     * Does the normal validation, but also verifies the PayPal API credentials work.
172
-     * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more
173
-     * tips) on each of the inputs that could be the cause of the problem.
174
-     * @throws EE_Error
175
-     */
176
-    public function _validate()
177
-    {
178
-        parent::_validate();
179
-        $credentials_message = $this->checkForCredentialsErrors();
180
-        if ($credentials_message !== '') {
181
-            $this->add_validation_error($credentials_message);
182
-            $this->get_input('PMD_debug_mode')->add_validation_error(
183
-                esc_html__(
184
-                    // @codingStandardsIgnoreStart
185
-                    'If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".',
186
-                    // @codingStandardsIgnoreEnd
187
-                    'event_espresso'
188
-                )
189
-            );
190
-            $this->get_input('api_username')->add_validation_error(
191
-                sprintf(
192
-                    // translators: $1$s HTML for a link to the help tab
193
-                    esc_html__(
194
-                        'Are you sure this is your API username, not your login username? %1$s',
195
-                        'event_espresso'
196
-                    ),
197
-                    $this->helpTabLink()
198
-                )
199
-            );
200
-            $this->get_input('api_password')->add_validation_error(
201
-                sprintf(
202
-                    // translators: $1$s HTML for a link to the help tab
203
-                    esc_html__(
204
-                        'Are you sure this is your API password, not your login password? %1$s',
205
-                        'event_espresso'
206
-                    ),
207
-                    $this->helpTabLink()
208
-                )
209
-            );
210
-            $this->get_input('api_signature')->add_validation_error(
211
-                sprintf(
212
-                    // translators: $1$s HTML for a link to the help tab
213
-                    esc_html__('Please verify your API signature is correct. %1$s', 'event_espresso'),
214
-                    $this->helpTabLink()
215
-                )
216
-            );
217
-        }
218
-    }
170
+	/**
171
+	 * Does the normal validation, but also verifies the PayPal API credentials work.
172
+	 * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more
173
+	 * tips) on each of the inputs that could be the cause of the problem.
174
+	 * @throws EE_Error
175
+	 */
176
+	public function _validate()
177
+	{
178
+		parent::_validate();
179
+		$credentials_message = $this->checkForCredentialsErrors();
180
+		if ($credentials_message !== '') {
181
+			$this->add_validation_error($credentials_message);
182
+			$this->get_input('PMD_debug_mode')->add_validation_error(
183
+				esc_html__(
184
+					// @codingStandardsIgnoreStart
185
+					'If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".',
186
+					// @codingStandardsIgnoreEnd
187
+					'event_espresso'
188
+				)
189
+			);
190
+			$this->get_input('api_username')->add_validation_error(
191
+				sprintf(
192
+					// translators: $1$s HTML for a link to the help tab
193
+					esc_html__(
194
+						'Are you sure this is your API username, not your login username? %1$s',
195
+						'event_espresso'
196
+					),
197
+					$this->helpTabLink()
198
+				)
199
+			);
200
+			$this->get_input('api_password')->add_validation_error(
201
+				sprintf(
202
+					// translators: $1$s HTML for a link to the help tab
203
+					esc_html__(
204
+						'Are you sure this is your API password, not your login password? %1$s',
205
+						'event_espresso'
206
+					),
207
+					$this->helpTabLink()
208
+				)
209
+			);
210
+			$this->get_input('api_signature')->add_validation_error(
211
+				sprintf(
212
+					// translators: $1$s HTML for a link to the help tab
213
+					esc_html__('Please verify your API signature is correct. %1$s', 'event_espresso'),
214
+					$this->helpTabLink()
215
+				)
216
+			);
217
+		}
218
+	}
219 219
 }
220 220
 // End of file PayPalSettingsForm.php
221 221
 // Location: ${NAMESPACE}/PayPalSettingsForm.php
Please login to merge, or discard this patch.
core/services/collections/CollectionDetails.php 2 patches
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
      */
194 194
     protected function setCollectionInterface($collection_interface)
195 195
     {
196
-        if (! (interface_exists($collection_interface) || class_exists($collection_interface))) {
196
+        if ( ! (interface_exists($collection_interface) || class_exists($collection_interface))) {
197 197
             throw new InvalidInterfaceException($collection_interface);
198 198
         }
199 199
         $this->collection_interface = $collection_interface;
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
      */
222 222
     protected function setCollectionName($collection_name)
223 223
     {
224
-        if (! is_string($collection_name)) {
224
+        if ( ! is_string($collection_name)) {
225 225
             throw new InvalidDataTypeException('$collection_name', $collection_name, 'string');
226 226
         }
227 227
         $this->collection_name = str_replace(
@@ -281,7 +281,7 @@  discard block
 block discarded – undo
281 281
      */
282 282
     protected function setIdentifierCallback($identifier_callback = 'identifier')
283 283
     {
284
-        if (! is_string($identifier_callback)) {
284
+        if ( ! is_string($identifier_callback)) {
285 285
             throw new InvalidDataTypeException('$identifier_callback', $identifier_callback, 'string');
286 286
         }
287 287
         $this->identifier_callback = $identifier_callback;
@@ -311,7 +311,7 @@  discard block
 block discarded – undo
311 311
         $this->file_mask = ! empty($file_mask) ? $file_mask : '*.php';
312 312
         // we know our default is a string, so if it's not a string now,
313 313
         // then that means the incoming parameter was something else
314
-        if (! is_string($this->file_mask)) {
314
+        if ( ! is_string($this->file_mask)) {
315 315
             throw new InvalidDataTypeException('$file_mask', $this->file_mask, 'string');
316 316
         }
317 317
     }
@@ -336,7 +336,7 @@  discard block
 block discarded – undo
336 336
     public function setCollectionFQCNs($collection_FQCNs)
337 337
     {
338 338
         foreach ((array) $collection_FQCNs as $collection_FQCN) {
339
-            if (! empty($collection_FQCN)) {
339
+            if ( ! empty($collection_FQCN)) {
340 340
                 if (class_exists($collection_FQCN)) {
341 341
                     $this->collection_FQCNs[] = $collection_FQCN;
342 342
                 } else {
@@ -358,7 +358,7 @@  discard block
 block discarded – undo
358 358
      */
359 359
     protected function getFQCNsFromPartialNamespace($partial_FQCN)
360 360
     {
361
-        if (! $this->file_locator instanceof FqcnLocator) {
361
+        if ( ! $this->file_locator instanceof FqcnLocator) {
362 362
             $this->file_locator = new FqcnLocator();
363 363
         }
364 364
         $this->file_locator->locate($partial_FQCN);
@@ -384,8 +384,8 @@  discard block
 block discarded – undo
384 384
     public function setCollectionPaths($collection_paths)
385 385
     {
386 386
         foreach ((array) $collection_paths as $collection_path) {
387
-            if (! empty($collection_path)) {
388
-                if (! is_readable($collection_path)) {
387
+            if ( ! empty($collection_path)) {
388
+                if ( ! is_readable($collection_path)) {
389 389
                     throw new InvalidFilePathException($collection_path);
390 390
                 }
391 391
                 $this->collection_paths[] = $collection_path;
Please login to merge, or discard this patch.
Indentation   +349 added lines, -349 removed lines patch added patch discarded remove patch
@@ -42,353 +42,353 @@
 block discarded – undo
42 42
  */
43 43
 class CollectionDetails implements CollectionDetailsInterface
44 44
 {
45
-    /**
46
-     * if $identifier_type is set to this,
47
-     * then the collection will use each object's spl_object_hash() as it's identifier
48
-     */
49
-    const ID_OBJECT_HASH = 'identifier-uses-spl-object-hash';
50
-
51
-    /**
52
-     * if $identifier_type is set to this,
53
-     * then the collection will use each object's class name as it's identifier
54
-     */
55
-    const ID_CLASS_NAME = 'identifier-uses-object-class-name';
56
-
57
-    /**
58
-     * if $identifier_type is set to this,
59
-     * then the collection will use the return value from a specified callback method on each object
60
-     */
61
-    const ID_CALLBACK_METHOD = 'identifier-uses-callback-method';
62
-
63
-    /**
64
-     * The interface used for controlling what gets added to the collection
65
-     *
66
-     * @var string $collection_interface
67
-     */
68
-    protected $collection_interface = '';
69
-
70
-    /**
71
-     * a unique name used to identify the collection in filter names
72
-     * supplied value is run through sanitize_title_with_dashes(),
73
-     * but then also converts dashes to underscores
74
-     *
75
-     * @var string $collection_name
76
-     */
77
-    protected $collection_name = '';
78
-
79
-    /**
80
-     * what the collection uses for the object identifier.
81
-     * corresponds to one of the class constants above.
82
-     * CollectionDetails::ID_OBJECT_HASH will use spl_object_hash( object ) for the identifier
83
-     * CollectionDetails::ID_CLASS_NAME will use get_class( object ) for the identifier
84
-     * CollectionDetails::ID_CALLBACK_METHOD will use a callback for the identifier
85
-     * defaults to using spl_object_hash() so that multiple objects of the same class can be added
86
-     *
87
-     * @var string $identifier_type
88
-     */
89
-    protected $identifier_type = CollectionDetails::ID_OBJECT_HASH;
90
-
91
-    /**
92
-     * the pattern applied to paths when searching for class files to add to the collection
93
-     * ie: "My_Awesome_*.class.php"
94
-     * defaults to "*.php"
95
-     *
96
-     * @var string $file_mask
97
-     */
98
-    protected $file_mask = '';
99
-
100
-    /**
101
-     * if the $identifier_type above is set to CollectionDetails::ID_CALLBACK_METHOD,
102
-     * then this specifies the method to use on each entity.
103
-     * If the callback method does not exist, then an exception will be thrown
104
-     *
105
-     * @var string $identifier_callback
106
-     */
107
-    protected $identifier_callback = '';
108
-
109
-    /**
110
-     * an array of Fully Qualified Class Names
111
-     *  for example:
112
-     *  $FQCNs = array(
113
-     *      '/Fully/Qualified/ClassNameA'
114
-     *      '/Fully/Qualified/Other/ClassNameB'
115
-     *  );
116
-     *
117
-     * @var array $collection_FQCNs
118
-     */
119
-    protected $collection_FQCNs = array();
120
-
121
-    /**
122
-     * an array of full server paths to folders containing files to be loaded into collection
123
-     *  for example:
124
-     *  $paths = array(
125
-     *      '/full/server/path/to/ClassNameA.ext.php' // for class ClassNameA
126
-     *      '/full/server/path/to/other/ClassNameB.php' // for class ClassNameB
127
-     *  );
128
-     *
129
-     * @var array $collection_paths
130
-     */
131
-    protected $collection_paths = array();
132
-
133
-    /**
134
-     * @var LocatorInterface $file_locator
135
-     */
136
-    protected $file_locator;
137
-
138
-
139
-    /**
140
-     * CollectionDetails constructor.
141
-     *
142
-     * @access public
143
-     * @param string           $collection_name
144
-     * @param string           $collection_interface
145
-     * @param array            $collection_FQCNs
146
-     * @param array            $collection_paths
147
-     * @param string           $file_mask
148
-     * @param string           $identifier_type
149
-     * @param string           $identifier_callback
150
-     * @param LocatorInterface $file_locator
151
-     * @throws CollectionDetailsException
152
-     */
153
-    public function __construct(
154
-        $collection_name,
155
-        $collection_interface,
156
-        array $collection_FQCNs = array(),
157
-        array $collection_paths = array(),
158
-        $file_mask = '',
159
-        $identifier_type = CollectionDetails::ID_OBJECT_HASH,
160
-        $identifier_callback = '',
161
-        LocatorInterface $file_locator = null
162
-    ) {
163
-        try {
164
-            $this->setCollectionName($collection_name);
165
-            $this->setCollectionInterface($collection_interface);
166
-            $this->setCollectionFQCNs($collection_FQCNs);
167
-            $this->setCollectionPaths($collection_paths);
168
-            $this->setFileMasks($file_mask);
169
-            $this->setIdentifierType($identifier_type);
170
-            $this->setIdentifierCallback($identifier_callback);
171
-            $this->file_locator = $file_locator;
172
-        } catch (Exception $exception) {
173
-            throw new CollectionDetailsException($exception);
174
-        }
175
-    }
176
-
177
-
178
-    /**
179
-     * @access public
180
-     * @return mixed
181
-     */
182
-    public function getCollectionInterface()
183
-    {
184
-        return $this->collection_interface;
185
-    }
186
-
187
-
188
-    /**
189
-     * @access protected
190
-     * @param string $collection_interface
191
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
192
-     */
193
-    protected function setCollectionInterface($collection_interface)
194
-    {
195
-        if (! (interface_exists($collection_interface) || class_exists($collection_interface))) {
196
-            throw new InvalidInterfaceException($collection_interface);
197
-        }
198
-        $this->collection_interface = $collection_interface;
199
-    }
200
-
201
-
202
-    /**
203
-     * the collection name will be used for creating dynamic filters
204
-     *
205
-     * @access public
206
-     * @return string
207
-     */
208
-    public function collectionName()
209
-    {
210
-        return $this->collection_name;
211
-    }
212
-
213
-
214
-    /**
215
-     * sanitizes collection name and converts spaces and dashes to underscores
216
-     *
217
-     * @access protected
218
-     * @param string $collection_name
219
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
220
-     */
221
-    protected function setCollectionName($collection_name)
222
-    {
223
-        if (! is_string($collection_name)) {
224
-            throw new InvalidDataTypeException('$collection_name', $collection_name, 'string');
225
-        }
226
-        $this->collection_name = str_replace(
227
-            '-',
228
-            '_',
229
-            sanitize_title_with_dashes($collection_name, '', 'save')
230
-        );
231
-    }
232
-
233
-
234
-    /**
235
-     * @access public
236
-     * @return string
237
-     */
238
-    public function identifierType()
239
-    {
240
-        return $this->identifier_type;
241
-    }
242
-
243
-
244
-    /**
245
-     * @access protected
246
-     * @param string $identifier_type
247
-     * @throws InvalidIdentifierException
248
-     */
249
-    protected function setIdentifierType($identifier_type)
250
-    {
251
-        if (
252
-            ! ($identifier_type === CollectionDetails::ID_CLASS_NAME
253
-               || $identifier_type === CollectionDetails::ID_OBJECT_HASH
254
-               || $identifier_type === CollectionDetails::ID_CALLBACK_METHOD
255
-            )
256
-        ) {
257
-            throw new InvalidIdentifierException(
258
-                $identifier_type,
259
-                'CollectionDetails::ID_CLASS_NAME or CollectionDetails::ID_OBJECT_HASH or CollectionDetails::ID_CALLBACK_METHOD'
260
-            );
261
-        }
262
-        $this->identifier_type = $identifier_type;
263
-    }
264
-
265
-
266
-    /**
267
-     * @access public
268
-     * @return string
269
-     */
270
-    public function identifierCallback()
271
-    {
272
-        return $this->identifier_callback;
273
-    }
274
-
275
-
276
-    /**
277
-     * @access protected
278
-     * @param string $identifier_callback
279
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
280
-     */
281
-    protected function setIdentifierCallback($identifier_callback = 'identifier')
282
-    {
283
-        if (! is_string($identifier_callback)) {
284
-            throw new InvalidDataTypeException('$identifier_callback', $identifier_callback, 'string');
285
-        }
286
-        $this->identifier_callback = $identifier_callback;
287
-    }
288
-
289
-
290
-    /**
291
-     * @access public
292
-     * @return string
293
-     */
294
-    public function getFileMask()
295
-    {
296
-        return $this->file_mask;
297
-    }
298
-
299
-
300
-    /**
301
-     * sets the file mask which is then used to filter what files get loaded
302
-     * when searching for classes to add to the collection. Defaults to '*.php'
303
-     *
304
-     * @access protected
305
-     * @param string $file_mask
306
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
307
-     */
308
-    protected function setFileMasks($file_mask)
309
-    {
310
-        $this->file_mask = ! empty($file_mask) ? $file_mask : '*.php';
311
-        // we know our default is a string, so if it's not a string now,
312
-        // then that means the incoming parameter was something else
313
-        if (! is_string($this->file_mask)) {
314
-            throw new InvalidDataTypeException('$file_mask', $this->file_mask, 'string');
315
-        }
316
-    }
317
-
318
-
319
-    /**
320
-     * @access public
321
-     * @return array
322
-     */
323
-    public function getCollectionFQCNs()
324
-    {
325
-        return $this->collection_FQCNs;
326
-    }
327
-
328
-
329
-    /**
330
-     * @access public
331
-     * @param string|array $collection_FQCNs
332
-     * @throws \EventEspresso\core\exceptions\InvalidClassException
333
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
334
-     */
335
-    public function setCollectionFQCNs($collection_FQCNs)
336
-    {
337
-        foreach ((array) $collection_FQCNs as $collection_FQCN) {
338
-            if (! empty($collection_FQCN)) {
339
-                if (class_exists($collection_FQCN)) {
340
-                    $this->collection_FQCNs[] = $collection_FQCN;
341
-                } else {
342
-                    foreach ($this->getFQCNsFromPartialNamespace($collection_FQCN) as $FQCN) {
343
-                        $this->collection_FQCNs[] = $FQCN;
344
-                    }
345
-                }
346
-            }
347
-        }
348
-    }
349
-
350
-
351
-    /**
352
-     * @access protected
353
-     * @param  string $partial_FQCN
354
-     * @return array
355
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
356
-     * @throws \EventEspresso\core\exceptions\InvalidClassException
357
-     */
358
-    protected function getFQCNsFromPartialNamespace($partial_FQCN)
359
-    {
360
-        if (! $this->file_locator instanceof FqcnLocator) {
361
-            $this->file_locator = new FqcnLocator();
362
-        }
363
-        $this->file_locator->locate($partial_FQCN);
364
-        return $this->file_locator->getFQCNs();
365
-    }
366
-
367
-
368
-    /**
369
-     * @access public
370
-     * @return array
371
-     */
372
-    public function getCollectionPaths()
373
-    {
374
-        return $this->collection_paths;
375
-    }
376
-
377
-
378
-    /**
379
-     * @access public
380
-     * @param string|array $collection_paths
381
-     * @throws \EventEspresso\core\exceptions\InvalidFilePathException
382
-     */
383
-    public function setCollectionPaths($collection_paths)
384
-    {
385
-        foreach ((array) $collection_paths as $collection_path) {
386
-            if (! empty($collection_path)) {
387
-                if (! is_readable($collection_path)) {
388
-                    throw new InvalidFilePathException($collection_path);
389
-                }
390
-                $this->collection_paths[] = $collection_path;
391
-            }
392
-        }
393
-    }
45
+	/**
46
+	 * if $identifier_type is set to this,
47
+	 * then the collection will use each object's spl_object_hash() as it's identifier
48
+	 */
49
+	const ID_OBJECT_HASH = 'identifier-uses-spl-object-hash';
50
+
51
+	/**
52
+	 * if $identifier_type is set to this,
53
+	 * then the collection will use each object's class name as it's identifier
54
+	 */
55
+	const ID_CLASS_NAME = 'identifier-uses-object-class-name';
56
+
57
+	/**
58
+	 * if $identifier_type is set to this,
59
+	 * then the collection will use the return value from a specified callback method on each object
60
+	 */
61
+	const ID_CALLBACK_METHOD = 'identifier-uses-callback-method';
62
+
63
+	/**
64
+	 * The interface used for controlling what gets added to the collection
65
+	 *
66
+	 * @var string $collection_interface
67
+	 */
68
+	protected $collection_interface = '';
69
+
70
+	/**
71
+	 * a unique name used to identify the collection in filter names
72
+	 * supplied value is run through sanitize_title_with_dashes(),
73
+	 * but then also converts dashes to underscores
74
+	 *
75
+	 * @var string $collection_name
76
+	 */
77
+	protected $collection_name = '';
78
+
79
+	/**
80
+	 * what the collection uses for the object identifier.
81
+	 * corresponds to one of the class constants above.
82
+	 * CollectionDetails::ID_OBJECT_HASH will use spl_object_hash( object ) for the identifier
83
+	 * CollectionDetails::ID_CLASS_NAME will use get_class( object ) for the identifier
84
+	 * CollectionDetails::ID_CALLBACK_METHOD will use a callback for the identifier
85
+	 * defaults to using spl_object_hash() so that multiple objects of the same class can be added
86
+	 *
87
+	 * @var string $identifier_type
88
+	 */
89
+	protected $identifier_type = CollectionDetails::ID_OBJECT_HASH;
90
+
91
+	/**
92
+	 * the pattern applied to paths when searching for class files to add to the collection
93
+	 * ie: "My_Awesome_*.class.php"
94
+	 * defaults to "*.php"
95
+	 *
96
+	 * @var string $file_mask
97
+	 */
98
+	protected $file_mask = '';
99
+
100
+	/**
101
+	 * if the $identifier_type above is set to CollectionDetails::ID_CALLBACK_METHOD,
102
+	 * then this specifies the method to use on each entity.
103
+	 * If the callback method does not exist, then an exception will be thrown
104
+	 *
105
+	 * @var string $identifier_callback
106
+	 */
107
+	protected $identifier_callback = '';
108
+
109
+	/**
110
+	 * an array of Fully Qualified Class Names
111
+	 *  for example:
112
+	 *  $FQCNs = array(
113
+	 *      '/Fully/Qualified/ClassNameA'
114
+	 *      '/Fully/Qualified/Other/ClassNameB'
115
+	 *  );
116
+	 *
117
+	 * @var array $collection_FQCNs
118
+	 */
119
+	protected $collection_FQCNs = array();
120
+
121
+	/**
122
+	 * an array of full server paths to folders containing files to be loaded into collection
123
+	 *  for example:
124
+	 *  $paths = array(
125
+	 *      '/full/server/path/to/ClassNameA.ext.php' // for class ClassNameA
126
+	 *      '/full/server/path/to/other/ClassNameB.php' // for class ClassNameB
127
+	 *  );
128
+	 *
129
+	 * @var array $collection_paths
130
+	 */
131
+	protected $collection_paths = array();
132
+
133
+	/**
134
+	 * @var LocatorInterface $file_locator
135
+	 */
136
+	protected $file_locator;
137
+
138
+
139
+	/**
140
+	 * CollectionDetails constructor.
141
+	 *
142
+	 * @access public
143
+	 * @param string           $collection_name
144
+	 * @param string           $collection_interface
145
+	 * @param array            $collection_FQCNs
146
+	 * @param array            $collection_paths
147
+	 * @param string           $file_mask
148
+	 * @param string           $identifier_type
149
+	 * @param string           $identifier_callback
150
+	 * @param LocatorInterface $file_locator
151
+	 * @throws CollectionDetailsException
152
+	 */
153
+	public function __construct(
154
+		$collection_name,
155
+		$collection_interface,
156
+		array $collection_FQCNs = array(),
157
+		array $collection_paths = array(),
158
+		$file_mask = '',
159
+		$identifier_type = CollectionDetails::ID_OBJECT_HASH,
160
+		$identifier_callback = '',
161
+		LocatorInterface $file_locator = null
162
+	) {
163
+		try {
164
+			$this->setCollectionName($collection_name);
165
+			$this->setCollectionInterface($collection_interface);
166
+			$this->setCollectionFQCNs($collection_FQCNs);
167
+			$this->setCollectionPaths($collection_paths);
168
+			$this->setFileMasks($file_mask);
169
+			$this->setIdentifierType($identifier_type);
170
+			$this->setIdentifierCallback($identifier_callback);
171
+			$this->file_locator = $file_locator;
172
+		} catch (Exception $exception) {
173
+			throw new CollectionDetailsException($exception);
174
+		}
175
+	}
176
+
177
+
178
+	/**
179
+	 * @access public
180
+	 * @return mixed
181
+	 */
182
+	public function getCollectionInterface()
183
+	{
184
+		return $this->collection_interface;
185
+	}
186
+
187
+
188
+	/**
189
+	 * @access protected
190
+	 * @param string $collection_interface
191
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
192
+	 */
193
+	protected function setCollectionInterface($collection_interface)
194
+	{
195
+		if (! (interface_exists($collection_interface) || class_exists($collection_interface))) {
196
+			throw new InvalidInterfaceException($collection_interface);
197
+		}
198
+		$this->collection_interface = $collection_interface;
199
+	}
200
+
201
+
202
+	/**
203
+	 * the collection name will be used for creating dynamic filters
204
+	 *
205
+	 * @access public
206
+	 * @return string
207
+	 */
208
+	public function collectionName()
209
+	{
210
+		return $this->collection_name;
211
+	}
212
+
213
+
214
+	/**
215
+	 * sanitizes collection name and converts spaces and dashes to underscores
216
+	 *
217
+	 * @access protected
218
+	 * @param string $collection_name
219
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
220
+	 */
221
+	protected function setCollectionName($collection_name)
222
+	{
223
+		if (! is_string($collection_name)) {
224
+			throw new InvalidDataTypeException('$collection_name', $collection_name, 'string');
225
+		}
226
+		$this->collection_name = str_replace(
227
+			'-',
228
+			'_',
229
+			sanitize_title_with_dashes($collection_name, '', 'save')
230
+		);
231
+	}
232
+
233
+
234
+	/**
235
+	 * @access public
236
+	 * @return string
237
+	 */
238
+	public function identifierType()
239
+	{
240
+		return $this->identifier_type;
241
+	}
242
+
243
+
244
+	/**
245
+	 * @access protected
246
+	 * @param string $identifier_type
247
+	 * @throws InvalidIdentifierException
248
+	 */
249
+	protected function setIdentifierType($identifier_type)
250
+	{
251
+		if (
252
+			! ($identifier_type === CollectionDetails::ID_CLASS_NAME
253
+			   || $identifier_type === CollectionDetails::ID_OBJECT_HASH
254
+			   || $identifier_type === CollectionDetails::ID_CALLBACK_METHOD
255
+			)
256
+		) {
257
+			throw new InvalidIdentifierException(
258
+				$identifier_type,
259
+				'CollectionDetails::ID_CLASS_NAME or CollectionDetails::ID_OBJECT_HASH or CollectionDetails::ID_CALLBACK_METHOD'
260
+			);
261
+		}
262
+		$this->identifier_type = $identifier_type;
263
+	}
264
+
265
+
266
+	/**
267
+	 * @access public
268
+	 * @return string
269
+	 */
270
+	public function identifierCallback()
271
+	{
272
+		return $this->identifier_callback;
273
+	}
274
+
275
+
276
+	/**
277
+	 * @access protected
278
+	 * @param string $identifier_callback
279
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
280
+	 */
281
+	protected function setIdentifierCallback($identifier_callback = 'identifier')
282
+	{
283
+		if (! is_string($identifier_callback)) {
284
+			throw new InvalidDataTypeException('$identifier_callback', $identifier_callback, 'string');
285
+		}
286
+		$this->identifier_callback = $identifier_callback;
287
+	}
288
+
289
+
290
+	/**
291
+	 * @access public
292
+	 * @return string
293
+	 */
294
+	public function getFileMask()
295
+	{
296
+		return $this->file_mask;
297
+	}
298
+
299
+
300
+	/**
301
+	 * sets the file mask which is then used to filter what files get loaded
302
+	 * when searching for classes to add to the collection. Defaults to '*.php'
303
+	 *
304
+	 * @access protected
305
+	 * @param string $file_mask
306
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
307
+	 */
308
+	protected function setFileMasks($file_mask)
309
+	{
310
+		$this->file_mask = ! empty($file_mask) ? $file_mask : '*.php';
311
+		// we know our default is a string, so if it's not a string now,
312
+		// then that means the incoming parameter was something else
313
+		if (! is_string($this->file_mask)) {
314
+			throw new InvalidDataTypeException('$file_mask', $this->file_mask, 'string');
315
+		}
316
+	}
317
+
318
+
319
+	/**
320
+	 * @access public
321
+	 * @return array
322
+	 */
323
+	public function getCollectionFQCNs()
324
+	{
325
+		return $this->collection_FQCNs;
326
+	}
327
+
328
+
329
+	/**
330
+	 * @access public
331
+	 * @param string|array $collection_FQCNs
332
+	 * @throws \EventEspresso\core\exceptions\InvalidClassException
333
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
334
+	 */
335
+	public function setCollectionFQCNs($collection_FQCNs)
336
+	{
337
+		foreach ((array) $collection_FQCNs as $collection_FQCN) {
338
+			if (! empty($collection_FQCN)) {
339
+				if (class_exists($collection_FQCN)) {
340
+					$this->collection_FQCNs[] = $collection_FQCN;
341
+				} else {
342
+					foreach ($this->getFQCNsFromPartialNamespace($collection_FQCN) as $FQCN) {
343
+						$this->collection_FQCNs[] = $FQCN;
344
+					}
345
+				}
346
+			}
347
+		}
348
+	}
349
+
350
+
351
+	/**
352
+	 * @access protected
353
+	 * @param  string $partial_FQCN
354
+	 * @return array
355
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
356
+	 * @throws \EventEspresso\core\exceptions\InvalidClassException
357
+	 */
358
+	protected function getFQCNsFromPartialNamespace($partial_FQCN)
359
+	{
360
+		if (! $this->file_locator instanceof FqcnLocator) {
361
+			$this->file_locator = new FqcnLocator();
362
+		}
363
+		$this->file_locator->locate($partial_FQCN);
364
+		return $this->file_locator->getFQCNs();
365
+	}
366
+
367
+
368
+	/**
369
+	 * @access public
370
+	 * @return array
371
+	 */
372
+	public function getCollectionPaths()
373
+	{
374
+		return $this->collection_paths;
375
+	}
376
+
377
+
378
+	/**
379
+	 * @access public
380
+	 * @param string|array $collection_paths
381
+	 * @throws \EventEspresso\core\exceptions\InvalidFilePathException
382
+	 */
383
+	public function setCollectionPaths($collection_paths)
384
+	{
385
+		foreach ((array) $collection_paths as $collection_path) {
386
+			if (! empty($collection_path)) {
387
+				if (! is_readable($collection_path)) {
388
+					throw new InvalidFilePathException($collection_path);
389
+				}
390
+				$this->collection_paths[] = $collection_path;
391
+			}
392
+		}
393
+	}
394 394
 }
Please login to merge, or discard this patch.
core/services/notifications/PersistentAdminNoticeManager.php 2 patches
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
      */
86 86
     public function setReturnUrl($return_url)
87 87
     {
88
-        if (! is_string($return_url)) {
88
+        if ( ! is_string($return_url)) {
89 89
             throw new InvalidDataTypeException('$return_url', $return_url, 'string');
90 90
         }
91 91
         $this->return_url = $return_url;
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
      */
103 103
     protected function getPersistentAdminNoticeCollection()
104 104
     {
105
-        if (! $this->notice_collection instanceof Collection) {
105
+        if ( ! $this->notice_collection instanceof Collection) {
106 106
             $this->notice_collection = new Collection(
107 107
                 'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
108 108
             );
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
     protected function retrieveStoredNotices()
126 126
     {
127 127
         $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
128
-        if (! empty($persistent_admin_notices)) {
128
+        if ( ! empty($persistent_admin_notices)) {
129 129
             foreach ($persistent_admin_notices as $name => $details) {
130 130
                 if (is_array($details)) {
131 131
                     if (
@@ -247,14 +247,14 @@  discard block
 block discarded – undo
247 247
     {
248 248
         wp_register_script(
249 249
             'espresso_core',
250
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
250
+            EE_GLOBAL_ASSETS_URL.'scripts/espresso_core.js',
251 251
             array('jquery'),
252 252
             EVENT_ESPRESSO_VERSION,
253 253
             true
254 254
         );
255 255
         wp_register_script(
256 256
             'ee_error_js',
257
-            EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
257
+            EE_GLOBAL_ASSETS_URL.'scripts/EE_Error.js',
258 258
             array('espresso_core'),
259 259
             EVENT_ESPRESSO_VERSION,
260 260
             true
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
         // used in template
286 286
         $persistent_admin_notice_name = $persistent_admin_notice->getName();
287 287
         $persistent_admin_notice_message = $persistent_admin_notice->getMessage();
288
-        require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
288
+        require EE_TEMPLATES.'/notifications/persistent_admin_notice.template.php';
289 289
     }
290 290
 
291 291
 
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
     {
311 311
         $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
312 312
         $this->notice_collection = $this->getPersistentAdminNoticeCollection();
313
-        if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
313
+        if ( ! empty($pan_name) && $this->notice_collection->has($pan_name)) {
314 314
             /** @var PersistentAdminNotice $persistent_admin_notice */
315 315
             $persistent_admin_notice = $this->notice_collection->get($pan_name);
316 316
             $persistent_admin_notice->setDismissed(true);
@@ -360,10 +360,10 @@  discard block
 block discarded – undo
360 360
             foreach ($this->notice_collection as $persistent_admin_notice) {
361 361
                 // are we deleting this notice ?
362 362
                 if ($persistent_admin_notice->getPurge()) {
363
-                    unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]);
363
+                    unset($persistent_admin_notices[$persistent_admin_notice->getName()]);
364 364
                 } else {
365 365
                     /** @var PersistentAdminNotice $persistent_admin_notice */
366
-                    $persistent_admin_notices[ $persistent_admin_notice->getName() ] = array(
366
+                    $persistent_admin_notices[$persistent_admin_notice->getName()] = array(
367 367
                         'message'     => $persistent_admin_notice->getMessage(),
368 368
                         'capability'  => $persistent_admin_notice->getCapability(),
369 369
                         'cap_context' => $persistent_admin_notice->getCapContext(),
Please login to merge, or discard this patch.
Indentation   +388 added lines, -388 removed lines patch added patch discarded remove patch
@@ -30,392 +30,392 @@
 block discarded – undo
30 30
  */
31 31
 class PersistentAdminNoticeManager
32 32
 {
33
-    const WP_OPTION_KEY = 'ee_pers_admin_notices';
34
-
35
-    /**
36
-     * @var Collection|PersistentAdminNotice[] $notice_collection
37
-     */
38
-    private $notice_collection;
39
-
40
-    /**
41
-     * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the
42
-     * persistent admin notice was displayed, and ultimately dismissed from.
43
-     *
44
-     * @var string $return_url
45
-     */
46
-    private $return_url;
47
-
48
-    /**
49
-     * @var CapabilitiesChecker $capabilities_checker
50
-     */
51
-    private $capabilities_checker;
52
-
53
-    /**
54
-     * @var RequestInterface $request
55
-     */
56
-    private $request;
57
-
58
-
59
-    /**
60
-     * PersistentAdminNoticeManager constructor
61
-     *
62
-     * @param CapabilitiesChecker $capabilities_checker
63
-     * @param RequestInterface    $request
64
-     * @param string              $return_url where to  redirect to after dismissing notices
65
-     * @throws InvalidDataTypeException
66
-     */
67
-    public function __construct(
68
-        CapabilitiesChecker $capabilities_checker,
69
-        RequestInterface $request,
70
-        string $return_url = ''
71
-    ) {
72
-        $this->setReturnUrl($return_url);
73
-        $this->capabilities_checker = $capabilities_checker;
74
-        $this->request = $request;
75
-        // setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10,
76
-        // and we want to retrieve and generate any nag notices at the last possible moment
77
-        add_action('admin_notices', array($this, 'displayNotices'), 9);
78
-        add_action('network_admin_notices', array($this, 'displayNotices'), 9);
79
-        add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice'));
80
-        add_action('shutdown', array($this, 'registerAndSaveNotices'), 998);
81
-    }
82
-
83
-
84
-    /**
85
-     * @param string $return_url
86
-     * @throws InvalidDataTypeException
87
-     */
88
-    public function setReturnUrl($return_url)
89
-    {
90
-        if (! is_string($return_url)) {
91
-            throw new InvalidDataTypeException('$return_url', $return_url, 'string');
92
-        }
93
-        $this->return_url = $return_url;
94
-    }
95
-
96
-
97
-    /**
98
-     * @return Collection
99
-     * @throws InvalidEntityException
100
-     * @throws InvalidInterfaceException
101
-     * @throws InvalidDataTypeException
102
-     * @throws DomainException
103
-     * @throws DuplicateCollectionIdentifierException
104
-     */
105
-    protected function getPersistentAdminNoticeCollection()
106
-    {
107
-        if (! $this->notice_collection instanceof Collection) {
108
-            $this->notice_collection = new Collection(
109
-                'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
110
-            );
111
-            $this->retrieveStoredNotices();
112
-            $this->registerNotices();
113
-        }
114
-        return $this->notice_collection;
115
-    }
116
-
117
-
118
-    /**
119
-     * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db
120
-     *
121
-     * @return void
122
-     * @throws InvalidEntityException
123
-     * @throws DomainException
124
-     * @throws InvalidDataTypeException
125
-     * @throws DuplicateCollectionIdentifierException
126
-     */
127
-    protected function retrieveStoredNotices()
128
-    {
129
-        $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
130
-        if (! empty($persistent_admin_notices)) {
131
-            foreach ($persistent_admin_notices as $name => $details) {
132
-                if (is_array($details)) {
133
-                    if (
134
-                        ! isset(
135
-                            $details['message'],
136
-                            $details['capability'],
137
-                            $details['cap_context'],
138
-                            $details['dismissed']
139
-                        )
140
-                    ) {
141
-                        throw new DomainException(
142
-                            sprintf(
143
-                                esc_html__(
144
-                                    'The "%1$s" PersistentAdminNotice could not be retrieved from the database.',
145
-                                    'event_espresso'
146
-                                ),
147
-                                $name
148
-                            )
149
-                        );
150
-                    }
151
-                    // new format for nag notices
152
-                    $this->notice_collection->add(
153
-                        new PersistentAdminNotice(
154
-                            $name,
155
-                            $details['message'],
156
-                            false,
157
-                            $details['capability'],
158
-                            $details['cap_context'],
159
-                            $details['dismissed']
160
-                        ),
161
-                        sanitize_key($name)
162
-                    );
163
-                } else {
164
-                    try {
165
-                        // old nag notices, that we want to convert to the new format
166
-                        $this->notice_collection->add(
167
-                            new PersistentAdminNotice(
168
-                                $name,
169
-                                (string) $details,
170
-                                false,
171
-                                '',
172
-                                '',
173
-                                empty($details)
174
-                            ),
175
-                            sanitize_key($name)
176
-                        );
177
-                    } catch (Exception $e) {
178
-                        EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
179
-                    }
180
-                }
181
-                // each notice will self register when the action hook in registerNotices is triggered
182
-            }
183
-        }
184
-    }
185
-
186
-
187
-    /**
188
-     * exposes the Persistent Admin Notice Collection via an action
189
-     * so that PersistentAdminNotice objects can be added and/or removed
190
-     * without compromising the actual collection like a filter would
191
-     */
192
-    protected function registerNotices()
193
-    {
194
-        do_action(
195
-            'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices',
196
-            $this->notice_collection
197
-        );
198
-    }
199
-
200
-
201
-    /**
202
-     * @throws DomainException
203
-     * @throws InvalidClassException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     * @throws InvalidEntityException
207
-     * @throws DuplicateCollectionIdentifierException
208
-     */
209
-    public function displayNotices()
210
-    {
211
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
212
-        if ($this->notice_collection->hasObjects()) {
213
-            $enqueue_assets = false;
214
-            // and display notices
215
-            foreach ($this->notice_collection as $persistent_admin_notice) {
216
-                /** @var PersistentAdminNotice $persistent_admin_notice */
217
-                // don't display notices that have already been dismissed
218
-                if ($persistent_admin_notice->getDismissed()) {
219
-                    continue;
220
-                }
221
-                try {
222
-                    $this->capabilities_checker->processCapCheck(
223
-                        $persistent_admin_notice->getCapCheck()
224
-                    );
225
-                } catch (InsufficientPermissionsException $e) {
226
-                    // user does not have required cap, so skip to next notice
227
-                    // and just eat the exception - nom nom nom nom
228
-                    continue;
229
-                }
230
-                if ($persistent_admin_notice->getMessage() === '') {
231
-                    continue;
232
-                }
233
-                $this->displayPersistentAdminNotice($persistent_admin_notice);
234
-                $enqueue_assets = true;
235
-            }
236
-            if ($enqueue_assets) {
237
-                $this->enqueueAssets();
238
-            }
239
-        }
240
-    }
241
-
242
-
243
-    /**
244
-     * does what it's named
245
-     *
246
-     * @return void
247
-     */
248
-    public function enqueueAssets()
249
-    {
250
-        wp_register_script(
251
-            'espresso_core',
252
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
253
-            array('jquery'),
254
-            EVENT_ESPRESSO_VERSION,
255
-            true
256
-        );
257
-        wp_register_script(
258
-            'ee_error_js',
259
-            EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
260
-            array('espresso_core'),
261
-            EVENT_ESPRESSO_VERSION,
262
-            true
263
-        );
264
-        wp_localize_script(
265
-            'ee_error_js',
266
-            'ee_dismiss',
267
-            array(
268
-                'return_url'    => urlencode($this->return_url),
269
-                'ajax_url'      => WP_AJAX_URL,
270
-                'unknown_error' => wp_strip_all_tags(
271
-                    __(
272
-                        'An unknown error has occurred on the server while attempting to dismiss this notice.',
273
-                        'event_espresso'
274
-                    )
275
-                ),
276
-            )
277
-        );
278
-        wp_enqueue_script('ee_error_js');
279
-    }
280
-
281
-
282
-    /**
283
-     * displayPersistentAdminNoticeHtml
284
-     *
285
-     * @param  PersistentAdminNotice $persistent_admin_notice
286
-     */
287
-    protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice)
288
-    {
289
-        // used in template
290
-        $persistent_admin_notice_name = $persistent_admin_notice->getName();
291
-        $persistent_admin_notice_message = $persistent_admin_notice->getMessage();
292
-        require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
293
-    }
294
-
295
-
296
-    /**
297
-     * dismissNotice
298
-     *
299
-     * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
300
-     * @param bool   $purge    if true, then delete it from the db
301
-     * @param bool   $return   forget all of this AJAX or redirect nonsense, and just return
302
-     * @return void
303
-     * @throws InvalidEntityException
304
-     * @throws InvalidInterfaceException
305
-     * @throws InvalidDataTypeException
306
-     * @throws DomainException
307
-     * @throws InvalidArgumentException
308
-     * @throws InvalidArgumentException
309
-     * @throws InvalidArgumentException
310
-     * @throws InvalidArgumentException
311
-     * @throws DuplicateCollectionIdentifierException
312
-     */
313
-    public function dismissNotice($pan_name = '', $purge = false, $return = false)
314
-    {
315
-        $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
316
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
317
-        if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
318
-            /** @var PersistentAdminNotice $persistent_admin_notice */
319
-            $persistent_admin_notice = $this->notice_collection->get($pan_name);
320
-            $persistent_admin_notice->setDismissed(true);
321
-            $persistent_admin_notice->setPurge($purge);
322
-            $this->saveNotices();
323
-        }
324
-        if ($return) {
325
-            return;
326
-        }
327
-        if ($this->request->isAjax()) {
328
-            // grab any notices and concatenate into string
329
-            echo wp_json_encode(
330
-                array(
331
-                    'errors' => implode('<br />', EE_Error::get_notices(false)),
332
-                )
333
-            );
334
-            exit();
335
-        }
336
-        // save errors to a transient to be displayed on next request (after redirect)
337
-        EE_Error::get_notices(false, true);
338
-        wp_safe_redirect(
339
-            urldecode(
340
-                $this->request->getRequestParam('return_url', '')
341
-            )
342
-        );
343
-    }
344
-
345
-
346
-    /**
347
-     * saveNotices
348
-     *
349
-     * @throws DomainException
350
-     * @throws InvalidDataTypeException
351
-     * @throws InvalidInterfaceException
352
-     * @throws InvalidEntityException
353
-     * @throws DuplicateCollectionIdentifierException
354
-     */
355
-    public function saveNotices()
356
-    {
357
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
358
-        if ($this->notice_collection->hasObjects()) {
359
-            $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
360
-            // maybe initialize persistent_admin_notices
361
-            if (empty($persistent_admin_notices)) {
362
-                add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no');
363
-            }
364
-            foreach ($this->notice_collection as $persistent_admin_notice) {
365
-                // are we deleting this notice ?
366
-                if ($persistent_admin_notice->getPurge()) {
367
-                    unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]);
368
-                } else {
369
-                    /** @var PersistentAdminNotice $persistent_admin_notice */
370
-                    $persistent_admin_notices[ $persistent_admin_notice->getName() ] = array(
371
-                        'message'     => $persistent_admin_notice->getMessage(),
372
-                        'capability'  => $persistent_admin_notice->getCapability(),
373
-                        'cap_context' => $persistent_admin_notice->getCapContext(),
374
-                        'dismissed'   => $persistent_admin_notice->getDismissed(),
375
-                    );
376
-                }
377
-            }
378
-            update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $persistent_admin_notices);
379
-        }
380
-    }
381
-
382
-
383
-    /**
384
-     * @throws DomainException
385
-     * @throws InvalidDataTypeException
386
-     * @throws InvalidEntityException
387
-     * @throws InvalidInterfaceException
388
-     * @throws DuplicateCollectionIdentifierException
389
-     */
390
-    public function registerAndSaveNotices()
391
-    {
392
-        $this->getPersistentAdminNoticeCollection();
393
-        $this->registerNotices();
394
-        $this->saveNotices();
395
-        add_filter(
396
-            'PersistentAdminNoticeManager__registerAndSaveNotices__complete',
397
-            '__return_true'
398
-        );
399
-    }
400
-
401
-
402
-    /**
403
-     * @throws DomainException
404
-     * @throws InvalidDataTypeException
405
-     * @throws InvalidEntityException
406
-     * @throws InvalidInterfaceException
407
-     * @throws InvalidArgumentException
408
-     * @throws DuplicateCollectionIdentifierException
409
-     */
410
-    public static function loadRegisterAndSaveNotices()
411
-    {
412
-        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
413
-        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
414
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
415
-        );
416
-        // if shutdown has already run, then call registerAndSaveNotices() manually
417
-        if (did_action('shutdown')) {
418
-            $persistent_admin_notice_manager->registerAndSaveNotices();
419
-        }
420
-    }
33
+	const WP_OPTION_KEY = 'ee_pers_admin_notices';
34
+
35
+	/**
36
+	 * @var Collection|PersistentAdminNotice[] $notice_collection
37
+	 */
38
+	private $notice_collection;
39
+
40
+	/**
41
+	 * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the
42
+	 * persistent admin notice was displayed, and ultimately dismissed from.
43
+	 *
44
+	 * @var string $return_url
45
+	 */
46
+	private $return_url;
47
+
48
+	/**
49
+	 * @var CapabilitiesChecker $capabilities_checker
50
+	 */
51
+	private $capabilities_checker;
52
+
53
+	/**
54
+	 * @var RequestInterface $request
55
+	 */
56
+	private $request;
57
+
58
+
59
+	/**
60
+	 * PersistentAdminNoticeManager constructor
61
+	 *
62
+	 * @param CapabilitiesChecker $capabilities_checker
63
+	 * @param RequestInterface    $request
64
+	 * @param string              $return_url where to  redirect to after dismissing notices
65
+	 * @throws InvalidDataTypeException
66
+	 */
67
+	public function __construct(
68
+		CapabilitiesChecker $capabilities_checker,
69
+		RequestInterface $request,
70
+		string $return_url = ''
71
+	) {
72
+		$this->setReturnUrl($return_url);
73
+		$this->capabilities_checker = $capabilities_checker;
74
+		$this->request = $request;
75
+		// setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10,
76
+		// and we want to retrieve and generate any nag notices at the last possible moment
77
+		add_action('admin_notices', array($this, 'displayNotices'), 9);
78
+		add_action('network_admin_notices', array($this, 'displayNotices'), 9);
79
+		add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice'));
80
+		add_action('shutdown', array($this, 'registerAndSaveNotices'), 998);
81
+	}
82
+
83
+
84
+	/**
85
+	 * @param string $return_url
86
+	 * @throws InvalidDataTypeException
87
+	 */
88
+	public function setReturnUrl($return_url)
89
+	{
90
+		if (! is_string($return_url)) {
91
+			throw new InvalidDataTypeException('$return_url', $return_url, 'string');
92
+		}
93
+		$this->return_url = $return_url;
94
+	}
95
+
96
+
97
+	/**
98
+	 * @return Collection
99
+	 * @throws InvalidEntityException
100
+	 * @throws InvalidInterfaceException
101
+	 * @throws InvalidDataTypeException
102
+	 * @throws DomainException
103
+	 * @throws DuplicateCollectionIdentifierException
104
+	 */
105
+	protected function getPersistentAdminNoticeCollection()
106
+	{
107
+		if (! $this->notice_collection instanceof Collection) {
108
+			$this->notice_collection = new Collection(
109
+				'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
110
+			);
111
+			$this->retrieveStoredNotices();
112
+			$this->registerNotices();
113
+		}
114
+		return $this->notice_collection;
115
+	}
116
+
117
+
118
+	/**
119
+	 * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db
120
+	 *
121
+	 * @return void
122
+	 * @throws InvalidEntityException
123
+	 * @throws DomainException
124
+	 * @throws InvalidDataTypeException
125
+	 * @throws DuplicateCollectionIdentifierException
126
+	 */
127
+	protected function retrieveStoredNotices()
128
+	{
129
+		$persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
130
+		if (! empty($persistent_admin_notices)) {
131
+			foreach ($persistent_admin_notices as $name => $details) {
132
+				if (is_array($details)) {
133
+					if (
134
+						! isset(
135
+							$details['message'],
136
+							$details['capability'],
137
+							$details['cap_context'],
138
+							$details['dismissed']
139
+						)
140
+					) {
141
+						throw new DomainException(
142
+							sprintf(
143
+								esc_html__(
144
+									'The "%1$s" PersistentAdminNotice could not be retrieved from the database.',
145
+									'event_espresso'
146
+								),
147
+								$name
148
+							)
149
+						);
150
+					}
151
+					// new format for nag notices
152
+					$this->notice_collection->add(
153
+						new PersistentAdminNotice(
154
+							$name,
155
+							$details['message'],
156
+							false,
157
+							$details['capability'],
158
+							$details['cap_context'],
159
+							$details['dismissed']
160
+						),
161
+						sanitize_key($name)
162
+					);
163
+				} else {
164
+					try {
165
+						// old nag notices, that we want to convert to the new format
166
+						$this->notice_collection->add(
167
+							new PersistentAdminNotice(
168
+								$name,
169
+								(string) $details,
170
+								false,
171
+								'',
172
+								'',
173
+								empty($details)
174
+							),
175
+							sanitize_key($name)
176
+						);
177
+					} catch (Exception $e) {
178
+						EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
179
+					}
180
+				}
181
+				// each notice will self register when the action hook in registerNotices is triggered
182
+			}
183
+		}
184
+	}
185
+
186
+
187
+	/**
188
+	 * exposes the Persistent Admin Notice Collection via an action
189
+	 * so that PersistentAdminNotice objects can be added and/or removed
190
+	 * without compromising the actual collection like a filter would
191
+	 */
192
+	protected function registerNotices()
193
+	{
194
+		do_action(
195
+			'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices',
196
+			$this->notice_collection
197
+		);
198
+	}
199
+
200
+
201
+	/**
202
+	 * @throws DomainException
203
+	 * @throws InvalidClassException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 * @throws InvalidEntityException
207
+	 * @throws DuplicateCollectionIdentifierException
208
+	 */
209
+	public function displayNotices()
210
+	{
211
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
212
+		if ($this->notice_collection->hasObjects()) {
213
+			$enqueue_assets = false;
214
+			// and display notices
215
+			foreach ($this->notice_collection as $persistent_admin_notice) {
216
+				/** @var PersistentAdminNotice $persistent_admin_notice */
217
+				// don't display notices that have already been dismissed
218
+				if ($persistent_admin_notice->getDismissed()) {
219
+					continue;
220
+				}
221
+				try {
222
+					$this->capabilities_checker->processCapCheck(
223
+						$persistent_admin_notice->getCapCheck()
224
+					);
225
+				} catch (InsufficientPermissionsException $e) {
226
+					// user does not have required cap, so skip to next notice
227
+					// and just eat the exception - nom nom nom nom
228
+					continue;
229
+				}
230
+				if ($persistent_admin_notice->getMessage() === '') {
231
+					continue;
232
+				}
233
+				$this->displayPersistentAdminNotice($persistent_admin_notice);
234
+				$enqueue_assets = true;
235
+			}
236
+			if ($enqueue_assets) {
237
+				$this->enqueueAssets();
238
+			}
239
+		}
240
+	}
241
+
242
+
243
+	/**
244
+	 * does what it's named
245
+	 *
246
+	 * @return void
247
+	 */
248
+	public function enqueueAssets()
249
+	{
250
+		wp_register_script(
251
+			'espresso_core',
252
+			EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
253
+			array('jquery'),
254
+			EVENT_ESPRESSO_VERSION,
255
+			true
256
+		);
257
+		wp_register_script(
258
+			'ee_error_js',
259
+			EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
260
+			array('espresso_core'),
261
+			EVENT_ESPRESSO_VERSION,
262
+			true
263
+		);
264
+		wp_localize_script(
265
+			'ee_error_js',
266
+			'ee_dismiss',
267
+			array(
268
+				'return_url'    => urlencode($this->return_url),
269
+				'ajax_url'      => WP_AJAX_URL,
270
+				'unknown_error' => wp_strip_all_tags(
271
+					__(
272
+						'An unknown error has occurred on the server while attempting to dismiss this notice.',
273
+						'event_espresso'
274
+					)
275
+				),
276
+			)
277
+		);
278
+		wp_enqueue_script('ee_error_js');
279
+	}
280
+
281
+
282
+	/**
283
+	 * displayPersistentAdminNoticeHtml
284
+	 *
285
+	 * @param  PersistentAdminNotice $persistent_admin_notice
286
+	 */
287
+	protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice)
288
+	{
289
+		// used in template
290
+		$persistent_admin_notice_name = $persistent_admin_notice->getName();
291
+		$persistent_admin_notice_message = $persistent_admin_notice->getMessage();
292
+		require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
293
+	}
294
+
295
+
296
+	/**
297
+	 * dismissNotice
298
+	 *
299
+	 * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
300
+	 * @param bool   $purge    if true, then delete it from the db
301
+	 * @param bool   $return   forget all of this AJAX or redirect nonsense, and just return
302
+	 * @return void
303
+	 * @throws InvalidEntityException
304
+	 * @throws InvalidInterfaceException
305
+	 * @throws InvalidDataTypeException
306
+	 * @throws DomainException
307
+	 * @throws InvalidArgumentException
308
+	 * @throws InvalidArgumentException
309
+	 * @throws InvalidArgumentException
310
+	 * @throws InvalidArgumentException
311
+	 * @throws DuplicateCollectionIdentifierException
312
+	 */
313
+	public function dismissNotice($pan_name = '', $purge = false, $return = false)
314
+	{
315
+		$pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
316
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
317
+		if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
318
+			/** @var PersistentAdminNotice $persistent_admin_notice */
319
+			$persistent_admin_notice = $this->notice_collection->get($pan_name);
320
+			$persistent_admin_notice->setDismissed(true);
321
+			$persistent_admin_notice->setPurge($purge);
322
+			$this->saveNotices();
323
+		}
324
+		if ($return) {
325
+			return;
326
+		}
327
+		if ($this->request->isAjax()) {
328
+			// grab any notices and concatenate into string
329
+			echo wp_json_encode(
330
+				array(
331
+					'errors' => implode('<br />', EE_Error::get_notices(false)),
332
+				)
333
+			);
334
+			exit();
335
+		}
336
+		// save errors to a transient to be displayed on next request (after redirect)
337
+		EE_Error::get_notices(false, true);
338
+		wp_safe_redirect(
339
+			urldecode(
340
+				$this->request->getRequestParam('return_url', '')
341
+			)
342
+		);
343
+	}
344
+
345
+
346
+	/**
347
+	 * saveNotices
348
+	 *
349
+	 * @throws DomainException
350
+	 * @throws InvalidDataTypeException
351
+	 * @throws InvalidInterfaceException
352
+	 * @throws InvalidEntityException
353
+	 * @throws DuplicateCollectionIdentifierException
354
+	 */
355
+	public function saveNotices()
356
+	{
357
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
358
+		if ($this->notice_collection->hasObjects()) {
359
+			$persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
360
+			// maybe initialize persistent_admin_notices
361
+			if (empty($persistent_admin_notices)) {
362
+				add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no');
363
+			}
364
+			foreach ($this->notice_collection as $persistent_admin_notice) {
365
+				// are we deleting this notice ?
366
+				if ($persistent_admin_notice->getPurge()) {
367
+					unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]);
368
+				} else {
369
+					/** @var PersistentAdminNotice $persistent_admin_notice */
370
+					$persistent_admin_notices[ $persistent_admin_notice->getName() ] = array(
371
+						'message'     => $persistent_admin_notice->getMessage(),
372
+						'capability'  => $persistent_admin_notice->getCapability(),
373
+						'cap_context' => $persistent_admin_notice->getCapContext(),
374
+						'dismissed'   => $persistent_admin_notice->getDismissed(),
375
+					);
376
+				}
377
+			}
378
+			update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $persistent_admin_notices);
379
+		}
380
+	}
381
+
382
+
383
+	/**
384
+	 * @throws DomainException
385
+	 * @throws InvalidDataTypeException
386
+	 * @throws InvalidEntityException
387
+	 * @throws InvalidInterfaceException
388
+	 * @throws DuplicateCollectionIdentifierException
389
+	 */
390
+	public function registerAndSaveNotices()
391
+	{
392
+		$this->getPersistentAdminNoticeCollection();
393
+		$this->registerNotices();
394
+		$this->saveNotices();
395
+		add_filter(
396
+			'PersistentAdminNoticeManager__registerAndSaveNotices__complete',
397
+			'__return_true'
398
+		);
399
+	}
400
+
401
+
402
+	/**
403
+	 * @throws DomainException
404
+	 * @throws InvalidDataTypeException
405
+	 * @throws InvalidEntityException
406
+	 * @throws InvalidInterfaceException
407
+	 * @throws InvalidArgumentException
408
+	 * @throws DuplicateCollectionIdentifierException
409
+	 */
410
+	public static function loadRegisterAndSaveNotices()
411
+	{
412
+		/** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
413
+		$persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
414
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
415
+		);
416
+		// if shutdown has already run, then call registerAndSaveNotices() manually
417
+		if (did_action('shutdown')) {
418
+			$persistent_admin_notice_manager->registerAndSaveNotices();
419
+		}
420
+	}
421 421
 }
Please login to merge, or discard this patch.
core/services/cache/TransientCacheStorage.php 2 patches
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@  discard block
 block discarded – undo
57 57
         // round current time down to closest 5 minutes to simplify scheduling
58 58
         $this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
59 59
         $this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
60
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
60
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
61 61
             add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
62 62
         }
63 63
     }
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
      */
191 191
     public function get($transient_key, $standard_cache = true)
192 192
     {
193
-        if (isset($this->transients[ $transient_key ])) {
193
+        if (isset($this->transients[$transient_key])) {
194 194
             // to avoid cache stampedes (AKA:dogpiles) for standard cache items,
195 195
             // check if known cache expires within the next minute,
196 196
             // and if so, remove it from our tracking and and return nothing.
@@ -199,17 +199,17 @@  discard block
 block discarded – undo
199 199
             // until it gets replaced with the refreshed content
200 200
             if (
201 201
                 $standard_cache
202
-                && $this->transients[ $transient_key ] - time() <= MINUTE_IN_SECONDS
202
+                && $this->transients[$transient_key] - time() <= MINUTE_IN_SECONDS
203 203
             ) {
204
-                unset($this->transients[ $transient_key ]);
204
+                unset($this->transients[$transient_key]);
205 205
                 $this->updateTransients();
206 206
                 return null;
207 207
             }
208 208
 
209 209
             // for non standard cache items, remove the key from our tracking,
210 210
             // but proceed to retrieve the transient so that it also gets removed from the db
211
-            if ($this->transients[ $transient_key ] <= time()) {
212
-                unset($this->transients[ $transient_key ]);
211
+            if ($this->transients[$transient_key] <= time()) {
212
+                unset($this->transients[$transient_key]);
213 213
                 $this->updateTransients();
214 214
             }
215 215
         }
@@ -282,7 +282,7 @@  discard block
 block discarded – undo
282 282
         // and round to the closest 15 minutes
283 283
         $expiration = $this->roundTimestamp($expiration);
284 284
         // save transients to clear using their ID as the key to avoid duplicates
285
-        $this->transients[ $transient_key ] = $expiration;
285
+        $this->transients[$transient_key] = $expiration;
286 286
         $this->updateTransients();
287 287
     }
288 288
 
@@ -334,8 +334,8 @@  discard block
 block discarded – undo
334 334
                 if ($expiration > $this->current_time) {
335 335
                     continue;
336 336
                 }
337
-                if (! $expiration || ! $transient_key) {
338
-                    unset($this->transients[ $transient_key ]);
337
+                if ( ! $expiration || ! $transient_key) {
338
+                    unset($this->transients[$transient_key]);
339 339
                     $update = true;
340 340
                     continue;
341 341
                 }
@@ -374,7 +374,7 @@  discard block
 block discarded – undo
374 374
                 ? str_replace('_transient_', '', $transient_key)
375 375
                 : $transient_key;
376 376
             delete_transient($transient_key);
377
-            unset($this->transients[ $transient_key ]);
377
+            unset($this->transients[$transient_key]);
378 378
             $counter++;
379 379
         }
380 380
         return $counter > 0;
Please login to merge, or discard this patch.
Indentation   +363 added lines, -363 removed lines patch added patch discarded remove patch
@@ -15,367 +15,367 @@
 block discarded – undo
15 15
  */
16 16
 class TransientCacheStorage implements CacheStorageInterface
17 17
 {
18
-    /**
19
-     * wp-option option_name for tracking transients
20
-     *
21
-     * @type string
22
-     */
23
-    const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule';
24
-
25
-    /**
26
-     * @var int $current_time
27
-     */
28
-    private $current_time;
29
-
30
-    /**
31
-     * how often to perform transient cleanup
32
-     *
33
-     * @var string $transient_cleanup_frequency
34
-     */
35
-    private $transient_cleanup_frequency;
36
-
37
-    /**
38
-     * options for how often to perform transient cleanup
39
-     *
40
-     * @var array $transient_cleanup_frequency_options
41
-     */
42
-    private $transient_cleanup_frequency_options = array();
43
-
44
-    /**
45
-     * @var array $transients
46
-     */
47
-    private $transients;
48
-
49
-
50
-    /**
51
-     * TransientCacheStorage constructor.
52
-     */
53
-    public function __construct()
54
-    {
55
-        $this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
56
-        // round current time down to closest 5 minutes to simplify scheduling
57
-        $this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
58
-        $this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
59
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
60
-            add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
61
-        }
62
-    }
63
-
64
-
65
-    /**
66
-     * Sets how often transient cleanup occurs
67
-     *
68
-     * @return string
69
-     */
70
-    private function setTransientCleanupFrequency()
71
-    {
72
-        // sets how often transients are cleaned up
73
-        $this->transient_cleanup_frequency_options = apply_filters(
74
-            'FHEE__TransientCacheStorage__transient_cleanup_schedule_options',
75
-            array(
76
-                'off',
77
-                '15-minutes',
78
-                'hour',
79
-                '12-hours',
80
-                'day',
81
-            )
82
-        );
83
-        $transient_cleanup_frequency = apply_filters(
84
-            'FHEE__TransientCacheStorage__transient_cleanup_schedule',
85
-            'hour'
86
-        );
87
-        return in_array(
88
-            $transient_cleanup_frequency,
89
-            $this->transient_cleanup_frequency_options,
90
-            true
91
-        )
92
-            ? $transient_cleanup_frequency
93
-            : 'hour';
94
-    }
95
-
96
-
97
-    /**
98
-     * we need to be able to round timestamps off to match the set transient cleanup frequency
99
-     * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour,
100
-     * then that timestamp needs to be rounded up to 2:00 pm so that it is removed
101
-     * during the next scheduled cleanup after its expiration.
102
-     * We also round off the current time timestamp to the closest 5 minutes
103
-     * just to make the timestamps a little easier to round which helps with debugging.
104
-     *
105
-     * @param int    $timestamp [required]
106
-     * @param string $cleanup_frequency
107
-     * @param bool   $round_up
108
-     * @return int
109
-     */
110
-    private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true)
111
-    {
112
-        $cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency;
113
-        // in order to round the time to the closest xx minutes (or hours),
114
-        // we take the minutes (or hours) portion of the timestamp and divide it by xx,
115
-        // round down to a whole number, then multiply by xx to bring us almost back up to where we were
116
-        // why round down ? so the minutes (or hours) don't go over 60 (or 24)
117
-        // and bump the hour, which could bump the day, which could bump the month, etc,
118
-        // which would be bad because we don't always want to round up,
119
-        // but when we do we can easily achieve that by simply adding the desired offset,
120
-        $minutes = '00';
121
-        $hours = 'H';
122
-        switch ($cleanup_frequency) {
123
-            case '5-minutes':
124
-                $minutes = floor((int) date('i', $timestamp) / 5) * 5;
125
-                $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
126
-                $offset = MINUTE_IN_SECONDS * 5;
127
-                break;
128
-            case '15-minutes':
129
-                $minutes = floor((int) date('i', $timestamp) / 15) * 15;
130
-                $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
131
-                $offset = MINUTE_IN_SECONDS * 15;
132
-                break;
133
-            case '12-hours':
134
-                $hours = floor((int) date('H', $timestamp) / 12) * 12;
135
-                $hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
136
-                $offset = HOUR_IN_SECONDS * 12;
137
-                break;
138
-            case 'day':
139
-                $hours = '03'; // run cleanup at 3:00 am (or first site hit after that)
140
-                $offset = DAY_IN_SECONDS;
141
-                break;
142
-            case 'hour':
143
-            default:
144
-                $offset = HOUR_IN_SECONDS;
145
-                break;
146
-        }
147
-        $rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp));
148
-        $rounded_timestamp += $round_up ? $offset : 0;
149
-        return apply_filters(
150
-            'FHEE__TransientCacheStorage__roundTimestamp__timestamp',
151
-            $rounded_timestamp,
152
-            $timestamp,
153
-            $cleanup_frequency,
154
-            $round_up
155
-        );
156
-    }
157
-
158
-
159
-    /**
160
-     * Saves supplied data to a transient
161
-     * if an expiration is set, then it automatically schedules the transient for cleanup
162
-     *
163
-     * @param string $transient_key [required]
164
-     * @param string $data          [required]
165
-     * @param int    $expiration    number of seconds until the cache expires
166
-     * @return bool
167
-     */
168
-    public function add($transient_key, $data, $expiration = 0)
169
-    {
170
-        $expiration = (int) abs($expiration);
171
-        $saved = set_transient($transient_key, $data, $expiration);
172
-        if ($saved && $expiration) {
173
-            $this->scheduleTransientCleanup($transient_key, $expiration);
174
-        }
175
-        return $saved;
176
-    }
177
-
178
-
179
-    /**
180
-     * retrieves transient data
181
-     * automatically triggers early cache refresh for standard cache items
182
-     * in order to avoid cache stampedes on busy sites.
183
-     * For non-standard cache items like PHP Session data where early refreshing is not wanted,
184
-     * the $standard_cache parameter should be set to false when retrieving data
185
-     *
186
-     * @param string $transient_key [required]
187
-     * @param bool   $standard_cache
188
-     * @return mixed|null
189
-     */
190
-    public function get($transient_key, $standard_cache = true)
191
-    {
192
-        if (isset($this->transients[ $transient_key ])) {
193
-            // to avoid cache stampedes (AKA:dogpiles) for standard cache items,
194
-            // check if known cache expires within the next minute,
195
-            // and if so, remove it from our tracking and and return nothing.
196
-            // this should trigger the cache content to be regenerated during this request,
197
-            // while allowing any following requests to still access the existing cache
198
-            // until it gets replaced with the refreshed content
199
-            if (
200
-                $standard_cache
201
-                && $this->transients[ $transient_key ] - time() <= MINUTE_IN_SECONDS
202
-            ) {
203
-                unset($this->transients[ $transient_key ]);
204
-                $this->updateTransients();
205
-                return null;
206
-            }
207
-
208
-            // for non standard cache items, remove the key from our tracking,
209
-            // but proceed to retrieve the transient so that it also gets removed from the db
210
-            if ($this->transients[ $transient_key ] <= time()) {
211
-                unset($this->transients[ $transient_key ]);
212
-                $this->updateTransients();
213
-            }
214
-        }
215
-
216
-        $content = get_transient($transient_key);
217
-        return $content !== false ? $content : null;
218
-    }
219
-
220
-
221
-    /**
222
-     * delete a single transient and remove tracking
223
-     *
224
-     * @param string $transient_key [required] full or partial transient key to be deleted
225
-     */
226
-    public function delete($transient_key)
227
-    {
228
-        $this->deleteMany(array($transient_key));
229
-    }
230
-
231
-
232
-    /**
233
-     * delete multiple transients and remove tracking
234
-     *
235
-     * @param array $transient_keys [required] array of full or partial transient keys to be deleted
236
-     * @param bool  $force_delete   [optional] if true, then will not check incoming keys against those being tracked
237
-     *                              and proceed directly to deleting those entries from the cache storage
238
-     */
239
-    public function deleteMany(array $transient_keys, $force_delete = false)
240
-    {
241
-        $full_transient_keys = $force_delete ? $transient_keys : array();
242
-        if (empty($full_transient_keys)) {
243
-            foreach ($this->transients as $transient_key => $expiration) {
244
-                foreach ($transient_keys as $transient_key_to_delete) {
245
-                    if (strpos($transient_key, $transient_key_to_delete) !== false) {
246
-                        $full_transient_keys[] = $transient_key;
247
-                    }
248
-                }
249
-            }
250
-        }
251
-        if ($this->deleteTransientKeys($full_transient_keys)) {
252
-            $this->updateTransients();
253
-        }
254
-    }
255
-
256
-
257
-    /**
258
-     * sorts transients numerically by timestamp
259
-     * then saves the transient schedule to a WP option
260
-     */
261
-    private function updateTransients()
262
-    {
263
-        asort($this->transients, SORT_NUMERIC);
264
-        update_option(
265
-            TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY,
266
-            $this->transients
267
-        );
268
-    }
269
-
270
-
271
-    /**
272
-     * schedules a transient for cleanup by adding it to the transient tracking
273
-     *
274
-     * @param string $transient_key [required]
275
-     * @param int    $expiration    [required]
276
-     */
277
-    private function scheduleTransientCleanup($transient_key, $expiration)
278
-    {
279
-        // make sure a valid future timestamp is set
280
-        $expiration += $expiration < time() ? time() : 0;
281
-        // and round to the closest 15 minutes
282
-        $expiration = $this->roundTimestamp($expiration);
283
-        // save transients to clear using their ID as the key to avoid duplicates
284
-        $this->transients[ $transient_key ] = $expiration;
285
-        $this->updateTransients();
286
-    }
287
-
288
-
289
-    /**
290
-     * Since our tracked transients are sorted by their timestamps
291
-     * we can grab the first transient and see when it is scheduled for cleanup.
292
-     * If that timestamp is less than or equal to the current time,
293
-     * then cleanup is triggered
294
-     */
295
-    public function checkTransientCleanupSchedule()
296
-    {
297
-        if (empty($this->transients)) {
298
-            return;
299
-        }
300
-        // when do we run the next cleanup job?
301
-        reset($this->transients);
302
-        $next_scheduled_cleanup = current($this->transients);
303
-        // if the next cleanup job is scheduled for the current hour
304
-        if ($next_scheduled_cleanup <= $this->current_time) {
305
-            if ($this->cleanupExpiredTransients()) {
306
-                $this->updateTransients();
307
-            }
308
-        }
309
-    }
310
-
311
-
312
-    /**
313
-     * loops through the array of tracked transients,
314
-     * compiles a list of those that have expired, and sends that list off for deletion.
315
-     * Also removes any bad records from the transients array
316
-     *
317
-     * @return bool
318
-     */
319
-    private function cleanupExpiredTransients()
320
-    {
321
-        $update = false;
322
-        // filter the query limit. Set to 0 to turn off garbage collection
323
-        $limit = (int) abs(
324
-            apply_filters(
325
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
326
-                50
327
-            )
328
-        );
329
-        // non-zero LIMIT means take out the trash
330
-        if ($limit) {
331
-            $transient_keys = array();
332
-            foreach ($this->transients as $transient_key => $expiration) {
333
-                if ($expiration > $this->current_time) {
334
-                    continue;
335
-                }
336
-                if (! $expiration || ! $transient_key) {
337
-                    unset($this->transients[ $transient_key ]);
338
-                    $update = true;
339
-                    continue;
340
-                }
341
-                $transient_keys[] = $transient_key;
342
-            }
343
-            // delete expired keys, but maintain value of $update if nothing is deleted
344
-            $update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
345
-            do_action('FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
346
-        }
347
-        return $update;
348
-    }
349
-
350
-
351
-    /**
352
-     * calls delete_transient() on each transient key provided, up to the specified limit
353
-     *
354
-     * @param array $transient_keys [required]
355
-     * @param int   $limit
356
-     * @return bool
357
-     */
358
-    private function deleteTransientKeys(array $transient_keys, $limit = 50)
359
-    {
360
-        if (empty($transient_keys)) {
361
-            return false;
362
-        }
363
-        $counter = 0;
364
-        foreach ($transient_keys as $transient_key) {
365
-            if ($counter === $limit) {
366
-                break;
367
-            }
368
-            // remove any transient prefixes
369
-            $transient_key = strpos($transient_key, '_transient_timeout_') === 0
370
-                ? str_replace('_transient_timeout_', '', $transient_key)
371
-                : $transient_key;
372
-            $transient_key = strpos($transient_key, '_transient_') === 0
373
-                ? str_replace('_transient_', '', $transient_key)
374
-                : $transient_key;
375
-            delete_transient($transient_key);
376
-            unset($this->transients[ $transient_key ]);
377
-            $counter++;
378
-        }
379
-        return $counter > 0;
380
-    }
18
+	/**
19
+	 * wp-option option_name for tracking transients
20
+	 *
21
+	 * @type string
22
+	 */
23
+	const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule';
24
+
25
+	/**
26
+	 * @var int $current_time
27
+	 */
28
+	private $current_time;
29
+
30
+	/**
31
+	 * how often to perform transient cleanup
32
+	 *
33
+	 * @var string $transient_cleanup_frequency
34
+	 */
35
+	private $transient_cleanup_frequency;
36
+
37
+	/**
38
+	 * options for how often to perform transient cleanup
39
+	 *
40
+	 * @var array $transient_cleanup_frequency_options
41
+	 */
42
+	private $transient_cleanup_frequency_options = array();
43
+
44
+	/**
45
+	 * @var array $transients
46
+	 */
47
+	private $transients;
48
+
49
+
50
+	/**
51
+	 * TransientCacheStorage constructor.
52
+	 */
53
+	public function __construct()
54
+	{
55
+		$this->transient_cleanup_frequency = $this->setTransientCleanupFrequency();
56
+		// round current time down to closest 5 minutes to simplify scheduling
57
+		$this->current_time = $this->roundTimestamp(time(), '5-minutes', false);
58
+		$this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array());
59
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') {
60
+			add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999);
61
+		}
62
+	}
63
+
64
+
65
+	/**
66
+	 * Sets how often transient cleanup occurs
67
+	 *
68
+	 * @return string
69
+	 */
70
+	private function setTransientCleanupFrequency()
71
+	{
72
+		// sets how often transients are cleaned up
73
+		$this->transient_cleanup_frequency_options = apply_filters(
74
+			'FHEE__TransientCacheStorage__transient_cleanup_schedule_options',
75
+			array(
76
+				'off',
77
+				'15-minutes',
78
+				'hour',
79
+				'12-hours',
80
+				'day',
81
+			)
82
+		);
83
+		$transient_cleanup_frequency = apply_filters(
84
+			'FHEE__TransientCacheStorage__transient_cleanup_schedule',
85
+			'hour'
86
+		);
87
+		return in_array(
88
+			$transient_cleanup_frequency,
89
+			$this->transient_cleanup_frequency_options,
90
+			true
91
+		)
92
+			? $transient_cleanup_frequency
93
+			: 'hour';
94
+	}
95
+
96
+
97
+	/**
98
+	 * we need to be able to round timestamps off to match the set transient cleanup frequency
99
+	 * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour,
100
+	 * then that timestamp needs to be rounded up to 2:00 pm so that it is removed
101
+	 * during the next scheduled cleanup after its expiration.
102
+	 * We also round off the current time timestamp to the closest 5 minutes
103
+	 * just to make the timestamps a little easier to round which helps with debugging.
104
+	 *
105
+	 * @param int    $timestamp [required]
106
+	 * @param string $cleanup_frequency
107
+	 * @param bool   $round_up
108
+	 * @return int
109
+	 */
110
+	private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true)
111
+	{
112
+		$cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency;
113
+		// in order to round the time to the closest xx minutes (or hours),
114
+		// we take the minutes (or hours) portion of the timestamp and divide it by xx,
115
+		// round down to a whole number, then multiply by xx to bring us almost back up to where we were
116
+		// why round down ? so the minutes (or hours) don't go over 60 (or 24)
117
+		// and bump the hour, which could bump the day, which could bump the month, etc,
118
+		// which would be bad because we don't always want to round up,
119
+		// but when we do we can easily achieve that by simply adding the desired offset,
120
+		$minutes = '00';
121
+		$hours = 'H';
122
+		switch ($cleanup_frequency) {
123
+			case '5-minutes':
124
+				$minutes = floor((int) date('i', $timestamp) / 5) * 5;
125
+				$minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
126
+				$offset = MINUTE_IN_SECONDS * 5;
127
+				break;
128
+			case '15-minutes':
129
+				$minutes = floor((int) date('i', $timestamp) / 15) * 15;
130
+				$minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT);
131
+				$offset = MINUTE_IN_SECONDS * 15;
132
+				break;
133
+			case '12-hours':
134
+				$hours = floor((int) date('H', $timestamp) / 12) * 12;
135
+				$hours = str_pad($hours, 2, '0', STR_PAD_LEFT);
136
+				$offset = HOUR_IN_SECONDS * 12;
137
+				break;
138
+			case 'day':
139
+				$hours = '03'; // run cleanup at 3:00 am (or first site hit after that)
140
+				$offset = DAY_IN_SECONDS;
141
+				break;
142
+			case 'hour':
143
+			default:
144
+				$offset = HOUR_IN_SECONDS;
145
+				break;
146
+		}
147
+		$rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp));
148
+		$rounded_timestamp += $round_up ? $offset : 0;
149
+		return apply_filters(
150
+			'FHEE__TransientCacheStorage__roundTimestamp__timestamp',
151
+			$rounded_timestamp,
152
+			$timestamp,
153
+			$cleanup_frequency,
154
+			$round_up
155
+		);
156
+	}
157
+
158
+
159
+	/**
160
+	 * Saves supplied data to a transient
161
+	 * if an expiration is set, then it automatically schedules the transient for cleanup
162
+	 *
163
+	 * @param string $transient_key [required]
164
+	 * @param string $data          [required]
165
+	 * @param int    $expiration    number of seconds until the cache expires
166
+	 * @return bool
167
+	 */
168
+	public function add($transient_key, $data, $expiration = 0)
169
+	{
170
+		$expiration = (int) abs($expiration);
171
+		$saved = set_transient($transient_key, $data, $expiration);
172
+		if ($saved && $expiration) {
173
+			$this->scheduleTransientCleanup($transient_key, $expiration);
174
+		}
175
+		return $saved;
176
+	}
177
+
178
+
179
+	/**
180
+	 * retrieves transient data
181
+	 * automatically triggers early cache refresh for standard cache items
182
+	 * in order to avoid cache stampedes on busy sites.
183
+	 * For non-standard cache items like PHP Session data where early refreshing is not wanted,
184
+	 * the $standard_cache parameter should be set to false when retrieving data
185
+	 *
186
+	 * @param string $transient_key [required]
187
+	 * @param bool   $standard_cache
188
+	 * @return mixed|null
189
+	 */
190
+	public function get($transient_key, $standard_cache = true)
191
+	{
192
+		if (isset($this->transients[ $transient_key ])) {
193
+			// to avoid cache stampedes (AKA:dogpiles) for standard cache items,
194
+			// check if known cache expires within the next minute,
195
+			// and if so, remove it from our tracking and and return nothing.
196
+			// this should trigger the cache content to be regenerated during this request,
197
+			// while allowing any following requests to still access the existing cache
198
+			// until it gets replaced with the refreshed content
199
+			if (
200
+				$standard_cache
201
+				&& $this->transients[ $transient_key ] - time() <= MINUTE_IN_SECONDS
202
+			) {
203
+				unset($this->transients[ $transient_key ]);
204
+				$this->updateTransients();
205
+				return null;
206
+			}
207
+
208
+			// for non standard cache items, remove the key from our tracking,
209
+			// but proceed to retrieve the transient so that it also gets removed from the db
210
+			if ($this->transients[ $transient_key ] <= time()) {
211
+				unset($this->transients[ $transient_key ]);
212
+				$this->updateTransients();
213
+			}
214
+		}
215
+
216
+		$content = get_transient($transient_key);
217
+		return $content !== false ? $content : null;
218
+	}
219
+
220
+
221
+	/**
222
+	 * delete a single transient and remove tracking
223
+	 *
224
+	 * @param string $transient_key [required] full or partial transient key to be deleted
225
+	 */
226
+	public function delete($transient_key)
227
+	{
228
+		$this->deleteMany(array($transient_key));
229
+	}
230
+
231
+
232
+	/**
233
+	 * delete multiple transients and remove tracking
234
+	 *
235
+	 * @param array $transient_keys [required] array of full or partial transient keys to be deleted
236
+	 * @param bool  $force_delete   [optional] if true, then will not check incoming keys against those being tracked
237
+	 *                              and proceed directly to deleting those entries from the cache storage
238
+	 */
239
+	public function deleteMany(array $transient_keys, $force_delete = false)
240
+	{
241
+		$full_transient_keys = $force_delete ? $transient_keys : array();
242
+		if (empty($full_transient_keys)) {
243
+			foreach ($this->transients as $transient_key => $expiration) {
244
+				foreach ($transient_keys as $transient_key_to_delete) {
245
+					if (strpos($transient_key, $transient_key_to_delete) !== false) {
246
+						$full_transient_keys[] = $transient_key;
247
+					}
248
+				}
249
+			}
250
+		}
251
+		if ($this->deleteTransientKeys($full_transient_keys)) {
252
+			$this->updateTransients();
253
+		}
254
+	}
255
+
256
+
257
+	/**
258
+	 * sorts transients numerically by timestamp
259
+	 * then saves the transient schedule to a WP option
260
+	 */
261
+	private function updateTransients()
262
+	{
263
+		asort($this->transients, SORT_NUMERIC);
264
+		update_option(
265
+			TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY,
266
+			$this->transients
267
+		);
268
+	}
269
+
270
+
271
+	/**
272
+	 * schedules a transient for cleanup by adding it to the transient tracking
273
+	 *
274
+	 * @param string $transient_key [required]
275
+	 * @param int    $expiration    [required]
276
+	 */
277
+	private function scheduleTransientCleanup($transient_key, $expiration)
278
+	{
279
+		// make sure a valid future timestamp is set
280
+		$expiration += $expiration < time() ? time() : 0;
281
+		// and round to the closest 15 minutes
282
+		$expiration = $this->roundTimestamp($expiration);
283
+		// save transients to clear using their ID as the key to avoid duplicates
284
+		$this->transients[ $transient_key ] = $expiration;
285
+		$this->updateTransients();
286
+	}
287
+
288
+
289
+	/**
290
+	 * Since our tracked transients are sorted by their timestamps
291
+	 * we can grab the first transient and see when it is scheduled for cleanup.
292
+	 * If that timestamp is less than or equal to the current time,
293
+	 * then cleanup is triggered
294
+	 */
295
+	public function checkTransientCleanupSchedule()
296
+	{
297
+		if (empty($this->transients)) {
298
+			return;
299
+		}
300
+		// when do we run the next cleanup job?
301
+		reset($this->transients);
302
+		$next_scheduled_cleanup = current($this->transients);
303
+		// if the next cleanup job is scheduled for the current hour
304
+		if ($next_scheduled_cleanup <= $this->current_time) {
305
+			if ($this->cleanupExpiredTransients()) {
306
+				$this->updateTransients();
307
+			}
308
+		}
309
+	}
310
+
311
+
312
+	/**
313
+	 * loops through the array of tracked transients,
314
+	 * compiles a list of those that have expired, and sends that list off for deletion.
315
+	 * Also removes any bad records from the transients array
316
+	 *
317
+	 * @return bool
318
+	 */
319
+	private function cleanupExpiredTransients()
320
+	{
321
+		$update = false;
322
+		// filter the query limit. Set to 0 to turn off garbage collection
323
+		$limit = (int) abs(
324
+			apply_filters(
325
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
326
+				50
327
+			)
328
+		);
329
+		// non-zero LIMIT means take out the trash
330
+		if ($limit) {
331
+			$transient_keys = array();
332
+			foreach ($this->transients as $transient_key => $expiration) {
333
+				if ($expiration > $this->current_time) {
334
+					continue;
335
+				}
336
+				if (! $expiration || ! $transient_key) {
337
+					unset($this->transients[ $transient_key ]);
338
+					$update = true;
339
+					continue;
340
+				}
341
+				$transient_keys[] = $transient_key;
342
+			}
343
+			// delete expired keys, but maintain value of $update if nothing is deleted
344
+			$update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update;
345
+			do_action('FHEE__TransientCacheStorage__clearExpiredTransients__end', $this);
346
+		}
347
+		return $update;
348
+	}
349
+
350
+
351
+	/**
352
+	 * calls delete_transient() on each transient key provided, up to the specified limit
353
+	 *
354
+	 * @param array $transient_keys [required]
355
+	 * @param int   $limit
356
+	 * @return bool
357
+	 */
358
+	private function deleteTransientKeys(array $transient_keys, $limit = 50)
359
+	{
360
+		if (empty($transient_keys)) {
361
+			return false;
362
+		}
363
+		$counter = 0;
364
+		foreach ($transient_keys as $transient_key) {
365
+			if ($counter === $limit) {
366
+				break;
367
+			}
368
+			// remove any transient prefixes
369
+			$transient_key = strpos($transient_key, '_transient_timeout_') === 0
370
+				? str_replace('_transient_timeout_', '', $transient_key)
371
+				: $transient_key;
372
+			$transient_key = strpos($transient_key, '_transient_') === 0
373
+				? str_replace('_transient_', '', $transient_key)
374
+				: $transient_key;
375
+			delete_transient($transient_key);
376
+			unset($this->transients[ $transient_key ]);
377
+			$counter++;
378
+		}
379
+		return $counter > 0;
380
+	}
381 381
 }
Please login to merge, or discard this patch.
core/services/container/DependencyInjector.php 2 patches
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -71,12 +71,12 @@  discard block
 block discarded – undo
71 71
     public function getReflectionClass($class_name)
72 72
     {
73 73
         if (
74
-            ! isset($this->reflectors[ $class_name ])
75
-            || ! $this->reflectors[ $class_name ] instanceof ReflectionClass
74
+            ! isset($this->reflectors[$class_name])
75
+            || ! $this->reflectors[$class_name] instanceof ReflectionClass
76 76
         ) {
77
-            $this->reflectors[ $class_name ] = new ReflectionClass($class_name);
77
+            $this->reflectors[$class_name] = new ReflectionClass($class_name);
78 78
         }
79
-        return $this->reflectors[ $class_name ];
79
+        return $this->reflectors[$class_name];
80 80
     }
81 81
 
82 82
 
@@ -91,12 +91,12 @@  discard block
 block discarded – undo
91 91
     protected function getConstructor(ReflectionClass $reflector)
92 92
     {
93 93
         if (
94
-            ! isset($this->constructors[ $reflector->getName() ])
95
-            || ! $this->constructors[ $reflector->getName() ] instanceof ReflectionMethod
94
+            ! isset($this->constructors[$reflector->getName()])
95
+            || ! $this->constructors[$reflector->getName()] instanceof ReflectionMethod
96 96
         ) {
97
-            $this->constructors[ $reflector->getName() ] = $reflector->getConstructor();
97
+            $this->constructors[$reflector->getName()] = $reflector->getConstructor();
98 98
         }
99
-        return $this->constructors[ $reflector->getName() ];
99
+        return $this->constructors[$reflector->getName()];
100 100
     }
101 101
 
102 102
 
@@ -110,10 +110,10 @@  discard block
 block discarded – undo
110 110
      */
111 111
     protected function getParameters(ReflectionMethod $constructor)
112 112
     {
113
-        if (! isset($this->parameters[ $constructor->class ])) {
114
-            $this->parameters[ $constructor->class ] = $constructor->getParameters();
113
+        if ( ! isset($this->parameters[$constructor->class])) {
114
+            $this->parameters[$constructor->class] = $constructor->getParameters();
115 115
         }
116
-        return $this->parameters[ $constructor->class ];
116
+        return $this->parameters[$constructor->class];
117 117
     }
118 118
 
119 119
 
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
         // let's examine the constructor
149 149
         $constructor = $this->getConstructor($reflector);
150 150
         // whu? huh? nothing?
151
-        if (! $constructor) {
151
+        if ( ! $constructor) {
152 152
             return $arguments;
153 153
         }
154 154
         // get constructor parameters
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
         $argument_keys = array_keys($arguments);
162 162
         // now loop thru all of the constructors expected parameters
163 163
         foreach ($params as $index => $param) {
164
-            if (! $param instanceof ReflectionParameter) {
164
+            if ( ! $param instanceof ReflectionParameter) {
165 165
                 continue;
166 166
             }
167 167
             // is this a dependency for a specific class ?
@@ -169,41 +169,41 @@  discard block
 block discarded – undo
169 169
             $param_name = $param->getName() ? $param->getName() : '';
170 170
             if (
171 171
 // param is not a class but is specified in the list of ingredients for this Recipe
172
-                is_string($param_name) && isset($ingredients[ $param_name ])
172
+                is_string($param_name) && isset($ingredients[$param_name])
173 173
             ) {
174 174
                 // attempt to inject the dependency
175
-                $resolved_parameters[ $index ] = $ingredients[ $param_name ];
175
+                $resolved_parameters[$index] = $ingredients[$param_name];
176 176
             } elseif (
177 177
 // param is specified in the list of ingredients for this Recipe
178
-                isset($ingredients[ $param_class ])
178
+                isset($ingredients[$param_class])
179 179
             ) { // attempt to inject the dependency
180
-                $resolved_parameters[ $index ] = $this->injectDependency($reflector, $ingredients[ $param_class ]);
180
+                $resolved_parameters[$index] = $this->injectDependency($reflector, $ingredients[$param_class]);
181 181
             } elseif (
182 182
 // param is not even a class
183 183
                 empty($param_class)
184 184
                 // and something already exists in the incoming arguments for this param
185
-                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
185
+                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
186 186
             ) {
187 187
                 // add parameter from incoming arguments
188
-                $resolved_parameters[ $index ] = $arguments[ $argument_keys[ $index ] ];
188
+                $resolved_parameters[$index] = $arguments[$argument_keys[$index]];
189 189
             } elseif (
190 190
 // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
191 191
                 ! empty($param_class)
192
-                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
193
-                && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
192
+                && isset($argument_keys[$index], $arguments[$argument_keys[$index]])
193
+                && $arguments[$argument_keys[$index]] instanceof $param_class
194 194
             ) {
195 195
                 // add parameter from incoming arguments
196
-                $resolved_parameters[ $index ] = $arguments[ $argument_keys[ $index ] ];
196
+                $resolved_parameters[$index] = $arguments[$argument_keys[$index]];
197 197
             } elseif (
198 198
 // parameter is type hinted as a class, and should be injected
199 199
                 ! empty($param_class)
200 200
             ) {
201 201
                 // attempt to inject the dependency
202
-                $resolved_parameters[ $index ] = $this->injectDependency($reflector, $param_class);
202
+                $resolved_parameters[$index] = $this->injectDependency($reflector, $param_class);
203 203
             } elseif ($param->isOptional()) {
204
-                $resolved_parameters[ $index ] = $param->getDefaultValue();
204
+                $resolved_parameters[$index] = $param->getDefaultValue();
205 205
             } else {
206
-                $resolved_parameters[ $index ] = null;
206
+                $resolved_parameters[$index] = null;
207 207
             }
208 208
         }
209 209
         return $resolved_parameters;
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
     private function injectDependency(ReflectionClass $reflector, $param_class)
220 220
     {
221 221
         $dependency = $this->coffee_pot->brew($param_class);
222
-        if (! $dependency instanceof $param_class) {
222
+        if ( ! $dependency instanceof $param_class) {
223 223
             throw new UnexpectedValueException(
224 224
                 sprintf(
225 225
                     esc_html__(
Please login to merge, or discard this patch.
Indentation   +207 added lines, -207 removed lines patch added patch discarded remove patch
@@ -20,216 +20,216 @@
 block discarded – undo
20 20
  */
21 21
 class DependencyInjector implements InjectorInterface
22 22
 {
23
-    /**
24
-     * @var CoffeePotInterface $coffee_pot
25
-     */
26
-    private $coffee_pot;
27
-
28
-    /**
29
-     * @var EEH_Array $array_helper
30
-     */
31
-    private $array_helper;
32
-
33
-    /**
34
-     * @var ReflectionClass[] $reflectors
35
-     */
36
-    private $reflectors;
37
-
38
-    /**
39
-     * @var ReflectionMethod[] $constructors
40
-     */
41
-    private $constructors;
42
-
43
-    /**
44
-     * @var ReflectionParameter[] $parameters
45
-     */
46
-    private $parameters;
47
-
48
-
49
-    /**
50
-     * DependencyInjector constructor
51
-     *
52
-     * @param CoffeePotInterface $coffee_pot
53
-     * @param EEH_Array          $array_helper
54
-     */
55
-    public function __construct(CoffeePotInterface $coffee_pot, EEH_Array $array_helper)
56
-    {
57
-        $this->coffee_pot = $coffee_pot;
58
-        $this->array_helper = $array_helper;
59
-    }
60
-
61
-
62
-    /**
63
-     * getReflectionClass
64
-     * checks if a ReflectionClass object has already been generated for a class
65
-     * and returns that instead of creating a new one
66
-     *
67
-     * @param string $class_name
68
-     * @return ReflectionClass
69
-     */
70
-    public function getReflectionClass($class_name)
71
-    {
72
-        if (
73
-            ! isset($this->reflectors[ $class_name ])
74
-            || ! $this->reflectors[ $class_name ] instanceof ReflectionClass
75
-        ) {
76
-            $this->reflectors[ $class_name ] = new ReflectionClass($class_name);
77
-        }
78
-        return $this->reflectors[ $class_name ];
79
-    }
80
-
81
-
82
-    /**
83
-     * getConstructor
84
-     * checks if a ReflectionMethod object has already been generated for the class constructor
85
-     * and returns that instead of creating a new one
86
-     *
87
-     * @param ReflectionClass $reflector
88
-     * @return ReflectionMethod
89
-     */
90
-    protected function getConstructor(ReflectionClass $reflector)
91
-    {
92
-        if (
93
-            ! isset($this->constructors[ $reflector->getName() ])
94
-            || ! $this->constructors[ $reflector->getName() ] instanceof ReflectionMethod
95
-        ) {
96
-            $this->constructors[ $reflector->getName() ] = $reflector->getConstructor();
97
-        }
98
-        return $this->constructors[ $reflector->getName() ];
99
-    }
100
-
101
-
102
-    /**
103
-     * getParameters
104
-     * checks if an array of ReflectionParameter objects has already been generated for the class constructor
105
-     * and returns that instead of creating a new one
106
-     *
107
-     * @param ReflectionMethod $constructor
108
-     * @return ReflectionParameter[]
109
-     */
110
-    protected function getParameters(ReflectionMethod $constructor)
111
-    {
112
-        if (! isset($this->parameters[ $constructor->class ])) {
113
-            $this->parameters[ $constructor->class ] = $constructor->getParameters();
114
-        }
115
-        return $this->parameters[ $constructor->class ];
116
-    }
117
-
118
-
119
-    /**
120
-     * resolveDependencies
121
-     * examines the constructor for the requested class to determine
122
-     * if any dependencies exist, and if they can be injected.
123
-     * If so, then those classes will be added to the array of arguments passed to the constructor
124
-     * PLZ NOTE: this is achieved by type hinting the constructor params
125
-     * For example:
126
-     *        if attempting to load a class "Foo" with the following constructor:
127
-     *        __construct( Bar $bar_class, Fighter $grohl_class )
128
-     *        then $bar_class and $grohl_class will be added to the $arguments array,
129
-     *        but only IF they are NOT already present in the incoming arguments array,
130
-     *        and the correct classes can be loaded
131
-     *
132
-     * @param RecipeInterface $recipe
133
-     * @param ReflectionClass $reflector
134
-     * @param array           $arguments
135
-     * @return array
136
-     * @throws UnexpectedValueException
137
-     */
138
-    public function resolveDependencies(RecipeInterface $recipe, ReflectionClass $reflector, $arguments = array())
139
-    {
140
-        // if arguments array is numerically and sequentially indexed, then we want it to remain as is,
141
-        // else wrap it in an additional array so that it doesn't get split into multiple parameters
142
-        $arguments = $this->array_helper->is_array_numerically_and_sequentially_indexed($arguments)
143
-            ? $arguments
144
-            : array($arguments);
145
-        $resolved_parameters = array();
146
-        // let's examine the constructor
147
-        // let's examine the constructor
148
-        $constructor = $this->getConstructor($reflector);
149
-        // whu? huh? nothing?
150
-        if (! $constructor) {
151
-            return $arguments;
152
-        }
153
-        // get constructor parameters
154
-        $params = $this->getParameters($constructor);
155
-        if (empty($params)) {
156
-            return $resolved_parameters;
157
-        }
158
-        $ingredients = $recipe->ingredients();
159
-        // and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
160
-        $argument_keys = array_keys($arguments);
161
-        // now loop thru all of the constructors expected parameters
162
-        foreach ($params as $index => $param) {
163
-            if (! $param instanceof ReflectionParameter) {
164
-                continue;
165
-            }
166
-            // is this a dependency for a specific class ?
167
-            $param_class = $param->getClass() ? $param->getClass()->name : '';
168
-            $param_name = $param->getName() ? $param->getName() : '';
169
-            if (
23
+	/**
24
+	 * @var CoffeePotInterface $coffee_pot
25
+	 */
26
+	private $coffee_pot;
27
+
28
+	/**
29
+	 * @var EEH_Array $array_helper
30
+	 */
31
+	private $array_helper;
32
+
33
+	/**
34
+	 * @var ReflectionClass[] $reflectors
35
+	 */
36
+	private $reflectors;
37
+
38
+	/**
39
+	 * @var ReflectionMethod[] $constructors
40
+	 */
41
+	private $constructors;
42
+
43
+	/**
44
+	 * @var ReflectionParameter[] $parameters
45
+	 */
46
+	private $parameters;
47
+
48
+
49
+	/**
50
+	 * DependencyInjector constructor
51
+	 *
52
+	 * @param CoffeePotInterface $coffee_pot
53
+	 * @param EEH_Array          $array_helper
54
+	 */
55
+	public function __construct(CoffeePotInterface $coffee_pot, EEH_Array $array_helper)
56
+	{
57
+		$this->coffee_pot = $coffee_pot;
58
+		$this->array_helper = $array_helper;
59
+	}
60
+
61
+
62
+	/**
63
+	 * getReflectionClass
64
+	 * checks if a ReflectionClass object has already been generated for a class
65
+	 * and returns that instead of creating a new one
66
+	 *
67
+	 * @param string $class_name
68
+	 * @return ReflectionClass
69
+	 */
70
+	public function getReflectionClass($class_name)
71
+	{
72
+		if (
73
+			! isset($this->reflectors[ $class_name ])
74
+			|| ! $this->reflectors[ $class_name ] instanceof ReflectionClass
75
+		) {
76
+			$this->reflectors[ $class_name ] = new ReflectionClass($class_name);
77
+		}
78
+		return $this->reflectors[ $class_name ];
79
+	}
80
+
81
+
82
+	/**
83
+	 * getConstructor
84
+	 * checks if a ReflectionMethod object has already been generated for the class constructor
85
+	 * and returns that instead of creating a new one
86
+	 *
87
+	 * @param ReflectionClass $reflector
88
+	 * @return ReflectionMethod
89
+	 */
90
+	protected function getConstructor(ReflectionClass $reflector)
91
+	{
92
+		if (
93
+			! isset($this->constructors[ $reflector->getName() ])
94
+			|| ! $this->constructors[ $reflector->getName() ] instanceof ReflectionMethod
95
+		) {
96
+			$this->constructors[ $reflector->getName() ] = $reflector->getConstructor();
97
+		}
98
+		return $this->constructors[ $reflector->getName() ];
99
+	}
100
+
101
+
102
+	/**
103
+	 * getParameters
104
+	 * checks if an array of ReflectionParameter objects has already been generated for the class constructor
105
+	 * and returns that instead of creating a new one
106
+	 *
107
+	 * @param ReflectionMethod $constructor
108
+	 * @return ReflectionParameter[]
109
+	 */
110
+	protected function getParameters(ReflectionMethod $constructor)
111
+	{
112
+		if (! isset($this->parameters[ $constructor->class ])) {
113
+			$this->parameters[ $constructor->class ] = $constructor->getParameters();
114
+		}
115
+		return $this->parameters[ $constructor->class ];
116
+	}
117
+
118
+
119
+	/**
120
+	 * resolveDependencies
121
+	 * examines the constructor for the requested class to determine
122
+	 * if any dependencies exist, and if they can be injected.
123
+	 * If so, then those classes will be added to the array of arguments passed to the constructor
124
+	 * PLZ NOTE: this is achieved by type hinting the constructor params
125
+	 * For example:
126
+	 *        if attempting to load a class "Foo" with the following constructor:
127
+	 *        __construct( Bar $bar_class, Fighter $grohl_class )
128
+	 *        then $bar_class and $grohl_class will be added to the $arguments array,
129
+	 *        but only IF they are NOT already present in the incoming arguments array,
130
+	 *        and the correct classes can be loaded
131
+	 *
132
+	 * @param RecipeInterface $recipe
133
+	 * @param ReflectionClass $reflector
134
+	 * @param array           $arguments
135
+	 * @return array
136
+	 * @throws UnexpectedValueException
137
+	 */
138
+	public function resolveDependencies(RecipeInterface $recipe, ReflectionClass $reflector, $arguments = array())
139
+	{
140
+		// if arguments array is numerically and sequentially indexed, then we want it to remain as is,
141
+		// else wrap it in an additional array so that it doesn't get split into multiple parameters
142
+		$arguments = $this->array_helper->is_array_numerically_and_sequentially_indexed($arguments)
143
+			? $arguments
144
+			: array($arguments);
145
+		$resolved_parameters = array();
146
+		// let's examine the constructor
147
+		// let's examine the constructor
148
+		$constructor = $this->getConstructor($reflector);
149
+		// whu? huh? nothing?
150
+		if (! $constructor) {
151
+			return $arguments;
152
+		}
153
+		// get constructor parameters
154
+		$params = $this->getParameters($constructor);
155
+		if (empty($params)) {
156
+			return $resolved_parameters;
157
+		}
158
+		$ingredients = $recipe->ingredients();
159
+		// and the keys for the incoming arguments array so that we can compare existing arguments with what is expected
160
+		$argument_keys = array_keys($arguments);
161
+		// now loop thru all of the constructors expected parameters
162
+		foreach ($params as $index => $param) {
163
+			if (! $param instanceof ReflectionParameter) {
164
+				continue;
165
+			}
166
+			// is this a dependency for a specific class ?
167
+			$param_class = $param->getClass() ? $param->getClass()->name : '';
168
+			$param_name = $param->getName() ? $param->getName() : '';
169
+			if (
170 170
 // param is not a class but is specified in the list of ingredients for this Recipe
171
-                is_string($param_name) && isset($ingredients[ $param_name ])
172
-            ) {
173
-                // attempt to inject the dependency
174
-                $resolved_parameters[ $index ] = $ingredients[ $param_name ];
175
-            } elseif (
171
+				is_string($param_name) && isset($ingredients[ $param_name ])
172
+			) {
173
+				// attempt to inject the dependency
174
+				$resolved_parameters[ $index ] = $ingredients[ $param_name ];
175
+			} elseif (
176 176
 // param is specified in the list of ingredients for this Recipe
177
-                isset($ingredients[ $param_class ])
178
-            ) { // attempt to inject the dependency
179
-                $resolved_parameters[ $index ] = $this->injectDependency($reflector, $ingredients[ $param_class ]);
180
-            } elseif (
177
+				isset($ingredients[ $param_class ])
178
+			) { // attempt to inject the dependency
179
+				$resolved_parameters[ $index ] = $this->injectDependency($reflector, $ingredients[ $param_class ]);
180
+			} elseif (
181 181
 // param is not even a class
182
-                empty($param_class)
183
-                // and something already exists in the incoming arguments for this param
184
-                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
185
-            ) {
186
-                // add parameter from incoming arguments
187
-                $resolved_parameters[ $index ] = $arguments[ $argument_keys[ $index ] ];
188
-            } elseif (
182
+				empty($param_class)
183
+				// and something already exists in the incoming arguments for this param
184
+				&& isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
185
+			) {
186
+				// add parameter from incoming arguments
187
+				$resolved_parameters[ $index ] = $arguments[ $argument_keys[ $index ] ];
188
+			} elseif (
189 189
 // parameter is type hinted as a class, exists as an incoming argument, AND it's the correct class
190
-                ! empty($param_class)
191
-                && isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
192
-                && $arguments[ $argument_keys[ $index ] ] instanceof $param_class
193
-            ) {
194
-                // add parameter from incoming arguments
195
-                $resolved_parameters[ $index ] = $arguments[ $argument_keys[ $index ] ];
196
-            } elseif (
190
+				! empty($param_class)
191
+				&& isset($argument_keys[ $index ], $arguments[ $argument_keys[ $index ] ])
192
+				&& $arguments[ $argument_keys[ $index ] ] instanceof $param_class
193
+			) {
194
+				// add parameter from incoming arguments
195
+				$resolved_parameters[ $index ] = $arguments[ $argument_keys[ $index ] ];
196
+			} elseif (
197 197
 // parameter is type hinted as a class, and should be injected
198
-                ! empty($param_class)
199
-            ) {
200
-                // attempt to inject the dependency
201
-                $resolved_parameters[ $index ] = $this->injectDependency($reflector, $param_class);
202
-            } elseif ($param->isOptional()) {
203
-                $resolved_parameters[ $index ] = $param->getDefaultValue();
204
-            } else {
205
-                $resolved_parameters[ $index ] = null;
206
-            }
207
-        }
208
-        return $resolved_parameters;
209
-    }
210
-
211
-
212
-    /**
213
-     * @param ReflectionClass $reflector
214
-     * @param string          $param_class
215
-     * @return mixed
216
-     * @throws UnexpectedValueException
217
-     */
218
-    private function injectDependency(ReflectionClass $reflector, $param_class)
219
-    {
220
-        $dependency = $this->coffee_pot->brew($param_class);
221
-        if (! $dependency instanceof $param_class) {
222
-            throw new UnexpectedValueException(
223
-                sprintf(
224
-                    esc_html__(
225
-                        'Could not resolve dependency for "%1$s" for the "%2$s" class constructor.',
226
-                        'event_espresso'
227
-                    ),
228
-                    $param_class,
229
-                    $reflector->getName()
230
-                )
231
-            );
232
-        }
233
-        return $dependency;
234
-    }
198
+				! empty($param_class)
199
+			) {
200
+				// attempt to inject the dependency
201
+				$resolved_parameters[ $index ] = $this->injectDependency($reflector, $param_class);
202
+			} elseif ($param->isOptional()) {
203
+				$resolved_parameters[ $index ] = $param->getDefaultValue();
204
+			} else {
205
+				$resolved_parameters[ $index ] = null;
206
+			}
207
+		}
208
+		return $resolved_parameters;
209
+	}
210
+
211
+
212
+	/**
213
+	 * @param ReflectionClass $reflector
214
+	 * @param string          $param_class
215
+	 * @return mixed
216
+	 * @throws UnexpectedValueException
217
+	 */
218
+	private function injectDependency(ReflectionClass $reflector, $param_class)
219
+	{
220
+		$dependency = $this->coffee_pot->brew($param_class);
221
+		if (! $dependency instanceof $param_class) {
222
+			throw new UnexpectedValueException(
223
+				sprintf(
224
+					esc_html__(
225
+						'Could not resolve dependency for "%1$s" for the "%2$s" class constructor.',
226
+						'event_espresso'
227
+					),
228
+					$param_class,
229
+					$reflector->getName()
230
+				)
231
+			);
232
+		}
233
+		return $dependency;
234
+	}
235 235
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Datetime.class.php 2 patches
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -533,7 +533,7 @@  discard block
 block discarded – undo
533 533
             $date_or_time,
534 534
             $echo
535 535
         );
536
-        if (! $echo) {
536
+        if ( ! $echo) {
537 537
             return $dtt;
538 538
         }
539 539
         return '';
@@ -635,7 +635,7 @@  discard block
 block discarded – undo
635 635
             '&nbsp;',
636 636
             $this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
637 637
         );
638
-        return $start !== $end ? $start . $conjunction . $end : $start;
638
+        return $start !== $end ? $start.$conjunction.$end : $start;
639 639
     }
640 640
 
641 641
 
@@ -743,7 +743,7 @@  discard block
 block discarded – undo
743 743
             '&nbsp;',
744 744
             $this->get_i18n_datetime('DTT_EVT_end', $tm_format)
745 745
         );
746
-        return $start !== $end ? $start . $conjunction . $end : $start;
746
+        return $start !== $end ? $start.$conjunction.$end : $start;
747 747
     }
748 748
 
749 749
 
@@ -788,7 +788,7 @@  discard block
 block discarded – undo
788 788
     ) {
789 789
         $dt_format = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
790 790
         $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
791
-        $full_format = $dt_format . $separator . $tm_format;
791
+        $full_format = $dt_format.$separator.$tm_format;
792 792
         // the range output depends on various conditions
793 793
         switch (true) {
794 794
             // start date timestamp and end date timestamp are the same.
@@ -1029,7 +1029,7 @@  discard block
 block discarded – undo
1029 1029
         // tickets remaining available for purchase
1030 1030
         // no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
1031 1031
         $dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
1032
-        if (! $consider_tickets) {
1032
+        if ( ! $consider_tickets) {
1033 1033
             return $dtt_remaining;
1034 1034
         }
1035 1035
         $tickets_remaining = $this->tickets_remaining();
@@ -1053,7 +1053,7 @@  discard block
 block discarded – undo
1053 1053
     {
1054 1054
         $sum = 0;
1055 1055
         $tickets = $this->tickets($query_params);
1056
-        if (! empty($tickets)) {
1056
+        if ( ! empty($tickets)) {
1057 1057
             foreach ($tickets as $ticket) {
1058 1058
                 if ($ticket instanceof EE_Ticket) {
1059 1059
                     // get the actual amount of tickets that can be sold
@@ -1204,7 +1204,7 @@  discard block
 block discarded – undo
1204 1204
     {
1205 1205
         if ($use_dtt_name) {
1206 1206
             $dtt_name = $this->name();
1207
-            if (! empty($dtt_name)) {
1207
+            if ( ! empty($dtt_name)) {
1208 1208
                 return $dtt_name;
1209 1209
             }
1210 1210
         }
@@ -1212,14 +1212,14 @@  discard block
 block discarded – undo
1212 1212
         if (
1213 1213
             date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1214 1214
         ) {
1215
-            $display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1215
+            $display_date = $this->start_date('M j\, Y g:i a').' - '.$this->end_date('M j\, Y g:i a');
1216 1216
             // next condition is if its the same month but different day
1217 1217
         } else {
1218 1218
             if (
1219 1219
                 date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1220 1220
                 && date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1221 1221
             ) {
1222
-                $display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1222
+                $display_date = $this->start_date('M j\, g:i a').' - '.$this->end_date('M j\, g:i a Y');
1223 1223
             } else {
1224 1224
                 $display_date = $this->start_date('F j\, Y')
1225 1225
                                 . ' @ '
Please login to merge, or discard this patch.
Indentation   +1552 added lines, -1552 removed lines patch added patch discarded remove patch
@@ -12,1560 +12,1560 @@
 block discarded – undo
12 12
  */
13 13
 class EE_Datetime extends EE_Soft_Delete_Base_Class
14 14
 {
15
-    /**
16
-     * constant used by get_active_status, indicates datetime has no more available spaces
17
-     */
18
-    const sold_out = 'DTS';
19
-
20
-    /**
21
-     * constant used by get_active_status, indicating datetime is still active (even is not over, can be registered-for)
22
-     */
23
-    const active = 'DTA';
24
-
25
-    /**
26
-     * constant used by get_active_status, indicating the datetime cannot be used for registrations yet, but has not
27
-     * expired
28
-     */
29
-    const upcoming = 'DTU';
30
-
31
-    /**
32
-     * Datetime is postponed
33
-     */
34
-    const postponed = 'DTP';
35
-
36
-    /**
37
-     * Datetime is cancelled
38
-     */
39
-    const cancelled = 'DTC';
40
-
41
-    /**
42
-     * constant used by get_active_status, indicates datetime has expired (event is over)
43
-     */
44
-    const expired = 'DTE';
45
-
46
-    /**
47
-     * constant used in various places indicating that an event is INACTIVE (not yet ready to be published)
48
-     */
49
-    const inactive = 'DTI';
50
-
51
-
52
-    /**
53
-     * @param array  $props_n_values    incoming values
54
-     * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
55
-     * @param array  $date_formats      incoming date_formats in an array where the first value is the date_format
56
-     *                                  and the second value is the time format
57
-     * @return EE_Datetime
58
-     * @throws ReflectionException
59
-     * @throws InvalidArgumentException
60
-     * @throws InvalidInterfaceException
61
-     * @throws InvalidDataTypeException
62
-     * @throws EE_Error
63
-     */
64
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
65
-    {
66
-        $has_object = parent::_check_for_object(
67
-            $props_n_values,
68
-            __CLASS__,
69
-            $timezone,
70
-            $date_formats
71
-        );
72
-        return $has_object
73
-            ? $has_object
74
-            : new self($props_n_values, false, $timezone, $date_formats);
75
-    }
76
-
77
-
78
-    /**
79
-     * @param array  $props_n_values  incoming values from the database
80
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
-     *                                the website will be used.
82
-     * @return EE_Datetime
83
-     * @throws ReflectionException
84
-     * @throws InvalidArgumentException
85
-     * @throws InvalidInterfaceException
86
-     * @throws InvalidDataTypeException
87
-     * @throws EE_Error
88
-     */
89
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
90
-    {
91
-        return new self($props_n_values, true, $timezone);
92
-    }
93
-
94
-
95
-    /**
96
-     * @param $name
97
-     * @throws ReflectionException
98
-     * @throws InvalidArgumentException
99
-     * @throws InvalidInterfaceException
100
-     * @throws InvalidDataTypeException
101
-     * @throws EE_Error
102
-     */
103
-    public function set_name($name)
104
-    {
105
-        $this->set('DTT_name', $name);
106
-    }
107
-
108
-
109
-    /**
110
-     * @param $description
111
-     * @throws ReflectionException
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidInterfaceException
114
-     * @throws InvalidDataTypeException
115
-     * @throws EE_Error
116
-     */
117
-    public function set_description($description)
118
-    {
119
-        $this->set('DTT_description', $description);
120
-    }
121
-
122
-
123
-    /**
124
-     * Set event start date
125
-     * set the start date for an event
126
-     *
127
-     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
128
-     * @throws ReflectionException
129
-     * @throws InvalidArgumentException
130
-     * @throws InvalidInterfaceException
131
-     * @throws InvalidDataTypeException
132
-     * @throws EE_Error
133
-     */
134
-    public function set_start_date($date)
135
-    {
136
-        $this->_set_date_for($date, 'DTT_EVT_start');
137
-    }
138
-
139
-
140
-    /**
141
-     * Set event start time
142
-     * set the start time for an event
143
-     *
144
-     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
145
-     * @throws ReflectionException
146
-     * @throws InvalidArgumentException
147
-     * @throws InvalidInterfaceException
148
-     * @throws InvalidDataTypeException
149
-     * @throws EE_Error
150
-     */
151
-    public function set_start_time($time)
152
-    {
153
-        $this->_set_time_for($time, 'DTT_EVT_start');
154
-    }
155
-
156
-
157
-    /**
158
-     * Set event end date
159
-     * set the end date for an event
160
-     *
161
-     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
162
-     * @throws ReflectionException
163
-     * @throws InvalidArgumentException
164
-     * @throws InvalidInterfaceException
165
-     * @throws InvalidDataTypeException
166
-     * @throws EE_Error
167
-     */
168
-    public function set_end_date($date)
169
-    {
170
-        $this->_set_date_for($date, 'DTT_EVT_end');
171
-    }
172
-
173
-
174
-    /**
175
-     * Set event end time
176
-     * set the end time for an event
177
-     *
178
-     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
179
-     * @throws ReflectionException
180
-     * @throws InvalidArgumentException
181
-     * @throws InvalidInterfaceException
182
-     * @throws InvalidDataTypeException
183
-     * @throws EE_Error
184
-     */
185
-    public function set_end_time($time)
186
-    {
187
-        $this->_set_time_for($time, 'DTT_EVT_end');
188
-    }
189
-
190
-
191
-    /**
192
-     * Set registration limit
193
-     * set the maximum number of attendees that can be registered for this datetime slot
194
-     *
195
-     * @param int|float $reg_limit
196
-     * @throws ReflectionException
197
-     * @throws InvalidArgumentException
198
-     * @throws InvalidInterfaceException
199
-     * @throws InvalidDataTypeException
200
-     * @throws EE_Error
201
-     */
202
-    public function set_reg_limit($reg_limit)
203
-    {
204
-        $this->set('DTT_reg_limit', $reg_limit);
205
-    }
206
-
207
-
208
-    /**
209
-     * get the number of tickets sold for this datetime slot
210
-     *
211
-     * @return mixed int on success, FALSE on fail
212
-     * @throws ReflectionException
213
-     * @throws InvalidArgumentException
214
-     * @throws InvalidInterfaceException
215
-     * @throws InvalidDataTypeException
216
-     * @throws EE_Error
217
-     */
218
-    public function sold()
219
-    {
220
-        return $this->get_raw('DTT_sold');
221
-    }
222
-
223
-
224
-    /**
225
-     * @param int $sold
226
-     * @throws ReflectionException
227
-     * @throws InvalidArgumentException
228
-     * @throws InvalidInterfaceException
229
-     * @throws InvalidDataTypeException
230
-     * @throws EE_Error
231
-     */
232
-    public function set_sold($sold)
233
-    {
234
-        // sold can not go below zero
235
-        $sold = max(0, $sold);
236
-        $this->set('DTT_sold', $sold);
237
-    }
238
-
239
-
240
-    /**
241
-     * Increments sold by amount passed by $qty, and persists it immediately to the database.
242
-     * Simultaneously decreases the reserved count, unless $also_decrease_reserved is false.
243
-     *
244
-     * @param int $qty
245
-     * @param boolean $also_decrease_reserved
246
-     * @return boolean indicating success
247
-     * @throws ReflectionException
248
-     * @throws InvalidArgumentException
249
-     * @throws InvalidInterfaceException
250
-     * @throws InvalidDataTypeException
251
-     * @throws EE_Error
252
-     */
253
-    public function increaseSold(int $qty = 1, bool $also_decrease_reserved = true): bool
254
-    {
255
-        $qty = absint($qty);
256
-        if ($also_decrease_reserved) {
257
-            $success = $this->adjustNumericFieldsInDb(
258
-                [
259
-                    'DTT_reserved' => $qty * -1,
260
-                    'DTT_sold' => $qty
261
-                ]
262
-            );
263
-        } else {
264
-            $success = $this->adjustNumericFieldsInDb(
265
-                [
266
-                    'DTT_sold' => $qty
267
-                ]
268
-            );
269
-        }
270
-
271
-        do_action(
272
-            'AHEE__EE_Datetime__increase_sold',
273
-            $this,
274
-            $qty,
275
-            $this->sold(),
276
-            $success
277
-        );
278
-        return $success;
279
-    }
280
-
281
-
282
-    /**
283
-     * Decrements (subtracts) sold amount passed by $qty directly in the DB and on the model object. (Ie, no need
284
-     * to save afterwards.)
285
-     *
286
-     * @param int $qty
287
-     * @return boolean indicating success
288
-     * @throws ReflectionException
289
-     * @throws InvalidArgumentException
290
-     * @throws InvalidInterfaceException
291
-     * @throws InvalidDataTypeException
292
-     * @throws EE_Error
293
-     */
294
-    public function decreaseSold(int $qty = 1): bool
295
-    {
296
-        $qty = absint($qty);
297
-        $success = $this->adjustNumericFieldsInDb(
298
-            [
299
-                'DTT_sold' => $qty * -1
300
-            ]
301
-        );
302
-        do_action(
303
-            'AHEE__EE_Datetime__decrease_sold',
304
-            $this,
305
-            $qty,
306
-            $this->sold(),
307
-            $success
308
-        );
309
-        return $success;
310
-    }
311
-
312
-
313
-    /**
314
-     * Gets qty of reserved tickets for this datetime
315
-     *
316
-     * @return int
317
-     * @throws ReflectionException
318
-     * @throws InvalidArgumentException
319
-     * @throws InvalidInterfaceException
320
-     * @throws InvalidDataTypeException
321
-     * @throws EE_Error
322
-     */
323
-    public function reserved(): int
324
-    {
325
-        return $this->get_raw('DTT_reserved');
326
-    }
327
-
328
-
329
-    /**
330
-     * Sets qty of reserved tickets for this datetime
331
-     *
332
-     * @param int $reserved
333
-     * @throws ReflectionException
334
-     * @throws InvalidArgumentException
335
-     * @throws InvalidInterfaceException
336
-     * @throws InvalidDataTypeException
337
-     * @throws EE_Error
338
-     */
339
-    public function set_reserved(int $reserved)
340
-    {
341
-        // reserved can not go below zero
342
-        $reserved = max(0, $reserved);
343
-        $this->set('DTT_reserved', $reserved);
344
-    }
345
-
346
-
347
-    /**
348
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
349
-     *
350
-     * @param int $qty
351
-     * @return boolean indicating success
352
-     * @throws ReflectionException
353
-     * @throws InvalidArgumentException
354
-     * @throws InvalidInterfaceException
355
-     * @throws InvalidDataTypeException
356
-     * @throws EE_Error
357
-     */
358
-    public function increaseReserved(int $qty = 1): bool
359
-    {
360
-        $qty = absint($qty);
361
-        $success = $this->incrementFieldConditionallyInDb(
362
-            'DTT_reserved',
363
-            'DTT_sold',
364
-            'DTT_reg_limit',
365
-            $qty
366
-        );
367
-        do_action(
368
-            'AHEE__EE_Datetime__increase_reserved',
369
-            $this,
370
-            $qty,
371
-            $this->reserved(),
372
-            $success
373
-        );
374
-        return $success;
375
-    }
376
-
377
-
378
-    /**
379
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
380
-     *
381
-     * @param int $qty
382
-     * @return boolean indicating success
383
-     * @throws ReflectionException
384
-     * @throws InvalidArgumentException
385
-     * @throws InvalidInterfaceException
386
-     * @throws InvalidDataTypeException
387
-     * @throws EE_Error
388
-     */
389
-    public function decreaseReserved(int $qty = 1): bool
390
-    {
391
-        $qty = absint($qty);
392
-        $success = $this->adjustNumericFieldsInDb(
393
-            [
394
-                'DTT_reserved' => $qty * -1
395
-            ]
396
-        );
397
-        do_action(
398
-            'AHEE__EE_Datetime__decrease_reserved',
399
-            $this,
400
-            $qty,
401
-            $this->reserved(),
402
-            $success
403
-        );
404
-        return $success;
405
-    }
406
-
407
-
408
-    /**
409
-     * total sold and reserved tickets
410
-     *
411
-     * @return int
412
-     * @throws ReflectionException
413
-     * @throws InvalidArgumentException
414
-     * @throws InvalidInterfaceException
415
-     * @throws InvalidDataTypeException
416
-     * @throws EE_Error
417
-     */
418
-    public function sold_and_reserved(): int
419
-    {
420
-        return $this->sold() + $this->reserved();
421
-    }
422
-
423
-
424
-    /**
425
-     * returns the datetime name
426
-     *
427
-     * @return string
428
-     * @throws ReflectionException
429
-     * @throws InvalidArgumentException
430
-     * @throws InvalidInterfaceException
431
-     * @throws InvalidDataTypeException
432
-     * @throws EE_Error
433
-     */
434
-    public function name(): string
435
-    {
436
-        return $this->get('DTT_name');
437
-    }
438
-
439
-
440
-    /**
441
-     * returns the datetime description
442
-     *
443
-     * @return string
444
-     * @throws ReflectionException
445
-     * @throws InvalidArgumentException
446
-     * @throws InvalidInterfaceException
447
-     * @throws InvalidDataTypeException
448
-     * @throws EE_Error
449
-     */
450
-    public function description(): string
451
-    {
452
-        return $this->get('DTT_description');
453
-    }
454
-
455
-
456
-    /**
457
-     * This helper simply returns whether the event_datetime for the current datetime is a primary datetime
458
-     *
459
-     * @return boolean  TRUE if is primary, FALSE if not.
460
-     * @throws ReflectionException
461
-     * @throws InvalidArgumentException
462
-     * @throws InvalidInterfaceException
463
-     * @throws InvalidDataTypeException
464
-     * @throws EE_Error
465
-     */
466
-    public function is_primary(): bool
467
-    {
468
-        return $this->get('DTT_is_primary');
469
-    }
470
-
471
-
472
-    /**
473
-     * This helper simply returns the order for the datetime
474
-     *
475
-     * @return int  The order of the datetime for this event.
476
-     * @throws ReflectionException
477
-     * @throws InvalidArgumentException
478
-     * @throws InvalidInterfaceException
479
-     * @throws InvalidDataTypeException
480
-     * @throws EE_Error
481
-     */
482
-    public function order(): int
483
-    {
484
-        return $this->get('DTT_order');
485
-    }
486
-
487
-
488
-    /**
489
-     * This helper simply returns the parent id for the datetime
490
-     *
491
-     * @return int
492
-     * @throws ReflectionException
493
-     * @throws InvalidArgumentException
494
-     * @throws InvalidInterfaceException
495
-     * @throws InvalidDataTypeException
496
-     * @throws EE_Error
497
-     */
498
-    public function parent(): int
499
-    {
500
-        return $this->get('DTT_parent');
501
-    }
502
-
503
-
504
-    /**
505
-     * show date and/or time
506
-     *
507
-     * @param string $date_or_time    whether to display a date or time or both
508
-     * @param string $start_or_end    whether to display start or end datetimes
509
-     * @param string $dt_frmt
510
-     * @param string $tm_frmt
511
-     * @param bool   $echo            whether we echo or return (note echoing uses "pretty" formats,
512
-     *                                otherwise we use the standard formats)
513
-     * @return string|bool  string on success, FALSE on fail
514
-     * @throws ReflectionException
515
-     * @throws InvalidArgumentException
516
-     * @throws InvalidInterfaceException
517
-     * @throws InvalidDataTypeException
518
-     * @throws EE_Error
519
-     */
520
-    private function _show_datetime(
521
-        $date_or_time = null,
522
-        $start_or_end = 'start',
523
-        $dt_frmt = '',
524
-        $tm_frmt = '',
525
-        $echo = false
526
-    ) {
527
-        $field_name = "DTT_EVT_{$start_or_end}";
528
-        $dtt = $this->_get_datetime(
529
-            $field_name,
530
-            $dt_frmt,
531
-            $tm_frmt,
532
-            $date_or_time,
533
-            $echo
534
-        );
535
-        if (! $echo) {
536
-            return $dtt;
537
-        }
538
-        return '';
539
-    }
540
-
541
-
542
-    /**
543
-     * get event start date.  Provide either the date format, or NULL to re-use the
544
-     * last-used format, or '' to use the default date format
545
-     *
546
-     * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
547
-     * @return mixed            string on success, FALSE on fail
548
-     * @throws ReflectionException
549
-     * @throws InvalidArgumentException
550
-     * @throws InvalidInterfaceException
551
-     * @throws InvalidDataTypeException
552
-     * @throws EE_Error
553
-     */
554
-    public function start_date($dt_frmt = '')
555
-    {
556
-        return $this->_show_datetime('D', 'start', $dt_frmt);
557
-    }
558
-
559
-
560
-    /**
561
-     * Echoes start_date()
562
-     *
563
-     * @param string $dt_frmt
564
-     * @throws ReflectionException
565
-     * @throws InvalidArgumentException
566
-     * @throws InvalidInterfaceException
567
-     * @throws InvalidDataTypeException
568
-     * @throws EE_Error
569
-     */
570
-    public function e_start_date($dt_frmt = '')
571
-    {
572
-        $this->_show_datetime('D', 'start', $dt_frmt, null, true);
573
-    }
574
-
575
-
576
-    /**
577
-     * get end date. Provide either the date format, or NULL to re-use the
578
-     * last-used format, or '' to use the default date format
579
-     *
580
-     * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
581
-     * @return mixed            string on success, FALSE on fail
582
-     * @throws ReflectionException
583
-     * @throws InvalidArgumentException
584
-     * @throws InvalidInterfaceException
585
-     * @throws InvalidDataTypeException
586
-     * @throws EE_Error
587
-     */
588
-    public function end_date($dt_frmt = '')
589
-    {
590
-        return $this->_show_datetime('D', 'end', $dt_frmt);
591
-    }
592
-
593
-
594
-    /**
595
-     * Echoes the end date. See end_date()
596
-     *
597
-     * @param string $dt_frmt
598
-     * @throws ReflectionException
599
-     * @throws InvalidArgumentException
600
-     * @throws InvalidInterfaceException
601
-     * @throws InvalidDataTypeException
602
-     * @throws EE_Error
603
-     */
604
-    public function e_end_date($dt_frmt = '')
605
-    {
606
-        $this->_show_datetime('D', 'end', $dt_frmt, null, true);
607
-    }
608
-
609
-
610
-    /**
611
-     * get date_range - meaning the start AND end date
612
-     *
613
-     * @access public
614
-     * @param string $dt_frmt     string representation of date format defaults to WP settings
615
-     * @param string $conjunction conjunction junction what's your function ?
616
-     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
617
-     * @return mixed              string on success, FALSE on fail
618
-     * @throws ReflectionException
619
-     * @throws InvalidArgumentException
620
-     * @throws InvalidInterfaceException
621
-     * @throws InvalidDataTypeException
622
-     * @throws EE_Error
623
-     */
624
-    public function date_range($dt_frmt = '', $conjunction = ' - ')
625
-    {
626
-        $dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
627
-        $start = str_replace(
628
-            ' ',
629
-            '&nbsp;',
630
-            $this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
631
-        );
632
-        $end = str_replace(
633
-            ' ',
634
-            '&nbsp;',
635
-            $this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
636
-        );
637
-        return $start !== $end ? $start . $conjunction . $end : $start;
638
-    }
639
-
640
-
641
-    /**
642
-     * @param string $dt_frmt
643
-     * @param string $conjunction
644
-     * @throws ReflectionException
645
-     * @throws InvalidArgumentException
646
-     * @throws InvalidInterfaceException
647
-     * @throws InvalidDataTypeException
648
-     * @throws EE_Error
649
-     */
650
-    public function e_date_range($dt_frmt = '', $conjunction = ' - ')
651
-    {
652
-        echo esc_html($this->date_range($dt_frmt, $conjunction));
653
-    }
654
-
655
-
656
-    /**
657
-     * get start time
658
-     *
659
-     * @param string $tm_format - string representation of time format defaults to 'g:i a'
660
-     * @return mixed        string on success, FALSE on fail
661
-     * @throws ReflectionException
662
-     * @throws InvalidArgumentException
663
-     * @throws InvalidInterfaceException
664
-     * @throws InvalidDataTypeException
665
-     * @throws EE_Error
666
-     */
667
-    public function start_time($tm_format = '')
668
-    {
669
-        return $this->_show_datetime('T', 'start', null, $tm_format);
670
-    }
671
-
672
-
673
-    /**
674
-     * @param string $tm_format
675
-     * @throws ReflectionException
676
-     * @throws InvalidArgumentException
677
-     * @throws InvalidInterfaceException
678
-     * @throws InvalidDataTypeException
679
-     * @throws EE_Error
680
-     */
681
-    public function e_start_time($tm_format = '')
682
-    {
683
-        $this->_show_datetime('T', 'start', null, $tm_format, true);
684
-    }
685
-
686
-
687
-    /**
688
-     * get end time
689
-     *
690
-     * @param string $tm_format string representation of time format defaults to 'g:i a'
691
-     * @return mixed                string on success, FALSE on fail
692
-     * @throws ReflectionException
693
-     * @throws InvalidArgumentException
694
-     * @throws InvalidInterfaceException
695
-     * @throws InvalidDataTypeException
696
-     * @throws EE_Error
697
-     */
698
-    public function end_time($tm_format = '')
699
-    {
700
-        return $this->_show_datetime('T', 'end', null, $tm_format);
701
-    }
702
-
703
-
704
-    /**
705
-     * @param string $tm_format
706
-     * @throws ReflectionException
707
-     * @throws InvalidArgumentException
708
-     * @throws InvalidInterfaceException
709
-     * @throws InvalidDataTypeException
710
-     * @throws EE_Error
711
-     */
712
-    public function e_end_time($tm_format = '')
713
-    {
714
-        $this->_show_datetime('T', 'end', null, $tm_format, true);
715
-    }
716
-
717
-
718
-    /**
719
-     * get time_range
720
-     *
721
-     * @access public
722
-     * @param string $tm_format   string representation of time format defaults to 'g:i a'
723
-     * @param string $conjunction conjunction junction what's your function ?
724
-     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
725
-     * @return mixed              string on success, FALSE on fail
726
-     * @throws ReflectionException
727
-     * @throws InvalidArgumentException
728
-     * @throws InvalidInterfaceException
729
-     * @throws InvalidDataTypeException
730
-     * @throws EE_Error
731
-     */
732
-    public function time_range($tm_format = '', $conjunction = ' - ')
733
-    {
734
-        $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
735
-        $start = str_replace(
736
-            ' ',
737
-            '&nbsp;',
738
-            $this->get_i18n_datetime('DTT_EVT_start', $tm_format)
739
-        );
740
-        $end = str_replace(
741
-            ' ',
742
-            '&nbsp;',
743
-            $this->get_i18n_datetime('DTT_EVT_end', $tm_format)
744
-        );
745
-        return $start !== $end ? $start . $conjunction . $end : $start;
746
-    }
747
-
748
-
749
-    /**
750
-     * @param string $tm_format
751
-     * @param string $conjunction
752
-     * @throws ReflectionException
753
-     * @throws InvalidArgumentException
754
-     * @throws InvalidInterfaceException
755
-     * @throws InvalidDataTypeException
756
-     * @throws EE_Error
757
-     */
758
-    public function e_time_range($tm_format = '', $conjunction = ' - ')
759
-    {
760
-        echo esc_html($this->time_range($tm_format, $conjunction));
761
-    }
762
-
763
-
764
-    /**
765
-     * This returns a range representation of the date and times.
766
-     * Output is dependent on the difference (or similarity) between DTT_EVT_start and DTT_EVT_end.
767
-     * Also, the return value is localized.
768
-     *
769
-     * @param string $dt_format
770
-     * @param string $tm_format
771
-     * @param string $conjunction used between two different dates or times.
772
-     *                            ex: Dec 1{$conjunction}}Dec 6, or 2pm{$conjunction}3pm
773
-     * @param string $separator   used between the date and time formats.
774
-     *                            ex: Dec 1, 2016{$separator}2pm
775
-     * @return string
776
-     * @throws ReflectionException
777
-     * @throws InvalidArgumentException
778
-     * @throws InvalidInterfaceException
779
-     * @throws InvalidDataTypeException
780
-     * @throws EE_Error
781
-     */
782
-    public function date_and_time_range(
783
-        $dt_format = '',
784
-        $tm_format = '',
785
-        $conjunction = ' - ',
786
-        $separator = ' '
787
-    ) {
788
-        $dt_format = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
789
-        $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
790
-        $full_format = $dt_format . $separator . $tm_format;
791
-        // the range output depends on various conditions
792
-        switch (true) {
793
-            // start date timestamp and end date timestamp are the same.
794
-            case ($this->get_raw('DTT_EVT_start') === $this->get_raw('DTT_EVT_end')):
795
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format);
796
-                break;
797
-            // start and end date are the same but times are different
798
-            case ($this->start_date() === $this->end_date()):
799
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
800
-                          . $conjunction
801
-                          . $this->get_i18n_datetime('DTT_EVT_end', $tm_format);
802
-                break;
803
-            // all other conditions
804
-            default:
805
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
806
-                          . $conjunction
807
-                          . $this->get_i18n_datetime('DTT_EVT_end', $full_format);
808
-                break;
809
-        }
810
-        return $output;
811
-    }
812
-
813
-
814
-    /**
815
-     * This echos the results of date and time range.
816
-     *
817
-     * @see date_and_time_range() for more details on purpose.
818
-     * @param string $dt_format
819
-     * @param string $tm_format
820
-     * @param string $conjunction
821
-     * @return void
822
-     * @throws ReflectionException
823
-     * @throws InvalidArgumentException
824
-     * @throws InvalidInterfaceException
825
-     * @throws InvalidDataTypeException
826
-     * @throws EE_Error
827
-     */
828
-    public function e_date_and_time_range($dt_format = '', $tm_format = '', $conjunction = ' - ')
829
-    {
830
-        echo esc_html($this->date_and_time_range($dt_format, $tm_format, $conjunction));
831
-    }
832
-
833
-
834
-    /**
835
-     * get start date and start time
836
-     *
837
-     * @param    string $dt_format - string representation of date format defaults to 'F j, Y'
838
-     * @param    string $tm_format - string representation of time format defaults to 'g:i a'
839
-     * @return    mixed    string on success, FALSE on fail
840
-     * @throws ReflectionException
841
-     * @throws InvalidArgumentException
842
-     * @throws InvalidInterfaceException
843
-     * @throws InvalidDataTypeException
844
-     * @throws EE_Error
845
-     */
846
-    public function start_date_and_time($dt_format = '', $tm_format = '')
847
-    {
848
-        return $this->_show_datetime('', 'start', $dt_format, $tm_format);
849
-    }
850
-
851
-
852
-    /**
853
-     * @param string $dt_frmt
854
-     * @param string $tm_format
855
-     * @throws ReflectionException
856
-     * @throws InvalidArgumentException
857
-     * @throws InvalidInterfaceException
858
-     * @throws InvalidDataTypeException
859
-     * @throws EE_Error
860
-     */
861
-    public function e_start_date_and_time($dt_frmt = '', $tm_format = '')
862
-    {
863
-        $this->_show_datetime('', 'start', $dt_frmt, $tm_format, true);
864
-    }
865
-
866
-
867
-    /**
868
-     * Shows the length of the event (start to end time).
869
-     * Can be shown in 'seconds','minutes','hours', or 'days'.
870
-     * By default, rounds up. (So if you use 'days', and then event
871
-     * only occurs for 1 hour, it will return 1 day).
872
-     *
873
-     * @param string $units 'seconds','minutes','hours','days'
874
-     * @param bool   $round_up
875
-     * @return float|int|mixed
876
-     * @throws ReflectionException
877
-     * @throws InvalidArgumentException
878
-     * @throws InvalidInterfaceException
879
-     * @throws InvalidDataTypeException
880
-     * @throws EE_Error
881
-     */
882
-    public function length($units = 'seconds', $round_up = false)
883
-    {
884
-        $start = $this->get_raw('DTT_EVT_start');
885
-        $end = $this->get_raw('DTT_EVT_end');
886
-        $length_in_units = $end - $start;
887
-        switch ($units) {
888
-            // NOTE: We purposefully don't use "break;" in order to chain the divisions
889
-            /** @noinspection PhpMissingBreakStatementInspection */
890
-            // phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
891
-            case 'days':
892
-                $length_in_units /= 24;
893
-            /** @noinspection PhpMissingBreakStatementInspection */
894
-            case 'hours':
895
-                // fall through is intentional
896
-                $length_in_units /= 60;
897
-            /** @noinspection PhpMissingBreakStatementInspection */
898
-            case 'minutes':
899
-                // fall through is intentional
900
-                $length_in_units /= 60;
901
-            case 'seconds':
902
-            default:
903
-                $length_in_units = ceil($length_in_units);
904
-        }
905
-        // phpcs:enable
906
-        if ($round_up) {
907
-            $length_in_units = max($length_in_units, 1);
908
-        }
909
-        return $length_in_units;
910
-    }
911
-
912
-
913
-    /**
914
-     *        get end date and time
915
-     *
916
-     * @param string $dt_frmt   - string representation of date format defaults to 'F j, Y'
917
-     * @param string $tm_format - string representation of time format defaults to 'g:i a'
918
-     * @return    mixed                string on success, FALSE on fail
919
-     * @throws ReflectionException
920
-     * @throws InvalidArgumentException
921
-     * @throws InvalidInterfaceException
922
-     * @throws InvalidDataTypeException
923
-     * @throws EE_Error
924
-     */
925
-    public function end_date_and_time($dt_frmt = '', $tm_format = '')
926
-    {
927
-        return $this->_show_datetime('', 'end', $dt_frmt, $tm_format);
928
-    }
929
-
930
-
931
-    /**
932
-     * @param string $dt_frmt
933
-     * @param string $tm_format
934
-     * @throws ReflectionException
935
-     * @throws InvalidArgumentException
936
-     * @throws InvalidInterfaceException
937
-     * @throws InvalidDataTypeException
938
-     * @throws EE_Error
939
-     */
940
-    public function e_end_date_and_time($dt_frmt = '', $tm_format = '')
941
-    {
942
-        $this->_show_datetime('', 'end', $dt_frmt, $tm_format, true);
943
-    }
944
-
945
-
946
-    /**
947
-     *        get start timestamp
948
-     *
949
-     * @return        int
950
-     * @throws ReflectionException
951
-     * @throws InvalidArgumentException
952
-     * @throws InvalidInterfaceException
953
-     * @throws InvalidDataTypeException
954
-     * @throws EE_Error
955
-     */
956
-    public function start()
957
-    {
958
-        return $this->get_raw('DTT_EVT_start');
959
-    }
960
-
961
-
962
-    /**
963
-     *        get end timestamp
964
-     *
965
-     * @return        int
966
-     * @throws ReflectionException
967
-     * @throws InvalidArgumentException
968
-     * @throws InvalidInterfaceException
969
-     * @throws InvalidDataTypeException
970
-     * @throws EE_Error
971
-     */
972
-    public function end()
973
-    {
974
-        return $this->get_raw('DTT_EVT_end');
975
-    }
976
-
977
-
978
-    /**
979
-     *    get the registration limit for this datetime slot
980
-     *
981
-     * @return int|float                int = finite limit   EE_INF(float) = unlimited
982
-     * @throws ReflectionException
983
-     * @throws InvalidArgumentException
984
-     * @throws InvalidInterfaceException
985
-     * @throws InvalidDataTypeException
986
-     * @throws EE_Error
987
-     */
988
-    public function reg_limit()
989
-    {
990
-        return $this->get_raw('DTT_reg_limit');
991
-    }
992
-
993
-
994
-    /**
995
-     *    have the tickets sold for this datetime, met or exceed the registration limit ?
996
-     *
997
-     * @return boolean
998
-     * @throws ReflectionException
999
-     * @throws InvalidArgumentException
1000
-     * @throws InvalidInterfaceException
1001
-     * @throws InvalidDataTypeException
1002
-     * @throws EE_Error
1003
-     */
1004
-    public function sold_out()
1005
-    {
1006
-        return $this->reg_limit() > 0 && $this->sold() >= $this->reg_limit();
1007
-    }
1008
-
1009
-
1010
-    /**
1011
-     * return the total number of spaces remaining at this venue.
1012
-     * This only takes the venue's capacity into account, NOT the tickets available for sale
1013
-     *
1014
-     * @param bool $consider_tickets Whether to consider tickets remaining when determining if there are any spaces left
1015
-     *                               Because if all tickets attached to this datetime have no spaces left,
1016
-     *                               then this datetime IS effectively sold out.
1017
-     *                               However, there are cases where we just want to know the spaces
1018
-     *                               remaining for this particular datetime, hence the flag.
1019
-     * @return int|float
1020
-     * @throws ReflectionException
1021
-     * @throws InvalidArgumentException
1022
-     * @throws InvalidInterfaceException
1023
-     * @throws InvalidDataTypeException
1024
-     * @throws EE_Error
1025
-     */
1026
-    public function spaces_remaining($consider_tickets = false)
1027
-    {
1028
-        // tickets remaining available for purchase
1029
-        // no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
1030
-        $dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
1031
-        if (! $consider_tickets) {
1032
-            return $dtt_remaining;
1033
-        }
1034
-        $tickets_remaining = $this->tickets_remaining();
1035
-        return min($dtt_remaining, $tickets_remaining);
1036
-    }
1037
-
1038
-
1039
-    /**
1040
-     * Counts the total tickets available
1041
-     * (from all the different types of tickets which are available for this datetime).
1042
-     *
1043
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1044
-     * @return int
1045
-     * @throws ReflectionException
1046
-     * @throws InvalidArgumentException
1047
-     * @throws InvalidInterfaceException
1048
-     * @throws InvalidDataTypeException
1049
-     * @throws EE_Error
1050
-     */
1051
-    public function tickets_remaining($query_params = array())
1052
-    {
1053
-        $sum = 0;
1054
-        $tickets = $this->tickets($query_params);
1055
-        if (! empty($tickets)) {
1056
-            foreach ($tickets as $ticket) {
1057
-                if ($ticket instanceof EE_Ticket) {
1058
-                    // get the actual amount of tickets that can be sold
1059
-                    $qty = $ticket->qty('saleable');
1060
-                    if ($qty === EE_INF) {
1061
-                        return EE_INF;
1062
-                    }
1063
-                    // no negative ticket quantities plz
1064
-                    if ($qty > 0) {
1065
-                        $sum += $qty;
1066
-                    }
1067
-                }
1068
-            }
1069
-        }
1070
-        return $sum;
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * Gets the count of all the tickets available at this datetime (not ticket types)
1076
-     * before any were sold
1077
-     *
1078
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1079
-     * @return int
1080
-     * @throws ReflectionException
1081
-     * @throws InvalidArgumentException
1082
-     * @throws InvalidInterfaceException
1083
-     * @throws InvalidDataTypeException
1084
-     * @throws EE_Error
1085
-     */
1086
-    public function sum_tickets_initially_available($query_params = array())
1087
-    {
1088
-        return $this->sum_related('Ticket', $query_params, 'TKT_qty');
1089
-    }
1090
-
1091
-
1092
-    /**
1093
-     * Returns the lesser-of-the two: spaces remaining at this datetime, or
1094
-     * the total tickets remaining (a sum of the tickets remaining for each ticket type
1095
-     * that is available for this datetime).
1096
-     *
1097
-     * @return int
1098
-     * @throws ReflectionException
1099
-     * @throws InvalidArgumentException
1100
-     * @throws InvalidInterfaceException
1101
-     * @throws InvalidDataTypeException
1102
-     * @throws EE_Error
1103
-     */
1104
-    public function total_tickets_available_at_this_datetime()
1105
-    {
1106
-        return $this->spaces_remaining(true);
1107
-    }
1108
-
1109
-
1110
-    /**
1111
-     * This simply compares the internal dtt for the given string with NOW
1112
-     * and determines if the date is upcoming or not.
1113
-     *
1114
-     * @access public
1115
-     * @return boolean
1116
-     * @throws ReflectionException
1117
-     * @throws InvalidArgumentException
1118
-     * @throws InvalidInterfaceException
1119
-     * @throws InvalidDataTypeException
1120
-     * @throws EE_Error
1121
-     */
1122
-    public function is_upcoming()
1123
-    {
1124
-        return ($this->get_raw('DTT_EVT_start') > time());
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     * This simply compares the internal datetime for the given string with NOW
1130
-     * and returns if the date is active (i.e. start and end time)
1131
-     *
1132
-     * @return boolean
1133
-     * @throws ReflectionException
1134
-     * @throws InvalidArgumentException
1135
-     * @throws InvalidInterfaceException
1136
-     * @throws InvalidDataTypeException
1137
-     * @throws EE_Error
1138
-     */
1139
-    public function is_active()
1140
-    {
1141
-        return ($this->get_raw('DTT_EVT_start') < time() && $this->get_raw('DTT_EVT_end') > time());
1142
-    }
1143
-
1144
-
1145
-    /**
1146
-     * This simply compares the internal dtt for the given string with NOW
1147
-     * and determines if the date is expired or not.
1148
-     *
1149
-     * @return boolean
1150
-     * @throws ReflectionException
1151
-     * @throws InvalidArgumentException
1152
-     * @throws InvalidInterfaceException
1153
-     * @throws InvalidDataTypeException
1154
-     * @throws EE_Error
1155
-     */
1156
-    public function is_expired()
1157
-    {
1158
-        return ($this->get_raw('DTT_EVT_end') < time());
1159
-    }
1160
-
1161
-
1162
-    /**
1163
-     * This returns the active status for whether an event is active, upcoming, or expired
1164
-     *
1165
-     * @return int return value will be one of the EE_Datetime status constants.
1166
-     * @throws ReflectionException
1167
-     * @throws InvalidArgumentException
1168
-     * @throws InvalidInterfaceException
1169
-     * @throws InvalidDataTypeException
1170
-     * @throws EE_Error
1171
-     */
1172
-    public function get_active_status()
1173
-    {
1174
-        $total_tickets_for_this_dtt = $this->total_tickets_available_at_this_datetime();
1175
-        if ($total_tickets_for_this_dtt !== false && $total_tickets_for_this_dtt < 1) {
1176
-            return EE_Datetime::sold_out;
1177
-        }
1178
-        if ($this->is_expired()) {
1179
-            return EE_Datetime::expired;
1180
-        }
1181
-        if ($this->is_upcoming()) {
1182
-            return EE_Datetime::upcoming;
1183
-        }
1184
-        if ($this->is_active()) {
1185
-            return EE_Datetime::active;
1186
-        }
1187
-        return null;
1188
-    }
1189
-
1190
-
1191
-    /**
1192
-     * This returns a nice display name for the datetime that is contingent on the span between the dates and times.
1193
-     *
1194
-     * @param  boolean $use_dtt_name if TRUE then we'll use DTT->name() if its not empty.
1195
-     * @return string
1196
-     * @throws ReflectionException
1197
-     * @throws InvalidArgumentException
1198
-     * @throws InvalidInterfaceException
1199
-     * @throws InvalidDataTypeException
1200
-     * @throws EE_Error
1201
-     */
1202
-    public function get_dtt_display_name($use_dtt_name = false)
1203
-    {
1204
-        if ($use_dtt_name) {
1205
-            $dtt_name = $this->name();
1206
-            if (! empty($dtt_name)) {
1207
-                return $dtt_name;
1208
-            }
1209
-        }
1210
-        // first condition is to see if the months are different
1211
-        if (
1212
-            date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1213
-        ) {
1214
-            $display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1215
-            // next condition is if its the same month but different day
1216
-        } else {
1217
-            if (
1218
-                date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1219
-                && date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1220
-            ) {
1221
-                $display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1222
-            } else {
1223
-                $display_date = $this->start_date('F j\, Y')
1224
-                                . ' @ '
1225
-                                . $this->start_date('g:i a')
1226
-                                . ' - '
1227
-                                . $this->end_date('g:i a');
1228
-            }
1229
-        }
1230
-        return $display_date;
1231
-    }
1232
-
1233
-
1234
-    /**
1235
-     * Gets all the tickets for this datetime
1236
-     *
1237
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1238
-     * @return EE_Base_Class[]|EE_Ticket[]
1239
-     * @throws ReflectionException
1240
-     * @throws InvalidArgumentException
1241
-     * @throws InvalidInterfaceException
1242
-     * @throws InvalidDataTypeException
1243
-     * @throws EE_Error
1244
-     */
1245
-    public function tickets($query_params = array())
1246
-    {
1247
-        return $this->get_many_related('Ticket', $query_params);
1248
-    }
1249
-
1250
-
1251
-    /**
1252
-     * Gets all the ticket types currently available for purchase
1253
-     *
1254
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1255
-     * @return EE_Ticket[]
1256
-     * @throws ReflectionException
1257
-     * @throws InvalidArgumentException
1258
-     * @throws InvalidInterfaceException
1259
-     * @throws InvalidDataTypeException
1260
-     * @throws EE_Error
1261
-     */
1262
-    public function ticket_types_available_for_purchase($query_params = array())
1263
-    {
1264
-        // first check if datetime is valid
1265
-        if ($this->sold_out() || ! ($this->is_upcoming() || $this->is_active())) {
1266
-            return array();
1267
-        }
1268
-        if (empty($query_params)) {
1269
-            $query_params = array(
1270
-                array(
1271
-                    'TKT_start_date' => array('<=', EEM_Ticket::instance()->current_time_for_query('TKT_start_date')),
1272
-                    'TKT_end_date'   => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
1273
-                    'TKT_deleted'    => false,
1274
-                ),
1275
-            );
1276
-        }
1277
-        return $this->tickets($query_params);
1278
-    }
1279
-
1280
-
1281
-    /**
1282
-     * @return EE_Base_Class|EE_Event
1283
-     * @throws ReflectionException
1284
-     * @throws InvalidArgumentException
1285
-     * @throws InvalidInterfaceException
1286
-     * @throws InvalidDataTypeException
1287
-     * @throws EE_Error
1288
-     */
1289
-    public function event()
1290
-    {
1291
-        return $this->get_first_related('Event');
1292
-    }
1293
-
1294
-
1295
-    /**
1296
-     * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime
1297
-     * (via the tickets).
1298
-     *
1299
-     * @return int
1300
-     * @throws ReflectionException
1301
-     * @throws InvalidArgumentException
1302
-     * @throws InvalidInterfaceException
1303
-     * @throws InvalidDataTypeException
1304
-     * @throws EE_Error
1305
-     */
1306
-    public function update_sold()
1307
-    {
1308
-        $count_regs_for_this_datetime = EEM_Registration::instance()->count(
1309
-            array(
1310
-                array(
1311
-                    'STS_ID'                 => EEM_Registration::status_id_approved,
1312
-                    'REG_deleted'            => 0,
1313
-                    'Ticket.Datetime.DTT_ID' => $this->ID(),
1314
-                ),
1315
-            )
1316
-        );
1317
-        $this->set_sold($count_regs_for_this_datetime);
1318
-        $this->save();
1319
-        return $count_regs_for_this_datetime;
1320
-    }
1321
-
1322
-
1323
-    /**
1324
-     * Adds a venue to this event
1325
-     *
1326
-     * @param int|EE_Venue /int $venue_id_or_obj
1327
-     * @return EE_Base_Class|EE_Venue
1328
-     * @throws EE_Error
1329
-     * @throws ReflectionException
1330
-     */
1331
-    public function add_venue($venue_id_or_obj): EE_Venue
1332
-    {
1333
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
1334
-    }
1335
-
1336
-
1337
-    /**
1338
-     * Removes a venue from the event
1339
-     *
1340
-     * @param EE_Venue /int $venue_id_or_obj
1341
-     * @return EE_Base_Class|EE_Venue
1342
-     * @throws EE_Error
1343
-     * @throws ReflectionException
1344
-     */
1345
-    public function remove_venue($venue_id_or_obj): EE_Venue
1346
-    {
1347
-        $venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
1348
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
1349
-    }
1350
-
1351
-
1352
-    /**
1353
-     * Gets the venue related to the event. May provide additional $query_params if desired
1354
-     *
1355
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1356
-     * @return int
1357
-     * @throws EE_Error
1358
-     * @throws ReflectionException
1359
-     */
1360
-    public function venue_ID(array $query_params = []): int
1361
-    {
1362
-        $venue = $this->get_first_related('Venue', $query_params);
1363
-        return $venue instanceof EE_Venue
1364
-            ? $venue->ID()
1365
-            : 0;
1366
-    }
1367
-
1368
-
1369
-    /**
1370
-     * Gets the venue related to the event. May provide additional $query_params if desired
1371
-     *
1372
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1373
-     * @return EE_Base_Class|EE_Venue
1374
-     * @throws EE_Error
1375
-     * @throws ReflectionException
1376
-     */
1377
-    public function venue(array $query_params = [])
1378
-    {
1379
-        return $this->get_first_related('Venue', $query_params);
1380
-    }
1381
-
1382
-
1383
-    /**
1384
-     * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1385
-     * @param string                   $relationName
1386
-     * @param array                    $extra_join_model_fields_n_values
1387
-     * @param string|null              $cache_id
1388
-     * @return EE_Base_Class
1389
-     * @throws EE_Error
1390
-     * @throws ReflectionException
1391
-     * @since   5.0.0.p
1392
-     */
1393
-    public function _add_relation_to(
1394
-        $otherObjectModelObjectOrID,
1395
-        $relationName,
1396
-        $extra_join_model_fields_n_values = [],
1397
-        $cache_id = null
1398
-    ) {
1399
-        // if we're adding a new relation to a ticket
1400
-        if ($relationName === 'Ticket' && ! $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1401
-            /** @var EE_Ticket $ticket */
1402
-            $ticket = EEM_Ticket::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1403
-            $this->increaseSold($ticket->sold(), false);
1404
-            $this->increaseReserved($ticket->reserved());
1405
-            $this->save();
1406
-            $otherObjectModelObjectOrID = $ticket;
1407
-        }
1408
-        return parent::_add_relation_to(
1409
-            $otherObjectModelObjectOrID,
1410
-            $relationName,
1411
-            $extra_join_model_fields_n_values,
1412
-            $cache_id
1413
-        );
1414
-    }
1415
-
1416
-
1417
-    /**
1418
-     * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1419
-     * @param string                   $relationName
1420
-     * @param array                    $where_query
1421
-     * @return bool|EE_Base_Class|null
1422
-     * @throws EE_Error
1423
-     * @throws ReflectionException
1424
-     * @since   5.0.0.p
1425
-     */
1426
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = [])
1427
-    {
1428
-        if ($relationName === 'Ticket' && $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1429
-            /** @var EE_Ticket $ticket */
1430
-            $ticket = EEM_Ticket::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1431
-            $this->decreaseSold($ticket->sold());
1432
-            $this->decreaseReserved($ticket->reserved());
1433
-            $this->save();
1434
-            $otherObjectModelObjectOrID = $ticket;
1435
-        }
1436
-        return parent::_remove_relation_to(
1437
-            $otherObjectModelObjectOrID,
1438
-            $relationName,
1439
-            $where_query
1440
-        );
1441
-    }
1442
-
1443
-
1444
-    /**
1445
-     * Removes ALL the related things for the $relationName.
1446
-     *
1447
-     * @param string $relationName
1448
-     * @param array  $where_query_params
1449
-     * @return EE_Base_Class
1450
-     * @throws ReflectionException
1451
-     * @throws InvalidArgumentException
1452
-     * @throws InvalidInterfaceException
1453
-     * @throws InvalidDataTypeException
1454
-     * @throws EE_Error
1455
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
1456
-     */
1457
-    public function _remove_relations($relationName, $where_query_params = [])
1458
-    {
1459
-        if ($relationName === 'Ticket') {
1460
-            $tickets = $this->tickets();
1461
-            foreach ($tickets as $ticket) {
1462
-                $this->decreaseSold($ticket->sold());
1463
-                $this->decreaseReserved($ticket->reserved());
1464
-                $this->save();
1465
-            }
1466
-        }
1467
-        return parent::_remove_relations($relationName, $where_query_params);
1468
-    }
1469
-
1470
-
1471
-    /*******************************************************************
15
+	/**
16
+	 * constant used by get_active_status, indicates datetime has no more available spaces
17
+	 */
18
+	const sold_out = 'DTS';
19
+
20
+	/**
21
+	 * constant used by get_active_status, indicating datetime is still active (even is not over, can be registered-for)
22
+	 */
23
+	const active = 'DTA';
24
+
25
+	/**
26
+	 * constant used by get_active_status, indicating the datetime cannot be used for registrations yet, but has not
27
+	 * expired
28
+	 */
29
+	const upcoming = 'DTU';
30
+
31
+	/**
32
+	 * Datetime is postponed
33
+	 */
34
+	const postponed = 'DTP';
35
+
36
+	/**
37
+	 * Datetime is cancelled
38
+	 */
39
+	const cancelled = 'DTC';
40
+
41
+	/**
42
+	 * constant used by get_active_status, indicates datetime has expired (event is over)
43
+	 */
44
+	const expired = 'DTE';
45
+
46
+	/**
47
+	 * constant used in various places indicating that an event is INACTIVE (not yet ready to be published)
48
+	 */
49
+	const inactive = 'DTI';
50
+
51
+
52
+	/**
53
+	 * @param array  $props_n_values    incoming values
54
+	 * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
55
+	 * @param array  $date_formats      incoming date_formats in an array where the first value is the date_format
56
+	 *                                  and the second value is the time format
57
+	 * @return EE_Datetime
58
+	 * @throws ReflectionException
59
+	 * @throws InvalidArgumentException
60
+	 * @throws InvalidInterfaceException
61
+	 * @throws InvalidDataTypeException
62
+	 * @throws EE_Error
63
+	 */
64
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
65
+	{
66
+		$has_object = parent::_check_for_object(
67
+			$props_n_values,
68
+			__CLASS__,
69
+			$timezone,
70
+			$date_formats
71
+		);
72
+		return $has_object
73
+			? $has_object
74
+			: new self($props_n_values, false, $timezone, $date_formats);
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param array  $props_n_values  incoming values from the database
80
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
+	 *                                the website will be used.
82
+	 * @return EE_Datetime
83
+	 * @throws ReflectionException
84
+	 * @throws InvalidArgumentException
85
+	 * @throws InvalidInterfaceException
86
+	 * @throws InvalidDataTypeException
87
+	 * @throws EE_Error
88
+	 */
89
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
90
+	{
91
+		return new self($props_n_values, true, $timezone);
92
+	}
93
+
94
+
95
+	/**
96
+	 * @param $name
97
+	 * @throws ReflectionException
98
+	 * @throws InvalidArgumentException
99
+	 * @throws InvalidInterfaceException
100
+	 * @throws InvalidDataTypeException
101
+	 * @throws EE_Error
102
+	 */
103
+	public function set_name($name)
104
+	{
105
+		$this->set('DTT_name', $name);
106
+	}
107
+
108
+
109
+	/**
110
+	 * @param $description
111
+	 * @throws ReflectionException
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidInterfaceException
114
+	 * @throws InvalidDataTypeException
115
+	 * @throws EE_Error
116
+	 */
117
+	public function set_description($description)
118
+	{
119
+		$this->set('DTT_description', $description);
120
+	}
121
+
122
+
123
+	/**
124
+	 * Set event start date
125
+	 * set the start date for an event
126
+	 *
127
+	 * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
128
+	 * @throws ReflectionException
129
+	 * @throws InvalidArgumentException
130
+	 * @throws InvalidInterfaceException
131
+	 * @throws InvalidDataTypeException
132
+	 * @throws EE_Error
133
+	 */
134
+	public function set_start_date($date)
135
+	{
136
+		$this->_set_date_for($date, 'DTT_EVT_start');
137
+	}
138
+
139
+
140
+	/**
141
+	 * Set event start time
142
+	 * set the start time for an event
143
+	 *
144
+	 * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
145
+	 * @throws ReflectionException
146
+	 * @throws InvalidArgumentException
147
+	 * @throws InvalidInterfaceException
148
+	 * @throws InvalidDataTypeException
149
+	 * @throws EE_Error
150
+	 */
151
+	public function set_start_time($time)
152
+	{
153
+		$this->_set_time_for($time, 'DTT_EVT_start');
154
+	}
155
+
156
+
157
+	/**
158
+	 * Set event end date
159
+	 * set the end date for an event
160
+	 *
161
+	 * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
162
+	 * @throws ReflectionException
163
+	 * @throws InvalidArgumentException
164
+	 * @throws InvalidInterfaceException
165
+	 * @throws InvalidDataTypeException
166
+	 * @throws EE_Error
167
+	 */
168
+	public function set_end_date($date)
169
+	{
170
+		$this->_set_date_for($date, 'DTT_EVT_end');
171
+	}
172
+
173
+
174
+	/**
175
+	 * Set event end time
176
+	 * set the end time for an event
177
+	 *
178
+	 * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
179
+	 * @throws ReflectionException
180
+	 * @throws InvalidArgumentException
181
+	 * @throws InvalidInterfaceException
182
+	 * @throws InvalidDataTypeException
183
+	 * @throws EE_Error
184
+	 */
185
+	public function set_end_time($time)
186
+	{
187
+		$this->_set_time_for($time, 'DTT_EVT_end');
188
+	}
189
+
190
+
191
+	/**
192
+	 * Set registration limit
193
+	 * set the maximum number of attendees that can be registered for this datetime slot
194
+	 *
195
+	 * @param int|float $reg_limit
196
+	 * @throws ReflectionException
197
+	 * @throws InvalidArgumentException
198
+	 * @throws InvalidInterfaceException
199
+	 * @throws InvalidDataTypeException
200
+	 * @throws EE_Error
201
+	 */
202
+	public function set_reg_limit($reg_limit)
203
+	{
204
+		$this->set('DTT_reg_limit', $reg_limit);
205
+	}
206
+
207
+
208
+	/**
209
+	 * get the number of tickets sold for this datetime slot
210
+	 *
211
+	 * @return mixed int on success, FALSE on fail
212
+	 * @throws ReflectionException
213
+	 * @throws InvalidArgumentException
214
+	 * @throws InvalidInterfaceException
215
+	 * @throws InvalidDataTypeException
216
+	 * @throws EE_Error
217
+	 */
218
+	public function sold()
219
+	{
220
+		return $this->get_raw('DTT_sold');
221
+	}
222
+
223
+
224
+	/**
225
+	 * @param int $sold
226
+	 * @throws ReflectionException
227
+	 * @throws InvalidArgumentException
228
+	 * @throws InvalidInterfaceException
229
+	 * @throws InvalidDataTypeException
230
+	 * @throws EE_Error
231
+	 */
232
+	public function set_sold($sold)
233
+	{
234
+		// sold can not go below zero
235
+		$sold = max(0, $sold);
236
+		$this->set('DTT_sold', $sold);
237
+	}
238
+
239
+
240
+	/**
241
+	 * Increments sold by amount passed by $qty, and persists it immediately to the database.
242
+	 * Simultaneously decreases the reserved count, unless $also_decrease_reserved is false.
243
+	 *
244
+	 * @param int $qty
245
+	 * @param boolean $also_decrease_reserved
246
+	 * @return boolean indicating success
247
+	 * @throws ReflectionException
248
+	 * @throws InvalidArgumentException
249
+	 * @throws InvalidInterfaceException
250
+	 * @throws InvalidDataTypeException
251
+	 * @throws EE_Error
252
+	 */
253
+	public function increaseSold(int $qty = 1, bool $also_decrease_reserved = true): bool
254
+	{
255
+		$qty = absint($qty);
256
+		if ($also_decrease_reserved) {
257
+			$success = $this->adjustNumericFieldsInDb(
258
+				[
259
+					'DTT_reserved' => $qty * -1,
260
+					'DTT_sold' => $qty
261
+				]
262
+			);
263
+		} else {
264
+			$success = $this->adjustNumericFieldsInDb(
265
+				[
266
+					'DTT_sold' => $qty
267
+				]
268
+			);
269
+		}
270
+
271
+		do_action(
272
+			'AHEE__EE_Datetime__increase_sold',
273
+			$this,
274
+			$qty,
275
+			$this->sold(),
276
+			$success
277
+		);
278
+		return $success;
279
+	}
280
+
281
+
282
+	/**
283
+	 * Decrements (subtracts) sold amount passed by $qty directly in the DB and on the model object. (Ie, no need
284
+	 * to save afterwards.)
285
+	 *
286
+	 * @param int $qty
287
+	 * @return boolean indicating success
288
+	 * @throws ReflectionException
289
+	 * @throws InvalidArgumentException
290
+	 * @throws InvalidInterfaceException
291
+	 * @throws InvalidDataTypeException
292
+	 * @throws EE_Error
293
+	 */
294
+	public function decreaseSold(int $qty = 1): bool
295
+	{
296
+		$qty = absint($qty);
297
+		$success = $this->adjustNumericFieldsInDb(
298
+			[
299
+				'DTT_sold' => $qty * -1
300
+			]
301
+		);
302
+		do_action(
303
+			'AHEE__EE_Datetime__decrease_sold',
304
+			$this,
305
+			$qty,
306
+			$this->sold(),
307
+			$success
308
+		);
309
+		return $success;
310
+	}
311
+
312
+
313
+	/**
314
+	 * Gets qty of reserved tickets for this datetime
315
+	 *
316
+	 * @return int
317
+	 * @throws ReflectionException
318
+	 * @throws InvalidArgumentException
319
+	 * @throws InvalidInterfaceException
320
+	 * @throws InvalidDataTypeException
321
+	 * @throws EE_Error
322
+	 */
323
+	public function reserved(): int
324
+	{
325
+		return $this->get_raw('DTT_reserved');
326
+	}
327
+
328
+
329
+	/**
330
+	 * Sets qty of reserved tickets for this datetime
331
+	 *
332
+	 * @param int $reserved
333
+	 * @throws ReflectionException
334
+	 * @throws InvalidArgumentException
335
+	 * @throws InvalidInterfaceException
336
+	 * @throws InvalidDataTypeException
337
+	 * @throws EE_Error
338
+	 */
339
+	public function set_reserved(int $reserved)
340
+	{
341
+		// reserved can not go below zero
342
+		$reserved = max(0, $reserved);
343
+		$this->set('DTT_reserved', $reserved);
344
+	}
345
+
346
+
347
+	/**
348
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
349
+	 *
350
+	 * @param int $qty
351
+	 * @return boolean indicating success
352
+	 * @throws ReflectionException
353
+	 * @throws InvalidArgumentException
354
+	 * @throws InvalidInterfaceException
355
+	 * @throws InvalidDataTypeException
356
+	 * @throws EE_Error
357
+	 */
358
+	public function increaseReserved(int $qty = 1): bool
359
+	{
360
+		$qty = absint($qty);
361
+		$success = $this->incrementFieldConditionallyInDb(
362
+			'DTT_reserved',
363
+			'DTT_sold',
364
+			'DTT_reg_limit',
365
+			$qty
366
+		);
367
+		do_action(
368
+			'AHEE__EE_Datetime__increase_reserved',
369
+			$this,
370
+			$qty,
371
+			$this->reserved(),
372
+			$success
373
+		);
374
+		return $success;
375
+	}
376
+
377
+
378
+	/**
379
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
380
+	 *
381
+	 * @param int $qty
382
+	 * @return boolean indicating success
383
+	 * @throws ReflectionException
384
+	 * @throws InvalidArgumentException
385
+	 * @throws InvalidInterfaceException
386
+	 * @throws InvalidDataTypeException
387
+	 * @throws EE_Error
388
+	 */
389
+	public function decreaseReserved(int $qty = 1): bool
390
+	{
391
+		$qty = absint($qty);
392
+		$success = $this->adjustNumericFieldsInDb(
393
+			[
394
+				'DTT_reserved' => $qty * -1
395
+			]
396
+		);
397
+		do_action(
398
+			'AHEE__EE_Datetime__decrease_reserved',
399
+			$this,
400
+			$qty,
401
+			$this->reserved(),
402
+			$success
403
+		);
404
+		return $success;
405
+	}
406
+
407
+
408
+	/**
409
+	 * total sold and reserved tickets
410
+	 *
411
+	 * @return int
412
+	 * @throws ReflectionException
413
+	 * @throws InvalidArgumentException
414
+	 * @throws InvalidInterfaceException
415
+	 * @throws InvalidDataTypeException
416
+	 * @throws EE_Error
417
+	 */
418
+	public function sold_and_reserved(): int
419
+	{
420
+		return $this->sold() + $this->reserved();
421
+	}
422
+
423
+
424
+	/**
425
+	 * returns the datetime name
426
+	 *
427
+	 * @return string
428
+	 * @throws ReflectionException
429
+	 * @throws InvalidArgumentException
430
+	 * @throws InvalidInterfaceException
431
+	 * @throws InvalidDataTypeException
432
+	 * @throws EE_Error
433
+	 */
434
+	public function name(): string
435
+	{
436
+		return $this->get('DTT_name');
437
+	}
438
+
439
+
440
+	/**
441
+	 * returns the datetime description
442
+	 *
443
+	 * @return string
444
+	 * @throws ReflectionException
445
+	 * @throws InvalidArgumentException
446
+	 * @throws InvalidInterfaceException
447
+	 * @throws InvalidDataTypeException
448
+	 * @throws EE_Error
449
+	 */
450
+	public function description(): string
451
+	{
452
+		return $this->get('DTT_description');
453
+	}
454
+
455
+
456
+	/**
457
+	 * This helper simply returns whether the event_datetime for the current datetime is a primary datetime
458
+	 *
459
+	 * @return boolean  TRUE if is primary, FALSE if not.
460
+	 * @throws ReflectionException
461
+	 * @throws InvalidArgumentException
462
+	 * @throws InvalidInterfaceException
463
+	 * @throws InvalidDataTypeException
464
+	 * @throws EE_Error
465
+	 */
466
+	public function is_primary(): bool
467
+	{
468
+		return $this->get('DTT_is_primary');
469
+	}
470
+
471
+
472
+	/**
473
+	 * This helper simply returns the order for the datetime
474
+	 *
475
+	 * @return int  The order of the datetime for this event.
476
+	 * @throws ReflectionException
477
+	 * @throws InvalidArgumentException
478
+	 * @throws InvalidInterfaceException
479
+	 * @throws InvalidDataTypeException
480
+	 * @throws EE_Error
481
+	 */
482
+	public function order(): int
483
+	{
484
+		return $this->get('DTT_order');
485
+	}
486
+
487
+
488
+	/**
489
+	 * This helper simply returns the parent id for the datetime
490
+	 *
491
+	 * @return int
492
+	 * @throws ReflectionException
493
+	 * @throws InvalidArgumentException
494
+	 * @throws InvalidInterfaceException
495
+	 * @throws InvalidDataTypeException
496
+	 * @throws EE_Error
497
+	 */
498
+	public function parent(): int
499
+	{
500
+		return $this->get('DTT_parent');
501
+	}
502
+
503
+
504
+	/**
505
+	 * show date and/or time
506
+	 *
507
+	 * @param string $date_or_time    whether to display a date or time or both
508
+	 * @param string $start_or_end    whether to display start or end datetimes
509
+	 * @param string $dt_frmt
510
+	 * @param string $tm_frmt
511
+	 * @param bool   $echo            whether we echo or return (note echoing uses "pretty" formats,
512
+	 *                                otherwise we use the standard formats)
513
+	 * @return string|bool  string on success, FALSE on fail
514
+	 * @throws ReflectionException
515
+	 * @throws InvalidArgumentException
516
+	 * @throws InvalidInterfaceException
517
+	 * @throws InvalidDataTypeException
518
+	 * @throws EE_Error
519
+	 */
520
+	private function _show_datetime(
521
+		$date_or_time = null,
522
+		$start_or_end = 'start',
523
+		$dt_frmt = '',
524
+		$tm_frmt = '',
525
+		$echo = false
526
+	) {
527
+		$field_name = "DTT_EVT_{$start_or_end}";
528
+		$dtt = $this->_get_datetime(
529
+			$field_name,
530
+			$dt_frmt,
531
+			$tm_frmt,
532
+			$date_or_time,
533
+			$echo
534
+		);
535
+		if (! $echo) {
536
+			return $dtt;
537
+		}
538
+		return '';
539
+	}
540
+
541
+
542
+	/**
543
+	 * get event start date.  Provide either the date format, or NULL to re-use the
544
+	 * last-used format, or '' to use the default date format
545
+	 *
546
+	 * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
547
+	 * @return mixed            string on success, FALSE on fail
548
+	 * @throws ReflectionException
549
+	 * @throws InvalidArgumentException
550
+	 * @throws InvalidInterfaceException
551
+	 * @throws InvalidDataTypeException
552
+	 * @throws EE_Error
553
+	 */
554
+	public function start_date($dt_frmt = '')
555
+	{
556
+		return $this->_show_datetime('D', 'start', $dt_frmt);
557
+	}
558
+
559
+
560
+	/**
561
+	 * Echoes start_date()
562
+	 *
563
+	 * @param string $dt_frmt
564
+	 * @throws ReflectionException
565
+	 * @throws InvalidArgumentException
566
+	 * @throws InvalidInterfaceException
567
+	 * @throws InvalidDataTypeException
568
+	 * @throws EE_Error
569
+	 */
570
+	public function e_start_date($dt_frmt = '')
571
+	{
572
+		$this->_show_datetime('D', 'start', $dt_frmt, null, true);
573
+	}
574
+
575
+
576
+	/**
577
+	 * get end date. Provide either the date format, or NULL to re-use the
578
+	 * last-used format, or '' to use the default date format
579
+	 *
580
+	 * @param string $dt_frmt string representation of date format defaults to 'F j, Y'
581
+	 * @return mixed            string on success, FALSE on fail
582
+	 * @throws ReflectionException
583
+	 * @throws InvalidArgumentException
584
+	 * @throws InvalidInterfaceException
585
+	 * @throws InvalidDataTypeException
586
+	 * @throws EE_Error
587
+	 */
588
+	public function end_date($dt_frmt = '')
589
+	{
590
+		return $this->_show_datetime('D', 'end', $dt_frmt);
591
+	}
592
+
593
+
594
+	/**
595
+	 * Echoes the end date. See end_date()
596
+	 *
597
+	 * @param string $dt_frmt
598
+	 * @throws ReflectionException
599
+	 * @throws InvalidArgumentException
600
+	 * @throws InvalidInterfaceException
601
+	 * @throws InvalidDataTypeException
602
+	 * @throws EE_Error
603
+	 */
604
+	public function e_end_date($dt_frmt = '')
605
+	{
606
+		$this->_show_datetime('D', 'end', $dt_frmt, null, true);
607
+	}
608
+
609
+
610
+	/**
611
+	 * get date_range - meaning the start AND end date
612
+	 *
613
+	 * @access public
614
+	 * @param string $dt_frmt     string representation of date format defaults to WP settings
615
+	 * @param string $conjunction conjunction junction what's your function ?
616
+	 *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
617
+	 * @return mixed              string on success, FALSE on fail
618
+	 * @throws ReflectionException
619
+	 * @throws InvalidArgumentException
620
+	 * @throws InvalidInterfaceException
621
+	 * @throws InvalidDataTypeException
622
+	 * @throws EE_Error
623
+	 */
624
+	public function date_range($dt_frmt = '', $conjunction = ' - ')
625
+	{
626
+		$dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
627
+		$start = str_replace(
628
+			' ',
629
+			'&nbsp;',
630
+			$this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
631
+		);
632
+		$end = str_replace(
633
+			' ',
634
+			'&nbsp;',
635
+			$this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
636
+		);
637
+		return $start !== $end ? $start . $conjunction . $end : $start;
638
+	}
639
+
640
+
641
+	/**
642
+	 * @param string $dt_frmt
643
+	 * @param string $conjunction
644
+	 * @throws ReflectionException
645
+	 * @throws InvalidArgumentException
646
+	 * @throws InvalidInterfaceException
647
+	 * @throws InvalidDataTypeException
648
+	 * @throws EE_Error
649
+	 */
650
+	public function e_date_range($dt_frmt = '', $conjunction = ' - ')
651
+	{
652
+		echo esc_html($this->date_range($dt_frmt, $conjunction));
653
+	}
654
+
655
+
656
+	/**
657
+	 * get start time
658
+	 *
659
+	 * @param string $tm_format - string representation of time format defaults to 'g:i a'
660
+	 * @return mixed        string on success, FALSE on fail
661
+	 * @throws ReflectionException
662
+	 * @throws InvalidArgumentException
663
+	 * @throws InvalidInterfaceException
664
+	 * @throws InvalidDataTypeException
665
+	 * @throws EE_Error
666
+	 */
667
+	public function start_time($tm_format = '')
668
+	{
669
+		return $this->_show_datetime('T', 'start', null, $tm_format);
670
+	}
671
+
672
+
673
+	/**
674
+	 * @param string $tm_format
675
+	 * @throws ReflectionException
676
+	 * @throws InvalidArgumentException
677
+	 * @throws InvalidInterfaceException
678
+	 * @throws InvalidDataTypeException
679
+	 * @throws EE_Error
680
+	 */
681
+	public function e_start_time($tm_format = '')
682
+	{
683
+		$this->_show_datetime('T', 'start', null, $tm_format, true);
684
+	}
685
+
686
+
687
+	/**
688
+	 * get end time
689
+	 *
690
+	 * @param string $tm_format string representation of time format defaults to 'g:i a'
691
+	 * @return mixed                string on success, FALSE on fail
692
+	 * @throws ReflectionException
693
+	 * @throws InvalidArgumentException
694
+	 * @throws InvalidInterfaceException
695
+	 * @throws InvalidDataTypeException
696
+	 * @throws EE_Error
697
+	 */
698
+	public function end_time($tm_format = '')
699
+	{
700
+		return $this->_show_datetime('T', 'end', null, $tm_format);
701
+	}
702
+
703
+
704
+	/**
705
+	 * @param string $tm_format
706
+	 * @throws ReflectionException
707
+	 * @throws InvalidArgumentException
708
+	 * @throws InvalidInterfaceException
709
+	 * @throws InvalidDataTypeException
710
+	 * @throws EE_Error
711
+	 */
712
+	public function e_end_time($tm_format = '')
713
+	{
714
+		$this->_show_datetime('T', 'end', null, $tm_format, true);
715
+	}
716
+
717
+
718
+	/**
719
+	 * get time_range
720
+	 *
721
+	 * @access public
722
+	 * @param string $tm_format   string representation of time format defaults to 'g:i a'
723
+	 * @param string $conjunction conjunction junction what's your function ?
724
+	 *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
725
+	 * @return mixed              string on success, FALSE on fail
726
+	 * @throws ReflectionException
727
+	 * @throws InvalidArgumentException
728
+	 * @throws InvalidInterfaceException
729
+	 * @throws InvalidDataTypeException
730
+	 * @throws EE_Error
731
+	 */
732
+	public function time_range($tm_format = '', $conjunction = ' - ')
733
+	{
734
+		$tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
735
+		$start = str_replace(
736
+			' ',
737
+			'&nbsp;',
738
+			$this->get_i18n_datetime('DTT_EVT_start', $tm_format)
739
+		);
740
+		$end = str_replace(
741
+			' ',
742
+			'&nbsp;',
743
+			$this->get_i18n_datetime('DTT_EVT_end', $tm_format)
744
+		);
745
+		return $start !== $end ? $start . $conjunction . $end : $start;
746
+	}
747
+
748
+
749
+	/**
750
+	 * @param string $tm_format
751
+	 * @param string $conjunction
752
+	 * @throws ReflectionException
753
+	 * @throws InvalidArgumentException
754
+	 * @throws InvalidInterfaceException
755
+	 * @throws InvalidDataTypeException
756
+	 * @throws EE_Error
757
+	 */
758
+	public function e_time_range($tm_format = '', $conjunction = ' - ')
759
+	{
760
+		echo esc_html($this->time_range($tm_format, $conjunction));
761
+	}
762
+
763
+
764
+	/**
765
+	 * This returns a range representation of the date and times.
766
+	 * Output is dependent on the difference (or similarity) between DTT_EVT_start and DTT_EVT_end.
767
+	 * Also, the return value is localized.
768
+	 *
769
+	 * @param string $dt_format
770
+	 * @param string $tm_format
771
+	 * @param string $conjunction used between two different dates or times.
772
+	 *                            ex: Dec 1{$conjunction}}Dec 6, or 2pm{$conjunction}3pm
773
+	 * @param string $separator   used between the date and time formats.
774
+	 *                            ex: Dec 1, 2016{$separator}2pm
775
+	 * @return string
776
+	 * @throws ReflectionException
777
+	 * @throws InvalidArgumentException
778
+	 * @throws InvalidInterfaceException
779
+	 * @throws InvalidDataTypeException
780
+	 * @throws EE_Error
781
+	 */
782
+	public function date_and_time_range(
783
+		$dt_format = '',
784
+		$tm_format = '',
785
+		$conjunction = ' - ',
786
+		$separator = ' '
787
+	) {
788
+		$dt_format = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
789
+		$tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
790
+		$full_format = $dt_format . $separator . $tm_format;
791
+		// the range output depends on various conditions
792
+		switch (true) {
793
+			// start date timestamp and end date timestamp are the same.
794
+			case ($this->get_raw('DTT_EVT_start') === $this->get_raw('DTT_EVT_end')):
795
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format);
796
+				break;
797
+			// start and end date are the same but times are different
798
+			case ($this->start_date() === $this->end_date()):
799
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
800
+						  . $conjunction
801
+						  . $this->get_i18n_datetime('DTT_EVT_end', $tm_format);
802
+				break;
803
+			// all other conditions
804
+			default:
805
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
806
+						  . $conjunction
807
+						  . $this->get_i18n_datetime('DTT_EVT_end', $full_format);
808
+				break;
809
+		}
810
+		return $output;
811
+	}
812
+
813
+
814
+	/**
815
+	 * This echos the results of date and time range.
816
+	 *
817
+	 * @see date_and_time_range() for more details on purpose.
818
+	 * @param string $dt_format
819
+	 * @param string $tm_format
820
+	 * @param string $conjunction
821
+	 * @return void
822
+	 * @throws ReflectionException
823
+	 * @throws InvalidArgumentException
824
+	 * @throws InvalidInterfaceException
825
+	 * @throws InvalidDataTypeException
826
+	 * @throws EE_Error
827
+	 */
828
+	public function e_date_and_time_range($dt_format = '', $tm_format = '', $conjunction = ' - ')
829
+	{
830
+		echo esc_html($this->date_and_time_range($dt_format, $tm_format, $conjunction));
831
+	}
832
+
833
+
834
+	/**
835
+	 * get start date and start time
836
+	 *
837
+	 * @param    string $dt_format - string representation of date format defaults to 'F j, Y'
838
+	 * @param    string $tm_format - string representation of time format defaults to 'g:i a'
839
+	 * @return    mixed    string on success, FALSE on fail
840
+	 * @throws ReflectionException
841
+	 * @throws InvalidArgumentException
842
+	 * @throws InvalidInterfaceException
843
+	 * @throws InvalidDataTypeException
844
+	 * @throws EE_Error
845
+	 */
846
+	public function start_date_and_time($dt_format = '', $tm_format = '')
847
+	{
848
+		return $this->_show_datetime('', 'start', $dt_format, $tm_format);
849
+	}
850
+
851
+
852
+	/**
853
+	 * @param string $dt_frmt
854
+	 * @param string $tm_format
855
+	 * @throws ReflectionException
856
+	 * @throws InvalidArgumentException
857
+	 * @throws InvalidInterfaceException
858
+	 * @throws InvalidDataTypeException
859
+	 * @throws EE_Error
860
+	 */
861
+	public function e_start_date_and_time($dt_frmt = '', $tm_format = '')
862
+	{
863
+		$this->_show_datetime('', 'start', $dt_frmt, $tm_format, true);
864
+	}
865
+
866
+
867
+	/**
868
+	 * Shows the length of the event (start to end time).
869
+	 * Can be shown in 'seconds','minutes','hours', or 'days'.
870
+	 * By default, rounds up. (So if you use 'days', and then event
871
+	 * only occurs for 1 hour, it will return 1 day).
872
+	 *
873
+	 * @param string $units 'seconds','minutes','hours','days'
874
+	 * @param bool   $round_up
875
+	 * @return float|int|mixed
876
+	 * @throws ReflectionException
877
+	 * @throws InvalidArgumentException
878
+	 * @throws InvalidInterfaceException
879
+	 * @throws InvalidDataTypeException
880
+	 * @throws EE_Error
881
+	 */
882
+	public function length($units = 'seconds', $round_up = false)
883
+	{
884
+		$start = $this->get_raw('DTT_EVT_start');
885
+		$end = $this->get_raw('DTT_EVT_end');
886
+		$length_in_units = $end - $start;
887
+		switch ($units) {
888
+			// NOTE: We purposefully don't use "break;" in order to chain the divisions
889
+			/** @noinspection PhpMissingBreakStatementInspection */
890
+			// phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
891
+			case 'days':
892
+				$length_in_units /= 24;
893
+			/** @noinspection PhpMissingBreakStatementInspection */
894
+			case 'hours':
895
+				// fall through is intentional
896
+				$length_in_units /= 60;
897
+			/** @noinspection PhpMissingBreakStatementInspection */
898
+			case 'minutes':
899
+				// fall through is intentional
900
+				$length_in_units /= 60;
901
+			case 'seconds':
902
+			default:
903
+				$length_in_units = ceil($length_in_units);
904
+		}
905
+		// phpcs:enable
906
+		if ($round_up) {
907
+			$length_in_units = max($length_in_units, 1);
908
+		}
909
+		return $length_in_units;
910
+	}
911
+
912
+
913
+	/**
914
+	 *        get end date and time
915
+	 *
916
+	 * @param string $dt_frmt   - string representation of date format defaults to 'F j, Y'
917
+	 * @param string $tm_format - string representation of time format defaults to 'g:i a'
918
+	 * @return    mixed                string on success, FALSE on fail
919
+	 * @throws ReflectionException
920
+	 * @throws InvalidArgumentException
921
+	 * @throws InvalidInterfaceException
922
+	 * @throws InvalidDataTypeException
923
+	 * @throws EE_Error
924
+	 */
925
+	public function end_date_and_time($dt_frmt = '', $tm_format = '')
926
+	{
927
+		return $this->_show_datetime('', 'end', $dt_frmt, $tm_format);
928
+	}
929
+
930
+
931
+	/**
932
+	 * @param string $dt_frmt
933
+	 * @param string $tm_format
934
+	 * @throws ReflectionException
935
+	 * @throws InvalidArgumentException
936
+	 * @throws InvalidInterfaceException
937
+	 * @throws InvalidDataTypeException
938
+	 * @throws EE_Error
939
+	 */
940
+	public function e_end_date_and_time($dt_frmt = '', $tm_format = '')
941
+	{
942
+		$this->_show_datetime('', 'end', $dt_frmt, $tm_format, true);
943
+	}
944
+
945
+
946
+	/**
947
+	 *        get start timestamp
948
+	 *
949
+	 * @return        int
950
+	 * @throws ReflectionException
951
+	 * @throws InvalidArgumentException
952
+	 * @throws InvalidInterfaceException
953
+	 * @throws InvalidDataTypeException
954
+	 * @throws EE_Error
955
+	 */
956
+	public function start()
957
+	{
958
+		return $this->get_raw('DTT_EVT_start');
959
+	}
960
+
961
+
962
+	/**
963
+	 *        get end timestamp
964
+	 *
965
+	 * @return        int
966
+	 * @throws ReflectionException
967
+	 * @throws InvalidArgumentException
968
+	 * @throws InvalidInterfaceException
969
+	 * @throws InvalidDataTypeException
970
+	 * @throws EE_Error
971
+	 */
972
+	public function end()
973
+	{
974
+		return $this->get_raw('DTT_EVT_end');
975
+	}
976
+
977
+
978
+	/**
979
+	 *    get the registration limit for this datetime slot
980
+	 *
981
+	 * @return int|float                int = finite limit   EE_INF(float) = unlimited
982
+	 * @throws ReflectionException
983
+	 * @throws InvalidArgumentException
984
+	 * @throws InvalidInterfaceException
985
+	 * @throws InvalidDataTypeException
986
+	 * @throws EE_Error
987
+	 */
988
+	public function reg_limit()
989
+	{
990
+		return $this->get_raw('DTT_reg_limit');
991
+	}
992
+
993
+
994
+	/**
995
+	 *    have the tickets sold for this datetime, met or exceed the registration limit ?
996
+	 *
997
+	 * @return boolean
998
+	 * @throws ReflectionException
999
+	 * @throws InvalidArgumentException
1000
+	 * @throws InvalidInterfaceException
1001
+	 * @throws InvalidDataTypeException
1002
+	 * @throws EE_Error
1003
+	 */
1004
+	public function sold_out()
1005
+	{
1006
+		return $this->reg_limit() > 0 && $this->sold() >= $this->reg_limit();
1007
+	}
1008
+
1009
+
1010
+	/**
1011
+	 * return the total number of spaces remaining at this venue.
1012
+	 * This only takes the venue's capacity into account, NOT the tickets available for sale
1013
+	 *
1014
+	 * @param bool $consider_tickets Whether to consider tickets remaining when determining if there are any spaces left
1015
+	 *                               Because if all tickets attached to this datetime have no spaces left,
1016
+	 *                               then this datetime IS effectively sold out.
1017
+	 *                               However, there are cases where we just want to know the spaces
1018
+	 *                               remaining for this particular datetime, hence the flag.
1019
+	 * @return int|float
1020
+	 * @throws ReflectionException
1021
+	 * @throws InvalidArgumentException
1022
+	 * @throws InvalidInterfaceException
1023
+	 * @throws InvalidDataTypeException
1024
+	 * @throws EE_Error
1025
+	 */
1026
+	public function spaces_remaining($consider_tickets = false)
1027
+	{
1028
+		// tickets remaining available for purchase
1029
+		// no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
1030
+		$dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
1031
+		if (! $consider_tickets) {
1032
+			return $dtt_remaining;
1033
+		}
1034
+		$tickets_remaining = $this->tickets_remaining();
1035
+		return min($dtt_remaining, $tickets_remaining);
1036
+	}
1037
+
1038
+
1039
+	/**
1040
+	 * Counts the total tickets available
1041
+	 * (from all the different types of tickets which are available for this datetime).
1042
+	 *
1043
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1044
+	 * @return int
1045
+	 * @throws ReflectionException
1046
+	 * @throws InvalidArgumentException
1047
+	 * @throws InvalidInterfaceException
1048
+	 * @throws InvalidDataTypeException
1049
+	 * @throws EE_Error
1050
+	 */
1051
+	public function tickets_remaining($query_params = array())
1052
+	{
1053
+		$sum = 0;
1054
+		$tickets = $this->tickets($query_params);
1055
+		if (! empty($tickets)) {
1056
+			foreach ($tickets as $ticket) {
1057
+				if ($ticket instanceof EE_Ticket) {
1058
+					// get the actual amount of tickets that can be sold
1059
+					$qty = $ticket->qty('saleable');
1060
+					if ($qty === EE_INF) {
1061
+						return EE_INF;
1062
+					}
1063
+					// no negative ticket quantities plz
1064
+					if ($qty > 0) {
1065
+						$sum += $qty;
1066
+					}
1067
+				}
1068
+			}
1069
+		}
1070
+		return $sum;
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * Gets the count of all the tickets available at this datetime (not ticket types)
1076
+	 * before any were sold
1077
+	 *
1078
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1079
+	 * @return int
1080
+	 * @throws ReflectionException
1081
+	 * @throws InvalidArgumentException
1082
+	 * @throws InvalidInterfaceException
1083
+	 * @throws InvalidDataTypeException
1084
+	 * @throws EE_Error
1085
+	 */
1086
+	public function sum_tickets_initially_available($query_params = array())
1087
+	{
1088
+		return $this->sum_related('Ticket', $query_params, 'TKT_qty');
1089
+	}
1090
+
1091
+
1092
+	/**
1093
+	 * Returns the lesser-of-the two: spaces remaining at this datetime, or
1094
+	 * the total tickets remaining (a sum of the tickets remaining for each ticket type
1095
+	 * that is available for this datetime).
1096
+	 *
1097
+	 * @return int
1098
+	 * @throws ReflectionException
1099
+	 * @throws InvalidArgumentException
1100
+	 * @throws InvalidInterfaceException
1101
+	 * @throws InvalidDataTypeException
1102
+	 * @throws EE_Error
1103
+	 */
1104
+	public function total_tickets_available_at_this_datetime()
1105
+	{
1106
+		return $this->spaces_remaining(true);
1107
+	}
1108
+
1109
+
1110
+	/**
1111
+	 * This simply compares the internal dtt for the given string with NOW
1112
+	 * and determines if the date is upcoming or not.
1113
+	 *
1114
+	 * @access public
1115
+	 * @return boolean
1116
+	 * @throws ReflectionException
1117
+	 * @throws InvalidArgumentException
1118
+	 * @throws InvalidInterfaceException
1119
+	 * @throws InvalidDataTypeException
1120
+	 * @throws EE_Error
1121
+	 */
1122
+	public function is_upcoming()
1123
+	{
1124
+		return ($this->get_raw('DTT_EVT_start') > time());
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 * This simply compares the internal datetime for the given string with NOW
1130
+	 * and returns if the date is active (i.e. start and end time)
1131
+	 *
1132
+	 * @return boolean
1133
+	 * @throws ReflectionException
1134
+	 * @throws InvalidArgumentException
1135
+	 * @throws InvalidInterfaceException
1136
+	 * @throws InvalidDataTypeException
1137
+	 * @throws EE_Error
1138
+	 */
1139
+	public function is_active()
1140
+	{
1141
+		return ($this->get_raw('DTT_EVT_start') < time() && $this->get_raw('DTT_EVT_end') > time());
1142
+	}
1143
+
1144
+
1145
+	/**
1146
+	 * This simply compares the internal dtt for the given string with NOW
1147
+	 * and determines if the date is expired or not.
1148
+	 *
1149
+	 * @return boolean
1150
+	 * @throws ReflectionException
1151
+	 * @throws InvalidArgumentException
1152
+	 * @throws InvalidInterfaceException
1153
+	 * @throws InvalidDataTypeException
1154
+	 * @throws EE_Error
1155
+	 */
1156
+	public function is_expired()
1157
+	{
1158
+		return ($this->get_raw('DTT_EVT_end') < time());
1159
+	}
1160
+
1161
+
1162
+	/**
1163
+	 * This returns the active status for whether an event is active, upcoming, or expired
1164
+	 *
1165
+	 * @return int return value will be one of the EE_Datetime status constants.
1166
+	 * @throws ReflectionException
1167
+	 * @throws InvalidArgumentException
1168
+	 * @throws InvalidInterfaceException
1169
+	 * @throws InvalidDataTypeException
1170
+	 * @throws EE_Error
1171
+	 */
1172
+	public function get_active_status()
1173
+	{
1174
+		$total_tickets_for_this_dtt = $this->total_tickets_available_at_this_datetime();
1175
+		if ($total_tickets_for_this_dtt !== false && $total_tickets_for_this_dtt < 1) {
1176
+			return EE_Datetime::sold_out;
1177
+		}
1178
+		if ($this->is_expired()) {
1179
+			return EE_Datetime::expired;
1180
+		}
1181
+		if ($this->is_upcoming()) {
1182
+			return EE_Datetime::upcoming;
1183
+		}
1184
+		if ($this->is_active()) {
1185
+			return EE_Datetime::active;
1186
+		}
1187
+		return null;
1188
+	}
1189
+
1190
+
1191
+	/**
1192
+	 * This returns a nice display name for the datetime that is contingent on the span between the dates and times.
1193
+	 *
1194
+	 * @param  boolean $use_dtt_name if TRUE then we'll use DTT->name() if its not empty.
1195
+	 * @return string
1196
+	 * @throws ReflectionException
1197
+	 * @throws InvalidArgumentException
1198
+	 * @throws InvalidInterfaceException
1199
+	 * @throws InvalidDataTypeException
1200
+	 * @throws EE_Error
1201
+	 */
1202
+	public function get_dtt_display_name($use_dtt_name = false)
1203
+	{
1204
+		if ($use_dtt_name) {
1205
+			$dtt_name = $this->name();
1206
+			if (! empty($dtt_name)) {
1207
+				return $dtt_name;
1208
+			}
1209
+		}
1210
+		// first condition is to see if the months are different
1211
+		if (
1212
+			date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1213
+		) {
1214
+			$display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1215
+			// next condition is if its the same month but different day
1216
+		} else {
1217
+			if (
1218
+				date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1219
+				&& date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1220
+			) {
1221
+				$display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1222
+			} else {
1223
+				$display_date = $this->start_date('F j\, Y')
1224
+								. ' @ '
1225
+								. $this->start_date('g:i a')
1226
+								. ' - '
1227
+								. $this->end_date('g:i a');
1228
+			}
1229
+		}
1230
+		return $display_date;
1231
+	}
1232
+
1233
+
1234
+	/**
1235
+	 * Gets all the tickets for this datetime
1236
+	 *
1237
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1238
+	 * @return EE_Base_Class[]|EE_Ticket[]
1239
+	 * @throws ReflectionException
1240
+	 * @throws InvalidArgumentException
1241
+	 * @throws InvalidInterfaceException
1242
+	 * @throws InvalidDataTypeException
1243
+	 * @throws EE_Error
1244
+	 */
1245
+	public function tickets($query_params = array())
1246
+	{
1247
+		return $this->get_many_related('Ticket', $query_params);
1248
+	}
1249
+
1250
+
1251
+	/**
1252
+	 * Gets all the ticket types currently available for purchase
1253
+	 *
1254
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1255
+	 * @return EE_Ticket[]
1256
+	 * @throws ReflectionException
1257
+	 * @throws InvalidArgumentException
1258
+	 * @throws InvalidInterfaceException
1259
+	 * @throws InvalidDataTypeException
1260
+	 * @throws EE_Error
1261
+	 */
1262
+	public function ticket_types_available_for_purchase($query_params = array())
1263
+	{
1264
+		// first check if datetime is valid
1265
+		if ($this->sold_out() || ! ($this->is_upcoming() || $this->is_active())) {
1266
+			return array();
1267
+		}
1268
+		if (empty($query_params)) {
1269
+			$query_params = array(
1270
+				array(
1271
+					'TKT_start_date' => array('<=', EEM_Ticket::instance()->current_time_for_query('TKT_start_date')),
1272
+					'TKT_end_date'   => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
1273
+					'TKT_deleted'    => false,
1274
+				),
1275
+			);
1276
+		}
1277
+		return $this->tickets($query_params);
1278
+	}
1279
+
1280
+
1281
+	/**
1282
+	 * @return EE_Base_Class|EE_Event
1283
+	 * @throws ReflectionException
1284
+	 * @throws InvalidArgumentException
1285
+	 * @throws InvalidInterfaceException
1286
+	 * @throws InvalidDataTypeException
1287
+	 * @throws EE_Error
1288
+	 */
1289
+	public function event()
1290
+	{
1291
+		return $this->get_first_related('Event');
1292
+	}
1293
+
1294
+
1295
+	/**
1296
+	 * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime
1297
+	 * (via the tickets).
1298
+	 *
1299
+	 * @return int
1300
+	 * @throws ReflectionException
1301
+	 * @throws InvalidArgumentException
1302
+	 * @throws InvalidInterfaceException
1303
+	 * @throws InvalidDataTypeException
1304
+	 * @throws EE_Error
1305
+	 */
1306
+	public function update_sold()
1307
+	{
1308
+		$count_regs_for_this_datetime = EEM_Registration::instance()->count(
1309
+			array(
1310
+				array(
1311
+					'STS_ID'                 => EEM_Registration::status_id_approved,
1312
+					'REG_deleted'            => 0,
1313
+					'Ticket.Datetime.DTT_ID' => $this->ID(),
1314
+				),
1315
+			)
1316
+		);
1317
+		$this->set_sold($count_regs_for_this_datetime);
1318
+		$this->save();
1319
+		return $count_regs_for_this_datetime;
1320
+	}
1321
+
1322
+
1323
+	/**
1324
+	 * Adds a venue to this event
1325
+	 *
1326
+	 * @param int|EE_Venue /int $venue_id_or_obj
1327
+	 * @return EE_Base_Class|EE_Venue
1328
+	 * @throws EE_Error
1329
+	 * @throws ReflectionException
1330
+	 */
1331
+	public function add_venue($venue_id_or_obj): EE_Venue
1332
+	{
1333
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
1334
+	}
1335
+
1336
+
1337
+	/**
1338
+	 * Removes a venue from the event
1339
+	 *
1340
+	 * @param EE_Venue /int $venue_id_or_obj
1341
+	 * @return EE_Base_Class|EE_Venue
1342
+	 * @throws EE_Error
1343
+	 * @throws ReflectionException
1344
+	 */
1345
+	public function remove_venue($venue_id_or_obj): EE_Venue
1346
+	{
1347
+		$venue_id_or_obj = ! empty($venue_id_or_obj) ? $venue_id_or_obj : $this->venue();
1348
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
1349
+	}
1350
+
1351
+
1352
+	/**
1353
+	 * Gets the venue related to the event. May provide additional $query_params if desired
1354
+	 *
1355
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1356
+	 * @return int
1357
+	 * @throws EE_Error
1358
+	 * @throws ReflectionException
1359
+	 */
1360
+	public function venue_ID(array $query_params = []): int
1361
+	{
1362
+		$venue = $this->get_first_related('Venue', $query_params);
1363
+		return $venue instanceof EE_Venue
1364
+			? $venue->ID()
1365
+			: 0;
1366
+	}
1367
+
1368
+
1369
+	/**
1370
+	 * Gets the venue related to the event. May provide additional $query_params if desired
1371
+	 *
1372
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1373
+	 * @return EE_Base_Class|EE_Venue
1374
+	 * @throws EE_Error
1375
+	 * @throws ReflectionException
1376
+	 */
1377
+	public function venue(array $query_params = [])
1378
+	{
1379
+		return $this->get_first_related('Venue', $query_params);
1380
+	}
1381
+
1382
+
1383
+	/**
1384
+	 * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1385
+	 * @param string                   $relationName
1386
+	 * @param array                    $extra_join_model_fields_n_values
1387
+	 * @param string|null              $cache_id
1388
+	 * @return EE_Base_Class
1389
+	 * @throws EE_Error
1390
+	 * @throws ReflectionException
1391
+	 * @since   5.0.0.p
1392
+	 */
1393
+	public function _add_relation_to(
1394
+		$otherObjectModelObjectOrID,
1395
+		$relationName,
1396
+		$extra_join_model_fields_n_values = [],
1397
+		$cache_id = null
1398
+	) {
1399
+		// if we're adding a new relation to a ticket
1400
+		if ($relationName === 'Ticket' && ! $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1401
+			/** @var EE_Ticket $ticket */
1402
+			$ticket = EEM_Ticket::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1403
+			$this->increaseSold($ticket->sold(), false);
1404
+			$this->increaseReserved($ticket->reserved());
1405
+			$this->save();
1406
+			$otherObjectModelObjectOrID = $ticket;
1407
+		}
1408
+		return parent::_add_relation_to(
1409
+			$otherObjectModelObjectOrID,
1410
+			$relationName,
1411
+			$extra_join_model_fields_n_values,
1412
+			$cache_id
1413
+		);
1414
+	}
1415
+
1416
+
1417
+	/**
1418
+	 * @param EE_Base_Class|int|string $otherObjectModelObjectOrID
1419
+	 * @param string                   $relationName
1420
+	 * @param array                    $where_query
1421
+	 * @return bool|EE_Base_Class|null
1422
+	 * @throws EE_Error
1423
+	 * @throws ReflectionException
1424
+	 * @since   5.0.0.p
1425
+	 */
1426
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = [])
1427
+	{
1428
+		if ($relationName === 'Ticket' && $this->hasRelation($otherObjectModelObjectOrID, $relationName)) {
1429
+			/** @var EE_Ticket $ticket */
1430
+			$ticket = EEM_Ticket::instance()->ensure_is_obj($otherObjectModelObjectOrID);
1431
+			$this->decreaseSold($ticket->sold());
1432
+			$this->decreaseReserved($ticket->reserved());
1433
+			$this->save();
1434
+			$otherObjectModelObjectOrID = $ticket;
1435
+		}
1436
+		return parent::_remove_relation_to(
1437
+			$otherObjectModelObjectOrID,
1438
+			$relationName,
1439
+			$where_query
1440
+		);
1441
+	}
1442
+
1443
+
1444
+	/**
1445
+	 * Removes ALL the related things for the $relationName.
1446
+	 *
1447
+	 * @param string $relationName
1448
+	 * @param array  $where_query_params
1449
+	 * @return EE_Base_Class
1450
+	 * @throws ReflectionException
1451
+	 * @throws InvalidArgumentException
1452
+	 * @throws InvalidInterfaceException
1453
+	 * @throws InvalidDataTypeException
1454
+	 * @throws EE_Error
1455
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
1456
+	 */
1457
+	public function _remove_relations($relationName, $where_query_params = [])
1458
+	{
1459
+		if ($relationName === 'Ticket') {
1460
+			$tickets = $this->tickets();
1461
+			foreach ($tickets as $ticket) {
1462
+				$this->decreaseSold($ticket->sold());
1463
+				$this->decreaseReserved($ticket->reserved());
1464
+				$this->save();
1465
+			}
1466
+		}
1467
+		return parent::_remove_relations($relationName, $where_query_params);
1468
+	}
1469
+
1470
+
1471
+	/*******************************************************************
1472 1472
      ***********************  DEPRECATED METHODS  **********************
1473 1473
      *******************************************************************/
1474 1474
 
1475 1475
 
1476
-    /**
1477
-     * Increments sold by amount passed by $qty, and persists it immediately to the database.
1478
-     *
1479
-     * @deprecated 4.9.80.p
1480
-     * @param int $qty
1481
-     * @return boolean
1482
-     * @throws ReflectionException
1483
-     * @throws InvalidArgumentException
1484
-     * @throws InvalidInterfaceException
1485
-     * @throws InvalidDataTypeException
1486
-     * @throws EE_Error
1487
-     */
1488
-    public function increase_sold($qty = 1)
1489
-    {
1490
-        EE_Error::doing_it_wrong(
1491
-            __FUNCTION__,
1492
-            esc_html__('Please use EE_Datetime::increaseSold() instead', 'event_espresso'),
1493
-            '4.9.80.p',
1494
-            '5.0.0.p'
1495
-        );
1496
-        return $this->increaseSold($qty);
1497
-    }
1498
-
1499
-
1500
-    /**
1501
-     * Decrements (subtracts) sold amount passed by $qty directly in the DB and on the model object. (Ie, no need
1502
-     * to save afterwards.)
1503
-     *
1504
-     * @deprecated 4.9.80.p
1505
-     * @param int $qty
1506
-     * @return boolean
1507
-     * @throws ReflectionException
1508
-     * @throws InvalidArgumentException
1509
-     * @throws InvalidInterfaceException
1510
-     * @throws InvalidDataTypeException
1511
-     * @throws EE_Error
1512
-     */
1513
-    public function decrease_sold($qty = 1)
1514
-    {
1515
-        EE_Error::doing_it_wrong(
1516
-            __FUNCTION__,
1517
-            esc_html__('Please use EE_Datetime::decreaseSold() instead', 'event_espresso'),
1518
-            '4.9.80.p',
1519
-            '5.0.0.p'
1520
-        );
1521
-        return $this->decreaseSold($qty);
1522
-    }
1523
-
1524
-
1525
-    /**
1526
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1527
-     *
1528
-     * @deprecated 4.9.80.p
1529
-     * @param int $qty
1530
-     * @return boolean indicating success
1531
-     * @throws ReflectionException
1532
-     * @throws InvalidArgumentException
1533
-     * @throws InvalidInterfaceException
1534
-     * @throws InvalidDataTypeException
1535
-     * @throws EE_Error
1536
-     */
1537
-    public function increase_reserved($qty = 1)
1538
-    {
1539
-        EE_Error::doing_it_wrong(
1540
-            __FUNCTION__,
1541
-            esc_html__('Please use EE_Datetime::increaseReserved() instead', 'event_espresso'),
1542
-            '4.9.80.p',
1543
-            '5.0.0.p'
1544
-        );
1545
-        return $this->increaseReserved($qty);
1546
-    }
1547
-
1548
-
1549
-    /**
1550
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1551
-     *
1552
-     * @deprecated 4.9.80.p
1553
-     * @param int $qty
1554
-     * @return boolean
1555
-     * @throws ReflectionException
1556
-     * @throws InvalidArgumentException
1557
-     * @throws InvalidInterfaceException
1558
-     * @throws InvalidDataTypeException
1559
-     * @throws EE_Error
1560
-     */
1561
-    public function decrease_reserved($qty = 1)
1562
-    {
1563
-        EE_Error::doing_it_wrong(
1564
-            __FUNCTION__,
1565
-            esc_html__('Please use EE_Datetime::decreaseReserved() instead', 'event_espresso'),
1566
-            '4.9.80.p',
1567
-            '5.0.0.p'
1568
-        );
1569
-        return $this->decreaseReserved($qty);
1570
-    }
1476
+	/**
1477
+	 * Increments sold by amount passed by $qty, and persists it immediately to the database.
1478
+	 *
1479
+	 * @deprecated 4.9.80.p
1480
+	 * @param int $qty
1481
+	 * @return boolean
1482
+	 * @throws ReflectionException
1483
+	 * @throws InvalidArgumentException
1484
+	 * @throws InvalidInterfaceException
1485
+	 * @throws InvalidDataTypeException
1486
+	 * @throws EE_Error
1487
+	 */
1488
+	public function increase_sold($qty = 1)
1489
+	{
1490
+		EE_Error::doing_it_wrong(
1491
+			__FUNCTION__,
1492
+			esc_html__('Please use EE_Datetime::increaseSold() instead', 'event_espresso'),
1493
+			'4.9.80.p',
1494
+			'5.0.0.p'
1495
+		);
1496
+		return $this->increaseSold($qty);
1497
+	}
1498
+
1499
+
1500
+	/**
1501
+	 * Decrements (subtracts) sold amount passed by $qty directly in the DB and on the model object. (Ie, no need
1502
+	 * to save afterwards.)
1503
+	 *
1504
+	 * @deprecated 4.9.80.p
1505
+	 * @param int $qty
1506
+	 * @return boolean
1507
+	 * @throws ReflectionException
1508
+	 * @throws InvalidArgumentException
1509
+	 * @throws InvalidInterfaceException
1510
+	 * @throws InvalidDataTypeException
1511
+	 * @throws EE_Error
1512
+	 */
1513
+	public function decrease_sold($qty = 1)
1514
+	{
1515
+		EE_Error::doing_it_wrong(
1516
+			__FUNCTION__,
1517
+			esc_html__('Please use EE_Datetime::decreaseSold() instead', 'event_espresso'),
1518
+			'4.9.80.p',
1519
+			'5.0.0.p'
1520
+		);
1521
+		return $this->decreaseSold($qty);
1522
+	}
1523
+
1524
+
1525
+	/**
1526
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1527
+	 *
1528
+	 * @deprecated 4.9.80.p
1529
+	 * @param int $qty
1530
+	 * @return boolean indicating success
1531
+	 * @throws ReflectionException
1532
+	 * @throws InvalidArgumentException
1533
+	 * @throws InvalidInterfaceException
1534
+	 * @throws InvalidDataTypeException
1535
+	 * @throws EE_Error
1536
+	 */
1537
+	public function increase_reserved($qty = 1)
1538
+	{
1539
+		EE_Error::doing_it_wrong(
1540
+			__FUNCTION__,
1541
+			esc_html__('Please use EE_Datetime::increaseReserved() instead', 'event_espresso'),
1542
+			'4.9.80.p',
1543
+			'5.0.0.p'
1544
+		);
1545
+		return $this->increaseReserved($qty);
1546
+	}
1547
+
1548
+
1549
+	/**
1550
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1551
+	 *
1552
+	 * @deprecated 4.9.80.p
1553
+	 * @param int $qty
1554
+	 * @return boolean
1555
+	 * @throws ReflectionException
1556
+	 * @throws InvalidArgumentException
1557
+	 * @throws InvalidInterfaceException
1558
+	 * @throws InvalidDataTypeException
1559
+	 * @throws EE_Error
1560
+	 */
1561
+	public function decrease_reserved($qty = 1)
1562
+	{
1563
+		EE_Error::doing_it_wrong(
1564
+			__FUNCTION__,
1565
+			esc_html__('Please use EE_Datetime::decreaseReserved() instead', 'event_espresso'),
1566
+			'4.9.80.p',
1567
+			'5.0.0.p'
1568
+		);
1569
+		return $this->decreaseReserved($qty);
1570
+	}
1571 1571
 }
Please login to merge, or discard this patch.