Completed
Branch back-compat-edtr-taxes (752e0e)
by
unknown
12:08 queued 09:43
created
modules/ticket_selector/EED_Ticket_Selector.module.php 2 patches
Indentation   +487 added lines, -487 removed lines patch added patch discarded remove patch
@@ -19,491 +19,491 @@
 block discarded – undo
19 19
 class EED_Ticket_Selector extends EED_Module
20 20
 {
21 21
 
22
-    /**
23
-     * @var DisplayTicketSelector $ticket_selector
24
-     */
25
-    private static $ticket_selector;
26
-
27
-    /**
28
-     * @var TicketSelectorIframeEmbedButton $iframe_embed_button
29
-     */
30
-    private static $iframe_embed_button;
31
-
32
-
33
-    /**
34
-     * @return EED_Module|EED_Ticket_Selector
35
-     * @throws EE_Error
36
-     * @throws ReflectionException
37
-     */
38
-    public static function instance()
39
-    {
40
-        return parent::get_instance(__CLASS__);
41
-    }
42
-
43
-
44
-    /**
45
-     * @return EE_Ticket_Selector_Config
46
-     * @throws EE_Error
47
-     * @throws ReflectionException
48
-     */
49
-    public static function ticketConfig()
50
-    {
51
-        EED_Ticket_Selector::instance()->set_config();
52
-        return EED_Ticket_Selector::instance()->config();
53
-    }
54
-
55
-
56
-    /**
57
-     * @return void
58
-     */
59
-    protected function set_config()
60
-    {
61
-        if ($this->_config instanceof EE_Ticket_Selector_Config) {
62
-            return;
63
-        }
64
-        $this->set_config_section('template_settings');
65
-        $this->set_config_class('EE_Ticket_Selector_Config');
66
-        $this->set_config_name('EED_Ticket_Selector');
67
-    }
68
-
69
-
70
-    /**
71
-     *    set_hooks - for hooking into EE Core, other modules, etc
72
-     *
73
-     * @return void
74
-     */
75
-    public static function set_hooks()
76
-    {
77
-        // routing
78
-        EE_Config::register_route(
79
-            'iframe',
80
-            'EED_Ticket_Selector',
81
-            'ticket_selector_iframe',
82
-            'ticket_selector'
83
-        );
84
-        EE_Config::register_route(
85
-            'process_ticket_selections',
86
-            'EED_Ticket_Selector',
87
-            'process_ticket_selections'
88
-        );
89
-        EE_Config::register_route(
90
-            'cancel_ticket_selections',
91
-            'EED_Ticket_Selector',
92
-            'cancel_ticket_selections'
93
-        );
94
-        add_action('wp_loaded', ['EED_Ticket_Selector', 'set_definitions'], 2);
95
-        add_action('AHEE_event_details_header_bottom', ['EED_Ticket_Selector', 'display_ticket_selector'], 10, 1);
96
-        add_action('wp_enqueue_scripts', ['EED_Ticket_Selector', 'translate_js_strings'], 0);
97
-        add_action('wp_enqueue_scripts', ['EED_Ticket_Selector', 'load_tckt_slctr_assets'], 10);
98
-        EED_Ticket_Selector::loadIframeAssets();
99
-    }
100
-
101
-
102
-    /**
103
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
104
-     *
105
-     * @return void
106
-     */
107
-    public static function set_hooks_admin()
108
-    {
109
-        // hook into the end of the \EE_Admin_Page::_load_page_dependencies()
110
-        // to load assets for "espresso_events" page on the "edit" route (action)
111
-        add_action(
112
-            'FHEE__EE_Admin_Page___load_page_dependencies__after_load__espresso_events__edit',
113
-            ['EED_Ticket_Selector', 'ticket_selector_iframe_embed_button'],
114
-            10
115
-        );
116
-        /**
117
-         * Make sure assets for the ticket selector are loaded on the espresso registrations route so  admin side
118
-         * registrations work.
119
-         */
120
-        add_action(
121
-            'FHEE__EE_Admin_Page___load_page_dependencies__after_load__espresso_registrations__new_registration',
122
-            ['EED_Ticket_Selector', 'set_definitions'],
123
-            10
124
-        );
125
-    }
126
-
127
-
128
-    /**
129
-     *    set_definitions
130
-     *
131
-     * @return void
132
-     * @throws EE_Error
133
-     * @throws ReflectionException
134
-     */
135
-    public static function set_definitions()
136
-    {
137
-        // don't do this twice
138
-        if (defined('TICKET_SELECTOR_ASSETS_URL')) {
139
-            return;
140
-        }
141
-        define('TICKET_SELECTOR_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
142
-        define(
143
-            'TICKET_SELECTOR_TEMPLATES_PATH',
144
-            str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/'
145
-        );
146
-        // initialize config
147
-        EED_Ticket_Selector::instance()->set_config();
148
-        // if config is not set, initialize
149
-        if (
150
-            ! EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config
151
-        ) {
152
-            EED_Ticket_Selector::instance()->set_config();
153
-            EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector =
154
-                EED_Ticket_Selector::instance()->config();
155
-        }
156
-    }
157
-
158
-
159
-    /**
160
-     * @return DisplayTicketSelector
161
-     * @throws EE_Error
162
-     * @throws ReflectionException
163
-     */
164
-    public static function ticketSelector()
165
-    {
166
-        if (! EED_Ticket_Selector::$ticket_selector instanceof DisplayTicketSelector) {
167
-            EED_Ticket_Selector::$ticket_selector = new DisplayTicketSelector(
168
-                EED_Ticket_Selector::getRequest(),
169
-                EED_Ticket_Selector::ticketConfig(),
170
-                EED_Events_Archive::is_iframe()
171
-            );
172
-        }
173
-        return EED_Ticket_Selector::$ticket_selector;
174
-    }
175
-
176
-
177
-    /**
178
-     * gets the ball rolling
179
-     *
180
-     * @param WP $WP
181
-     * @return void
182
-     */
183
-    public function run($WP)
184
-    {
185
-    }
186
-
187
-
188
-    /**
189
-     * @return TicketSelectorIframeEmbedButton
190
-     */
191
-    public static function getIframeEmbedButton()
192
-    {
193
-        if (! self::$iframe_embed_button instanceof TicketSelectorIframeEmbedButton) {
194
-            self::$iframe_embed_button = new TicketSelectorIframeEmbedButton();
195
-        }
196
-        return self::$iframe_embed_button;
197
-    }
198
-
199
-
200
-    /**
201
-     * ticket_selector_iframe_embed_button
202
-     *
203
-     * @return void
204
-     */
205
-    public static function ticket_selector_iframe_embed_button()
206
-    {
207
-        $iframe_embed_button = EED_Ticket_Selector::getIframeEmbedButton();
208
-        $iframe_embed_button->addEventEditorIframeEmbedButton();
209
-    }
210
-
211
-
212
-    /**
213
-     * ticket_selector_iframe
214
-     *
215
-     * @return void
216
-     * @throws DomainException
217
-     */
218
-    public function ticket_selector_iframe()
219
-    {
220
-        EE_Dependency_Map::register_dependencies(
221
-            TicketSelectorIframe::class,
222
-            [
223
-                'EEM_Event'                                            => EE_Dependency_Map::load_from_cache,
224
-                'EventEspresso\core\services\request\CurrentPage'      => EE_Dependency_Map::load_from_cache,
225
-                'EventEspresso\core\services\request\RequestInterface' => EE_Dependency_Map::load_from_cache,
226
-            ]
227
-        );
228
-        $ticket_selector_iframe = LoaderFactory::getLoader()->getNew(TicketSelectorIframe::class);
229
-        $ticket_selector_iframe->display();
230
-    }
231
-
232
-
233
-    /**
234
-     * creates buttons for selecting number of attendees for an event
235
-     *
236
-     * @param WP_Post|int $event
237
-     * @param bool        $view_details
238
-     * @return string
239
-     * @throws EE_Error
240
-     * @throws ReflectionException
241
-     */
242
-    public static function display_ticket_selector($event = null, $view_details = false)
243
-    {
244
-        return EED_Ticket_Selector::ticketSelector()->display($event, $view_details);
245
-    }
246
-
247
-
248
-    /**
249
-     * @return bool  or FALSE
250
-     * @throws EE_Error
251
-     * @throws InvalidArgumentException
252
-     * @throws InvalidInterfaceException
253
-     * @throws InvalidDataTypeException
254
-     * @throws ReflectionException
255
-     */
256
-    public function process_ticket_selections()
257
-    {
258
-        /** @var EventEspresso\modules\ticket_selector\ProcessTicketSelector $form */
259
-        $form = LoaderFactory::getLoader()->getShared('EventEspresso\modules\ticket_selector\ProcessTicketSelector');
260
-        return $form->processTicketSelections();
261
-    }
262
-
263
-
264
-    /**
265
-     * @return bool
266
-     * @throws InvalidArgumentException
267
-     * @throws InvalidInterfaceException
268
-     * @throws InvalidDataTypeException
269
-     * @throws EE_Error
270
-     * @throws ReflectionException
271
-     */
272
-    public static function cancel_ticket_selections()
273
-    {
274
-        /** @var EventEspresso\modules\ticket_selector\ProcessTicketSelector $form */
275
-        $form = LoaderFactory::getLoader()->getShared('EventEspresso\modules\ticket_selector\ProcessTicketSelector');
276
-        return $form->cancelTicketSelections();
277
-    }
278
-
279
-
280
-    /**
281
-     * @return void
282
-     */
283
-    public static function translate_js_strings()
284
-    {
285
-        EE_Registry::$i18n_js_strings['please_select_date_filter_notice'] = esc_html__(
286
-            'please select a datetime',
287
-            'event_espresso'
288
-        );
289
-    }
290
-
291
-
292
-    /**
293
-     * @return void
294
-     */
295
-    public static function load_tckt_slctr_assets()
296
-    {
297
-        if (apply_filters('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', false)) {
298
-            // add some style
299
-            wp_register_style(
300
-                'ticket_selector',
301
-                TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css',
302
-                [],
303
-                EVENT_ESPRESSO_VERSION
304
-            );
305
-            wp_enqueue_style('ticket_selector');
306
-            // make it dance
307
-            wp_register_script(
308
-                'ticket_selector',
309
-                TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.js',
310
-                ['espresso_core'],
311
-                EVENT_ESPRESSO_VERSION,
312
-                true
313
-            );
314
-            wp_enqueue_script('ticket_selector');
315
-            require_once EE_LIBRARIES
316
-                         . 'form_sections/strategies/display/EE_Checkbox_Dropdown_Selector_Display_Strategy.strategy.php';
317
-            EE_Checkbox_Dropdown_Selector_Display_Strategy::enqueue_styles_and_scripts();
318
-        }
319
-    }
320
-
321
-
322
-    /**
323
-     * @return void
324
-     */
325
-    public static function loadIframeAssets()
326
-    {
327
-        // for event lists
328
-        add_filter(
329
-            'FHEE__EventEspresso_modules_events_archive_EventsArchiveIframe__display__css',
330
-            ['EED_Ticket_Selector', 'iframeCss']
331
-        );
332
-        add_filter(
333
-            'FHEE__EventEspresso_modules_events_archive_EventsArchiveIframe__display__js',
334
-            ['EED_Ticket_Selector', 'iframeJs']
335
-        );
336
-        // for ticket selectors
337
-        add_filter(
338
-            'FHEE__EED_Ticket_Selector__ticket_selector_iframe__css',
339
-            ['EED_Ticket_Selector', 'iframeCss']
340
-        );
341
-        add_filter(
342
-            'FHEE__EED_Ticket_Selector__ticket_selector_iframe__js',
343
-            ['EED_Ticket_Selector', 'iframeJs']
344
-        );
345
-    }
346
-
347
-
348
-    /**
349
-     * Informs the rest of the forms system what CSS and JS is needed to display the input
350
-     *
351
-     * @param array $iframe_css
352
-     * @return array
353
-     */
354
-    public static function iframeCss(array $iframe_css)
355
-    {
356
-        $iframe_css['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css';
357
-        return $iframe_css;
358
-    }
359
-
360
-
361
-    /**
362
-     * Informs the rest of the forms system what CSS and JS is needed to display the input
363
-     *
364
-     * @param array $iframe_js
365
-     * @return array
366
-     */
367
-    public static function iframeJs(array $iframe_js)
368
-    {
369
-        $iframe_js['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.js';
370
-        return $iframe_js;
371
-    }
372
-
373
-
374
-    /****************************** DEPRECATED ******************************/
375
-
376
-
377
-    /**
378
-     * @return string
379
-     * @throws EE_Error
380
-     * @throws ReflectionException
381
-     * @deprecated
382
-     */
383
-    public static function display_view_details_btn()
384
-    {
385
-        // todo add doing_it_wrong() notice during next major version
386
-        return EED_Ticket_Selector::ticketSelector()->displayViewDetailsButton();
387
-    }
388
-
389
-
390
-    /**
391
-     * @return string
392
-     * @throws EE_Error
393
-     * @throws ReflectionException
394
-     * @deprecated
395
-     */
396
-    public static function display_ticket_selector_submit()
397
-    {
398
-        // todo add doing_it_wrong() notice during next major version
399
-        return EED_Ticket_Selector::ticketSelector()->displaySubmitButton();
400
-    }
401
-
402
-
403
-    /**
404
-     * @param string $permalink_string
405
-     * @param int    $id
406
-     * @param string $new_title
407
-     * @param string $new_slug
408
-     * @return string
409
-     * @throws InvalidArgumentException
410
-     * @throws InvalidDataTypeException
411
-     * @throws InvalidInterfaceException
412
-     * @deprecated
413
-     */
414
-    public static function iframe_code_button($permalink_string, $id, $new_title = '', $new_slug = '')
415
-    {
416
-        $request = self::getRequest();
417
-        // todo add doing_it_wrong() notice during next major version
418
-        if (
419
-            $request->getRequestParam('page') === 'espresso_events'
420
-            && $request->getRequestParam('action') === 'edit'
421
-        ) {
422
-            $iframe_embed_button = EED_Ticket_Selector::getIframeEmbedButton();
423
-            $iframe_embed_button->addEventEditorIframeEmbedButton();
424
-        }
425
-        return '';
426
-    }
427
-
428
-
429
-    /**
430
-     * @param int    $ID
431
-     * @param string $external_url
432
-     * @return string
433
-     * @throws EE_Error
434
-     * @throws ReflectionException
435
-     * @deprecated
436
-     */
437
-    public static function ticket_selector_form_open($ID = 0, $external_url = '')
438
-    {
439
-        // todo add doing_it_wrong() notice during next major version
440
-        return EED_Ticket_Selector::ticketSelector()->formOpen($ID, $external_url);
441
-    }
442
-
443
-
444
-    /**
445
-     * @return string
446
-     * @throws EE_Error
447
-     * @throws ReflectionException
448
-     * @deprecated
449
-     */
450
-    public static function ticket_selector_form_close()
451
-    {
452
-        // todo add doing_it_wrong() notice during next major version
453
-        return EED_Ticket_Selector::ticketSelector()->formClose();
454
-    }
455
-
456
-
457
-    /**
458
-     * @return string
459
-     * @throws EE_Error
460
-     * @throws ReflectionException
461
-     * @deprecated
462
-     */
463
-    public static function no_tkt_slctr_end_dv()
464
-    {
465
-        // todo add doing_it_wrong() notice during next major version
466
-        return EED_Ticket_Selector::ticketSelector()->ticketSelectorEndDiv();
467
-    }
468
-
469
-
470
-    /**
471
-     * @return string
472
-     * @throws EE_Error
473
-     * @throws ReflectionException
474
-     * @deprecated 4.9.13
475
-     */
476
-    public static function tkt_slctr_end_dv()
477
-    {
478
-        return EED_Ticket_Selector::ticketSelector()->clearTicketSelector();
479
-    }
480
-
481
-
482
-    /**
483
-     * @return string
484
-     * @throws EE_Error
485
-     * @throws ReflectionException
486
-     * @deprecated
487
-     */
488
-    public static function clear_tkt_slctr()
489
-    {
490
-        return EED_Ticket_Selector::ticketSelector()->clearTicketSelector();
491
-    }
492
-
493
-
494
-    /**
495
-     * @deprecated
496
-     */
497
-    public static function load_tckt_slctr_assets_admin()
498
-    {
499
-        $request = self::getRequest();
500
-        // todo add doing_it_wrong() notice during next major version
501
-        if (
502
-            $request->getRequestParam('page') === 'espresso_events'
503
-            && $request->getRequestParam('action') === 'edit'
504
-        ) {
505
-            $iframe_embed_button = EED_Ticket_Selector::getIframeEmbedButton();
506
-            $iframe_embed_button->embedButtonAssets();
507
-        }
508
-    }
22
+	/**
23
+	 * @var DisplayTicketSelector $ticket_selector
24
+	 */
25
+	private static $ticket_selector;
26
+
27
+	/**
28
+	 * @var TicketSelectorIframeEmbedButton $iframe_embed_button
29
+	 */
30
+	private static $iframe_embed_button;
31
+
32
+
33
+	/**
34
+	 * @return EED_Module|EED_Ticket_Selector
35
+	 * @throws EE_Error
36
+	 * @throws ReflectionException
37
+	 */
38
+	public static function instance()
39
+	{
40
+		return parent::get_instance(__CLASS__);
41
+	}
42
+
43
+
44
+	/**
45
+	 * @return EE_Ticket_Selector_Config
46
+	 * @throws EE_Error
47
+	 * @throws ReflectionException
48
+	 */
49
+	public static function ticketConfig()
50
+	{
51
+		EED_Ticket_Selector::instance()->set_config();
52
+		return EED_Ticket_Selector::instance()->config();
53
+	}
54
+
55
+
56
+	/**
57
+	 * @return void
58
+	 */
59
+	protected function set_config()
60
+	{
61
+		if ($this->_config instanceof EE_Ticket_Selector_Config) {
62
+			return;
63
+		}
64
+		$this->set_config_section('template_settings');
65
+		$this->set_config_class('EE_Ticket_Selector_Config');
66
+		$this->set_config_name('EED_Ticket_Selector');
67
+	}
68
+
69
+
70
+	/**
71
+	 *    set_hooks - for hooking into EE Core, other modules, etc
72
+	 *
73
+	 * @return void
74
+	 */
75
+	public static function set_hooks()
76
+	{
77
+		// routing
78
+		EE_Config::register_route(
79
+			'iframe',
80
+			'EED_Ticket_Selector',
81
+			'ticket_selector_iframe',
82
+			'ticket_selector'
83
+		);
84
+		EE_Config::register_route(
85
+			'process_ticket_selections',
86
+			'EED_Ticket_Selector',
87
+			'process_ticket_selections'
88
+		);
89
+		EE_Config::register_route(
90
+			'cancel_ticket_selections',
91
+			'EED_Ticket_Selector',
92
+			'cancel_ticket_selections'
93
+		);
94
+		add_action('wp_loaded', ['EED_Ticket_Selector', 'set_definitions'], 2);
95
+		add_action('AHEE_event_details_header_bottom', ['EED_Ticket_Selector', 'display_ticket_selector'], 10, 1);
96
+		add_action('wp_enqueue_scripts', ['EED_Ticket_Selector', 'translate_js_strings'], 0);
97
+		add_action('wp_enqueue_scripts', ['EED_Ticket_Selector', 'load_tckt_slctr_assets'], 10);
98
+		EED_Ticket_Selector::loadIframeAssets();
99
+	}
100
+
101
+
102
+	/**
103
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
104
+	 *
105
+	 * @return void
106
+	 */
107
+	public static function set_hooks_admin()
108
+	{
109
+		// hook into the end of the \EE_Admin_Page::_load_page_dependencies()
110
+		// to load assets for "espresso_events" page on the "edit" route (action)
111
+		add_action(
112
+			'FHEE__EE_Admin_Page___load_page_dependencies__after_load__espresso_events__edit',
113
+			['EED_Ticket_Selector', 'ticket_selector_iframe_embed_button'],
114
+			10
115
+		);
116
+		/**
117
+		 * Make sure assets for the ticket selector are loaded on the espresso registrations route so  admin side
118
+		 * registrations work.
119
+		 */
120
+		add_action(
121
+			'FHEE__EE_Admin_Page___load_page_dependencies__after_load__espresso_registrations__new_registration',
122
+			['EED_Ticket_Selector', 'set_definitions'],
123
+			10
124
+		);
125
+	}
126
+
127
+
128
+	/**
129
+	 *    set_definitions
130
+	 *
131
+	 * @return void
132
+	 * @throws EE_Error
133
+	 * @throws ReflectionException
134
+	 */
135
+	public static function set_definitions()
136
+	{
137
+		// don't do this twice
138
+		if (defined('TICKET_SELECTOR_ASSETS_URL')) {
139
+			return;
140
+		}
141
+		define('TICKET_SELECTOR_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
142
+		define(
143
+			'TICKET_SELECTOR_TEMPLATES_PATH',
144
+			str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/'
145
+		);
146
+		// initialize config
147
+		EED_Ticket_Selector::instance()->set_config();
148
+		// if config is not set, initialize
149
+		if (
150
+			! EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config
151
+		) {
152
+			EED_Ticket_Selector::instance()->set_config();
153
+			EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector =
154
+				EED_Ticket_Selector::instance()->config();
155
+		}
156
+	}
157
+
158
+
159
+	/**
160
+	 * @return DisplayTicketSelector
161
+	 * @throws EE_Error
162
+	 * @throws ReflectionException
163
+	 */
164
+	public static function ticketSelector()
165
+	{
166
+		if (! EED_Ticket_Selector::$ticket_selector instanceof DisplayTicketSelector) {
167
+			EED_Ticket_Selector::$ticket_selector = new DisplayTicketSelector(
168
+				EED_Ticket_Selector::getRequest(),
169
+				EED_Ticket_Selector::ticketConfig(),
170
+				EED_Events_Archive::is_iframe()
171
+			);
172
+		}
173
+		return EED_Ticket_Selector::$ticket_selector;
174
+	}
175
+
176
+
177
+	/**
178
+	 * gets the ball rolling
179
+	 *
180
+	 * @param WP $WP
181
+	 * @return void
182
+	 */
183
+	public function run($WP)
184
+	{
185
+	}
186
+
187
+
188
+	/**
189
+	 * @return TicketSelectorIframeEmbedButton
190
+	 */
191
+	public static function getIframeEmbedButton()
192
+	{
193
+		if (! self::$iframe_embed_button instanceof TicketSelectorIframeEmbedButton) {
194
+			self::$iframe_embed_button = new TicketSelectorIframeEmbedButton();
195
+		}
196
+		return self::$iframe_embed_button;
197
+	}
198
+
199
+
200
+	/**
201
+	 * ticket_selector_iframe_embed_button
202
+	 *
203
+	 * @return void
204
+	 */
205
+	public static function ticket_selector_iframe_embed_button()
206
+	{
207
+		$iframe_embed_button = EED_Ticket_Selector::getIframeEmbedButton();
208
+		$iframe_embed_button->addEventEditorIframeEmbedButton();
209
+	}
210
+
211
+
212
+	/**
213
+	 * ticket_selector_iframe
214
+	 *
215
+	 * @return void
216
+	 * @throws DomainException
217
+	 */
218
+	public function ticket_selector_iframe()
219
+	{
220
+		EE_Dependency_Map::register_dependencies(
221
+			TicketSelectorIframe::class,
222
+			[
223
+				'EEM_Event'                                            => EE_Dependency_Map::load_from_cache,
224
+				'EventEspresso\core\services\request\CurrentPage'      => EE_Dependency_Map::load_from_cache,
225
+				'EventEspresso\core\services\request\RequestInterface' => EE_Dependency_Map::load_from_cache,
226
+			]
227
+		);
228
+		$ticket_selector_iframe = LoaderFactory::getLoader()->getNew(TicketSelectorIframe::class);
229
+		$ticket_selector_iframe->display();
230
+	}
231
+
232
+
233
+	/**
234
+	 * creates buttons for selecting number of attendees for an event
235
+	 *
236
+	 * @param WP_Post|int $event
237
+	 * @param bool        $view_details
238
+	 * @return string
239
+	 * @throws EE_Error
240
+	 * @throws ReflectionException
241
+	 */
242
+	public static function display_ticket_selector($event = null, $view_details = false)
243
+	{
244
+		return EED_Ticket_Selector::ticketSelector()->display($event, $view_details);
245
+	}
246
+
247
+
248
+	/**
249
+	 * @return bool  or FALSE
250
+	 * @throws EE_Error
251
+	 * @throws InvalidArgumentException
252
+	 * @throws InvalidInterfaceException
253
+	 * @throws InvalidDataTypeException
254
+	 * @throws ReflectionException
255
+	 */
256
+	public function process_ticket_selections()
257
+	{
258
+		/** @var EventEspresso\modules\ticket_selector\ProcessTicketSelector $form */
259
+		$form = LoaderFactory::getLoader()->getShared('EventEspresso\modules\ticket_selector\ProcessTicketSelector');
260
+		return $form->processTicketSelections();
261
+	}
262
+
263
+
264
+	/**
265
+	 * @return bool
266
+	 * @throws InvalidArgumentException
267
+	 * @throws InvalidInterfaceException
268
+	 * @throws InvalidDataTypeException
269
+	 * @throws EE_Error
270
+	 * @throws ReflectionException
271
+	 */
272
+	public static function cancel_ticket_selections()
273
+	{
274
+		/** @var EventEspresso\modules\ticket_selector\ProcessTicketSelector $form */
275
+		$form = LoaderFactory::getLoader()->getShared('EventEspresso\modules\ticket_selector\ProcessTicketSelector');
276
+		return $form->cancelTicketSelections();
277
+	}
278
+
279
+
280
+	/**
281
+	 * @return void
282
+	 */
283
+	public static function translate_js_strings()
284
+	{
285
+		EE_Registry::$i18n_js_strings['please_select_date_filter_notice'] = esc_html__(
286
+			'please select a datetime',
287
+			'event_espresso'
288
+		);
289
+	}
290
+
291
+
292
+	/**
293
+	 * @return void
294
+	 */
295
+	public static function load_tckt_slctr_assets()
296
+	{
297
+		if (apply_filters('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', false)) {
298
+			// add some style
299
+			wp_register_style(
300
+				'ticket_selector',
301
+				TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css',
302
+				[],
303
+				EVENT_ESPRESSO_VERSION
304
+			);
305
+			wp_enqueue_style('ticket_selector');
306
+			// make it dance
307
+			wp_register_script(
308
+				'ticket_selector',
309
+				TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.js',
310
+				['espresso_core'],
311
+				EVENT_ESPRESSO_VERSION,
312
+				true
313
+			);
314
+			wp_enqueue_script('ticket_selector');
315
+			require_once EE_LIBRARIES
316
+						 . 'form_sections/strategies/display/EE_Checkbox_Dropdown_Selector_Display_Strategy.strategy.php';
317
+			EE_Checkbox_Dropdown_Selector_Display_Strategy::enqueue_styles_and_scripts();
318
+		}
319
+	}
320
+
321
+
322
+	/**
323
+	 * @return void
324
+	 */
325
+	public static function loadIframeAssets()
326
+	{
327
+		// for event lists
328
+		add_filter(
329
+			'FHEE__EventEspresso_modules_events_archive_EventsArchiveIframe__display__css',
330
+			['EED_Ticket_Selector', 'iframeCss']
331
+		);
332
+		add_filter(
333
+			'FHEE__EventEspresso_modules_events_archive_EventsArchiveIframe__display__js',
334
+			['EED_Ticket_Selector', 'iframeJs']
335
+		);
336
+		// for ticket selectors
337
+		add_filter(
338
+			'FHEE__EED_Ticket_Selector__ticket_selector_iframe__css',
339
+			['EED_Ticket_Selector', 'iframeCss']
340
+		);
341
+		add_filter(
342
+			'FHEE__EED_Ticket_Selector__ticket_selector_iframe__js',
343
+			['EED_Ticket_Selector', 'iframeJs']
344
+		);
345
+	}
346
+
347
+
348
+	/**
349
+	 * Informs the rest of the forms system what CSS and JS is needed to display the input
350
+	 *
351
+	 * @param array $iframe_css
352
+	 * @return array
353
+	 */
354
+	public static function iframeCss(array $iframe_css)
355
+	{
356
+		$iframe_css['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css';
357
+		return $iframe_css;
358
+	}
359
+
360
+
361
+	/**
362
+	 * Informs the rest of the forms system what CSS and JS is needed to display the input
363
+	 *
364
+	 * @param array $iframe_js
365
+	 * @return array
366
+	 */
367
+	public static function iframeJs(array $iframe_js)
368
+	{
369
+		$iframe_js['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.js';
370
+		return $iframe_js;
371
+	}
372
+
373
+
374
+	/****************************** DEPRECATED ******************************/
375
+
376
+
377
+	/**
378
+	 * @return string
379
+	 * @throws EE_Error
380
+	 * @throws ReflectionException
381
+	 * @deprecated
382
+	 */
383
+	public static function display_view_details_btn()
384
+	{
385
+		// todo add doing_it_wrong() notice during next major version
386
+		return EED_Ticket_Selector::ticketSelector()->displayViewDetailsButton();
387
+	}
388
+
389
+
390
+	/**
391
+	 * @return string
392
+	 * @throws EE_Error
393
+	 * @throws ReflectionException
394
+	 * @deprecated
395
+	 */
396
+	public static function display_ticket_selector_submit()
397
+	{
398
+		// todo add doing_it_wrong() notice during next major version
399
+		return EED_Ticket_Selector::ticketSelector()->displaySubmitButton();
400
+	}
401
+
402
+
403
+	/**
404
+	 * @param string $permalink_string
405
+	 * @param int    $id
406
+	 * @param string $new_title
407
+	 * @param string $new_slug
408
+	 * @return string
409
+	 * @throws InvalidArgumentException
410
+	 * @throws InvalidDataTypeException
411
+	 * @throws InvalidInterfaceException
412
+	 * @deprecated
413
+	 */
414
+	public static function iframe_code_button($permalink_string, $id, $new_title = '', $new_slug = '')
415
+	{
416
+		$request = self::getRequest();
417
+		// todo add doing_it_wrong() notice during next major version
418
+		if (
419
+			$request->getRequestParam('page') === 'espresso_events'
420
+			&& $request->getRequestParam('action') === 'edit'
421
+		) {
422
+			$iframe_embed_button = EED_Ticket_Selector::getIframeEmbedButton();
423
+			$iframe_embed_button->addEventEditorIframeEmbedButton();
424
+		}
425
+		return '';
426
+	}
427
+
428
+
429
+	/**
430
+	 * @param int    $ID
431
+	 * @param string $external_url
432
+	 * @return string
433
+	 * @throws EE_Error
434
+	 * @throws ReflectionException
435
+	 * @deprecated
436
+	 */
437
+	public static function ticket_selector_form_open($ID = 0, $external_url = '')
438
+	{
439
+		// todo add doing_it_wrong() notice during next major version
440
+		return EED_Ticket_Selector::ticketSelector()->formOpen($ID, $external_url);
441
+	}
442
+
443
+
444
+	/**
445
+	 * @return string
446
+	 * @throws EE_Error
447
+	 * @throws ReflectionException
448
+	 * @deprecated
449
+	 */
450
+	public static function ticket_selector_form_close()
451
+	{
452
+		// todo add doing_it_wrong() notice during next major version
453
+		return EED_Ticket_Selector::ticketSelector()->formClose();
454
+	}
455
+
456
+
457
+	/**
458
+	 * @return string
459
+	 * @throws EE_Error
460
+	 * @throws ReflectionException
461
+	 * @deprecated
462
+	 */
463
+	public static function no_tkt_slctr_end_dv()
464
+	{
465
+		// todo add doing_it_wrong() notice during next major version
466
+		return EED_Ticket_Selector::ticketSelector()->ticketSelectorEndDiv();
467
+	}
468
+
469
+
470
+	/**
471
+	 * @return string
472
+	 * @throws EE_Error
473
+	 * @throws ReflectionException
474
+	 * @deprecated 4.9.13
475
+	 */
476
+	public static function tkt_slctr_end_dv()
477
+	{
478
+		return EED_Ticket_Selector::ticketSelector()->clearTicketSelector();
479
+	}
480
+
481
+
482
+	/**
483
+	 * @return string
484
+	 * @throws EE_Error
485
+	 * @throws ReflectionException
486
+	 * @deprecated
487
+	 */
488
+	public static function clear_tkt_slctr()
489
+	{
490
+		return EED_Ticket_Selector::ticketSelector()->clearTicketSelector();
491
+	}
492
+
493
+
494
+	/**
495
+	 * @deprecated
496
+	 */
497
+	public static function load_tckt_slctr_assets_admin()
498
+	{
499
+		$request = self::getRequest();
500
+		// todo add doing_it_wrong() notice during next major version
501
+		if (
502
+			$request->getRequestParam('page') === 'espresso_events'
503
+			&& $request->getRequestParam('action') === 'edit'
504
+		) {
505
+			$iframe_embed_button = EED_Ticket_Selector::getIframeEmbedButton();
506
+			$iframe_embed_button->embedButtonAssets();
507
+		}
508
+	}
509 509
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -138,10 +138,10 @@  discard block
 block discarded – undo
138 138
         if (defined('TICKET_SELECTOR_ASSETS_URL')) {
139 139
             return;
140 140
         }
141
-        define('TICKET_SELECTOR_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
141
+        define('TICKET_SELECTOR_ASSETS_URL', plugin_dir_url(__FILE__).'assets/');
142 142
         define(
143 143
             'TICKET_SELECTOR_TEMPLATES_PATH',
144
-            str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/'
144
+            str_replace('\\', '/', plugin_dir_path(__FILE__)).'templates/'
145 145
         );
146 146
         // initialize config
147 147
         EED_Ticket_Selector::instance()->set_config();
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
      */
164 164
     public static function ticketSelector()
165 165
     {
166
-        if (! EED_Ticket_Selector::$ticket_selector instanceof DisplayTicketSelector) {
166
+        if ( ! EED_Ticket_Selector::$ticket_selector instanceof DisplayTicketSelector) {
167 167
             EED_Ticket_Selector::$ticket_selector = new DisplayTicketSelector(
168 168
                 EED_Ticket_Selector::getRequest(),
169 169
                 EED_Ticket_Selector::ticketConfig(),
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
      */
191 191
     public static function getIframeEmbedButton()
192 192
     {
193
-        if (! self::$iframe_embed_button instanceof TicketSelectorIframeEmbedButton) {
193
+        if ( ! self::$iframe_embed_button instanceof TicketSelectorIframeEmbedButton) {
194 194
             self::$iframe_embed_button = new TicketSelectorIframeEmbedButton();
195 195
         }
196 196
         return self::$iframe_embed_button;
@@ -298,7 +298,7 @@  discard block
 block discarded – undo
298 298
             // add some style
299 299
             wp_register_style(
300 300
                 'ticket_selector',
301
-                TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css',
301
+                TICKET_SELECTOR_ASSETS_URL.'ticket_selector.css',
302 302
                 [],
303 303
                 EVENT_ESPRESSO_VERSION
304 304
             );
@@ -306,7 +306,7 @@  discard block
 block discarded – undo
306 306
             // make it dance
307 307
             wp_register_script(
308 308
                 'ticket_selector',
309
-                TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.js',
309
+                TICKET_SELECTOR_ASSETS_URL.'ticket_selector.js',
310 310
                 ['espresso_core'],
311 311
                 EVENT_ESPRESSO_VERSION,
312 312
                 true
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
      */
354 354
     public static function iframeCss(array $iframe_css)
355 355
     {
356
-        $iframe_css['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.css';
356
+        $iframe_css['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL.'ticket_selector.css';
357 357
         return $iframe_css;
358 358
     }
359 359
 
@@ -366,7 +366,7 @@  discard block
 block discarded – undo
366 366
      */
367 367
     public static function iframeJs(array $iframe_js)
368 368
     {
369
-        $iframe_js['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL . 'ticket_selector.js';
369
+        $iframe_js['ticket_selector'] = TICKET_SELECTOR_ASSETS_URL.'ticket_selector.js';
370 370
         return $iframe_js;
371 371
     }
372 372
 
Please login to merge, or discard this patch.
support/templates/support_admin_details_contact_support.template.php 1 patch
Indentation   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -3,102 +3,102 @@
 block discarded – undo
3 3
 
4 4
     <h4>
5 5
         <?php
6
-        esc_html_e(
7
-            'You may be able to find an answer for your question or concern here:',
8
-            'event_espresso'
9
-        );
10
-        ?>
6
+		esc_html_e(
7
+			'You may be able to find an answer for your question or concern here:',
8
+			'event_espresso'
9
+		);
10
+		?>
11 11
     </h4>
12 12
     <ol>
13 13
         <li>
14 14
             <strong><em><?php esc_html_e('A known issue.', 'event_espresso'); ?></em></strong>
15 15
             <?php
16
-            printf(
17
-                esc_html__(
18
-                    'Some themes and plugins have %1$sknown conflicts%2$s with Event Espresso. (You can also browse the %3$sEvent Espresso support pages%2$s or %4$sEvent Espresso support forums%2$s to see if other members have experienced and solved the problem.)',
19
-                    'event_espresso'
20
-                ),
21
-                '<a href="https://eventespresso.com/wiki/known-third-party-plugin-theme-conflicts/" target="_blank">',
22
-                '</a>',
23
-                '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4" target="_blank">',
24
-                '<a href="https://eventespresso.com/support/forums/" target="_blank">'
25
-            );
26
-            ?>
16
+			printf(
17
+				esc_html__(
18
+					'Some themes and plugins have %1$sknown conflicts%2$s with Event Espresso. (You can also browse the %3$sEvent Espresso support pages%2$s or %4$sEvent Espresso support forums%2$s to see if other members have experienced and solved the problem.)',
19
+					'event_espresso'
20
+				),
21
+				'<a href="https://eventespresso.com/wiki/known-third-party-plugin-theme-conflicts/" target="_blank">',
22
+				'</a>',
23
+				'<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4" target="_blank">',
24
+				'<a href="https://eventespresso.com/support/forums/" target="_blank">'
25
+			);
26
+			?>
27 27
         </li>
28 28
         <li>
29 29
             <strong><em><?php esc_html_e('A plugin conflict.', 'event_espresso'); ?></em></strong>
30 30
             <?php
31
-            esc_html_e(
32
-                'You can check to see if there is a plugin conflict by temporarily deactivating all plugins except for Event Espresso. If the problem goes away, then reactivate your plugins one by one until the issue returns. This will help you pinpoint the source of the conflict.',
33
-                'event_espresso'
34
-            );
35
-            ?>
31
+			esc_html_e(
32
+				'You can check to see if there is a plugin conflict by temporarily deactivating all plugins except for Event Espresso. If the problem goes away, then reactivate your plugins one by one until the issue returns. This will help you pinpoint the source of the conflict.',
33
+				'event_espresso'
34
+			);
35
+			?>
36 36
         </li>
37 37
         <li>
38 38
             <strong><em><?php esc_html_e('A theme conflict.', 'event_espresso'); ?></em></strong>
39 39
             <?php
40
-            $default_theme = wp_get_theme(WP_DEFAULT_THEME);
40
+			$default_theme = wp_get_theme(WP_DEFAULT_THEME);
41 41
 
42
-            if ($default_theme->exists()) {
43
-                printf(
44
-                    esc_html__(
45
-                        'If your problem is not a known issue or caused by a plugin, then try activating %s (the default WordPress theme).',
46
-                        'event_espresso'
47
-                    ),
48
-                    $default_theme->get('Name')
49
-                );
50
-            } else {
51
-                esc_html_e(
52
-                    'If your problem is not a known issue or caused by a plugin, then try activating the default WordPress theme.',
53
-                    'event_espresso'
54
-                );
55
-            }
56
-            ?>
42
+			if ($default_theme->exists()) {
43
+				printf(
44
+					esc_html__(
45
+						'If your problem is not a known issue or caused by a plugin, then try activating %s (the default WordPress theme).',
46
+						'event_espresso'
47
+					),
48
+					$default_theme->get('Name')
49
+				);
50
+			} else {
51
+				esc_html_e(
52
+					'If your problem is not a known issue or caused by a plugin, then try activating the default WordPress theme.',
53
+					'event_espresso'
54
+				);
55
+			}
56
+			?>
57 57
             <?php
58
-            esc_html_e(
59
-                'If this solves the problem for you, then something in your theme is causing this issue. Check to see if an update is available for your WordPress theme or reach out to the theme author.',
60
-                'event_espresso'
61
-            );
62
-            ?>
58
+			esc_html_e(
59
+				'If this solves the problem for you, then something in your theme is causing this issue. Check to see if an update is available for your WordPress theme or reach out to the theme author.',
60
+				'event_espresso'
61
+			);
62
+			?>
63 63
         </li>
64 64
     </ol>
65 65
 
66 66
     <p>
67 67
         <?php
68
-        esc_html_e(
69
-            'If none of the suggestions above help you find a solution, then feel free to reach out to the support team at Event Espresso.',
70
-            'event_espresso'
71
-        );
72
-        ?>
68
+		esc_html_e(
69
+			'If none of the suggestions above help you find a solution, then feel free to reach out to the support team at Event Espresso.',
70
+			'event_espresso'
71
+		);
72
+		?>
73 73
     </p>
74 74
     <p>
75 75
         <?php
76
-        printf(
77
-            esc_html__(
78
-                'Login to your account on EventEspresso.com and %1$screate a support post in our member support forums%2$s. Use a %3$sclear and descriptive title%4$s in your support post, %3$sdescribe the issue to the best of your knowledge%4$s, and %3$snever post any sensitive information such as login details%4$s. Be sure to also include %5$simportant information in the section below%2$s about your WordPress site.',
79
-                'event_espresso'
80
-            ),
81
-            '<a href="https://eventespresso.com/support/forums/" target="_blank">',
82
-            '</a>',
83
-            '<strong>',
84
-            '</strong>',
85
-            '<a href="#espresso_important_information_settings">'
86
-        );
87
-        ?>
76
+		printf(
77
+			esc_html__(
78
+				'Login to your account on EventEspresso.com and %1$screate a support post in our member support forums%2$s. Use a %3$sclear and descriptive title%4$s in your support post, %3$sdescribe the issue to the best of your knowledge%4$s, and %3$snever post any sensitive information such as login details%4$s. Be sure to also include %5$simportant information in the section below%2$s about your WordPress site.',
79
+				'event_espresso'
80
+			),
81
+			'<a href="https://eventespresso.com/support/forums/" target="_blank">',
82
+			'</a>',
83
+			'<strong>',
84
+			'</strong>',
85
+			'<a href="#espresso_important_information_settings">'
86
+		);
87
+		?>
88 88
     </p>
89 89
 
90 90
     <h4><?php esc_html_e('Have an emergency?', 'event_espresso'); ?></h4>
91 91
 
92 92
     <p>
93 93
         <?php
94
-        printf(
95
-            esc_html__(
96
-                'We offer support tokens to members that need help with a time-sensitive issue. A support token will provide you with up to 30 minutes of one-on-one time with a team member at Event Espresso. If you have an emergency and need help quickly, then please %1$spurchase a support token%2$s.',
97
-                'event_espresso'
98
-            ),
99
-            '<a href="https://eventespresso.com/product/premium-support-token/?utm_source=ee4_plugin_admin&utm_medium=link&utm_campaign=help_support_tab&utm_content=support_token" target="_blank">',
100
-            '</a>'
101
-        );
102
-        ?>
94
+		printf(
95
+			esc_html__(
96
+				'We offer support tokens to members that need help with a time-sensitive issue. A support token will provide you with up to 30 minutes of one-on-one time with a team member at Event Espresso. If you have an emergency and need help quickly, then please %1$spurchase a support token%2$s.',
97
+				'event_espresso'
98
+			),
99
+			'<a href="https://eventespresso.com/product/premium-support-token/?utm_source=ee4_plugin_admin&utm_medium=link&utm_campaign=help_support_tab&utm_content=support_token" target="_blank">',
100
+			'</a>'
101
+		);
102
+		?>
103 103
     </p>
104 104
 </div>
105 105
\ No newline at end of file
Please login to merge, or discard this patch.
admin_pages/registration_form/Registration_Form_Admin_Page.core.php 2 patches
Indentation   +770 added lines, -770 removed lines patch added patch discarded remove patch
@@ -16,713 +16,713 @@  discard block
 block discarded – undo
16 16
 class Registration_Form_Admin_Page extends EE_Admin_Page
17 17
 {
18 18
 
19
-    /**
20
-     * holds the specific question object for the question details screen
21
-     *
22
-     * @var EE_Question $_question
23
-     */
24
-    protected $_question;
25
-
26
-    /**
27
-     * holds the specific question group object for the question group details screen
28
-     *
29
-     * @var EE_Question_Group $_question_group
30
-     */
31
-    protected $_question_group;
32
-
33
-    /**
34
-     *_question_model EEM_Question model instance (for queries)
35
-     *
36
-     * @var EEM_Question $_question_model ;
37
-     */
38
-    protected $_question_model;
39
-
40
-    /**
41
-     * _question_group_model EEM_Question_group instance (for queries)
42
-     *
43
-     * @var EEM_Question_Group $_question_group_model
44
-     */
45
-    protected $_question_group_model;
46
-
47
-
48
-    /**
49
-     * @Constructor
50
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
51
-     * @throws EE_Error
52
-     * @throws ReflectionException
53
-     */
54
-    public function __construct($routing = true)
55
-    {
56
-        require_once(EE_MODELS . 'EEM_Question.model.php');
57
-        require_once(EE_MODELS . 'EEM_Question_Group.model.php');
58
-        $this->_question_model       = EEM_Question::instance();
59
-        $this->_question_group_model = EEM_Question_Group::instance();
60
-        parent::__construct($routing);
61
-    }
62
-
63
-
64
-    protected function _init_page_props()
65
-    {
66
-        $this->page_slug        = REGISTRATION_FORM_PG_SLUG;
67
-        $this->page_label       = esc_html__('Registration Form', 'event_espresso');
68
-        $this->_admin_base_url  = REGISTRATION_FORM_ADMIN_URL;
69
-        $this->_admin_base_path = REGISTRATION_FORM_ADMIN;
70
-    }
71
-
72
-
73
-    protected function _ajax_hooks()
74
-    {
75
-    }
76
-
77
-
78
-    protected function _define_page_props()
79
-    {
80
-        $this->_admin_page_title = esc_html__('Registration Form', 'event_espresso');
81
-        $this->_labels           = [
82
-            'buttons' => [
83
-                'edit_question' => esc_html__('Edit Question', 'event_espresso'),
84
-            ],
85
-        ];
86
-    }
87
-
88
-
89
-    /**
90
-     *_set_page_routes
91
-     */
92
-    protected function _set_page_routes()
93
-    {
94
-        $qst_id             =
95
-            ! empty($this->_req_data['QST_ID'])
96
-                ? $this->_req_data['QST_ID']
97
-                : 0;
98
-        $this->_page_routes = [
99
-            'default' => [
100
-                'func'       => '_questions_overview_list_table',
101
-                'capability' => 'ee_read_questions',
102
-            ],
103
-
104
-            'edit_question' => [
105
-                'func'       => '_edit_question',
106
-                'capability' => 'ee_edit_question',
107
-                'obj_id'     => $qst_id,
108
-                'args'       => ['edit'],
109
-            ],
110
-
111
-            'question_groups' => [
112
-                'func'       => '_questions_groups_preview',
113
-                'capability' => 'ee_read_question_groups',
114
-            ],
115
-
116
-            'update_question' => [
117
-                'func'       => '_insert_or_update_question',
118
-                'args'       => ['new_question' => false],
119
-                'capability' => 'ee_edit_question',
120
-                'obj_id'     => $qst_id,
121
-                'noheader'   => true,
122
-            ],
123
-        ];
124
-    }
125
-
126
-
127
-    protected function _set_page_config()
128
-    {
129
-        $this->_page_config = [
130
-            'default' => [
131
-                'nav'           => [
132
-                    'label' => esc_html__('Questions', 'event_espresso'),
133
-                    'order' => 10,
134
-                ],
135
-                'list_table'    => 'Registration_Form_Questions_Admin_List_Table',
136
-                'metaboxes'     => $this->_default_espresso_metaboxes,
137
-                'help_tabs'     => [
138
-                    'registration_form_questions_overview_help_tab'                           => [
139
-                        'title'    => esc_html__('Questions Overview', 'event_espresso'),
140
-                        'filename' => 'registration_form_questions_overview',
141
-                    ],
142
-                    'registration_form_questions_overview_table_column_headings_help_tab'     => [
143
-                        'title'    => esc_html__('Questions Overview Table Column Headings', 'event_espresso'),
144
-                        'filename' => 'registration_form_questions_overview_table_column_headings',
145
-                    ],
146
-                    'registration_form_questions_overview_views_bulk_actions_search_help_tab' => [
147
-                        'title'    => esc_html__('Question Overview Views & Bulk Actions & Search', 'event_espresso'),
148
-                        'filename' => 'registration_form_questions_overview_views_bulk_actions_search',
149
-                    ],
150
-                ],
151
-                // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
152
-                // 'help_tour'     => array('Registration_Form_Questions_Overview_Help_Tour'),
153
-                'require_nonce' => false,
154
-                'qtips'         => [
155
-                    'EE_Registration_Form_Tips',
156
-                ]/**/
157
-            ],
158
-
159
-            'question_groups' => [
160
-                'nav'           => [
161
-                    'label' => esc_html__('Question Groups', 'event_espresso'),
162
-                    'order' => 20,
163
-                ],
164
-                'metaboxes'     => $this->_default_espresso_metaboxes,
165
-                'help_tabs'     => [
166
-                    'registration_form_question_groups_help_tab' => [
167
-                        'title'    => esc_html__('Question Groups', 'event_espresso'),
168
-                        'filename' => 'registration_form_question_groups',
169
-                    ],
170
-                ],
171
-                // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
172
-                // 'help_tour'     => array('Registration_Form_Question_Groups_Help_Tour'),
173
-                'require_nonce' => false,
174
-            ],
175
-
176
-            'edit_question' => [
177
-                'nav'           => [
178
-                    'label'      => esc_html__('Edit Question', 'event_espresso'),
179
-                    'order'      => 15,
180
-                    'persistent' => false,
181
-                    'url'        => isset($this->_req_data['question_id'])
182
-                        ? add_query_arg(
183
-                            ['question_id' => $this->_req_data['question_id']],
184
-                            $this->_current_page_view_url
185
-                        )
186
-                        : $this->_admin_base_url,
187
-                ],
188
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
189
-                'help_tabs'     => [
190
-                    'registration_form_edit_question_group_help_tab' => [
191
-                        'title'    => esc_html__('Edit Question', 'event_espresso'),
192
-                        'filename' => 'registration_form_edit_question',
193
-                    ],
194
-                ],
195
-                // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
196
-                // 'help_tour'     => array('Registration_Form_Edit_Question_Help_Tour'),
197
-                'require_nonce' => false,
198
-            ],
199
-        ];
200
-    }
201
-
202
-
203
-    protected function _add_screen_options()
204
-    {
205
-        // todo
206
-    }
207
-
208
-
209
-    protected function _add_screen_options_default()
210
-    {
211
-        $page_title              = $this->_admin_page_title;
212
-        $this->_admin_page_title = esc_html__('Questions', 'event_espresso');
213
-        $this->_per_page_screen_option();
214
-        $this->_admin_page_title = $page_title;
215
-    }
216
-
217
-
218
-    protected function _add_screen_options_question_groups()
219
-    {
220
-        $page_title              = $this->_admin_page_title;
221
-        $this->_admin_page_title = esc_html__('Question Groups', 'event_espresso');
222
-        $this->_per_page_screen_option();
223
-        $this->_admin_page_title = $page_title;
224
-    }
225
-
226
-
227
-    // none of the below group are currently used for Event Categories
228
-    protected function _add_feature_pointers()
229
-    {
230
-    }
231
-
232
-
233
-    public function load_scripts_styles()
234
-    {
235
-        wp_register_style(
236
-            'espresso_registration',
237
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css',
238
-            [],
239
-            EVENT_ESPRESSO_VERSION
240
-        );
241
-        wp_enqueue_style('espresso_registration');
242
-    }
243
-
244
-
245
-    public function admin_init()
246
-    {
247
-    }
248
-
249
-
250
-    public function admin_notices()
251
-    {
252
-    }
253
-
254
-
255
-    public function admin_footer_scripts()
256
-    {
257
-    }
258
-
259
-
260
-    public function load_scripts_styles_default()
261
-    {
262
-    }
263
-
264
-
265
-    /**
266
-     * @throws EE_Error
267
-     */
268
-    public function load_scripts_styles_add_question()
269
-    {
270
-        $this->load_scripts_styles_question_details();
271
-    }
272
-
273
-
274
-    /**
275
-     * @throws EE_Error
276
-     */
277
-    public function load_scripts_styles_edit_question()
278
-    {
279
-        $this->load_scripts_styles_question_details();
280
-    }
281
-
282
-
283
-    /**
284
-     * Loads the JS required for adding or editing a question
285
-     *
286
-     * @throws EE_Error
287
-     * @throws EE_Error
288
-     */
289
-    protected function load_scripts_styles_question_details()
290
-    {
291
-        $this->load_scripts_styles_forms();
292
-        wp_register_script(
293
-            'espresso_registration_form_single',
294
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js',
295
-            ['jquery-ui-sortable'],
296
-            EVENT_ESPRESSO_VERSION,
297
-            true
298
-        );
299
-        wp_enqueue_script('espresso_registration_form_single');
300
-        wp_localize_script(
301
-            'espresso_registration_form_single',
302
-            'ee_question_data',
303
-            [
304
-                'question_types_with_max'    => EEM_Question::instance()->questionTypesWithMaxLength(),
305
-                'question_type_with_options' => EEM_Question::instance()->question_types_with_options(),
306
-            ]
307
-        );
308
-    }
309
-
310
-
311
-    public function recaptcha_info_help_tab()
312
-    {
313
-        $template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
314
-        EEH_Template::display_template($template, []);
315
-    }
316
-
317
-
318
-    public function load_scripts_styles_forms()
319
-    {
320
-        // styles
321
-        wp_enqueue_style('espresso-ui-theme');
322
-        // scripts
323
-        wp_enqueue_script('ee_admin_js');
324
-    }
325
-
326
-
327
-    protected function _set_list_table_views_default()
328
-    {
329
-        $this->_views = [
330
-            'all' => [
331
-                'slug'  => 'all',
332
-                'label' => esc_html__('View All Questions', 'event_espresso'),
333
-                'count' => 0,
334
-            ],
335
-        ];
336
-
337
-        if (
338
-            EE_Registry::instance()->CAP->current_user_can(
339
-                'ee_delete_questions',
340
-                'espresso_registration_form_trash_questions'
341
-            )
342
-        ) {
343
-            $this->_views['trash'] = [
344
-                'slug'  => 'trash',
345
-                'label' => esc_html__('Trash', 'event_espresso'),
346
-                'count' => 0,
347
-            ];
348
-        }
349
-    }
350
-
351
-
352
-    /**
353
-     * This just previews the question groups tab that comes in caffeinated.
354
-     *
355
-     * @return void html
356
-     * @throws EE_Error
357
-     */
358
-    protected function _questions_groups_preview()
359
-    {
360
-        $this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
361
-        $this->_template_args['preview_img']  =
362
-            '<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="'
363
-            . esc_attr__(
364
-                'Preview Question Groups Overview List Table screenshot',
365
-                'event_espresso'
366
-            ) . '" />';
367
-        $this->_template_args['preview_text'] = '<strong>'
368
-                                                . esc_html__(
369
-                                                    'Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
370
-                                                    'event_espresso'
371
-                                                ) . '</strong>';
372
-        $this->display_admin_caf_preview_page('question_groups_tab');
373
-    }
374
-
375
-
376
-    /**
377
-     * Extracts the question field's values from the POST request to update or insert them
378
-     *
379
-     * @param EEM_Base $model
380
-     * @return array where each key is the name of a model's field/db column, and each value is its value.
381
-     * @throws EE_Error
382
-     */
383
-    protected function _set_column_values_for(EEM_Base $model)
384
-    {
385
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
386
-        $set_column_values = [];
387
-
388
-        // some initial checks for proper values.
389
-        // if QST_admin_only, then no matter what QST_required is we disable.
390
-        if (! empty($this->_req_data['QST_admin_only'])) {
391
-            $this->_req_data['QST_required'] = 0;
392
-        }
393
-        // if the question shouldn't have a max length, don't let them set one
394
-        if (
395
-            ! isset(
396
-                $this->_req_data['QST_type'],
397
-                $this->_req_data['QST_max']
398
-            )
399
-            || ! in_array(
400
-                $this->_req_data['QST_type'],
401
-                EEM_Question::instance()->questionTypesWithMaxLength(),
402
-                true
403
-            )
404
-        ) {
405
-            // they're not allowed to set the max
406
-            $this->_req_data['QST_max'] = null;
407
-        }
408
-        foreach ($model->field_settings() as $fieldName => $settings) {
409
-            // basically if QSG_identifier is empty or not set
410
-            if (
411
-                $fieldName === 'QSG_identifier'
412
-                && (isset($this->_req_data['QSG_identifier']) && empty($this->_req_data['QSG_identifier']))
413
-            ) {
414
-                $QSG_name = isset($this->_req_data['QSG_name'])
415
-                    ? $this->_req_data['QSG_name']
416
-                    : '';
417
-                $set_column_values[ $fieldName ] = sanitize_title($QSG_name) . '-' . uniqid('', true);
418
-            } elseif (
419
-                $fieldName === 'QST_admin_label'
420
-                && (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))
421
-            ) {
422
-                // the admin label is blank, use a slug version of the question text
423
-                $QST_text                        =
424
-                    isset($this->_req_data['QST_display_text'])
425
-                        ? $this->_req_data['QST_display_text']
426
-                        : '';
427
-                $set_column_values[ $fieldName ] = sanitize_title(wp_trim_words($QST_text, 10));
428
-            } elseif ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
429
-                $set_column_values[ $fieldName ] = 0;
430
-            } elseif ($fieldName === 'QST_max') {
431
-                $qst_system = EEM_Question::instance()->get_var(
432
-                    [
433
-                        [
434
-                            'QST_ID' => isset($this->_req_data['QST_ID'])
435
-                                ? $this->_req_data['QST_ID']
436
-                                : 0,
437
-                        ],
438
-                    ],
439
-                    'QST_system'
440
-                );
441
-                $max_max    = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
442
-                if (
443
-                    empty($this->_req_data['QST_max']) || $this->_req_data['QST_max'] > $max_max
444
-                ) {
445
-                    $set_column_values[ $fieldName ] = $max_max;
446
-                }
447
-            }
448
-
449
-
450
-            // only add a property to the array if it's not null (otherwise the model should just use the default value)
451
-            if (
452
-                ! isset($set_column_values[ $fieldName ]) && isset($this->_req_data[ $fieldName ])
453
-            ) {
454
-                $set_column_values[ $fieldName ] = $this->_req_data[ $fieldName ];
455
-            }
456
-        }
457
-        return $set_column_values;// validation fo this data to be performed by the model before insertion.
458
-    }
459
-
460
-
461
-    /**
462
-     *_questions_overview_list_table
463
-     *
464
-     * @throws EE_Error
465
-     */
466
-    protected function _questions_overview_list_table()
467
-    {
468
-        $this->_search_btn_label = esc_html__('Questions', 'event_espresso');
469
-        $this->display_admin_list_table_page_with_sidebar();
470
-    }
471
-
472
-
473
-    /**
474
-     * _edit_question
475
-     *
476
-     * @throws EE_Error
477
-     * @throws ReflectionException
478
-     */
479
-    protected function _edit_question()
480
-    {
481
-        $ID = isset($this->_req_data['QST_ID']) && ! empty($this->_req_data['QST_ID'])
482
-            ? absint($this->_req_data['QST_ID'])
483
-            : false;
484
-
485
-        switch ($this->_req_action) {
486
-            case 'add_question':
487
-                $this->_admin_page_title = esc_html__('Add Question', 'event_espresso');
488
-                break;
489
-            case 'edit_question':
490
-                $this->_admin_page_title = esc_html__('Edit Question', 'event_espresso');
491
-                break;
492
-            default:
493
-                $this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
494
-        }
495
-
496
-        // add PRC_ID to title if editing
497
-        $this->_admin_page_title =
498
-            $ID
499
-                ? $this->_admin_page_title . ' # ' . $ID
500
-                : $this->_admin_page_title;
501
-        if ($ID) {
502
-            $question                 = $this->_question_model->get_one_by_ID($ID);
503
-            $additional_hidden_fields = ['QST_ID' => ['type' => 'hidden', 'value' => $ID]];
504
-            $this->_set_add_edit_form_tags('update_question', $additional_hidden_fields);
505
-        } else {
506
-            $question = EE_Question::new_instance();
507
-            $question->set_order_to_latest();
508
-            $this->_set_add_edit_form_tags('insert_question');
509
-        }
510
-        if ($question->system_ID() === EEM_Attendee::system_question_phone) {
511
-            $question_types = array_intersect_key(
512
-                EEM_Question::instance()->allowed_question_types(),
513
-                array_flip(
514
-                    [
515
-                        EEM_Question::QST_type_text,
516
-                        EEM_Question::QST_type_us_phone,
517
-                    ]
518
-                )
519
-            );
520
-        } else {
521
-            $question_types = $question->has_answers()
522
-                ? $this->_question_model->question_types_in_same_category($question->type())
523
-                : $this->_question_model->allowed_question_types();
524
-        }
525
-        $this->_template_args['QST_ID']                     = $ID;
526
-        $this->_template_args['question']                   = $question;
527
-        $this->_template_args['question_types']             = $question_types;
528
-        $this->_template_args['max_max']                    =
529
-            EEM_Question::instance()->absolute_max_for_system_question(
530
-                $question->system_ID()
531
-            );
532
-        $this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
533
-        $this->_set_publish_post_box_vars('id', $ID);
534
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
535
-            REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
536
-            $this->_template_args,
537
-            true
538
-        );
539
-
540
-        // the details template wrapper
541
-        $this->display_admin_page_with_sidebar();
542
-    }
543
-
544
-
545
-    /**
546
-     * @return string
547
-     * @throws EE_Error
548
-     * @throws ReflectionException
549
-     */
550
-    protected function _get_question_type_descriptions()
551
-    {
552
-        EE_Registry::instance()->load_helper('HTML');
553
-        $descriptions               = '';
554
-        $question_type_descriptions = EEM_Question::instance()->question_descriptions();
555
-        foreach ($question_type_descriptions as $type => $question_type_description) {
556
-            if ($type == 'HTML_TEXTAREA') {
557
-                $html                      = new EE_Simple_HTML_Validation_Strategy();
558
-                $question_type_description .= sprintf(
559
-                    esc_html__('%1$s(allowed tags: %2$s)', 'event_espresso'),
560
-                    '<br/>',
561
-                    $html->get_list_of_allowed_tags()
562
-                );
563
-            }
564
-            $descriptions .= EEH_HTML::p(
565
-                $question_type_description,
566
-                'question_type_description-' . $type,
567
-                'question_type_description description',
568
-                'display:none;'
569
-            );
570
-        }
571
-        return $descriptions;
572
-    }
573
-
574
-
575
-    /**
576
-     * @param bool|true $new_question
577
-     * @throws EE_Error
578
-     * @throws ReflectionException
579
-     */
580
-    protected function _insert_or_update_question($new_question = true)
581
-    {
582
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
583
-        $set_column_values = $this->_set_column_values_for($this->_question_model);
584
-        if ($new_question) {
585
-            $question    = EE_Question::new_instance($set_column_values);
586
-            $action_desc = 'added';
587
-        } else {
588
-            $question = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
589
-            foreach ($set_column_values as $field => $new_value) {
590
-                $question->set($field, $new_value);
591
-            }
592
-            $action_desc = 'updated';
593
-        }
594
-        $success = $question->save();
595
-        $ID      = $question->ID();
596
-        if ($ID && $question->should_have_question_options()) {
597
-            // save the related options
598
-            // trash removed options, save old ones
599
-            // get list of all options
600
-            $options = $question->options();
601
-            if (! empty($options)) {
602
-                foreach ($options as $option_ID => $option) {
603
-                    $option_req_index = $this->_get_option_req_data_index($option_ID);
604
-                    if ($option_req_index !== false) {
605
-                        $option->save($this->_req_data['question_options'][ $option_req_index ]);
606
-                    } else {
607
-                        // not found, remove it
608
-                        $option->delete();
609
-                    }
610
-                }
611
-            }
612
-            // save new related options
613
-            foreach ($this->_req_data['question_options'] as $index => $option_req_data) {
614
-                // skip $index that is from our sample
615
-                if ($index === 'xxcountxx') {
616
-                    continue;
617
-                }
618
-                // note we allow saving blank options.
619
-                if (empty($option_req_data['QSO_ID'])) {
620
-                    // no ID! save it!
621
-                    $new_option = EE_Question_Option::new_instance(
622
-                        [
623
-                            'QSO_value' => $option_req_data['QSO_value'],
624
-                            'QSO_desc'  => $option_req_data['QSO_desc'],
625
-                            'QSO_order' => $option_req_data['QSO_order'],
626
-                            'QST_ID'    => $question->ID(),
627
-                        ]
628
-                    );
629
-                    $new_option->save();
630
-                }
631
-            }
632
-        }
633
-        $query_args = ['action' => 'edit_question', 'QST_ID' => $ID];
634
-        if ($success !== 0) {
635
-            $msg = $new_question
636
-                ? sprintf(
637
-                    esc_html__('The %s has been created', 'event_espresso'),
638
-                    $this->_question_model->item_name()
639
-                )
640
-                : sprintf(
641
-                    esc_html__('The %s has been updated', 'event_espresso'),
642
-                    $this->_question_model->item_name()
643
-                );
644
-            EE_Error::add_success($msg);
645
-        }
646
-
647
-        $this->_redirect_after_action(false, '', $action_desc, $query_args, true);
648
-    }
649
-
650
-
651
-    /**
652
-     * Upon saving a question, there should be an array of 'question_options'. This array is index numerically, but not
653
-     * by ID
654
-     * (this is done because new question options don't have an ID, but we may want to add multiple simultaneously).
655
-     * So, this function gets the index in that request data array called question_options. Returns FALSE if not found.
656
-     *
657
-     * @param int $ID of the question option to find
658
-     * @return int index in question_options array if successful, FALSE if unsuccessful
659
-     */
660
-    protected function _get_option_req_data_index($ID)
661
-    {
662
-        $req_data_for_question_options = $this->_req_data['question_options'];
663
-        foreach ($req_data_for_question_options as $num => $option_data) {
664
-            if (array_key_exists('QSO_ID', $option_data) && (int) $option_data['QSO_ID'] === $ID) {
665
-                return $num;
666
-            }
667
-        }
668
-        return false;
669
-    }
670
-
671
-
672
-
673
-
674
-    /***********/
675
-    /* QUERIES */
676
-    /**
677
-     * For internal use in getting all the query parameters
678
-     * (because it's pretty well the same between question, question groups,
679
-     * and for both when searching for trashed and untrashed ones)
680
-     *
681
-     * @param EEM_Base $model either EEM_Question or EEM_Question_Group
682
-     * @param int      $per_page
683
-     * @param int      $current_page
684
-     * @return array model query params, @see
685
-     *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
686
-     */
687
-    protected function get_query_params($model, $per_page = 10, $current_page = 10)
688
-    {
689
-        $query_params             = [];
690
-        $offset                   = ($current_page - 1) * $per_page;
691
-        $query_params['limit']    = [$offset, $per_page];
692
-        $order                    =
693
-            (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
694
-                ? $this->_req_data['order']
695
-                : 'ASC';
696
-        $orderby_field            =
697
-            $model instanceof EEM_Question
698
-                ? 'QST_ID'
699
-                : 'QSG_order';
700
-        $field_to_order_by        =
701
-            empty($this->_req_data['orderby'])
702
-                ? $orderby_field
703
-                : $this->_req_data['orderby'];
704
-        $query_params['order_by'] = [$field_to_order_by => $order];
705
-        $search_string            =
706
-            array_key_exists('s', $this->_req_data)
707
-                ? $this->_req_data['s']
708
-                : null;
709
-        if (! empty($search_string)) {
710
-            if ($model instanceof EEM_Question_Group) {
711
-                $query_params[0] = [
712
-                    'OR' => [
713
-                        'QSG_name' => ['LIKE', "%$search_string%"],
714
-                        'QSG_desc' => ['LIKE', "%$search_string%"],
715
-                    ],
716
-                ];
717
-            } else {
718
-                $query_params[0] = [
719
-                    'QST_display_text' => ['LIKE', "%$search_string%"],
720
-                ];
721
-            }
722
-        }
723
-
724
-        // capability checks (just leaving this commented out for reference because it illustrates some complicated query params that could be useful when fully implemented)
725
-        /*if ( $model instanceof EEM_Question_Group ) {
19
+	/**
20
+	 * holds the specific question object for the question details screen
21
+	 *
22
+	 * @var EE_Question $_question
23
+	 */
24
+	protected $_question;
25
+
26
+	/**
27
+	 * holds the specific question group object for the question group details screen
28
+	 *
29
+	 * @var EE_Question_Group $_question_group
30
+	 */
31
+	protected $_question_group;
32
+
33
+	/**
34
+	 *_question_model EEM_Question model instance (for queries)
35
+	 *
36
+	 * @var EEM_Question $_question_model ;
37
+	 */
38
+	protected $_question_model;
39
+
40
+	/**
41
+	 * _question_group_model EEM_Question_group instance (for queries)
42
+	 *
43
+	 * @var EEM_Question_Group $_question_group_model
44
+	 */
45
+	protected $_question_group_model;
46
+
47
+
48
+	/**
49
+	 * @Constructor
50
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
51
+	 * @throws EE_Error
52
+	 * @throws ReflectionException
53
+	 */
54
+	public function __construct($routing = true)
55
+	{
56
+		require_once(EE_MODELS . 'EEM_Question.model.php');
57
+		require_once(EE_MODELS . 'EEM_Question_Group.model.php');
58
+		$this->_question_model       = EEM_Question::instance();
59
+		$this->_question_group_model = EEM_Question_Group::instance();
60
+		parent::__construct($routing);
61
+	}
62
+
63
+
64
+	protected function _init_page_props()
65
+	{
66
+		$this->page_slug        = REGISTRATION_FORM_PG_SLUG;
67
+		$this->page_label       = esc_html__('Registration Form', 'event_espresso');
68
+		$this->_admin_base_url  = REGISTRATION_FORM_ADMIN_URL;
69
+		$this->_admin_base_path = REGISTRATION_FORM_ADMIN;
70
+	}
71
+
72
+
73
+	protected function _ajax_hooks()
74
+	{
75
+	}
76
+
77
+
78
+	protected function _define_page_props()
79
+	{
80
+		$this->_admin_page_title = esc_html__('Registration Form', 'event_espresso');
81
+		$this->_labels           = [
82
+			'buttons' => [
83
+				'edit_question' => esc_html__('Edit Question', 'event_espresso'),
84
+			],
85
+		];
86
+	}
87
+
88
+
89
+	/**
90
+	 *_set_page_routes
91
+	 */
92
+	protected function _set_page_routes()
93
+	{
94
+		$qst_id             =
95
+			! empty($this->_req_data['QST_ID'])
96
+				? $this->_req_data['QST_ID']
97
+				: 0;
98
+		$this->_page_routes = [
99
+			'default' => [
100
+				'func'       => '_questions_overview_list_table',
101
+				'capability' => 'ee_read_questions',
102
+			],
103
+
104
+			'edit_question' => [
105
+				'func'       => '_edit_question',
106
+				'capability' => 'ee_edit_question',
107
+				'obj_id'     => $qst_id,
108
+				'args'       => ['edit'],
109
+			],
110
+
111
+			'question_groups' => [
112
+				'func'       => '_questions_groups_preview',
113
+				'capability' => 'ee_read_question_groups',
114
+			],
115
+
116
+			'update_question' => [
117
+				'func'       => '_insert_or_update_question',
118
+				'args'       => ['new_question' => false],
119
+				'capability' => 'ee_edit_question',
120
+				'obj_id'     => $qst_id,
121
+				'noheader'   => true,
122
+			],
123
+		];
124
+	}
125
+
126
+
127
+	protected function _set_page_config()
128
+	{
129
+		$this->_page_config = [
130
+			'default' => [
131
+				'nav'           => [
132
+					'label' => esc_html__('Questions', 'event_espresso'),
133
+					'order' => 10,
134
+				],
135
+				'list_table'    => 'Registration_Form_Questions_Admin_List_Table',
136
+				'metaboxes'     => $this->_default_espresso_metaboxes,
137
+				'help_tabs'     => [
138
+					'registration_form_questions_overview_help_tab'                           => [
139
+						'title'    => esc_html__('Questions Overview', 'event_espresso'),
140
+						'filename' => 'registration_form_questions_overview',
141
+					],
142
+					'registration_form_questions_overview_table_column_headings_help_tab'     => [
143
+						'title'    => esc_html__('Questions Overview Table Column Headings', 'event_espresso'),
144
+						'filename' => 'registration_form_questions_overview_table_column_headings',
145
+					],
146
+					'registration_form_questions_overview_views_bulk_actions_search_help_tab' => [
147
+						'title'    => esc_html__('Question Overview Views & Bulk Actions & Search', 'event_espresso'),
148
+						'filename' => 'registration_form_questions_overview_views_bulk_actions_search',
149
+					],
150
+				],
151
+				// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
152
+				// 'help_tour'     => array('Registration_Form_Questions_Overview_Help_Tour'),
153
+				'require_nonce' => false,
154
+				'qtips'         => [
155
+					'EE_Registration_Form_Tips',
156
+				]/**/
157
+			],
158
+
159
+			'question_groups' => [
160
+				'nav'           => [
161
+					'label' => esc_html__('Question Groups', 'event_espresso'),
162
+					'order' => 20,
163
+				],
164
+				'metaboxes'     => $this->_default_espresso_metaboxes,
165
+				'help_tabs'     => [
166
+					'registration_form_question_groups_help_tab' => [
167
+						'title'    => esc_html__('Question Groups', 'event_espresso'),
168
+						'filename' => 'registration_form_question_groups',
169
+					],
170
+				],
171
+				// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
172
+				// 'help_tour'     => array('Registration_Form_Question_Groups_Help_Tour'),
173
+				'require_nonce' => false,
174
+			],
175
+
176
+			'edit_question' => [
177
+				'nav'           => [
178
+					'label'      => esc_html__('Edit Question', 'event_espresso'),
179
+					'order'      => 15,
180
+					'persistent' => false,
181
+					'url'        => isset($this->_req_data['question_id'])
182
+						? add_query_arg(
183
+							['question_id' => $this->_req_data['question_id']],
184
+							$this->_current_page_view_url
185
+						)
186
+						: $this->_admin_base_url,
187
+				],
188
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
189
+				'help_tabs'     => [
190
+					'registration_form_edit_question_group_help_tab' => [
191
+						'title'    => esc_html__('Edit Question', 'event_espresso'),
192
+						'filename' => 'registration_form_edit_question',
193
+					],
194
+				],
195
+				// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
196
+				// 'help_tour'     => array('Registration_Form_Edit_Question_Help_Tour'),
197
+				'require_nonce' => false,
198
+			],
199
+		];
200
+	}
201
+
202
+
203
+	protected function _add_screen_options()
204
+	{
205
+		// todo
206
+	}
207
+
208
+
209
+	protected function _add_screen_options_default()
210
+	{
211
+		$page_title              = $this->_admin_page_title;
212
+		$this->_admin_page_title = esc_html__('Questions', 'event_espresso');
213
+		$this->_per_page_screen_option();
214
+		$this->_admin_page_title = $page_title;
215
+	}
216
+
217
+
218
+	protected function _add_screen_options_question_groups()
219
+	{
220
+		$page_title              = $this->_admin_page_title;
221
+		$this->_admin_page_title = esc_html__('Question Groups', 'event_espresso');
222
+		$this->_per_page_screen_option();
223
+		$this->_admin_page_title = $page_title;
224
+	}
225
+
226
+
227
+	// none of the below group are currently used for Event Categories
228
+	protected function _add_feature_pointers()
229
+	{
230
+	}
231
+
232
+
233
+	public function load_scripts_styles()
234
+	{
235
+		wp_register_style(
236
+			'espresso_registration',
237
+			REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css',
238
+			[],
239
+			EVENT_ESPRESSO_VERSION
240
+		);
241
+		wp_enqueue_style('espresso_registration');
242
+	}
243
+
244
+
245
+	public function admin_init()
246
+	{
247
+	}
248
+
249
+
250
+	public function admin_notices()
251
+	{
252
+	}
253
+
254
+
255
+	public function admin_footer_scripts()
256
+	{
257
+	}
258
+
259
+
260
+	public function load_scripts_styles_default()
261
+	{
262
+	}
263
+
264
+
265
+	/**
266
+	 * @throws EE_Error
267
+	 */
268
+	public function load_scripts_styles_add_question()
269
+	{
270
+		$this->load_scripts_styles_question_details();
271
+	}
272
+
273
+
274
+	/**
275
+	 * @throws EE_Error
276
+	 */
277
+	public function load_scripts_styles_edit_question()
278
+	{
279
+		$this->load_scripts_styles_question_details();
280
+	}
281
+
282
+
283
+	/**
284
+	 * Loads the JS required for adding or editing a question
285
+	 *
286
+	 * @throws EE_Error
287
+	 * @throws EE_Error
288
+	 */
289
+	protected function load_scripts_styles_question_details()
290
+	{
291
+		$this->load_scripts_styles_forms();
292
+		wp_register_script(
293
+			'espresso_registration_form_single',
294
+			REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js',
295
+			['jquery-ui-sortable'],
296
+			EVENT_ESPRESSO_VERSION,
297
+			true
298
+		);
299
+		wp_enqueue_script('espresso_registration_form_single');
300
+		wp_localize_script(
301
+			'espresso_registration_form_single',
302
+			'ee_question_data',
303
+			[
304
+				'question_types_with_max'    => EEM_Question::instance()->questionTypesWithMaxLength(),
305
+				'question_type_with_options' => EEM_Question::instance()->question_types_with_options(),
306
+			]
307
+		);
308
+	}
309
+
310
+
311
+	public function recaptcha_info_help_tab()
312
+	{
313
+		$template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
314
+		EEH_Template::display_template($template, []);
315
+	}
316
+
317
+
318
+	public function load_scripts_styles_forms()
319
+	{
320
+		// styles
321
+		wp_enqueue_style('espresso-ui-theme');
322
+		// scripts
323
+		wp_enqueue_script('ee_admin_js');
324
+	}
325
+
326
+
327
+	protected function _set_list_table_views_default()
328
+	{
329
+		$this->_views = [
330
+			'all' => [
331
+				'slug'  => 'all',
332
+				'label' => esc_html__('View All Questions', 'event_espresso'),
333
+				'count' => 0,
334
+			],
335
+		];
336
+
337
+		if (
338
+			EE_Registry::instance()->CAP->current_user_can(
339
+				'ee_delete_questions',
340
+				'espresso_registration_form_trash_questions'
341
+			)
342
+		) {
343
+			$this->_views['trash'] = [
344
+				'slug'  => 'trash',
345
+				'label' => esc_html__('Trash', 'event_espresso'),
346
+				'count' => 0,
347
+			];
348
+		}
349
+	}
350
+
351
+
352
+	/**
353
+	 * This just previews the question groups tab that comes in caffeinated.
354
+	 *
355
+	 * @return void html
356
+	 * @throws EE_Error
357
+	 */
358
+	protected function _questions_groups_preview()
359
+	{
360
+		$this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
361
+		$this->_template_args['preview_img']  =
362
+			'<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="'
363
+			. esc_attr__(
364
+				'Preview Question Groups Overview List Table screenshot',
365
+				'event_espresso'
366
+			) . '" />';
367
+		$this->_template_args['preview_text'] = '<strong>'
368
+												. esc_html__(
369
+													'Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
370
+													'event_espresso'
371
+												) . '</strong>';
372
+		$this->display_admin_caf_preview_page('question_groups_tab');
373
+	}
374
+
375
+
376
+	/**
377
+	 * Extracts the question field's values from the POST request to update or insert them
378
+	 *
379
+	 * @param EEM_Base $model
380
+	 * @return array where each key is the name of a model's field/db column, and each value is its value.
381
+	 * @throws EE_Error
382
+	 */
383
+	protected function _set_column_values_for(EEM_Base $model)
384
+	{
385
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
386
+		$set_column_values = [];
387
+
388
+		// some initial checks for proper values.
389
+		// if QST_admin_only, then no matter what QST_required is we disable.
390
+		if (! empty($this->_req_data['QST_admin_only'])) {
391
+			$this->_req_data['QST_required'] = 0;
392
+		}
393
+		// if the question shouldn't have a max length, don't let them set one
394
+		if (
395
+			! isset(
396
+				$this->_req_data['QST_type'],
397
+				$this->_req_data['QST_max']
398
+			)
399
+			|| ! in_array(
400
+				$this->_req_data['QST_type'],
401
+				EEM_Question::instance()->questionTypesWithMaxLength(),
402
+				true
403
+			)
404
+		) {
405
+			// they're not allowed to set the max
406
+			$this->_req_data['QST_max'] = null;
407
+		}
408
+		foreach ($model->field_settings() as $fieldName => $settings) {
409
+			// basically if QSG_identifier is empty or not set
410
+			if (
411
+				$fieldName === 'QSG_identifier'
412
+				&& (isset($this->_req_data['QSG_identifier']) && empty($this->_req_data['QSG_identifier']))
413
+			) {
414
+				$QSG_name = isset($this->_req_data['QSG_name'])
415
+					? $this->_req_data['QSG_name']
416
+					: '';
417
+				$set_column_values[ $fieldName ] = sanitize_title($QSG_name) . '-' . uniqid('', true);
418
+			} elseif (
419
+				$fieldName === 'QST_admin_label'
420
+				&& (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))
421
+			) {
422
+				// the admin label is blank, use a slug version of the question text
423
+				$QST_text                        =
424
+					isset($this->_req_data['QST_display_text'])
425
+						? $this->_req_data['QST_display_text']
426
+						: '';
427
+				$set_column_values[ $fieldName ] = sanitize_title(wp_trim_words($QST_text, 10));
428
+			} elseif ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
429
+				$set_column_values[ $fieldName ] = 0;
430
+			} elseif ($fieldName === 'QST_max') {
431
+				$qst_system = EEM_Question::instance()->get_var(
432
+					[
433
+						[
434
+							'QST_ID' => isset($this->_req_data['QST_ID'])
435
+								? $this->_req_data['QST_ID']
436
+								: 0,
437
+						],
438
+					],
439
+					'QST_system'
440
+				);
441
+				$max_max    = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
442
+				if (
443
+					empty($this->_req_data['QST_max']) || $this->_req_data['QST_max'] > $max_max
444
+				) {
445
+					$set_column_values[ $fieldName ] = $max_max;
446
+				}
447
+			}
448
+
449
+
450
+			// only add a property to the array if it's not null (otherwise the model should just use the default value)
451
+			if (
452
+				! isset($set_column_values[ $fieldName ]) && isset($this->_req_data[ $fieldName ])
453
+			) {
454
+				$set_column_values[ $fieldName ] = $this->_req_data[ $fieldName ];
455
+			}
456
+		}
457
+		return $set_column_values;// validation fo this data to be performed by the model before insertion.
458
+	}
459
+
460
+
461
+	/**
462
+	 *_questions_overview_list_table
463
+	 *
464
+	 * @throws EE_Error
465
+	 */
466
+	protected function _questions_overview_list_table()
467
+	{
468
+		$this->_search_btn_label = esc_html__('Questions', 'event_espresso');
469
+		$this->display_admin_list_table_page_with_sidebar();
470
+	}
471
+
472
+
473
+	/**
474
+	 * _edit_question
475
+	 *
476
+	 * @throws EE_Error
477
+	 * @throws ReflectionException
478
+	 */
479
+	protected function _edit_question()
480
+	{
481
+		$ID = isset($this->_req_data['QST_ID']) && ! empty($this->_req_data['QST_ID'])
482
+			? absint($this->_req_data['QST_ID'])
483
+			: false;
484
+
485
+		switch ($this->_req_action) {
486
+			case 'add_question':
487
+				$this->_admin_page_title = esc_html__('Add Question', 'event_espresso');
488
+				break;
489
+			case 'edit_question':
490
+				$this->_admin_page_title = esc_html__('Edit Question', 'event_espresso');
491
+				break;
492
+			default:
493
+				$this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
494
+		}
495
+
496
+		// add PRC_ID to title if editing
497
+		$this->_admin_page_title =
498
+			$ID
499
+				? $this->_admin_page_title . ' # ' . $ID
500
+				: $this->_admin_page_title;
501
+		if ($ID) {
502
+			$question                 = $this->_question_model->get_one_by_ID($ID);
503
+			$additional_hidden_fields = ['QST_ID' => ['type' => 'hidden', 'value' => $ID]];
504
+			$this->_set_add_edit_form_tags('update_question', $additional_hidden_fields);
505
+		} else {
506
+			$question = EE_Question::new_instance();
507
+			$question->set_order_to_latest();
508
+			$this->_set_add_edit_form_tags('insert_question');
509
+		}
510
+		if ($question->system_ID() === EEM_Attendee::system_question_phone) {
511
+			$question_types = array_intersect_key(
512
+				EEM_Question::instance()->allowed_question_types(),
513
+				array_flip(
514
+					[
515
+						EEM_Question::QST_type_text,
516
+						EEM_Question::QST_type_us_phone,
517
+					]
518
+				)
519
+			);
520
+		} else {
521
+			$question_types = $question->has_answers()
522
+				? $this->_question_model->question_types_in_same_category($question->type())
523
+				: $this->_question_model->allowed_question_types();
524
+		}
525
+		$this->_template_args['QST_ID']                     = $ID;
526
+		$this->_template_args['question']                   = $question;
527
+		$this->_template_args['question_types']             = $question_types;
528
+		$this->_template_args['max_max']                    =
529
+			EEM_Question::instance()->absolute_max_for_system_question(
530
+				$question->system_ID()
531
+			);
532
+		$this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
533
+		$this->_set_publish_post_box_vars('id', $ID);
534
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
535
+			REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
536
+			$this->_template_args,
537
+			true
538
+		);
539
+
540
+		// the details template wrapper
541
+		$this->display_admin_page_with_sidebar();
542
+	}
543
+
544
+
545
+	/**
546
+	 * @return string
547
+	 * @throws EE_Error
548
+	 * @throws ReflectionException
549
+	 */
550
+	protected function _get_question_type_descriptions()
551
+	{
552
+		EE_Registry::instance()->load_helper('HTML');
553
+		$descriptions               = '';
554
+		$question_type_descriptions = EEM_Question::instance()->question_descriptions();
555
+		foreach ($question_type_descriptions as $type => $question_type_description) {
556
+			if ($type == 'HTML_TEXTAREA') {
557
+				$html                      = new EE_Simple_HTML_Validation_Strategy();
558
+				$question_type_description .= sprintf(
559
+					esc_html__('%1$s(allowed tags: %2$s)', 'event_espresso'),
560
+					'<br/>',
561
+					$html->get_list_of_allowed_tags()
562
+				);
563
+			}
564
+			$descriptions .= EEH_HTML::p(
565
+				$question_type_description,
566
+				'question_type_description-' . $type,
567
+				'question_type_description description',
568
+				'display:none;'
569
+			);
570
+		}
571
+		return $descriptions;
572
+	}
573
+
574
+
575
+	/**
576
+	 * @param bool|true $new_question
577
+	 * @throws EE_Error
578
+	 * @throws ReflectionException
579
+	 */
580
+	protected function _insert_or_update_question($new_question = true)
581
+	{
582
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
583
+		$set_column_values = $this->_set_column_values_for($this->_question_model);
584
+		if ($new_question) {
585
+			$question    = EE_Question::new_instance($set_column_values);
586
+			$action_desc = 'added';
587
+		} else {
588
+			$question = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
589
+			foreach ($set_column_values as $field => $new_value) {
590
+				$question->set($field, $new_value);
591
+			}
592
+			$action_desc = 'updated';
593
+		}
594
+		$success = $question->save();
595
+		$ID      = $question->ID();
596
+		if ($ID && $question->should_have_question_options()) {
597
+			// save the related options
598
+			// trash removed options, save old ones
599
+			// get list of all options
600
+			$options = $question->options();
601
+			if (! empty($options)) {
602
+				foreach ($options as $option_ID => $option) {
603
+					$option_req_index = $this->_get_option_req_data_index($option_ID);
604
+					if ($option_req_index !== false) {
605
+						$option->save($this->_req_data['question_options'][ $option_req_index ]);
606
+					} else {
607
+						// not found, remove it
608
+						$option->delete();
609
+					}
610
+				}
611
+			}
612
+			// save new related options
613
+			foreach ($this->_req_data['question_options'] as $index => $option_req_data) {
614
+				// skip $index that is from our sample
615
+				if ($index === 'xxcountxx') {
616
+					continue;
617
+				}
618
+				// note we allow saving blank options.
619
+				if (empty($option_req_data['QSO_ID'])) {
620
+					// no ID! save it!
621
+					$new_option = EE_Question_Option::new_instance(
622
+						[
623
+							'QSO_value' => $option_req_data['QSO_value'],
624
+							'QSO_desc'  => $option_req_data['QSO_desc'],
625
+							'QSO_order' => $option_req_data['QSO_order'],
626
+							'QST_ID'    => $question->ID(),
627
+						]
628
+					);
629
+					$new_option->save();
630
+				}
631
+			}
632
+		}
633
+		$query_args = ['action' => 'edit_question', 'QST_ID' => $ID];
634
+		if ($success !== 0) {
635
+			$msg = $new_question
636
+				? sprintf(
637
+					esc_html__('The %s has been created', 'event_espresso'),
638
+					$this->_question_model->item_name()
639
+				)
640
+				: sprintf(
641
+					esc_html__('The %s has been updated', 'event_espresso'),
642
+					$this->_question_model->item_name()
643
+				);
644
+			EE_Error::add_success($msg);
645
+		}
646
+
647
+		$this->_redirect_after_action(false, '', $action_desc, $query_args, true);
648
+	}
649
+
650
+
651
+	/**
652
+	 * Upon saving a question, there should be an array of 'question_options'. This array is index numerically, but not
653
+	 * by ID
654
+	 * (this is done because new question options don't have an ID, but we may want to add multiple simultaneously).
655
+	 * So, this function gets the index in that request data array called question_options. Returns FALSE if not found.
656
+	 *
657
+	 * @param int $ID of the question option to find
658
+	 * @return int index in question_options array if successful, FALSE if unsuccessful
659
+	 */
660
+	protected function _get_option_req_data_index($ID)
661
+	{
662
+		$req_data_for_question_options = $this->_req_data['question_options'];
663
+		foreach ($req_data_for_question_options as $num => $option_data) {
664
+			if (array_key_exists('QSO_ID', $option_data) && (int) $option_data['QSO_ID'] === $ID) {
665
+				return $num;
666
+			}
667
+		}
668
+		return false;
669
+	}
670
+
671
+
672
+
673
+
674
+	/***********/
675
+	/* QUERIES */
676
+	/**
677
+	 * For internal use in getting all the query parameters
678
+	 * (because it's pretty well the same between question, question groups,
679
+	 * and for both when searching for trashed and untrashed ones)
680
+	 *
681
+	 * @param EEM_Base $model either EEM_Question or EEM_Question_Group
682
+	 * @param int      $per_page
683
+	 * @param int      $current_page
684
+	 * @return array model query params, @see
685
+	 *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
686
+	 */
687
+	protected function get_query_params($model, $per_page = 10, $current_page = 10)
688
+	{
689
+		$query_params             = [];
690
+		$offset                   = ($current_page - 1) * $per_page;
691
+		$query_params['limit']    = [$offset, $per_page];
692
+		$order                    =
693
+			(isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
694
+				? $this->_req_data['order']
695
+				: 'ASC';
696
+		$orderby_field            =
697
+			$model instanceof EEM_Question
698
+				? 'QST_ID'
699
+				: 'QSG_order';
700
+		$field_to_order_by        =
701
+			empty($this->_req_data['orderby'])
702
+				? $orderby_field
703
+				: $this->_req_data['orderby'];
704
+		$query_params['order_by'] = [$field_to_order_by => $order];
705
+		$search_string            =
706
+			array_key_exists('s', $this->_req_data)
707
+				? $this->_req_data['s']
708
+				: null;
709
+		if (! empty($search_string)) {
710
+			if ($model instanceof EEM_Question_Group) {
711
+				$query_params[0] = [
712
+					'OR' => [
713
+						'QSG_name' => ['LIKE', "%$search_string%"],
714
+						'QSG_desc' => ['LIKE', "%$search_string%"],
715
+					],
716
+				];
717
+			} else {
718
+				$query_params[0] = [
719
+					'QST_display_text' => ['LIKE', "%$search_string%"],
720
+				];
721
+			}
722
+		}
723
+
724
+		// capability checks (just leaving this commented out for reference because it illustrates some complicated query params that could be useful when fully implemented)
725
+		/*if ( $model instanceof EEM_Question_Group ) {
726 726
             if ( ! EE_Registry::instance()->CAP->current_user_can( 'edit_others_question_groups', 'espresso_registration_form_edit_question_group' ) ) {
727 727
                 $query_params[0] = array(
728 728
                     'AND' => array(
@@ -752,67 +752,67 @@  discard block
 block discarded – undo
752 752
             }
753 753
         }/**/
754 754
 
755
-        return $query_params;
756
-    }
757
-
758
-
759
-    /**
760
-     * @param int        $per_page
761
-     * @param int        $current_page
762
-     * @param bool|false $count
763
-     * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]|int
764
-     * @throws EE_Error
765
-     */
766
-    public function get_questions($per_page = 10, $current_page = 1, $count = false)
767
-    {
768
-        $QST          = EEM_Question::instance();
769
-        $query_params = $this->get_query_params($QST, $per_page, $current_page);
770
-        if ($count) {
771
-            $where   =
772
-                isset($query_params[0])
773
-                    ? [$query_params[0]]
774
-                    : [];
775
-            $results = $QST->count($where);
776
-        } else {
777
-            $results = $QST->get_all($query_params);
778
-        }
779
-        return $results;
780
-    }
781
-
782
-
783
-    /**
784
-     * @param            $per_page
785
-     * @param int        $current_page
786
-     * @param bool|false $count
787
-     * @return EE_Soft_Delete_Base_Class[]|int
788
-     * @throws EE_Error
789
-     */
790
-    public function get_trashed_questions($per_page, $current_page = 1, $count = false)
791
-    {
792
-        $query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
793
-        $where        =
794
-            isset($query_params[0])
795
-                ? [$query_params[0]]
796
-                : [];
797
-        return $count
798
-            ? EEM_Question::instance()->count_deleted($where)
799
-            : EEM_Question::instance()->get_all_deleted($query_params);
800
-    }
801
-
802
-
803
-    /**
804
-     * @param            $per_page
805
-     * @param int        $current_page
806
-     * @param bool|false $count
807
-     * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]
808
-     * @throws EE_Error
809
-     */
810
-    public function get_question_groups($per_page, $current_page = 1, $count = false)
811
-    {
812
-        $questionGroupModel = EEM_Question_Group::instance();
813
-        // note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
814
-        return $questionGroupModel->get_all(
815
-            $this->get_query_params($questionGroupModel, $per_page, $current_page)
816
-        );
817
-    }
755
+		return $query_params;
756
+	}
757
+
758
+
759
+	/**
760
+	 * @param int        $per_page
761
+	 * @param int        $current_page
762
+	 * @param bool|false $count
763
+	 * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]|int
764
+	 * @throws EE_Error
765
+	 */
766
+	public function get_questions($per_page = 10, $current_page = 1, $count = false)
767
+	{
768
+		$QST          = EEM_Question::instance();
769
+		$query_params = $this->get_query_params($QST, $per_page, $current_page);
770
+		if ($count) {
771
+			$where   =
772
+				isset($query_params[0])
773
+					? [$query_params[0]]
774
+					: [];
775
+			$results = $QST->count($where);
776
+		} else {
777
+			$results = $QST->get_all($query_params);
778
+		}
779
+		return $results;
780
+	}
781
+
782
+
783
+	/**
784
+	 * @param            $per_page
785
+	 * @param int        $current_page
786
+	 * @param bool|false $count
787
+	 * @return EE_Soft_Delete_Base_Class[]|int
788
+	 * @throws EE_Error
789
+	 */
790
+	public function get_trashed_questions($per_page, $current_page = 1, $count = false)
791
+	{
792
+		$query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
793
+		$where        =
794
+			isset($query_params[0])
795
+				? [$query_params[0]]
796
+				: [];
797
+		return $count
798
+			? EEM_Question::instance()->count_deleted($where)
799
+			: EEM_Question::instance()->get_all_deleted($query_params);
800
+	}
801
+
802
+
803
+	/**
804
+	 * @param            $per_page
805
+	 * @param int        $current_page
806
+	 * @param bool|false $count
807
+	 * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]
808
+	 * @throws EE_Error
809
+	 */
810
+	public function get_question_groups($per_page, $current_page = 1, $count = false)
811
+	{
812
+		$questionGroupModel = EEM_Question_Group::instance();
813
+		// note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
814
+		return $questionGroupModel->get_all(
815
+			$this->get_query_params($questionGroupModel, $per_page, $current_page)
816
+		);
817
+	}
818 818
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -53,8 +53,8 @@  discard block
 block discarded – undo
53 53
      */
54 54
     public function __construct($routing = true)
55 55
     {
56
-        require_once(EE_MODELS . 'EEM_Question.model.php');
57
-        require_once(EE_MODELS . 'EEM_Question_Group.model.php');
56
+        require_once(EE_MODELS.'EEM_Question.model.php');
57
+        require_once(EE_MODELS.'EEM_Question_Group.model.php');
58 58
         $this->_question_model       = EEM_Question::instance();
59 59
         $this->_question_group_model = EEM_Question_Group::instance();
60 60
         parent::__construct($routing);
@@ -91,7 +91,7 @@  discard block
 block discarded – undo
91 91
      */
92 92
     protected function _set_page_routes()
93 93
     {
94
-        $qst_id             =
94
+        $qst_id =
95 95
             ! empty($this->_req_data['QST_ID'])
96 96
                 ? $this->_req_data['QST_ID']
97 97
                 : 0;
@@ -234,7 +234,7 @@  discard block
 block discarded – undo
234 234
     {
235 235
         wp_register_style(
236 236
             'espresso_registration',
237
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css',
237
+            REGISTRATION_FORM_ASSETS_URL.'espresso_registration_form_admin.css',
238 238
             [],
239 239
             EVENT_ESPRESSO_VERSION
240 240
         );
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
         $this->load_scripts_styles_forms();
292 292
         wp_register_script(
293 293
             'espresso_registration_form_single',
294
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js',
294
+            REGISTRATION_FORM_ASSETS_URL.'espresso_registration_form_admin.js',
295 295
             ['jquery-ui-sortable'],
296 296
             EVENT_ESPRESSO_VERSION,
297 297
             true
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
 
311 311
     public function recaptcha_info_help_tab()
312 312
     {
313
-        $template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
313
+        $template = REGISTRATION_FORM_TEMPLATE_PATH.'recaptcha_info_help_tab.template.php';
314 314
         EEH_Template::display_template($template, []);
315 315
     }
316 316
 
@@ -359,16 +359,16 @@  discard block
 block discarded – undo
359 359
     {
360 360
         $this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
361 361
         $this->_template_args['preview_img']  =
362
-            '<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="'
362
+            '<img src="'.REGISTRATION_FORM_ASSETS_URL.'caf_reg_form_preview.jpg" alt="'
363 363
             . esc_attr__(
364 364
                 'Preview Question Groups Overview List Table screenshot',
365 365
                 'event_espresso'
366
-            ) . '" />';
366
+            ).'" />';
367 367
         $this->_template_args['preview_text'] = '<strong>'
368 368
                                                 . esc_html__(
369 369
                                                     'Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
370 370
                                                     'event_espresso'
371
-                                                ) . '</strong>';
371
+                                                ).'</strong>';
372 372
         $this->display_admin_caf_preview_page('question_groups_tab');
373 373
     }
374 374
 
@@ -387,7 +387,7 @@  discard block
 block discarded – undo
387 387
 
388 388
         // some initial checks for proper values.
389 389
         // if QST_admin_only, then no matter what QST_required is we disable.
390
-        if (! empty($this->_req_data['QST_admin_only'])) {
390
+        if ( ! empty($this->_req_data['QST_admin_only'])) {
391 391
             $this->_req_data['QST_required'] = 0;
392 392
         }
393 393
         // if the question shouldn't have a max length, don't let them set one
@@ -414,19 +414,19 @@  discard block
 block discarded – undo
414 414
                 $QSG_name = isset($this->_req_data['QSG_name'])
415 415
                     ? $this->_req_data['QSG_name']
416 416
                     : '';
417
-                $set_column_values[ $fieldName ] = sanitize_title($QSG_name) . '-' . uniqid('', true);
417
+                $set_column_values[$fieldName] = sanitize_title($QSG_name).'-'.uniqid('', true);
418 418
             } elseif (
419 419
                 $fieldName === 'QST_admin_label'
420 420
                 && (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))
421 421
             ) {
422 422
                 // the admin label is blank, use a slug version of the question text
423
-                $QST_text                        =
423
+                $QST_text =
424 424
                     isset($this->_req_data['QST_display_text'])
425 425
                         ? $this->_req_data['QST_display_text']
426 426
                         : '';
427
-                $set_column_values[ $fieldName ] = sanitize_title(wp_trim_words($QST_text, 10));
428
-            } elseif ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
429
-                $set_column_values[ $fieldName ] = 0;
427
+                $set_column_values[$fieldName] = sanitize_title(wp_trim_words($QST_text, 10));
428
+            } elseif ($fieldName === 'QST_admin_only' && ( ! isset($this->_req_data['QST_admin_only']))) {
429
+                $set_column_values[$fieldName] = 0;
430 430
             } elseif ($fieldName === 'QST_max') {
431 431
                 $qst_system = EEM_Question::instance()->get_var(
432 432
                     [
@@ -438,23 +438,23 @@  discard block
 block discarded – undo
438 438
                     ],
439 439
                     'QST_system'
440 440
                 );
441
-                $max_max    = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
441
+                $max_max = EEM_Question::instance()->absolute_max_for_system_question($qst_system);
442 442
                 if (
443 443
                     empty($this->_req_data['QST_max']) || $this->_req_data['QST_max'] > $max_max
444 444
                 ) {
445
-                    $set_column_values[ $fieldName ] = $max_max;
445
+                    $set_column_values[$fieldName] = $max_max;
446 446
                 }
447 447
             }
448 448
 
449 449
 
450 450
             // only add a property to the array if it's not null (otherwise the model should just use the default value)
451 451
             if (
452
-                ! isset($set_column_values[ $fieldName ]) && isset($this->_req_data[ $fieldName ])
452
+                ! isset($set_column_values[$fieldName]) && isset($this->_req_data[$fieldName])
453 453
             ) {
454
-                $set_column_values[ $fieldName ] = $this->_req_data[ $fieldName ];
454
+                $set_column_values[$fieldName] = $this->_req_data[$fieldName];
455 455
             }
456 456
         }
457
-        return $set_column_values;// validation fo this data to be performed by the model before insertion.
457
+        return $set_column_values; // validation fo this data to be performed by the model before insertion.
458 458
     }
459 459
 
460 460
 
@@ -496,7 +496,7 @@  discard block
 block discarded – undo
496 496
         // add PRC_ID to title if editing
497 497
         $this->_admin_page_title =
498 498
             $ID
499
-                ? $this->_admin_page_title . ' # ' . $ID
499
+                ? $this->_admin_page_title.' # '.$ID
500 500
                 : $this->_admin_page_title;
501 501
         if ($ID) {
502 502
             $question                 = $this->_question_model->get_one_by_ID($ID);
@@ -532,7 +532,7 @@  discard block
 block discarded – undo
532 532
         $this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
533 533
         $this->_set_publish_post_box_vars('id', $ID);
534 534
         $this->_template_args['admin_page_content'] = EEH_Template::display_template(
535
-            REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
535
+            REGISTRATION_FORM_TEMPLATE_PATH.'questions_main_meta_box.template.php',
536 536
             $this->_template_args,
537 537
             true
538 538
         );
@@ -554,7 +554,7 @@  discard block
 block discarded – undo
554 554
         $question_type_descriptions = EEM_Question::instance()->question_descriptions();
555 555
         foreach ($question_type_descriptions as $type => $question_type_description) {
556 556
             if ($type == 'HTML_TEXTAREA') {
557
-                $html                      = new EE_Simple_HTML_Validation_Strategy();
557
+                $html = new EE_Simple_HTML_Validation_Strategy();
558 558
                 $question_type_description .= sprintf(
559 559
                     esc_html__('%1$s(allowed tags: %2$s)', 'event_espresso'),
560 560
                     '<br/>',
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
             }
564 564
             $descriptions .= EEH_HTML::p(
565 565
                 $question_type_description,
566
-                'question_type_description-' . $type,
566
+                'question_type_description-'.$type,
567 567
                 'question_type_description description',
568 568
                 'display:none;'
569 569
             );
@@ -598,11 +598,11 @@  discard block
 block discarded – undo
598 598
             // trash removed options, save old ones
599 599
             // get list of all options
600 600
             $options = $question->options();
601
-            if (! empty($options)) {
601
+            if ( ! empty($options)) {
602 602
                 foreach ($options as $option_ID => $option) {
603 603
                     $option_req_index = $this->_get_option_req_data_index($option_ID);
604 604
                     if ($option_req_index !== false) {
605
-                        $option->save($this->_req_data['question_options'][ $option_req_index ]);
605
+                        $option->save($this->_req_data['question_options'][$option_req_index]);
606 606
                     } else {
607 607
                         // not found, remove it
608 608
                         $option->delete();
@@ -693,11 +693,11 @@  discard block
 block discarded – undo
693 693
             (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
694 694
                 ? $this->_req_data['order']
695 695
                 : 'ASC';
696
-        $orderby_field            =
696
+        $orderby_field =
697 697
             $model instanceof EEM_Question
698 698
                 ? 'QST_ID'
699 699
                 : 'QSG_order';
700
-        $field_to_order_by        =
700
+        $field_to_order_by =
701 701
             empty($this->_req_data['orderby'])
702 702
                 ? $orderby_field
703 703
                 : $this->_req_data['orderby'];
@@ -706,7 +706,7 @@  discard block
 block discarded – undo
706 706
             array_key_exists('s', $this->_req_data)
707 707
                 ? $this->_req_data['s']
708 708
                 : null;
709
-        if (! empty($search_string)) {
709
+        if ( ! empty($search_string)) {
710 710
             if ($model instanceof EEM_Question_Group) {
711 711
                 $query_params[0] = [
712 712
                     'OR' => [
@@ -768,7 +768,7 @@  discard block
 block discarded – undo
768 768
         $QST          = EEM_Question::instance();
769 769
         $query_params = $this->get_query_params($QST, $per_page, $current_page);
770 770
         if ($count) {
771
-            $where   =
771
+            $where =
772 772
                 isset($query_params[0])
773 773
                     ? [$query_params[0]]
774 774
                     : [];
Please login to merge, or discard this patch.
caffeinated/core/libraries/shortcodes/EE_Question_List_Shortcodes.lib.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -94,16 +94,16 @@
 block discarded – undo
94 94
             ? $this->_extra_data['template']['question_list']
95 95
             : $template;
96 96
         $ans_result       = '';
97
-        $answers          = ! empty($this->_extra_data['data']->registrations[ $reg_obj->ID() ]['ans_objs'])
98
-            ? $this->_extra_data['data']->registrations[ $reg_obj->ID() ]['ans_objs']
97
+        $answers          = ! empty($this->_extra_data['data']->registrations[$reg_obj->ID()]['ans_objs'])
98
+            ? $this->_extra_data['data']->registrations[$reg_obj->ID()]['ans_objs']
99 99
             : [];
100 100
         $questions        = ! empty($this->_extra_data['data']->questions)
101 101
             ? $this->_extra_data['data']->questions
102 102
             : [];
103 103
         foreach ($answers as $answer) {
104 104
             // first see if the question is in our $questions array.  If not then try to get from answer object
105
-            $question = isset($questions[ $answer->ID() ])
106
-                ? $questions[ $answer->ID() ]
105
+            $question = isset($questions[$answer->ID()])
106
+                ? $questions[$answer->ID()]
107 107
                 : null;
108 108
             $question = ! $question instanceof EE_Question
109 109
                 ? $answer->question()
Please login to merge, or discard this patch.
Indentation   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -16,109 +16,109 @@
 block discarded – undo
16 16
 class EE_Question_List_Shortcodes extends EE_Shortcodes
17 17
 {
18 18
 
19
-    public function __construct()
20
-    {
21
-        parent::__construct();
22
-    }
19
+	public function __construct()
20
+	{
21
+		parent::__construct();
22
+	}
23 23
 
24 24
 
25
-    protected function _init_props()
26
-    {
27
-        $this->label       = esc_html__('Questions and Answers Shortcodes', 'event_espresso');
28
-        $this->description = esc_html__('All shortcodes related to custom questions and answers', 'event_espresso');
29
-        $this->_shortcodes = [
30
-            '[QUESTION_LIST]' => esc_html__(
31
-                'This is used to indicate where you want the list of questions and answers to show for the registrant.  You place this within the "[attendee_list]" field.',
32
-                'event_espresso'
33
-            ),
34
-        ];
35
-    }
25
+	protected function _init_props()
26
+	{
27
+		$this->label       = esc_html__('Questions and Answers Shortcodes', 'event_espresso');
28
+		$this->description = esc_html__('All shortcodes related to custom questions and answers', 'event_espresso');
29
+		$this->_shortcodes = [
30
+			'[QUESTION_LIST]' => esc_html__(
31
+				'This is used to indicate where you want the list of questions and answers to show for the registrant.  You place this within the "[attendee_list]" field.',
32
+				'event_espresso'
33
+			),
34
+		];
35
+	}
36 36
 
37 37
 
38
-    /**
39
-     * @throws EE_Error
40
-     * @throws ReflectionException
41
-     */
42
-    protected function _parser($shortcode)
43
-    {
44
-        switch ($shortcode) {
45
-            case '[QUESTION_LIST]':
46
-                return $this->_get_question_list();
47
-        }
48
-        return '';
49
-    }
38
+	/**
39
+	 * @throws EE_Error
40
+	 * @throws ReflectionException
41
+	 */
42
+	protected function _parser($shortcode)
43
+	{
44
+		switch ($shortcode) {
45
+			case '[QUESTION_LIST]':
46
+				return $this->_get_question_list();
47
+		}
48
+		return '';
49
+	}
50 50
 
51 51
 
52
-    /**
53
-     * @throws EE_Error
54
-     * @throws ReflectionException
55
-     */
56
-    protected function _get_question_list()
57
-    {
58
-        $this->_validate_list_requirements();
52
+	/**
53
+	 * @throws EE_Error
54
+	 * @throws ReflectionException
55
+	 */
56
+	protected function _get_question_list()
57
+	{
58
+		$this->_validate_list_requirements();
59 59
 
60
-        // for when [QUESTION_LIST] is used in the [attendee_list] field.
61
-        if ($this->_data['data'] instanceof EE_Registration) {
62
-            return $this->_get_question_answer_list_for_attendee();
63
-        }
64
-        // for when [QUESTION_LIST] is used in the main content field.
65
-        if (
66
-            $this->_data['data'] instanceof EE_Messages_Addressee
67
-            && $this->_data['data']->reg_obj instanceof EE_Registration
68
-        ) {
69
-            return $this->_get_question_answer_list_for_attendee($this->_data['data']->reg_obj);
70
-        }
71
-        return '';
72
-    }
60
+		// for when [QUESTION_LIST] is used in the [attendee_list] field.
61
+		if ($this->_data['data'] instanceof EE_Registration) {
62
+			return $this->_get_question_answer_list_for_attendee();
63
+		}
64
+		// for when [QUESTION_LIST] is used in the main content field.
65
+		if (
66
+			$this->_data['data'] instanceof EE_Messages_Addressee
67
+			&& $this->_data['data']->reg_obj instanceof EE_Registration
68
+		) {
69
+			return $this->_get_question_answer_list_for_attendee($this->_data['data']->reg_obj);
70
+		}
71
+		return '';
72
+	}
73 73
 
74 74
 
75
-    /**
76
-     * Note when we parse the "[question_list]" shortcode for attendees we're actually going to retrieve the list of
77
-     * answers for that attendee since that is what we really need (we can derive the questions from the answers);
78
-     *
79
-     * @param null $reg_obj
80
-     * @return string parsed template.
81
-     * @throws EE_Error
82
-     * @throws ReflectionException
83
-     */
84
-    private function _get_question_answer_list_for_attendee($reg_obj = null)
85
-    {
86
-        $valid_shortcodes = ['question'];
87
-        $reg_obj          = $reg_obj instanceof EE_Registration
88
-            ? $reg_obj
89
-            : $this->_data['data'];
90
-        $template         = is_array($this->_data['template']) && isset($this->_data['template']['question_list'])
91
-            ? $this->_data['template']['question_list']
92
-            : '';
93
-        $template         = empty($template) && isset($this->_extra_data['template']['question_list'])
94
-            ? $this->_extra_data['template']['question_list']
95
-            : $template;
96
-        $ans_result       = '';
97
-        $answers          = ! empty($this->_extra_data['data']->registrations[ $reg_obj->ID() ]['ans_objs'])
98
-            ? $this->_extra_data['data']->registrations[ $reg_obj->ID() ]['ans_objs']
99
-            : [];
100
-        $questions        = ! empty($this->_extra_data['data']->questions)
101
-            ? $this->_extra_data['data']->questions
102
-            : [];
103
-        foreach ($answers as $answer) {
104
-            // first see if the question is in our $questions array.  If not then try to get from answer object
105
-            $question = isset($questions[ $answer->ID() ])
106
-                ? $questions[ $answer->ID() ]
107
-                : null;
108
-            $question = ! $question instanceof EE_Question
109
-                ? $answer->question()
110
-                : $question;
111
-            if ($question instanceof EE_Question and $question->admin_only()) {
112
-                continue;
113
-            }
114
-            $ans_result .= $this->_shortcode_helper->parse_question_list_template(
115
-                $template,
116
-                $answer,
117
-                $valid_shortcodes,
118
-                $this->_extra_data
119
-            );
120
-        }
75
+	/**
76
+	 * Note when we parse the "[question_list]" shortcode for attendees we're actually going to retrieve the list of
77
+	 * answers for that attendee since that is what we really need (we can derive the questions from the answers);
78
+	 *
79
+	 * @param null $reg_obj
80
+	 * @return string parsed template.
81
+	 * @throws EE_Error
82
+	 * @throws ReflectionException
83
+	 */
84
+	private function _get_question_answer_list_for_attendee($reg_obj = null)
85
+	{
86
+		$valid_shortcodes = ['question'];
87
+		$reg_obj          = $reg_obj instanceof EE_Registration
88
+			? $reg_obj
89
+			: $this->_data['data'];
90
+		$template         = is_array($this->_data['template']) && isset($this->_data['template']['question_list'])
91
+			? $this->_data['template']['question_list']
92
+			: '';
93
+		$template         = empty($template) && isset($this->_extra_data['template']['question_list'])
94
+			? $this->_extra_data['template']['question_list']
95
+			: $template;
96
+		$ans_result       = '';
97
+		$answers          = ! empty($this->_extra_data['data']->registrations[ $reg_obj->ID() ]['ans_objs'])
98
+			? $this->_extra_data['data']->registrations[ $reg_obj->ID() ]['ans_objs']
99
+			: [];
100
+		$questions        = ! empty($this->_extra_data['data']->questions)
101
+			? $this->_extra_data['data']->questions
102
+			: [];
103
+		foreach ($answers as $answer) {
104
+			// first see if the question is in our $questions array.  If not then try to get from answer object
105
+			$question = isset($questions[ $answer->ID() ])
106
+				? $questions[ $answer->ID() ]
107
+				: null;
108
+			$question = ! $question instanceof EE_Question
109
+				? $answer->question()
110
+				: $question;
111
+			if ($question instanceof EE_Question and $question->admin_only()) {
112
+				continue;
113
+			}
114
+			$ans_result .= $this->_shortcode_helper->parse_question_list_template(
115
+				$template,
116
+				$answer,
117
+				$valid_shortcodes,
118
+				$this->_extra_data
119
+			);
120
+		}
121 121
 
122
-        return $ans_result;
123
-    }
122
+		return $ans_result;
123
+	}
124 124
 }
Please login to merge, or discard this patch.
Paypal_Pro/help_tabs/payment_methods_overview_paypalpro.help_tab.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -4,10 +4,10 @@  discard block
 block discarded – undo
4 4
 </p>
5 5
 <p>
6 6
     <?php printf(
7
-        esc_html__('See %1$shere%2$s for list of currencies supported by Paypal Pro.', 'event_espresso'),
8
-        "<a href='https://www.paypal.com/multicurrency' target='_blank' rel='noopener noreferrer'>",
9
-        "</a>"
10
-    ); ?>
7
+		esc_html__('See %1$shere%2$s for list of currencies supported by Paypal Pro.', 'event_espresso'),
8
+		"<a href='https://www.paypal.com/multicurrency' target='_blank' rel='noopener noreferrer'>",
9
+		"</a>"
10
+	); ?>
11 11
 </p>
12 12
 <p><strong><?php esc_html_e('PayPal Pro Settings', 'event_espresso'); ?></strong></p>
13 13
 <ul>
@@ -18,48 +18,48 @@  discard block
 block discarded – undo
18 18
     <li>
19 19
         <strong><?php esc_html_e('PayPal API Username', 'event_espresso'); ?></strong><br/>
20 20
         <?php
21
-        printf(
22
-            esc_html__(
23
-                'Enter your API Username for PayPal. Learn how to find your %1$sAPI Username%2$s.',
24
-                'event_espresso'
25
-            ),
26
-            '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">',
27
-            '</a>'
28
-        );
29
-        ?>
21
+		printf(
22
+			esc_html__(
23
+				'Enter your API Username for PayPal. Learn how to find your %1$sAPI Username%2$s.',
24
+				'event_espresso'
25
+			),
26
+			'<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">',
27
+			'</a>'
28
+		);
29
+		?>
30 30
     </li>
31 31
     <li>
32 32
         <strong><?php esc_html_e('PayPal API Password', 'event_espresso'); ?></strong><br/>
33 33
         <?php
34
-        printf(
35
-            esc_html__(
36
-                'Enter your API Password for PayPal. Learn how to find your %1$sAPI Password%2$s.',
37
-                'event_espresso'
38
-            ),
39
-            '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">',
40
-            '</a>'
41
-        );
42
-        ?>
34
+		printf(
35
+			esc_html__(
36
+				'Enter your API Password for PayPal. Learn how to find your %1$sAPI Password%2$s.',
37
+				'event_espresso'
38
+			),
39
+			'<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">',
40
+			'</a>'
41
+		);
42
+		?>
43 43
     </li>
44 44
     <li>
45 45
         <strong><?php esc_html_e('PayPal API Signature', 'event_espresso'); ?></strong><br/>
46 46
         <?php
47
-        printf(
48
-            esc_html__(
49
-                'Enter your API Signature for PayPal. Learn how to find your %1$sAPI Signature%2$s.',
50
-                'event_espresso'
51
-            ),
52
-            '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">',
53
-            '</a>'
54
-        );
55
-        ?>
47
+		printf(
48
+			esc_html__(
49
+				'Enter your API Signature for PayPal. Learn how to find your %1$sAPI Signature%2$s.',
50
+				'event_espresso'
51
+			),
52
+			'<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">',
53
+			'</a>'
54
+		);
55
+		?>
56 56
     </li>
57 57
     <li>
58 58
         <strong><?php esc_html_e('Country Currency', 'event_espresso'); ?></strong><br/>
59 59
         <?php esc_html_e(
60
-            'Select the currency for your country. Payments will be accepted in this currency.',
61
-            'event_espresso'
62
-        ); ?>
60
+			'Select the currency for your country. Payments will be accepted in this currency.',
61
+			'event_espresso'
62
+		); ?>
63 63
     </li>
64 64
     <li>
65 65
         <strong><?php esc_html_e('Accepted Card Types', 'event_espresso'); ?></strong><br/>
@@ -68,9 +68,9 @@  discard block
 block discarded – undo
68 68
     <li>
69 69
         <strong><?php esc_html_e('Use the Debugging Feature and the PayPal Sandbox', 'event_espresso'); ?></strong><br/>
70 70
         <?php esc_html_e(
71
-            'Specify if you want to test the payment gateway by submitting a test transaction. If this option is enabled, be sure to enter your PayPal sandbox credentials in the fields above. Be sure to turn this setting off when you are done testing.',
72
-            'event_espresso'
73
-        ); ?>
71
+			'Specify if you want to test the payment gateway by submitting a test transaction. If this option is enabled, be sure to enter your PayPal sandbox credentials in the fields above. Be sure to turn this setting off when you are done testing.',
72
+			'event_espresso'
73
+		); ?>
74 74
     </li>
75 75
     <li>
76 76
         <strong><?php esc_html_e('Button Image URL', 'event_espresso'); ?></strong><br/>
Please login to merge, or discard this patch.
payment_methods/Aim/help_tabs/payment_methods_overview_aim.help_tab.php 1 patch
Indentation   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -6,15 +6,15 @@  discard block
 block discarded – undo
6 6
 </p>
7 7
 <p>
8 8
     <?php
9
-    printf(
10
-        esc_html__(
11
-            'See %1$shere%2$s for list of currencies supported by Authorize.net AIM.',
12
-            'event_espresso'
13
-        ),
14
-        "<a href='https://support.authorize.net/s/article/Which-Currencies-Does-Authorize-Net-Support/' target='_blank' rel='noopener noreferrer'>",
15
-        "</a>"
16
-    );
17
-    ?>
9
+	printf(
10
+		esc_html__(
11
+			'See %1$shere%2$s for list of currencies supported by Authorize.net AIM.',
12
+			'event_espresso'
13
+		),
14
+		"<a href='https://support.authorize.net/s/article/Which-Currencies-Does-Authorize-Net-Support/' target='_blank' rel='noopener noreferrer'>",
15
+		"</a>"
16
+	);
17
+	?>
18 18
 </p>
19 19
 <p>
20 20
     <strong><?php esc_html_e('Authorize.net AIM Settings', 'event_espresso'); ?></strong>
@@ -24,70 +24,70 @@  discard block
 block discarded – undo
24 24
         <strong><?php esc_html_e('Authorize.net API Login ID', 'event_espresso'); ?></strong>
25 25
         <br/>
26 26
         <?php
27
-        printf(
28
-            esc_html__(
29
-                'Enter your API Login ID for Authorize.net. Learn how to find your %1$sAPI Login%2$s ID.',
30
-                'event_espresso'
31
-            ),
32
-            '<a href="https://support.authorize.net/authkb/index?page=content&id=A405" target="_blank" rel="noopener noreferrer">',
33
-            '</a>'
34
-        );
35
-        ?>
27
+		printf(
28
+			esc_html__(
29
+				'Enter your API Login ID for Authorize.net. Learn how to find your %1$sAPI Login%2$s ID.',
30
+				'event_espresso'
31
+			),
32
+			'<a href="https://support.authorize.net/authkb/index?page=content&id=A405" target="_blank" rel="noopener noreferrer">',
33
+			'</a>'
34
+		);
35
+		?>
36 36
     </li>
37 37
     <li>
38 38
         <strong><?php esc_html_e('Authorize.net Transaction Key', 'event_espresso'); ?></strong>
39 39
         <br/>
40 40
         <?php
41
-        printf(
42
-            esc_html__(
43
-                'Enter your Transaction Key for Authorize.net. Learn how to find your %1$sTransaction Key%2$s.',
44
-                'event_espresso'
45
-            ),
46
-            '<a href="https://support.authorize.net/authkb/index?page=content&id=A405" target="_blank" rel="noopener noreferrer">',
47
-            '</a>'
48
-        );
49
-        ?>
41
+		printf(
42
+			esc_html__(
43
+				'Enter your Transaction Key for Authorize.net. Learn how to find your %1$sTransaction Key%2$s.',
44
+				'event_espresso'
45
+			),
46
+			'<a href="https://support.authorize.net/authkb/index?page=content&id=A405" target="_blank" rel="noopener noreferrer">',
47
+			'</a>'
48
+		);
49
+		?>
50 50
     </li>
51 51
     <li>
52 52
         <strong>
53 53
             <?php esc_html_e(
54
-                'Is this an account on the Authorize.net development server?',
55
-                'event_espresso'
56
-            ); ?>
54
+				'Is this an account on the Authorize.net development server?',
55
+				'event_espresso'
56
+			); ?>
57 57
         </strong>
58 58
         <br/>
59 59
         <?php esc_html_e(
60
-            'Specify whether this is a live/production account or a test account on the Authorize.net development server.',
61
-            'event_espresso'
62
-        ); ?>
60
+			'Specify whether this is a live/production account or a test account on the Authorize.net development server.',
61
+			'event_espresso'
62
+		); ?>
63 63
     </li>
64 64
     <li>
65 65
         <strong><?php esc_html_e('Do you want to submit a test transaction?', 'event_espresso'); ?></strong>
66 66
         <br/>
67 67
         <?php esc_html_e(
68
-            'Specify if you want to test the Authorize.net AIM payment gateway by submitting a test transaction. Be sure to turn this setting off when you are done testing.',
69
-            'event_espresso'
70
-        ); ?>
68
+			'Specify if you want to test the Authorize.net AIM payment gateway by submitting a test transaction. Be sure to turn this setting off when you are done testing.',
69
+			'event_espresso'
70
+		); ?>
71 71
     </li>
72 72
     <li>
73 73
         <strong><?php esc_html_e('Excluded and Required Payment Form Fields', 'event_espresso'); ?></strong>
74 74
         <br/>
75 75
         <?php esc_html_e(
76
-            'By logging into Authorize.net, you can change which payment fields are required by Authorize.net when processing payments. These settings affect both the Advanced Integration Method (AIM, this) and the Simple Integration Method (SIM, different). The payment method settings "Excluded Payment Form Fields" and "Required Payment Form Fields" allow you to change the billing form in Event Espresso to reflect your payment form settings in Authorize.net.',
77
-            'event_espresso'
78
-        ); ?>
76
+			'By logging into Authorize.net, you can change which payment fields are required by Authorize.net when processing payments. These settings affect both the Advanced Integration Method (AIM, this) and the Simple Integration Method (SIM, different). The payment method settings "Excluded Payment Form Fields" and "Required Payment Form Fields" allow you to change the billing form in Event Espresso to reflect your payment form settings in Authorize.net.',
77
+			'event_espresso'
78
+		); ?>
79 79
         <br>
80 80
         <?php printf(
81
-            esc_html__(
82
-                'To change your payment form settings in Authorize.net, %1$slog in to authorize.net%2$s, go to %3$sAccount then Payment Form%2$s, then %4$sForm Fields%2$s. It will look similar to %5$sthis%2$s. If you make a field required in Authorize.net, you should also make it required in Event Espresso. If it isn\'t required in Authorize.net, and you want to simplify the billing form in Event Espresso, you can exclude it from the Event Espresso Form too.',
83
-                'event_espresso'
84
-            ),
85
-            '<a href="http://authorize.net" target="_blank" rel="noopener noreferrer">',
86
-            '</a>',
87
-            '<a href="https://monosnap.com/file/nebVteOkEXcdDIos88SojStWOifP23" target="_blank" rel="noopener noreferrer">',
88
-            '<a href="https://monosnap.com/file/WyxGJtev87TcDmdGBEZ2oi1xaBIQAm" target="_blank" rel="noopener noreferrer">',
89
-            '<a href="https://monosnap.com/image/DbCJNfEesWXeSNUs1wLIpGYODFw52m" target="_blank" rel="noopener noreferrer">'
90
-        ); ?>
81
+			esc_html__(
82
+				'To change your payment form settings in Authorize.net, %1$slog in to authorize.net%2$s, go to %3$sAccount then Payment Form%2$s, then %4$sForm Fields%2$s. It will look similar to %5$sthis%2$s. If you make a field required in Authorize.net, you should also make it required in Event Espresso. If it isn\'t required in Authorize.net, and you want to simplify the billing form in Event Espresso, you can exclude it from the Event Espresso Form too.',
83
+				'event_espresso'
84
+			),
85
+			'<a href="http://authorize.net" target="_blank" rel="noopener noreferrer">',
86
+			'</a>',
87
+			'<a href="https://monosnap.com/file/nebVteOkEXcdDIos88SojStWOifP23" target="_blank" rel="noopener noreferrer">',
88
+			'<a href="https://monosnap.com/file/WyxGJtev87TcDmdGBEZ2oi1xaBIQAm" target="_blank" rel="noopener noreferrer">',
89
+			'<a href="https://monosnap.com/image/DbCJNfEesWXeSNUs1wLIpGYODFw52m" target="_blank" rel="noopener noreferrer">'
90
+		); ?>
91 91
     </li>
92 92
     <li>
93 93
         <strong><?php esc_html_e('Button Image URL', 'event_espresso'); ?></strong>
@@ -97,10 +97,10 @@  discard block
 block discarded – undo
97 97
     <li>
98 98
         <strong><?php esc_html_e('Note About Special Characters', 'event_espresso'); ?></strong>
99 99
         <?php
100
-        esc_html_e(
101
-            'If your event name, ticket name or ticket description contain special characters (eg emojis, foreign language characters, or curly quotes) they will be removed when sent to Authorize.net. This is because Authorize.net doesn\'t support them.',
102
-            'event_espresso'
103
-        );
104
-        ?>
100
+		esc_html_e(
101
+			'If your event name, ticket name or ticket description contain special characters (eg emojis, foreign language characters, or curly quotes) they will be removed when sent to Authorize.net. This is because Authorize.net doesn\'t support them.',
102
+			'event_espresso'
103
+		);
104
+		?>
105 105
     </li>
106 106
 </ul>
107 107
\ No newline at end of file
Please login to merge, or discard this patch.
caffeinated/brewing_regular.php 2 patches
Spacing   +31 added lines, -31 removed lines patch added patch discarded remove patch
@@ -12,10 +12,10 @@  discard block
 block discarded – undo
12 12
 use EventEspresso\core\services\database\TableAnalysis;
13 13
 
14 14
 // defined some new constants related to caffeinated folder
15
-define('EE_CAF_URL', EE_PLUGIN_DIR_URL . 'caffeinated/');
16
-define('EE_CAF_CORE', EE_CAFF_PATH . 'core/');
17
-define('EE_CAF_LIBRARIES', EE_CAF_CORE . 'libraries/');
18
-define('EE_CAF_PAYMENT_METHODS', EE_CAFF_PATH . 'payment_methods/');
15
+define('EE_CAF_URL', EE_PLUGIN_DIR_URL.'caffeinated/');
16
+define('EE_CAF_CORE', EE_CAFF_PATH.'core/');
17
+define('EE_CAF_LIBRARIES', EE_CAF_CORE.'libraries/');
18
+define('EE_CAF_PAYMENT_METHODS', EE_CAFF_PATH.'payment_methods/');
19 19
 
20 20
 
21 21
 /**
@@ -65,11 +65,11 @@  discard block
 block discarded – undo
65 65
         add_filter('FHEE__EE_Registry__load_helper__helper_paths', [$this, 'caf_helper_paths'], 10);
66 66
         add_filter(
67 67
             'AHEE__EE_System__load_core_configuration__complete',
68
-            function () {
68
+            function() {
69 69
                 EE_Register_Payment_Method::register(
70 70
                     'caffeinated_payment_methods',
71 71
                     [
72
-                        'payment_method_paths' => glob(EE_CAF_PAYMENT_METHODS . '*', GLOB_ONLYDIR),
72
+                        'payment_method_paths' => glob(EE_CAF_PAYMENT_METHODS.'*', GLOB_ONLYDIR),
73 73
                     ]
74 74
                 );
75 75
             }
@@ -124,7 +124,7 @@  discard block
 block discarded – undo
124 124
      */
125 125
     public function caf_helper_paths($paths)
126 126
     {
127
-        $paths[] = EE_CAF_CORE . 'helpers/';
127
+        $paths[] = EE_CAF_CORE.'helpers/';
128 128
         return $paths;
129 129
     }
130 130
 
@@ -145,11 +145,11 @@  discard block
 block discarded – undo
145 145
         global $wpdb;
146 146
         // use same method of getting creator id as the version introducing the change
147 147
         $default_creator_id = apply_filters('FHEE__EE_DMS_Core_4_5_0__get_default_creator_id', get_current_user_id());
148
-        $price_type_table   = $wpdb->prefix . "esp_price_type";
149
-        $price_table        = $wpdb->prefix . "esp_price";
148
+        $price_type_table   = $wpdb->prefix."esp_price_type";
149
+        $price_table        = $wpdb->prefix."esp_price";
150 150
         if ($this->_get_table_analysis()->tableExists($price_type_table)) {
151 151
             $SQL                  =
152
-                'SELECT COUNT(PRT_ID) FROM ' . $price_type_table . ' WHERE PBT_ID=4';// include trashed price types
152
+                'SELECT COUNT(PRT_ID) FROM '.$price_type_table.' WHERE PBT_ID=4'; // include trashed price types
153 153
             $tax_price_type_count = $wpdb->get_var($SQL);
154 154
             if ($tax_price_type_count <= 1) {
155 155
                 $wpdb->insert(
@@ -163,11 +163,11 @@  discard block
 block discarded – undo
163 163
                         'PRT_wp_user'    => $default_creator_id,
164 164
                     ],
165 165
                     [
166
-                        '%s',// PRT_name
167
-                        '%d',// PBT_id
168
-                        '%d',// PRT_is_percent
169
-                        '%d',// PRT_order
170
-                        '%d',// PRT_deleted
166
+                        '%s', // PRT_name
167
+                        '%d', // PBT_id
168
+                        '%d', // PRT_is_percent
169
+                        '%d', // PRT_order
170
+                        '%d', // PRT_deleted
171 171
                         '%d', // PRT_wp_user
172 172
                     ]
173 173
                 );
@@ -183,11 +183,11 @@  discard block
 block discarded – undo
183 183
                         'PRT_wp_user'    => $default_creator_id,
184 184
                     ],
185 185
                     [
186
-                        '%s',// PRT_name
187
-                        '%d',// PBT_id
188
-                        '%d',// PRT_is_percent
189
-                        '%d',// PRT_order
190
-                        '%d',// PRT_deleted
186
+                        '%s', // PRT_name
187
+                        '%d', // PBT_id
188
+                        '%d', // PRT_is_percent
189
+                        '%d', // PRT_order
190
+                        '%d', // PRT_deleted
191 191
                         '%d' // PRT_wp_user
192 192
                     ]
193 193
                 );
@@ -207,15 +207,15 @@  discard block
 block discarded – undo
207 207
                             'PRC_wp_user'    => $default_creator_id,
208 208
                         ],
209 209
                         [
210
-                            '%d',// PRT_id
211
-                            '%f',// PRC_amount
212
-                            '%s',// PRC_name
213
-                            '%s',// PRC_desc
214
-                            '%d',// PRC_is_default
215
-                            '%d',// PRC_overrides
216
-                            '%d',// PRC_deleted
217
-                            '%d',// PRC_order
218
-                            '%d',// PRC_parent
210
+                            '%d', // PRT_id
211
+                            '%f', // PRC_amount
212
+                            '%s', // PRC_name
213
+                            '%s', // PRC_desc
214
+                            '%d', // PRC_is_default
215
+                            '%d', // PRC_overrides
216
+                            '%d', // PRC_deleted
217
+                            '%d', // PRC_order
218
+                            '%d', // PRC_parent
219 219
                             '%d' // PRC_wp_user
220 220
                         ]
221 221
                     );
@@ -234,8 +234,8 @@  discard block
 block discarded – undo
234 234
      */
235 235
     public function caffeinated_modules_to_register($modules_to_register = [])
236 236
     {
237
-        if (is_readable(EE_CAFF_PATH . 'modules')) {
238
-            $caffeinated_modules_to_register = glob(EE_CAFF_PATH . 'modules/*', GLOB_ONLYDIR);
237
+        if (is_readable(EE_CAFF_PATH.'modules')) {
238
+            $caffeinated_modules_to_register = glob(EE_CAFF_PATH.'modules/*', GLOB_ONLYDIR);
239 239
             if (is_array($caffeinated_modules_to_register) && ! empty($caffeinated_modules_to_register)) {
240 240
                 $modules_to_register = array_merge($modules_to_register, $caffeinated_modules_to_register);
241 241
             }
Please login to merge, or discard this patch.
Indentation   +315 added lines, -315 removed lines patch added patch discarded remove patch
@@ -28,323 +28,323 @@
 block discarded – undo
28 28
 class EE_Brewing_Regular extends EE_BASE implements InterminableInterface
29 29
 {
30 30
 
31
-    /**
32
-     * @var TableAnalysis $table_analysis
33
-     */
34
-    protected $_table_analysis;
35
-
36
-
37
-    /**
38
-     * EE_Brewing_Regular constructor.
39
-     *
40
-     * @param TableAnalysis $table_analysis
41
-     */
42
-    public function __construct(TableAnalysis $table_analysis)
43
-    {
44
-        $this->_table_analysis = $table_analysis;
45
-        if (defined('EE_CAFF_PATH')) {
46
-            $this->setInitializationHooks();
47
-            $this->setApiRegistrationHooks();
48
-            $this->setSwitchHooks();
49
-            $this->setDefaultFilterHooks();
50
-            // caffeinated constructed
51
-            do_action('AHEE__EE_Brewing_Regular__construct__complete');
52
-        }
53
-    }
54
-
55
-
56
-    /**
57
-     * Various hooks used for extending features via registration of modules or extensions.
58
-     */
59
-    private function setApiRegistrationHooks()
60
-    {
61
-        add_filter(
62
-            'FHEE__EE_Config__register_modules__modules_to_register',
63
-            [$this, 'caffeinated_modules_to_register']
64
-        );
65
-        add_filter('FHEE__EE_Registry__load_helper__helper_paths', [$this, 'caf_helper_paths'], 10);
66
-        add_filter(
67
-            'AHEE__EE_System__load_core_configuration__complete',
68
-            function () {
69
-                EE_Register_Payment_Method::register(
70
-                    'caffeinated_payment_methods',
71
-                    [
72
-                        'payment_method_paths' => glob(EE_CAF_PAYMENT_METHODS . '*', GLOB_ONLYDIR),
73
-                    ]
74
-                );
75
-            }
76
-        );
77
-    }
78
-
79
-
80
-    /**
81
-     * Various hooks used for modifying initialization or activation processes.
82
-     */
83
-    private function setInitializationHooks()
84
-    {
85
-        // activation
86
-        add_action('AHEE__EEH_Activation__initialize_db_content', [$this, 'initialize_caf_db_content']);
87
-        // load caff init
88
-        add_action('AHEE__EE_System__set_hooks_for_core', [$this, 'caffeinated_init']);
89
-        // load caff scripts
90
-        add_action('wp_enqueue_scripts', [$this, 'enqueue_caffeinated_scripts'], 10);
91
-    }
92
-
93
-
94
-    /**
95
-     * Various hooks used for switch (on/off) type filters.
96
-     */
97
-    private function setSwitchHooks()
98
-    {
99
-        // remove the "powered by" credit link from receipts and invoices
100
-        add_filter('FHEE_EE_Html_messenger__add_powered_by_credit_link_to_receipt_and_invoice', '__return_false');
101
-        // seeing how this is caf, which isn't put on WordPress.org, we can have affiliate links without a disclaimer
102
-        add_filter('FHEE__ee_show_affiliate_links', '__return_false');
103
-    }
104
-
105
-
106
-    /**
107
-     * Various filters for affecting default configuration values in the caffeinated
108
-     * context.
109
-     */
110
-    private function setDefaultFilterHooks()
111
-    {
112
-        add_filter(
113
-            'FHEE__EE_Admin_Config__show_reg_footer__default',
114
-            '__return_true'
115
-        );
116
-    }
117
-
118
-
119
-    /**
120
-     * callback for the FHEE__EE_Registry__load_helper__helper_paths filter to add the caffeinated paths
121
-     *
122
-     * @param array $paths original helper paths array
123
-     * @return array             new array of paths
124
-     */
125
-    public function caf_helper_paths($paths)
126
-    {
127
-        $paths[] = EE_CAF_CORE . 'helpers/';
128
-        return $paths;
129
-    }
130
-
131
-
132
-    /**
133
-     * Upon brand-new activation, if this is a new activation of CAF, we want to add
134
-     * some global prices that will show off EE4's capabilities. However, if they're upgrading
135
-     * from 3.1, or simply EE4.x decaf, we assume they don't want us to suddenly introduce these extra prices.
136
-     * This action should only be called when EE 4.x.0.P is initially activated.
137
-     * Right now the only CAF content are these global prices. If there's more in the future, then
138
-     * we should probably create a caf file to contain it all instead just a function like this.
139
-     * Right now, we ASSUME the only price types in the system are default ones
140
-     *
141
-     * @global wpdb $wpdb
142
-     */
143
-    public function initialize_caf_db_content()
144
-    {
145
-        global $wpdb;
146
-        // use same method of getting creator id as the version introducing the change
147
-        $default_creator_id = apply_filters('FHEE__EE_DMS_Core_4_5_0__get_default_creator_id', get_current_user_id());
148
-        $price_type_table   = $wpdb->prefix . "esp_price_type";
149
-        $price_table        = $wpdb->prefix . "esp_price";
150
-        if ($this->_get_table_analysis()->tableExists($price_type_table)) {
151
-            $SQL                  =
152
-                'SELECT COUNT(PRT_ID) FROM ' . $price_type_table . ' WHERE PBT_ID=4';// include trashed price types
153
-            $tax_price_type_count = $wpdb->get_var($SQL);
154
-            if ($tax_price_type_count <= 1) {
155
-                $wpdb->insert(
156
-                    $price_type_table,
157
-                    [
158
-                        'PRT_name'       => esc_html__("Regional Tax", "event_espresso"),
159
-                        'PBT_ID'         => 4,
160
-                        'PRT_is_percent' => true,
161
-                        'PRT_order'      => 60,
162
-                        'PRT_deleted'    => false,
163
-                        'PRT_wp_user'    => $default_creator_id,
164
-                    ],
165
-                    [
166
-                        '%s',// PRT_name
167
-                        '%d',// PBT_id
168
-                        '%d',// PRT_is_percent
169
-                        '%d',// PRT_order
170
-                        '%d',// PRT_deleted
171
-                        '%d', // PRT_wp_user
172
-                    ]
173
-                );
174
-                // federal tax
175
-                $result = $wpdb->insert(
176
-                    $price_type_table,
177
-                    [
178
-                        'PRT_name'       => esc_html__("Federal Tax", "event_espresso"),
179
-                        'PBT_ID'         => 4,
180
-                        'PRT_is_percent' => true,
181
-                        'PRT_order'      => 70,
182
-                        'PRT_deleted'    => false,
183
-                        'PRT_wp_user'    => $default_creator_id,
184
-                    ],
185
-                    [
186
-                        '%s',// PRT_name
187
-                        '%d',// PBT_id
188
-                        '%d',// PRT_is_percent
189
-                        '%d',// PRT_order
190
-                        '%d',// PRT_deleted
191
-                        '%d' // PRT_wp_user
192
-                    ]
193
-                );
194
-                if ($result) {
195
-                    $wpdb->insert(
196
-                        $price_table,
197
-                        [
198
-                            'PRT_ID'         => $wpdb->insert_id,
199
-                            'PRC_amount'     => 15.00,
200
-                            'PRC_name'       => esc_html__("Sales Tax", "event_espresso"),
201
-                            'PRC_desc'       => '',
202
-                            'PRC_is_default' => true,
203
-                            'PRC_overrides'  => null,
204
-                            'PRC_deleted'    => false,
205
-                            'PRC_order'      => 50,
206
-                            'PRC_parent'     => null,
207
-                            'PRC_wp_user'    => $default_creator_id,
208
-                        ],
209
-                        [
210
-                            '%d',// PRT_id
211
-                            '%f',// PRC_amount
212
-                            '%s',// PRC_name
213
-                            '%s',// PRC_desc
214
-                            '%d',// PRC_is_default
215
-                            '%d',// PRC_overrides
216
-                            '%d',// PRC_deleted
217
-                            '%d',// PRC_order
218
-                            '%d',// PRC_parent
219
-                            '%d' // PRC_wp_user
220
-                        ]
221
-                    );
222
-                }
223
-            }
224
-        }
225
-    }
226
-
227
-
228
-    /**
229
-     *    caffeinated_modules_to_register
230
-     *
231
-     * @access public
232
-     * @param array $modules_to_register
233
-     * @return array
234
-     */
235
-    public function caffeinated_modules_to_register($modules_to_register = [])
236
-    {
237
-        if (is_readable(EE_CAFF_PATH . 'modules')) {
238
-            $caffeinated_modules_to_register = glob(EE_CAFF_PATH . 'modules/*', GLOB_ONLYDIR);
239
-            if (is_array($caffeinated_modules_to_register) && ! empty($caffeinated_modules_to_register)) {
240
-                $modules_to_register = array_merge($modules_to_register, $caffeinated_modules_to_register);
241
-            }
242
-        }
243
-        return $modules_to_register;
244
-    }
245
-
246
-
247
-    /**
248
-     * @throws EE_Error
249
-     * @throws InvalidArgumentException
250
-     * @throws ReflectionException
251
-     * @throws InvalidDataTypeException
252
-     * @throws InvalidInterfaceException
253
-     */
254
-    public function caffeinated_init()
255
-    {
256
-        // Custom Post Type hooks
257
-        add_filter(
258
-            'FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies',
259
-            [$this, 'filter_taxonomies']
260
-        );
261
-        add_filter(
262
-            'FHEE__EventEspresso_core_domain_entities_custom_post_types_CustomPostTypeDefinitions__getCustomPostTypes',
263
-            [$this, 'filter_cpts']
264
-        );
265
-        add_filter(
266
-            'FHEE__EE_Admin__get_extra_nav_menu_pages_items',
267
-            [$this, 'nav_metabox_items']
268
-        );
269
-        EE_Registry::instance()->load_file(
270
-            EE_CAFF_PATH,
271
-            'EE_Caf_Messages',
272
-            'class',
273
-            [],
274
-            false
275
-        );
276
-        // caffeinated_init__complete hook
277
-        do_action('AHEE__EE_Brewing_Regular__caffeinated_init__complete');
278
-    }
279
-
280
-
281
-    public function enqueue_caffeinated_scripts()
282
-    {
283
-        // sound of crickets...
284
-    }
285
-
286
-
287
-    /**
288
-     * callbacks below here
289
-     *
290
-     * @param array $taxonomy_array
291
-     * @return array
292
-     */
293
-    public function filter_taxonomies(array $taxonomy_array)
294
-    {
295
-        $taxonomy_array['espresso_venue_categories']['args']['show_in_nav_menus'] = true;
296
-        return $taxonomy_array;
297
-    }
298
-
299
-
300
-    /**
301
-     * @param array $cpt_array
302
-     * @return mixed
303
-     */
304
-    public function filter_cpts(array $cpt_array)
305
-    {
306
-        $cpt_array['espresso_venues']['args']['show_in_nav_menus'] = true;
307
-        return $cpt_array;
308
-    }
309
-
310
-
311
-    /**
312
-     * @param array $menuitems
313
-     * @return array
314
-     */
315
-    public function nav_metabox_items(array $menuitems)
316
-    {
317
-        $menuitems[] = [
318
-            'title'       => esc_html__('Venue List', 'event_espresso'),
319
-            'url'         => get_post_type_archive_link('espresso_venues'),
320
-            'description' => esc_html__('Archive page for all venues.', 'event_espresso'),
321
-        ];
322
-        return $menuitems;
323
-    }
324
-
325
-
326
-    /**
327
-     * Gets the injected table analyzer, or throws an exception
328
-     *
329
-     * @return TableAnalysis
330
-     * @throws \EE_Error
331
-     */
332
-    protected function _get_table_analysis()
333
-    {
334
-        if ($this->_table_analysis instanceof TableAnalysis) {
335
-            return $this->_table_analysis;
336
-        } else {
337
-            throw new \EE_Error(
338
-                sprintf(
339
-                    esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
340
-                    get_class($this)
341
-                )
342
-            );
343
-        }
344
-    }
31
+	/**
32
+	 * @var TableAnalysis $table_analysis
33
+	 */
34
+	protected $_table_analysis;
35
+
36
+
37
+	/**
38
+	 * EE_Brewing_Regular constructor.
39
+	 *
40
+	 * @param TableAnalysis $table_analysis
41
+	 */
42
+	public function __construct(TableAnalysis $table_analysis)
43
+	{
44
+		$this->_table_analysis = $table_analysis;
45
+		if (defined('EE_CAFF_PATH')) {
46
+			$this->setInitializationHooks();
47
+			$this->setApiRegistrationHooks();
48
+			$this->setSwitchHooks();
49
+			$this->setDefaultFilterHooks();
50
+			// caffeinated constructed
51
+			do_action('AHEE__EE_Brewing_Regular__construct__complete');
52
+		}
53
+	}
54
+
55
+
56
+	/**
57
+	 * Various hooks used for extending features via registration of modules or extensions.
58
+	 */
59
+	private function setApiRegistrationHooks()
60
+	{
61
+		add_filter(
62
+			'FHEE__EE_Config__register_modules__modules_to_register',
63
+			[$this, 'caffeinated_modules_to_register']
64
+		);
65
+		add_filter('FHEE__EE_Registry__load_helper__helper_paths', [$this, 'caf_helper_paths'], 10);
66
+		add_filter(
67
+			'AHEE__EE_System__load_core_configuration__complete',
68
+			function () {
69
+				EE_Register_Payment_Method::register(
70
+					'caffeinated_payment_methods',
71
+					[
72
+						'payment_method_paths' => glob(EE_CAF_PAYMENT_METHODS . '*', GLOB_ONLYDIR),
73
+					]
74
+				);
75
+			}
76
+		);
77
+	}
78
+
79
+
80
+	/**
81
+	 * Various hooks used for modifying initialization or activation processes.
82
+	 */
83
+	private function setInitializationHooks()
84
+	{
85
+		// activation
86
+		add_action('AHEE__EEH_Activation__initialize_db_content', [$this, 'initialize_caf_db_content']);
87
+		// load caff init
88
+		add_action('AHEE__EE_System__set_hooks_for_core', [$this, 'caffeinated_init']);
89
+		// load caff scripts
90
+		add_action('wp_enqueue_scripts', [$this, 'enqueue_caffeinated_scripts'], 10);
91
+	}
92
+
93
+
94
+	/**
95
+	 * Various hooks used for switch (on/off) type filters.
96
+	 */
97
+	private function setSwitchHooks()
98
+	{
99
+		// remove the "powered by" credit link from receipts and invoices
100
+		add_filter('FHEE_EE_Html_messenger__add_powered_by_credit_link_to_receipt_and_invoice', '__return_false');
101
+		// seeing how this is caf, which isn't put on WordPress.org, we can have affiliate links without a disclaimer
102
+		add_filter('FHEE__ee_show_affiliate_links', '__return_false');
103
+	}
104
+
105
+
106
+	/**
107
+	 * Various filters for affecting default configuration values in the caffeinated
108
+	 * context.
109
+	 */
110
+	private function setDefaultFilterHooks()
111
+	{
112
+		add_filter(
113
+			'FHEE__EE_Admin_Config__show_reg_footer__default',
114
+			'__return_true'
115
+		);
116
+	}
117
+
118
+
119
+	/**
120
+	 * callback for the FHEE__EE_Registry__load_helper__helper_paths filter to add the caffeinated paths
121
+	 *
122
+	 * @param array $paths original helper paths array
123
+	 * @return array             new array of paths
124
+	 */
125
+	public function caf_helper_paths($paths)
126
+	{
127
+		$paths[] = EE_CAF_CORE . 'helpers/';
128
+		return $paths;
129
+	}
130
+
131
+
132
+	/**
133
+	 * Upon brand-new activation, if this is a new activation of CAF, we want to add
134
+	 * some global prices that will show off EE4's capabilities. However, if they're upgrading
135
+	 * from 3.1, or simply EE4.x decaf, we assume they don't want us to suddenly introduce these extra prices.
136
+	 * This action should only be called when EE 4.x.0.P is initially activated.
137
+	 * Right now the only CAF content are these global prices. If there's more in the future, then
138
+	 * we should probably create a caf file to contain it all instead just a function like this.
139
+	 * Right now, we ASSUME the only price types in the system are default ones
140
+	 *
141
+	 * @global wpdb $wpdb
142
+	 */
143
+	public function initialize_caf_db_content()
144
+	{
145
+		global $wpdb;
146
+		// use same method of getting creator id as the version introducing the change
147
+		$default_creator_id = apply_filters('FHEE__EE_DMS_Core_4_5_0__get_default_creator_id', get_current_user_id());
148
+		$price_type_table   = $wpdb->prefix . "esp_price_type";
149
+		$price_table        = $wpdb->prefix . "esp_price";
150
+		if ($this->_get_table_analysis()->tableExists($price_type_table)) {
151
+			$SQL                  =
152
+				'SELECT COUNT(PRT_ID) FROM ' . $price_type_table . ' WHERE PBT_ID=4';// include trashed price types
153
+			$tax_price_type_count = $wpdb->get_var($SQL);
154
+			if ($tax_price_type_count <= 1) {
155
+				$wpdb->insert(
156
+					$price_type_table,
157
+					[
158
+						'PRT_name'       => esc_html__("Regional Tax", "event_espresso"),
159
+						'PBT_ID'         => 4,
160
+						'PRT_is_percent' => true,
161
+						'PRT_order'      => 60,
162
+						'PRT_deleted'    => false,
163
+						'PRT_wp_user'    => $default_creator_id,
164
+					],
165
+					[
166
+						'%s',// PRT_name
167
+						'%d',// PBT_id
168
+						'%d',// PRT_is_percent
169
+						'%d',// PRT_order
170
+						'%d',// PRT_deleted
171
+						'%d', // PRT_wp_user
172
+					]
173
+				);
174
+				// federal tax
175
+				$result = $wpdb->insert(
176
+					$price_type_table,
177
+					[
178
+						'PRT_name'       => esc_html__("Federal Tax", "event_espresso"),
179
+						'PBT_ID'         => 4,
180
+						'PRT_is_percent' => true,
181
+						'PRT_order'      => 70,
182
+						'PRT_deleted'    => false,
183
+						'PRT_wp_user'    => $default_creator_id,
184
+					],
185
+					[
186
+						'%s',// PRT_name
187
+						'%d',// PBT_id
188
+						'%d',// PRT_is_percent
189
+						'%d',// PRT_order
190
+						'%d',// PRT_deleted
191
+						'%d' // PRT_wp_user
192
+					]
193
+				);
194
+				if ($result) {
195
+					$wpdb->insert(
196
+						$price_table,
197
+						[
198
+							'PRT_ID'         => $wpdb->insert_id,
199
+							'PRC_amount'     => 15.00,
200
+							'PRC_name'       => esc_html__("Sales Tax", "event_espresso"),
201
+							'PRC_desc'       => '',
202
+							'PRC_is_default' => true,
203
+							'PRC_overrides'  => null,
204
+							'PRC_deleted'    => false,
205
+							'PRC_order'      => 50,
206
+							'PRC_parent'     => null,
207
+							'PRC_wp_user'    => $default_creator_id,
208
+						],
209
+						[
210
+							'%d',// PRT_id
211
+							'%f',// PRC_amount
212
+							'%s',// PRC_name
213
+							'%s',// PRC_desc
214
+							'%d',// PRC_is_default
215
+							'%d',// PRC_overrides
216
+							'%d',// PRC_deleted
217
+							'%d',// PRC_order
218
+							'%d',// PRC_parent
219
+							'%d' // PRC_wp_user
220
+						]
221
+					);
222
+				}
223
+			}
224
+		}
225
+	}
226
+
227
+
228
+	/**
229
+	 *    caffeinated_modules_to_register
230
+	 *
231
+	 * @access public
232
+	 * @param array $modules_to_register
233
+	 * @return array
234
+	 */
235
+	public function caffeinated_modules_to_register($modules_to_register = [])
236
+	{
237
+		if (is_readable(EE_CAFF_PATH . 'modules')) {
238
+			$caffeinated_modules_to_register = glob(EE_CAFF_PATH . 'modules/*', GLOB_ONLYDIR);
239
+			if (is_array($caffeinated_modules_to_register) && ! empty($caffeinated_modules_to_register)) {
240
+				$modules_to_register = array_merge($modules_to_register, $caffeinated_modules_to_register);
241
+			}
242
+		}
243
+		return $modules_to_register;
244
+	}
245
+
246
+
247
+	/**
248
+	 * @throws EE_Error
249
+	 * @throws InvalidArgumentException
250
+	 * @throws ReflectionException
251
+	 * @throws InvalidDataTypeException
252
+	 * @throws InvalidInterfaceException
253
+	 */
254
+	public function caffeinated_init()
255
+	{
256
+		// Custom Post Type hooks
257
+		add_filter(
258
+			'FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies',
259
+			[$this, 'filter_taxonomies']
260
+		);
261
+		add_filter(
262
+			'FHEE__EventEspresso_core_domain_entities_custom_post_types_CustomPostTypeDefinitions__getCustomPostTypes',
263
+			[$this, 'filter_cpts']
264
+		);
265
+		add_filter(
266
+			'FHEE__EE_Admin__get_extra_nav_menu_pages_items',
267
+			[$this, 'nav_metabox_items']
268
+		);
269
+		EE_Registry::instance()->load_file(
270
+			EE_CAFF_PATH,
271
+			'EE_Caf_Messages',
272
+			'class',
273
+			[],
274
+			false
275
+		);
276
+		// caffeinated_init__complete hook
277
+		do_action('AHEE__EE_Brewing_Regular__caffeinated_init__complete');
278
+	}
279
+
280
+
281
+	public function enqueue_caffeinated_scripts()
282
+	{
283
+		// sound of crickets...
284
+	}
285
+
286
+
287
+	/**
288
+	 * callbacks below here
289
+	 *
290
+	 * @param array $taxonomy_array
291
+	 * @return array
292
+	 */
293
+	public function filter_taxonomies(array $taxonomy_array)
294
+	{
295
+		$taxonomy_array['espresso_venue_categories']['args']['show_in_nav_menus'] = true;
296
+		return $taxonomy_array;
297
+	}
298
+
299
+
300
+	/**
301
+	 * @param array $cpt_array
302
+	 * @return mixed
303
+	 */
304
+	public function filter_cpts(array $cpt_array)
305
+	{
306
+		$cpt_array['espresso_venues']['args']['show_in_nav_menus'] = true;
307
+		return $cpt_array;
308
+	}
309
+
310
+
311
+	/**
312
+	 * @param array $menuitems
313
+	 * @return array
314
+	 */
315
+	public function nav_metabox_items(array $menuitems)
316
+	{
317
+		$menuitems[] = [
318
+			'title'       => esc_html__('Venue List', 'event_espresso'),
319
+			'url'         => get_post_type_archive_link('espresso_venues'),
320
+			'description' => esc_html__('Archive page for all venues.', 'event_espresso'),
321
+		];
322
+		return $menuitems;
323
+	}
324
+
325
+
326
+	/**
327
+	 * Gets the injected table analyzer, or throws an exception
328
+	 *
329
+	 * @return TableAnalysis
330
+	 * @throws \EE_Error
331
+	 */
332
+	protected function _get_table_analysis()
333
+	{
334
+		if ($this->_table_analysis instanceof TableAnalysis) {
335
+			return $this->_table_analysis;
336
+		} else {
337
+			throw new \EE_Error(
338
+				sprintf(
339
+					esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
340
+					get_class($this)
341
+				)
342
+			);
343
+		}
344
+	}
345 345
 }
346 346
 
347 347
 
348 348
 $brewing = new EE_Brewing_Regular(
349
-    EE_Registry::instance()->create('TableAnalysis', [], true)
349
+	EE_Registry::instance()->create('TableAnalysis', [], true)
350 350
 );
Please login to merge, or discard this patch.
core/libraries/messages/validators/EE_Messages_Validator.core.php 2 patches
Indentation   +622 added lines, -622 removed lines patch added patch discarded remove patch
@@ -17,626 +17,626 @@
 block discarded – undo
17 17
 {
18 18
 
19 19
 
20
-    /**
21
-     * These properties just hold the name for the Messenger and Message Type (defined by child classes).
22
-     * These are used for retrieving objects etc.
23
-     *
24
-     * @var string
25
-     */
26
-    protected $_m_name;
27
-
28
-    protected $_mt_name;
29
-
30
-
31
-    /**
32
-     * This will hold any error messages from the validation process.
33
-     * The _errors property holds an associative array of error messages
34
-     * listing the field as the key and the message as the value.
35
-     *
36
-     * @var array()
37
-     */
38
-    private $_errors = [];
39
-
40
-
41
-    /**
42
-     * holds an array of fields being validated
43
-     *
44
-     * @var array
45
-     */
46
-    protected $_fields;
47
-
48
-
49
-    /**
50
-     * this will hold the incoming context
51
-     *
52
-     * @var string
53
-     */
54
-    protected $_context;
55
-
56
-
57
-    /**
58
-     * this holds an array of fields and the relevant validation information
59
-     * that the incoming fields data get validated against.
60
-     * This gets setup in the _set_props() method.
61
-     *
62
-     * @var array
63
-     */
64
-    protected $_validators;
65
-
66
-
67
-    /**
68
-     * holds the messenger object
69
-     *
70
-     * @var object
71
-     */
72
-    protected $_messenger;
73
-
74
-
75
-    /**
76
-     * holds the message type object
77
-     *
78
-     * @var object
79
-     */
80
-    protected $_message_type;
81
-
82
-
83
-    /**
84
-     * will hold any valid_shortcode modifications made by the _modify_validator() method.
85
-     *
86
-     * @var array
87
-     */
88
-    protected $_valid_shortcodes_modifier;
89
-
90
-
91
-    /**
92
-     * There may be times where a message type wants to include a shortcode group but exclude specific
93
-     * shortcodes.  If that's the case then it can set this property as an array of shortcodes to exclude and
94
-     * they will not be allowed.
95
-     * Array should be indexed by field and values are an array of specific shortcodes to exclude.
96
-     *
97
-     * @var array
98
-     */
99
-    protected $_specific_shortcode_excludes = [];
100
-
101
-
102
-    /**
103
-     * Runs the validator using the incoming fields array as the fields/values to check.
104
-     *
105
-     * @param array $fields The fields sent by the EEM object.
106
-     * @param       $context
107
-     * @throws EE_Error
108
-     * @throws ReflectionException
109
-     */
110
-    public function __construct($fields, $context)
111
-    {
112
-        // check that _m_name and _mt_name have been set by child class otherwise we get out.
113
-        if (empty($this->_m_name) || empty($this->_mt_name)) {
114
-            throw new EE_Error(
115
-                esc_html__(
116
-                    'EE_Messages_Validator child classes MUST set the $_m_name and $_mt_name property.  Check that the child class is doing this',
117
-                    'event_espresso'
118
-                )
119
-            );
120
-        }
121
-        $this->_fields  = $fields;
122
-        $this->_context = $context;
123
-
124
-        // load messenger and message_type objects and the related shortcode objects.
125
-        $this->_load_objects();
126
-
127
-
128
-        // modify any messenger/message_type specific validation instructions.  This is what child classes define.
129
-        $this->_modify_validator();
130
-
131
-
132
-        // let's set validators property
133
-        $this->_set_validators();
134
-    }
135
-
136
-
137
-    /**
138
-     * Child classes instantiate this and use it to modify the _validator_config array property
139
-     * for the messenger using messengers set_validate_config() method.
140
-     * This is so we can specify specific validation instructions for a messenger/message_type combo
141
-     * that aren't handled by the defaults setup in the messenger.
142
-     *
143
-     * @abstract
144
-     * @return void
145
-     */
146
-    abstract protected function _modify_validator();
147
-
148
-
149
-    /**
150
-     * loads all objects used by validator
151
-     *
152
-     * @throws EE_Error
153
-     */
154
-    private function _load_objects()
155
-    {
156
-        // load messenger
157
-        $messenger = ucwords(str_replace('_', ' ', $this->_m_name));
158
-        $messenger = str_replace(' ', '_', $messenger);
159
-        $messenger = 'EE_' . $messenger . '_messenger';
160
-
161
-        if (! class_exists($messenger)) {
162
-            throw new EE_Error(
163
-                sprintf(
164
-                    esc_html__('There is no messenger class for the given string (%s)', 'event_espresso'),
165
-                    $this->_m_name
166
-                )
167
-            );
168
-        }
169
-
170
-        $this->_messenger = new $messenger();
171
-
172
-        // load message type
173
-        $message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
174
-        $message_type = str_replace(' ', '_', $message_type);
175
-        $message_type = 'EE_' . $message_type . '_message_type';
176
-
177
-        if (! class_exists($message_type)) {
178
-            throw new EE_Error(
179
-                sprintf(
180
-                    esc_html__('There is no message type class for the given string (%s)', 'event_espresso'),
181
-                    $this->_mt_name
182
-                )
183
-            );
184
-        }
185
-
186
-        $this->_message_type = new $message_type();
187
-    }
188
-
189
-
190
-    /**
191
-     * used to set the $_validators property
192
-     *
193
-     * @return void
194
-     * @throws ReflectionException
195
-     */
196
-    private function _set_validators()
197
-    {
198
-        // let's get all valid shortcodes from mt and message type
199
-        // (messenger will have its set in the _validator_config property for the messenger)
200
-        $mt_codes = $this->_message_type->get_valid_shortcodes();
201
-
202
-
203
-        // get messenger validator_config
204
-        $msgr_validator = $this->_messenger->get_validator_config();
205
-
206
-
207
-        // we only want the valid shortcodes for the given context!
208
-        $context  = $this->_context;
209
-        $mt_codes = $mt_codes[ $context ];
210
-
211
-        // in this first loop we're just getting all shortcode group indexes from the msgr_validator
212
-        // into a single array (so we can get the appropriate shortcode objects for the groups)
213
-        $shortcode_groups = $mt_codes;
214
-        $groups_per_field = [];
215
-
216
-        foreach ($msgr_validator as $field => $config) {
217
-            if (empty($config) || ! isset($config['shortcodes'])) {
218
-                continue;
219
-            }  //Nothing to see here.
220
-            $groups_per_field[ $field ] = array_intersect($config['shortcodes'], $mt_codes);
221
-            $shortcode_groups           = array_merge($config['shortcodes'], $shortcode_groups);
222
-        }
223
-
224
-        $shortcode_groups = array_unique($shortcode_groups);
225
-
226
-        // okay now we've got our groups.
227
-        // Let's get the codes from the objects into an array indexed by group for easy retrieval later.
228
-        $codes_from_objs = [];
229
-
230
-        foreach ($shortcode_groups as $group) {
231
-            $ref       = ucwords(str_replace('_', ' ', $group));
232
-            $ref       = str_replace(' ', '_', $ref);
233
-            $classname = 'EE_' . $ref . '_Shortcodes';
234
-            if (class_exists($classname)) {
235
-                $a                         = new ReflectionClass($classname);
236
-                $obj                       = $a->newInstance();
237
-                $codes_from_objs[ $group ] = $obj->get_shortcodes();
238
-            }
239
-        }
240
-
241
-
242
-        // let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
243
-        $final_mt_codes = [];
244
-        foreach ($mt_codes as $group) {
245
-            $final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[ $group ]);
246
-        }
247
-
248
-        $mt_codes = $final_mt_codes;
249
-
250
-
251
-        // k now in this next loop we're going to loop through $msgr_validator again
252
-        // and setup the _validators property from the data we've setup so far.
253
-        foreach ($msgr_validator as $field => $config) {
254
-            // if required shortcode is not in our list of codes for the given field, then we skip this field.
255
-            $required = isset($config['required'])
256
-                ? array_intersect($config['required'], array_keys($mt_codes))
257
-                : true;
258
-            if (empty($required)) {
259
-                continue;
260
-            }
261
-
262
-            // If we have an override then we use it to indicate the codes we want.
263
-            if (isset($this->_valid_shortcodes_modifier[ $context ][ $field ])) {
264
-                $this->_validators[ $field ]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
265
-                    $this->_valid_shortcodes_modifier[ $context ][ $field ],
266
-                    $codes_from_objs
267
-                );
268
-            } elseif (isset($groups_per_field[ $field ])) {
269
-                // we have specific shortcodes for a field so we need to use them
270
-                $this->_validators[ $field ]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
271
-                    $groups_per_field[ $field ],
272
-                    $codes_from_objs
273
-                );
274
-            } elseif (empty($config)) {
275
-                // no config so we're assuming we're just going to use the shortcodes from the message type context
276
-                $this->_validators[ $field ]['shortcodes'] = $mt_codes;
277
-            } elseif (isset($config['specific_shortcodes'])) {
278
-                // we have specific shortcodes so we need to use them
279
-                $this->_validators[ $field ]['shortcodes'] = $config['specific_shortcodes'];
280
-            } else {
281
-                // otherwise the shortcodes are what is set by the messenger for that field
282
-                foreach ($config['shortcodes'] as $group) {
283
-                    $this->_validators[ $field ]['shortcodes'] = isset($this->_validators[ $field ]['shortcodes'])
284
-                        ? array_merge($this->_validators[ $field ]['shortcodes'], $codes_from_objs[ $group ])
285
-                        : $codes_from_objs[ $group ];
286
-                }
287
-            }
288
-
289
-            // now let's just make sure that any excluded specific shortcodes are removed.
290
-            $specific_excludes = $this->get_specific_shortcode_excludes();
291
-            if (isset($specific_excludes[ $field ])) {
292
-                foreach ($specific_excludes[ $field ] as $sex) {
293
-                    if (isset($this->_validators[ $field ]['shortcodes'][ $sex ])) {
294
-                        unset($this->_validators[ $field ]['shortcodes'][ $sex ]);
295
-                    }
296
-                }
297
-            }
298
-
299
-            // hey! don't forget to include the type if present!
300
-            $this->_validators[ $field ]['type'] =
301
-                isset($config['type'])
302
-                    ? $config['type']
303
-                    : null;
304
-        }
305
-    }
306
-
307
-
308
-    /**
309
-     * This just returns the validators property that contains information
310
-     * about the various shortcodes and their availability with each field
311
-     *
312
-     * @return array
313
-     */
314
-    public function get_validators()
315
-    {
316
-        return $this->_validators;
317
-    }
318
-
319
-
320
-    /**
321
-     * This simply returns the specific shortcode_excludes property that is set.
322
-     *
323
-     * @return array
324
-     * @since 4.5.0
325
-     */
326
-    public function get_specific_shortcode_excludes()
327
-    {
328
-        // specific validator filter
329
-        $shortcode_excludes = apply_filters(
330
-            'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
331
-            $this->_specific_shortcode_excludes,
332
-            $this->_context
333
-        );
334
-        // global filter
335
-        return apply_filters(
336
-            'FHEE__EE_Messages_Validator__get_specific_shortcode_excludes',
337
-            $shortcode_excludes,
338
-            $this->_context,
339
-            $this
340
-        );
341
-    }
342
-
343
-
344
-    /**
345
-     * This is the main method that handles validation
346
-     * What it does is loop through the _fields (the ones that get validated)
347
-     * and checks them against the shortcodes array for the field and the 'type' indicated by the
348
-     *
349
-     * @return array|bool if errors present we return the array otherwise true
350
-     */
351
-    public function validate()
352
-    {
353
-        // some defaults
354
-        $template_fields = $this->_messenger->get_template_fields();
355
-        // loop through the fields and check!
356
-        foreach ($this->_fields as $field => $value) {
357
-            $this->_errors[ $field ] = [];
358
-            $err_msg                 = '';
359
-            $field_label             = '';
360
-            // if field is not present in the _validators array then we continue
361
-            if (! isset($this->_validators[ $field ])) {
362
-                unset($this->_errors[ $field ]);
363
-                continue;
364
-            }
365
-
366
-            // get the translated field label!
367
-            // first check if it's in the main fields list
368
-            if (isset($template_fields[ $field ])) {
369
-                // most likely the field is found in the 'extra' array.
370
-                $field_label = ! empty($template_fields[ $field ])
371
-                    ? $template_fields[ $field ]['label']
372
-                    : $field;
373
-            }
374
-
375
-            // if field label is empty OR is equal to the current field
376
-            // then we need to loop through the 'extra' fields in the template_fields config (if present)
377
-            if (isset($template_fields['extra']) && (empty($field_label) || $field_label === $field)) {
378
-                foreach ($template_fields['extra'] as $main_field => $secondary_field) {
379
-                    foreach ($secondary_field as $name => $values) {
380
-                        if ($name === $field) {
381
-                            $field_label = $values['label'];
382
-                        }
383
-
384
-                        // if we've got a 'main' secondary field, let's see if that matches what field we're on
385
-                        // which means it contains the label for this field.
386
-                        if ($name === 'main' && $main_field === $field_label) {
387
-                            $field_label = $values['label'];
388
-                        }
389
-                    }
390
-                }
391
-            }
392
-
393
-            // field is present. Let's validate shortcodes first (but only if shortcodes present).
394
-            if (
395
-                isset($this->_validators[ $field ]['shortcodes'])
396
-                && ! empty($this->_validators[ $field ]['shortcodes'])
397
-            ) {
398
-                $invalid_shortcodes = $this->_invalid_shortcodes($value, $this->_validators[ $field ]['shortcodes']);
399
-                // if true then that means there is a returned error message
400
-                // that we'll need to add to the _errors array for this field.
401
-                if ($invalid_shortcodes) {
402
-                    $v_s     = array_keys($this->_validators[ $field ]['shortcodes']);
403
-                    $err_msg = sprintf(
404
-                        esc_html__(
405
-                            '%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
406
-                            'event_espresso'
407
-                        ),
408
-                        '<strong>' . $field_label . '</strong>',
409
-                        $invalid_shortcodes,
410
-                        '<p>',
411
-                        '</p >'
412
-                    );
413
-                    $err_msg .= sprintf(
414
-                        esc_html__('%2$sValid shortcodes for this field are: %1$s%3$s', 'event_espresso'),
415
-                        implode(', ', $v_s),
416
-                        '<strong>',
417
-                        '</strong>'
418
-                    );
419
-                }
420
-            }
421
-
422
-            // if there's a "type" to be validated then let's do that too.
423
-            if (isset($this->_validators[ $field ]['type']) && ! empty($this->_validators[ $field ]['type'])) {
424
-                switch ($this->_validators[ $field ]['type']) {
425
-                    case 'number':
426
-                        if (! is_numeric($value)) {
427
-                            $err_msg .= sprintf(
428
-                                esc_html__(
429
-                                    '%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
430
-                                    'event_espresso'
431
-                                ),
432
-                                $field_label,
433
-                                $value,
434
-                                '<p>',
435
-                                '</p >'
436
-                            );
437
-                        }
438
-                        break;
439
-                    case 'email':
440
-                        $valid_email = $this->_validate_email($value);
441
-                        if (! $valid_email) {
442
-                            $err_msg .= htmlentities(
443
-                                sprintf(
444
-                                    esc_html__(
445
-                                        'The %1$s field has at least one string that is not a valid email address record.  Valid emails are in the format: "Name <[email protected]>" or "[email protected]" and multiple emails can be separated by a comma.',
446
-                                        'event_espresso'
447
-                                    ),
448
-                                    $field_label
449
-                                )
450
-                            );
451
-                        }
452
-                        break;
453
-                    default:
454
-                        break;
455
-                }
456
-            }
457
-
458
-            // if $err_msg isn't empty let's setup the _errors array for this field.
459
-            if (! empty($err_msg)) {
460
-                $this->_errors[ $field ]['msg'] = $err_msg;
461
-            } else {
462
-                unset($this->_errors[ $field ]);
463
-            }
464
-        }
465
-
466
-        // if we have ANY errors, then we want to make sure we return the values
467
-        // for ALL the fields so the user doesn't have to retype them all.
468
-        if (! empty($this->_errors)) {
469
-            foreach ($this->_fields as $field => $value) {
470
-                $this->_errors[ $field ]['value'] = stripslashes($value);
471
-            }
472
-        }
473
-
474
-        // return any errors or just TRUE if everything validates
475
-        return empty($this->_errors)
476
-            ? true
477
-            : $this->_errors;
478
-    }
479
-
480
-
481
-    /**
482
-     * Reassembles and returns an array of valid shortcodes
483
-     * given the array of groups and array of shortcodes indexed by group.
484
-     *
485
-     * @param array $groups          array of shortcode groups that we want shortcodes for
486
-     * @param array $codes_from_objs All the codes available.
487
-     * @return array                   an array of actual shortcodes (that will be used for validation).
488
-     */
489
-    private function _reassemble_valid_shortcodes_from_group($groups, $codes_from_objs)
490
-    {
491
-        $shortcodes = [];
492
-        foreach ($groups as $group) {
493
-            $shortcodes = array_merge($shortcodes, $codes_from_objs[ $group ]);
494
-        }
495
-        return $shortcodes;
496
-    }
497
-
498
-
499
-    /**
500
-     * Validates a string against a list of accepted shortcodes
501
-     * This function takes in an array of shortcodes
502
-     * and makes sure that the given string ONLY contains shortcodes in that array.
503
-     *
504
-     * @param string $value            string to evaluate
505
-     * @param array  $valid_shortcodes array of shortcodes that are acceptable.
506
-     * @return bool|string  return either a list of invalid shortcodes OR false if the shortcodes validate.
507
-     */
508
-    protected function _invalid_shortcodes($value, $valid_shortcodes)
509
-    {
510
-        // first we need to go through the string and get the shortcodes in the string
511
-        preg_match_all('/(\[.+?\])/', $value, $matches);
512
-        $incoming_shortcodes = (array) $matches[0];
513
-
514
-        // get a diff of the shortcodes in the string vs the valid shortcodes
515
-        $diff = array_diff($incoming_shortcodes, array_keys($valid_shortcodes));
516
-
517
-        // we need to account for custom codes so let's loop through the diff and remove any of those type of codes
518
-        foreach ($diff as $ind => $code) {
519
-            if (preg_match('/(\[[A-Za-z0-9\_]+_\*)/', $code)) {
520
-                // strip the shortcode so we just have the BASE string (i.e. [ANSWER_*] )
521
-                $dynamic_sc = preg_replace('/(_\*+.+)/', '_*]', $code);
522
-                // does this exist in the $valid_shortcodes?  If so then unset.
523
-                if (isset($valid_shortcodes[ $dynamic_sc ])) {
524
-                    unset($diff[ $ind ]);
525
-                }
526
-            }
527
-        }
528
-
529
-        if (empty($diff)) {
530
-            return false;
531
-        } //there is no diff, we have no invalid shortcodes, so return
532
-
533
-        // made it here? then let's assemble the error message
534
-        $invalid_shortcodes = implode('</strong>,<strong>', $diff);
535
-        return '<strong>' . $invalid_shortcodes . '</strong>';
536
-    }
537
-
538
-
539
-    /**
540
-     * Validates an incoming string and makes sure we have valid emails in the string.
541
-     *
542
-     * @param string $value incoming value to validate
543
-     * @return bool        true if the string validates, false if it doesn't
544
-     */
545
-    protected function _validate_email($value)
546
-    {
547
-        $validate = true;
548
-        $or_val   = $value;
549
-
550
-        // empty strings will validate because this is how a message template
551
-        // for a particular context can be "turned off" (if there is no email then no message)
552
-        if (empty($value)) {
553
-            return $validate;
554
-        }
555
-
556
-        // first determine if there ARE any shortcodes.
557
-        // If there are shortcodes and then later we find that there were no other valid emails
558
-        // but the field isn't empty...
559
-        // that means we've got extra commas that were left after stripping out shortcodes so probably still valid.
560
-        $has_shortcodes = preg_match('/(\[.+?\])/', $value);
561
-
562
-        // first we need to strip out all the shortcodes!
563
-        $value = preg_replace('/(\[.+?\])/', '', $value);
564
-
565
-        // if original value is not empty and new value is, then we've parsed out a shortcode
566
-        // and we now have an empty string which DOES validate.
567
-        // We also validate complete empty field for email because
568
-        // its possible that this message is being "turned off" for a particular context
569
-
570
-
571
-        if (! empty($or_val) && empty($value)) {
572
-            return $validate;
573
-        }
574
-
575
-        // trim any commas from beginning and end of string ( after whitespace trimmed );
576
-        $value = trim(trim($value), ',');
577
-
578
-
579
-        // next we need to split up the string if its comma delimited.
580
-        $emails = explode(',', $value);
581
-        $empty  = false; // used to indicate that there is an empty comma.
582
-        // now let's loop through the emails and do our checks
583
-        foreach ($emails as $email) {
584
-            if (empty($email)) {
585
-                $empty = true;
586
-                continue;
587
-            }
588
-
589
-            // trim whitespace
590
-            $email = trim($email);
591
-            // either its of type "[email protected]", or its of type "fname lname <[email protected]>"
592
-            if (is_email($email)) {
593
-                continue;
594
-            }
595
-            $matches  = [];
596
-            $validate = (bool) preg_match('/(.*)<(.+)>/', $email, $matches);
597
-            if ($validate && is_email($matches[2])) {
598
-                continue;
599
-            }
600
-            return false;
601
-        }
602
-
603
-        return $empty && ! $has_shortcodes
604
-            ? false
605
-            : $validate;
606
-    }
607
-
608
-
609
-    /**
610
-     * Magic getter
611
-     * Using this to provide back compat with add-ons referencing deprecated properties.
612
-     *
613
-     * @param string $property Property being requested
614
-     * @return mixed
615
-     * @throws Exception
616
-     */
617
-    public function __get($property)
618
-    {
619
-        $expected_properties_map = [
620
-            /**
621
-             * @deprecated 4.9.0
622
-             */
623
-            '_MSGR'   => '_messenger',
624
-            /**
625
-             * @deprecated 4.9.0
626
-             */
627
-            '_MSGTYP' => '_message_type',
628
-        ];
629
-
630
-        if (isset($expected_properties_map[ $property ])) {
631
-            return $this->{$expected_properties_map[ $property ]};
632
-        }
633
-
634
-        throw new Exception(
635
-            sprintf(
636
-                esc_html__('The property %1$s being requested on %2$s does not exist', 'event_espresso'),
637
-                $property,
638
-                get_class($this)
639
-            )
640
-        );
641
-    }
20
+	/**
21
+	 * These properties just hold the name for the Messenger and Message Type (defined by child classes).
22
+	 * These are used for retrieving objects etc.
23
+	 *
24
+	 * @var string
25
+	 */
26
+	protected $_m_name;
27
+
28
+	protected $_mt_name;
29
+
30
+
31
+	/**
32
+	 * This will hold any error messages from the validation process.
33
+	 * The _errors property holds an associative array of error messages
34
+	 * listing the field as the key and the message as the value.
35
+	 *
36
+	 * @var array()
37
+	 */
38
+	private $_errors = [];
39
+
40
+
41
+	/**
42
+	 * holds an array of fields being validated
43
+	 *
44
+	 * @var array
45
+	 */
46
+	protected $_fields;
47
+
48
+
49
+	/**
50
+	 * this will hold the incoming context
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $_context;
55
+
56
+
57
+	/**
58
+	 * this holds an array of fields and the relevant validation information
59
+	 * that the incoming fields data get validated against.
60
+	 * This gets setup in the _set_props() method.
61
+	 *
62
+	 * @var array
63
+	 */
64
+	protected $_validators;
65
+
66
+
67
+	/**
68
+	 * holds the messenger object
69
+	 *
70
+	 * @var object
71
+	 */
72
+	protected $_messenger;
73
+
74
+
75
+	/**
76
+	 * holds the message type object
77
+	 *
78
+	 * @var object
79
+	 */
80
+	protected $_message_type;
81
+
82
+
83
+	/**
84
+	 * will hold any valid_shortcode modifications made by the _modify_validator() method.
85
+	 *
86
+	 * @var array
87
+	 */
88
+	protected $_valid_shortcodes_modifier;
89
+
90
+
91
+	/**
92
+	 * There may be times where a message type wants to include a shortcode group but exclude specific
93
+	 * shortcodes.  If that's the case then it can set this property as an array of shortcodes to exclude and
94
+	 * they will not be allowed.
95
+	 * Array should be indexed by field and values are an array of specific shortcodes to exclude.
96
+	 *
97
+	 * @var array
98
+	 */
99
+	protected $_specific_shortcode_excludes = [];
100
+
101
+
102
+	/**
103
+	 * Runs the validator using the incoming fields array as the fields/values to check.
104
+	 *
105
+	 * @param array $fields The fields sent by the EEM object.
106
+	 * @param       $context
107
+	 * @throws EE_Error
108
+	 * @throws ReflectionException
109
+	 */
110
+	public function __construct($fields, $context)
111
+	{
112
+		// check that _m_name and _mt_name have been set by child class otherwise we get out.
113
+		if (empty($this->_m_name) || empty($this->_mt_name)) {
114
+			throw new EE_Error(
115
+				esc_html__(
116
+					'EE_Messages_Validator child classes MUST set the $_m_name and $_mt_name property.  Check that the child class is doing this',
117
+					'event_espresso'
118
+				)
119
+			);
120
+		}
121
+		$this->_fields  = $fields;
122
+		$this->_context = $context;
123
+
124
+		// load messenger and message_type objects and the related shortcode objects.
125
+		$this->_load_objects();
126
+
127
+
128
+		// modify any messenger/message_type specific validation instructions.  This is what child classes define.
129
+		$this->_modify_validator();
130
+
131
+
132
+		// let's set validators property
133
+		$this->_set_validators();
134
+	}
135
+
136
+
137
+	/**
138
+	 * Child classes instantiate this and use it to modify the _validator_config array property
139
+	 * for the messenger using messengers set_validate_config() method.
140
+	 * This is so we can specify specific validation instructions for a messenger/message_type combo
141
+	 * that aren't handled by the defaults setup in the messenger.
142
+	 *
143
+	 * @abstract
144
+	 * @return void
145
+	 */
146
+	abstract protected function _modify_validator();
147
+
148
+
149
+	/**
150
+	 * loads all objects used by validator
151
+	 *
152
+	 * @throws EE_Error
153
+	 */
154
+	private function _load_objects()
155
+	{
156
+		// load messenger
157
+		$messenger = ucwords(str_replace('_', ' ', $this->_m_name));
158
+		$messenger = str_replace(' ', '_', $messenger);
159
+		$messenger = 'EE_' . $messenger . '_messenger';
160
+
161
+		if (! class_exists($messenger)) {
162
+			throw new EE_Error(
163
+				sprintf(
164
+					esc_html__('There is no messenger class for the given string (%s)', 'event_espresso'),
165
+					$this->_m_name
166
+				)
167
+			);
168
+		}
169
+
170
+		$this->_messenger = new $messenger();
171
+
172
+		// load message type
173
+		$message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
174
+		$message_type = str_replace(' ', '_', $message_type);
175
+		$message_type = 'EE_' . $message_type . '_message_type';
176
+
177
+		if (! class_exists($message_type)) {
178
+			throw new EE_Error(
179
+				sprintf(
180
+					esc_html__('There is no message type class for the given string (%s)', 'event_espresso'),
181
+					$this->_mt_name
182
+				)
183
+			);
184
+		}
185
+
186
+		$this->_message_type = new $message_type();
187
+	}
188
+
189
+
190
+	/**
191
+	 * used to set the $_validators property
192
+	 *
193
+	 * @return void
194
+	 * @throws ReflectionException
195
+	 */
196
+	private function _set_validators()
197
+	{
198
+		// let's get all valid shortcodes from mt and message type
199
+		// (messenger will have its set in the _validator_config property for the messenger)
200
+		$mt_codes = $this->_message_type->get_valid_shortcodes();
201
+
202
+
203
+		// get messenger validator_config
204
+		$msgr_validator = $this->_messenger->get_validator_config();
205
+
206
+
207
+		// we only want the valid shortcodes for the given context!
208
+		$context  = $this->_context;
209
+		$mt_codes = $mt_codes[ $context ];
210
+
211
+		// in this first loop we're just getting all shortcode group indexes from the msgr_validator
212
+		// into a single array (so we can get the appropriate shortcode objects for the groups)
213
+		$shortcode_groups = $mt_codes;
214
+		$groups_per_field = [];
215
+
216
+		foreach ($msgr_validator as $field => $config) {
217
+			if (empty($config) || ! isset($config['shortcodes'])) {
218
+				continue;
219
+			}  //Nothing to see here.
220
+			$groups_per_field[ $field ] = array_intersect($config['shortcodes'], $mt_codes);
221
+			$shortcode_groups           = array_merge($config['shortcodes'], $shortcode_groups);
222
+		}
223
+
224
+		$shortcode_groups = array_unique($shortcode_groups);
225
+
226
+		// okay now we've got our groups.
227
+		// Let's get the codes from the objects into an array indexed by group for easy retrieval later.
228
+		$codes_from_objs = [];
229
+
230
+		foreach ($shortcode_groups as $group) {
231
+			$ref       = ucwords(str_replace('_', ' ', $group));
232
+			$ref       = str_replace(' ', '_', $ref);
233
+			$classname = 'EE_' . $ref . '_Shortcodes';
234
+			if (class_exists($classname)) {
235
+				$a                         = new ReflectionClass($classname);
236
+				$obj                       = $a->newInstance();
237
+				$codes_from_objs[ $group ] = $obj->get_shortcodes();
238
+			}
239
+		}
240
+
241
+
242
+		// let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
243
+		$final_mt_codes = [];
244
+		foreach ($mt_codes as $group) {
245
+			$final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[ $group ]);
246
+		}
247
+
248
+		$mt_codes = $final_mt_codes;
249
+
250
+
251
+		// k now in this next loop we're going to loop through $msgr_validator again
252
+		// and setup the _validators property from the data we've setup so far.
253
+		foreach ($msgr_validator as $field => $config) {
254
+			// if required shortcode is not in our list of codes for the given field, then we skip this field.
255
+			$required = isset($config['required'])
256
+				? array_intersect($config['required'], array_keys($mt_codes))
257
+				: true;
258
+			if (empty($required)) {
259
+				continue;
260
+			}
261
+
262
+			// If we have an override then we use it to indicate the codes we want.
263
+			if (isset($this->_valid_shortcodes_modifier[ $context ][ $field ])) {
264
+				$this->_validators[ $field ]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
265
+					$this->_valid_shortcodes_modifier[ $context ][ $field ],
266
+					$codes_from_objs
267
+				);
268
+			} elseif (isset($groups_per_field[ $field ])) {
269
+				// we have specific shortcodes for a field so we need to use them
270
+				$this->_validators[ $field ]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
271
+					$groups_per_field[ $field ],
272
+					$codes_from_objs
273
+				);
274
+			} elseif (empty($config)) {
275
+				// no config so we're assuming we're just going to use the shortcodes from the message type context
276
+				$this->_validators[ $field ]['shortcodes'] = $mt_codes;
277
+			} elseif (isset($config['specific_shortcodes'])) {
278
+				// we have specific shortcodes so we need to use them
279
+				$this->_validators[ $field ]['shortcodes'] = $config['specific_shortcodes'];
280
+			} else {
281
+				// otherwise the shortcodes are what is set by the messenger for that field
282
+				foreach ($config['shortcodes'] as $group) {
283
+					$this->_validators[ $field ]['shortcodes'] = isset($this->_validators[ $field ]['shortcodes'])
284
+						? array_merge($this->_validators[ $field ]['shortcodes'], $codes_from_objs[ $group ])
285
+						: $codes_from_objs[ $group ];
286
+				}
287
+			}
288
+
289
+			// now let's just make sure that any excluded specific shortcodes are removed.
290
+			$specific_excludes = $this->get_specific_shortcode_excludes();
291
+			if (isset($specific_excludes[ $field ])) {
292
+				foreach ($specific_excludes[ $field ] as $sex) {
293
+					if (isset($this->_validators[ $field ]['shortcodes'][ $sex ])) {
294
+						unset($this->_validators[ $field ]['shortcodes'][ $sex ]);
295
+					}
296
+				}
297
+			}
298
+
299
+			// hey! don't forget to include the type if present!
300
+			$this->_validators[ $field ]['type'] =
301
+				isset($config['type'])
302
+					? $config['type']
303
+					: null;
304
+		}
305
+	}
306
+
307
+
308
+	/**
309
+	 * This just returns the validators property that contains information
310
+	 * about the various shortcodes and their availability with each field
311
+	 *
312
+	 * @return array
313
+	 */
314
+	public function get_validators()
315
+	{
316
+		return $this->_validators;
317
+	}
318
+
319
+
320
+	/**
321
+	 * This simply returns the specific shortcode_excludes property that is set.
322
+	 *
323
+	 * @return array
324
+	 * @since 4.5.0
325
+	 */
326
+	public function get_specific_shortcode_excludes()
327
+	{
328
+		// specific validator filter
329
+		$shortcode_excludes = apply_filters(
330
+			'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
331
+			$this->_specific_shortcode_excludes,
332
+			$this->_context
333
+		);
334
+		// global filter
335
+		return apply_filters(
336
+			'FHEE__EE_Messages_Validator__get_specific_shortcode_excludes',
337
+			$shortcode_excludes,
338
+			$this->_context,
339
+			$this
340
+		);
341
+	}
342
+
343
+
344
+	/**
345
+	 * This is the main method that handles validation
346
+	 * What it does is loop through the _fields (the ones that get validated)
347
+	 * and checks them against the shortcodes array for the field and the 'type' indicated by the
348
+	 *
349
+	 * @return array|bool if errors present we return the array otherwise true
350
+	 */
351
+	public function validate()
352
+	{
353
+		// some defaults
354
+		$template_fields = $this->_messenger->get_template_fields();
355
+		// loop through the fields and check!
356
+		foreach ($this->_fields as $field => $value) {
357
+			$this->_errors[ $field ] = [];
358
+			$err_msg                 = '';
359
+			$field_label             = '';
360
+			// if field is not present in the _validators array then we continue
361
+			if (! isset($this->_validators[ $field ])) {
362
+				unset($this->_errors[ $field ]);
363
+				continue;
364
+			}
365
+
366
+			// get the translated field label!
367
+			// first check if it's in the main fields list
368
+			if (isset($template_fields[ $field ])) {
369
+				// most likely the field is found in the 'extra' array.
370
+				$field_label = ! empty($template_fields[ $field ])
371
+					? $template_fields[ $field ]['label']
372
+					: $field;
373
+			}
374
+
375
+			// if field label is empty OR is equal to the current field
376
+			// then we need to loop through the 'extra' fields in the template_fields config (if present)
377
+			if (isset($template_fields['extra']) && (empty($field_label) || $field_label === $field)) {
378
+				foreach ($template_fields['extra'] as $main_field => $secondary_field) {
379
+					foreach ($secondary_field as $name => $values) {
380
+						if ($name === $field) {
381
+							$field_label = $values['label'];
382
+						}
383
+
384
+						// if we've got a 'main' secondary field, let's see if that matches what field we're on
385
+						// which means it contains the label for this field.
386
+						if ($name === 'main' && $main_field === $field_label) {
387
+							$field_label = $values['label'];
388
+						}
389
+					}
390
+				}
391
+			}
392
+
393
+			// field is present. Let's validate shortcodes first (but only if shortcodes present).
394
+			if (
395
+				isset($this->_validators[ $field ]['shortcodes'])
396
+				&& ! empty($this->_validators[ $field ]['shortcodes'])
397
+			) {
398
+				$invalid_shortcodes = $this->_invalid_shortcodes($value, $this->_validators[ $field ]['shortcodes']);
399
+				// if true then that means there is a returned error message
400
+				// that we'll need to add to the _errors array for this field.
401
+				if ($invalid_shortcodes) {
402
+					$v_s     = array_keys($this->_validators[ $field ]['shortcodes']);
403
+					$err_msg = sprintf(
404
+						esc_html__(
405
+							'%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
406
+							'event_espresso'
407
+						),
408
+						'<strong>' . $field_label . '</strong>',
409
+						$invalid_shortcodes,
410
+						'<p>',
411
+						'</p >'
412
+					);
413
+					$err_msg .= sprintf(
414
+						esc_html__('%2$sValid shortcodes for this field are: %1$s%3$s', 'event_espresso'),
415
+						implode(', ', $v_s),
416
+						'<strong>',
417
+						'</strong>'
418
+					);
419
+				}
420
+			}
421
+
422
+			// if there's a "type" to be validated then let's do that too.
423
+			if (isset($this->_validators[ $field ]['type']) && ! empty($this->_validators[ $field ]['type'])) {
424
+				switch ($this->_validators[ $field ]['type']) {
425
+					case 'number':
426
+						if (! is_numeric($value)) {
427
+							$err_msg .= sprintf(
428
+								esc_html__(
429
+									'%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
430
+									'event_espresso'
431
+								),
432
+								$field_label,
433
+								$value,
434
+								'<p>',
435
+								'</p >'
436
+							);
437
+						}
438
+						break;
439
+					case 'email':
440
+						$valid_email = $this->_validate_email($value);
441
+						if (! $valid_email) {
442
+							$err_msg .= htmlentities(
443
+								sprintf(
444
+									esc_html__(
445
+										'The %1$s field has at least one string that is not a valid email address record.  Valid emails are in the format: "Name <[email protected]>" or "[email protected]" and multiple emails can be separated by a comma.',
446
+										'event_espresso'
447
+									),
448
+									$field_label
449
+								)
450
+							);
451
+						}
452
+						break;
453
+					default:
454
+						break;
455
+				}
456
+			}
457
+
458
+			// if $err_msg isn't empty let's setup the _errors array for this field.
459
+			if (! empty($err_msg)) {
460
+				$this->_errors[ $field ]['msg'] = $err_msg;
461
+			} else {
462
+				unset($this->_errors[ $field ]);
463
+			}
464
+		}
465
+
466
+		// if we have ANY errors, then we want to make sure we return the values
467
+		// for ALL the fields so the user doesn't have to retype them all.
468
+		if (! empty($this->_errors)) {
469
+			foreach ($this->_fields as $field => $value) {
470
+				$this->_errors[ $field ]['value'] = stripslashes($value);
471
+			}
472
+		}
473
+
474
+		// return any errors or just TRUE if everything validates
475
+		return empty($this->_errors)
476
+			? true
477
+			: $this->_errors;
478
+	}
479
+
480
+
481
+	/**
482
+	 * Reassembles and returns an array of valid shortcodes
483
+	 * given the array of groups and array of shortcodes indexed by group.
484
+	 *
485
+	 * @param array $groups          array of shortcode groups that we want shortcodes for
486
+	 * @param array $codes_from_objs All the codes available.
487
+	 * @return array                   an array of actual shortcodes (that will be used for validation).
488
+	 */
489
+	private function _reassemble_valid_shortcodes_from_group($groups, $codes_from_objs)
490
+	{
491
+		$shortcodes = [];
492
+		foreach ($groups as $group) {
493
+			$shortcodes = array_merge($shortcodes, $codes_from_objs[ $group ]);
494
+		}
495
+		return $shortcodes;
496
+	}
497
+
498
+
499
+	/**
500
+	 * Validates a string against a list of accepted shortcodes
501
+	 * This function takes in an array of shortcodes
502
+	 * and makes sure that the given string ONLY contains shortcodes in that array.
503
+	 *
504
+	 * @param string $value            string to evaluate
505
+	 * @param array  $valid_shortcodes array of shortcodes that are acceptable.
506
+	 * @return bool|string  return either a list of invalid shortcodes OR false if the shortcodes validate.
507
+	 */
508
+	protected function _invalid_shortcodes($value, $valid_shortcodes)
509
+	{
510
+		// first we need to go through the string and get the shortcodes in the string
511
+		preg_match_all('/(\[.+?\])/', $value, $matches);
512
+		$incoming_shortcodes = (array) $matches[0];
513
+
514
+		// get a diff of the shortcodes in the string vs the valid shortcodes
515
+		$diff = array_diff($incoming_shortcodes, array_keys($valid_shortcodes));
516
+
517
+		// we need to account for custom codes so let's loop through the diff and remove any of those type of codes
518
+		foreach ($diff as $ind => $code) {
519
+			if (preg_match('/(\[[A-Za-z0-9\_]+_\*)/', $code)) {
520
+				// strip the shortcode so we just have the BASE string (i.e. [ANSWER_*] )
521
+				$dynamic_sc = preg_replace('/(_\*+.+)/', '_*]', $code);
522
+				// does this exist in the $valid_shortcodes?  If so then unset.
523
+				if (isset($valid_shortcodes[ $dynamic_sc ])) {
524
+					unset($diff[ $ind ]);
525
+				}
526
+			}
527
+		}
528
+
529
+		if (empty($diff)) {
530
+			return false;
531
+		} //there is no diff, we have no invalid shortcodes, so return
532
+
533
+		// made it here? then let's assemble the error message
534
+		$invalid_shortcodes = implode('</strong>,<strong>', $diff);
535
+		return '<strong>' . $invalid_shortcodes . '</strong>';
536
+	}
537
+
538
+
539
+	/**
540
+	 * Validates an incoming string and makes sure we have valid emails in the string.
541
+	 *
542
+	 * @param string $value incoming value to validate
543
+	 * @return bool        true if the string validates, false if it doesn't
544
+	 */
545
+	protected function _validate_email($value)
546
+	{
547
+		$validate = true;
548
+		$or_val   = $value;
549
+
550
+		// empty strings will validate because this is how a message template
551
+		// for a particular context can be "turned off" (if there is no email then no message)
552
+		if (empty($value)) {
553
+			return $validate;
554
+		}
555
+
556
+		// first determine if there ARE any shortcodes.
557
+		// If there are shortcodes and then later we find that there were no other valid emails
558
+		// but the field isn't empty...
559
+		// that means we've got extra commas that were left after stripping out shortcodes so probably still valid.
560
+		$has_shortcodes = preg_match('/(\[.+?\])/', $value);
561
+
562
+		// first we need to strip out all the shortcodes!
563
+		$value = preg_replace('/(\[.+?\])/', '', $value);
564
+
565
+		// if original value is not empty and new value is, then we've parsed out a shortcode
566
+		// and we now have an empty string which DOES validate.
567
+		// We also validate complete empty field for email because
568
+		// its possible that this message is being "turned off" for a particular context
569
+
570
+
571
+		if (! empty($or_val) && empty($value)) {
572
+			return $validate;
573
+		}
574
+
575
+		// trim any commas from beginning and end of string ( after whitespace trimmed );
576
+		$value = trim(trim($value), ',');
577
+
578
+
579
+		// next we need to split up the string if its comma delimited.
580
+		$emails = explode(',', $value);
581
+		$empty  = false; // used to indicate that there is an empty comma.
582
+		// now let's loop through the emails and do our checks
583
+		foreach ($emails as $email) {
584
+			if (empty($email)) {
585
+				$empty = true;
586
+				continue;
587
+			}
588
+
589
+			// trim whitespace
590
+			$email = trim($email);
591
+			// either its of type "[email protected]", or its of type "fname lname <[email protected]>"
592
+			if (is_email($email)) {
593
+				continue;
594
+			}
595
+			$matches  = [];
596
+			$validate = (bool) preg_match('/(.*)<(.+)>/', $email, $matches);
597
+			if ($validate && is_email($matches[2])) {
598
+				continue;
599
+			}
600
+			return false;
601
+		}
602
+
603
+		return $empty && ! $has_shortcodes
604
+			? false
605
+			: $validate;
606
+	}
607
+
608
+
609
+	/**
610
+	 * Magic getter
611
+	 * Using this to provide back compat with add-ons referencing deprecated properties.
612
+	 *
613
+	 * @param string $property Property being requested
614
+	 * @return mixed
615
+	 * @throws Exception
616
+	 */
617
+	public function __get($property)
618
+	{
619
+		$expected_properties_map = [
620
+			/**
621
+			 * @deprecated 4.9.0
622
+			 */
623
+			'_MSGR'   => '_messenger',
624
+			/**
625
+			 * @deprecated 4.9.0
626
+			 */
627
+			'_MSGTYP' => '_message_type',
628
+		];
629
+
630
+		if (isset($expected_properties_map[ $property ])) {
631
+			return $this->{$expected_properties_map[ $property ]};
632
+		}
633
+
634
+		throw new Exception(
635
+			sprintf(
636
+				esc_html__('The property %1$s being requested on %2$s does not exist', 'event_espresso'),
637
+				$property,
638
+				get_class($this)
639
+			)
640
+		);
641
+	}
642 642
 }
Please login to merge, or discard this patch.
Spacing   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -156,9 +156,9 @@  discard block
 block discarded – undo
156 156
         // load messenger
157 157
         $messenger = ucwords(str_replace('_', ' ', $this->_m_name));
158 158
         $messenger = str_replace(' ', '_', $messenger);
159
-        $messenger = 'EE_' . $messenger . '_messenger';
159
+        $messenger = 'EE_'.$messenger.'_messenger';
160 160
 
161
-        if (! class_exists($messenger)) {
161
+        if ( ! class_exists($messenger)) {
162 162
             throw new EE_Error(
163 163
                 sprintf(
164 164
                     esc_html__('There is no messenger class for the given string (%s)', 'event_espresso'),
@@ -172,9 +172,9 @@  discard block
 block discarded – undo
172 172
         // load message type
173 173
         $message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
174 174
         $message_type = str_replace(' ', '_', $message_type);
175
-        $message_type = 'EE_' . $message_type . '_message_type';
175
+        $message_type = 'EE_'.$message_type.'_message_type';
176 176
 
177
-        if (! class_exists($message_type)) {
177
+        if ( ! class_exists($message_type)) {
178 178
             throw new EE_Error(
179 179
                 sprintf(
180 180
                     esc_html__('There is no message type class for the given string (%s)', 'event_espresso'),
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 
207 207
         // we only want the valid shortcodes for the given context!
208 208
         $context  = $this->_context;
209
-        $mt_codes = $mt_codes[ $context ];
209
+        $mt_codes = $mt_codes[$context];
210 210
 
211 211
         // in this first loop we're just getting all shortcode group indexes from the msgr_validator
212 212
         // into a single array (so we can get the appropriate shortcode objects for the groups)
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
             if (empty($config) || ! isset($config['shortcodes'])) {
218 218
                 continue;
219 219
             }  //Nothing to see here.
220
-            $groups_per_field[ $field ] = array_intersect($config['shortcodes'], $mt_codes);
220
+            $groups_per_field[$field] = array_intersect($config['shortcodes'], $mt_codes);
221 221
             $shortcode_groups           = array_merge($config['shortcodes'], $shortcode_groups);
222 222
         }
223 223
 
@@ -230,11 +230,11 @@  discard block
 block discarded – undo
230 230
         foreach ($shortcode_groups as $group) {
231 231
             $ref       = ucwords(str_replace('_', ' ', $group));
232 232
             $ref       = str_replace(' ', '_', $ref);
233
-            $classname = 'EE_' . $ref . '_Shortcodes';
233
+            $classname = 'EE_'.$ref.'_Shortcodes';
234 234
             if (class_exists($classname)) {
235 235
                 $a                         = new ReflectionClass($classname);
236 236
                 $obj                       = $a->newInstance();
237
-                $codes_from_objs[ $group ] = $obj->get_shortcodes();
237
+                $codes_from_objs[$group] = $obj->get_shortcodes();
238 238
             }
239 239
         }
240 240
 
@@ -242,7 +242,7 @@  discard block
 block discarded – undo
242 242
         // let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
243 243
         $final_mt_codes = [];
244 244
         foreach ($mt_codes as $group) {
245
-            $final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[ $group ]);
245
+            $final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[$group]);
246 246
         }
247 247
 
248 248
         $mt_codes = $final_mt_codes;
@@ -260,44 +260,44 @@  discard block
 block discarded – undo
260 260
             }
261 261
 
262 262
             // If we have an override then we use it to indicate the codes we want.
263
-            if (isset($this->_valid_shortcodes_modifier[ $context ][ $field ])) {
264
-                $this->_validators[ $field ]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
265
-                    $this->_valid_shortcodes_modifier[ $context ][ $field ],
263
+            if (isset($this->_valid_shortcodes_modifier[$context][$field])) {
264
+                $this->_validators[$field]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
265
+                    $this->_valid_shortcodes_modifier[$context][$field],
266 266
                     $codes_from_objs
267 267
                 );
268
-            } elseif (isset($groups_per_field[ $field ])) {
268
+            } elseif (isset($groups_per_field[$field])) {
269 269
                 // we have specific shortcodes for a field so we need to use them
270
-                $this->_validators[ $field ]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
271
-                    $groups_per_field[ $field ],
270
+                $this->_validators[$field]['shortcodes'] = $this->_reassemble_valid_shortcodes_from_group(
271
+                    $groups_per_field[$field],
272 272
                     $codes_from_objs
273 273
                 );
274 274
             } elseif (empty($config)) {
275 275
                 // no config so we're assuming we're just going to use the shortcodes from the message type context
276
-                $this->_validators[ $field ]['shortcodes'] = $mt_codes;
276
+                $this->_validators[$field]['shortcodes'] = $mt_codes;
277 277
             } elseif (isset($config['specific_shortcodes'])) {
278 278
                 // we have specific shortcodes so we need to use them
279
-                $this->_validators[ $field ]['shortcodes'] = $config['specific_shortcodes'];
279
+                $this->_validators[$field]['shortcodes'] = $config['specific_shortcodes'];
280 280
             } else {
281 281
                 // otherwise the shortcodes are what is set by the messenger for that field
282 282
                 foreach ($config['shortcodes'] as $group) {
283
-                    $this->_validators[ $field ]['shortcodes'] = isset($this->_validators[ $field ]['shortcodes'])
284
-                        ? array_merge($this->_validators[ $field ]['shortcodes'], $codes_from_objs[ $group ])
285
-                        : $codes_from_objs[ $group ];
283
+                    $this->_validators[$field]['shortcodes'] = isset($this->_validators[$field]['shortcodes'])
284
+                        ? array_merge($this->_validators[$field]['shortcodes'], $codes_from_objs[$group])
285
+                        : $codes_from_objs[$group];
286 286
                 }
287 287
             }
288 288
 
289 289
             // now let's just make sure that any excluded specific shortcodes are removed.
290 290
             $specific_excludes = $this->get_specific_shortcode_excludes();
291
-            if (isset($specific_excludes[ $field ])) {
292
-                foreach ($specific_excludes[ $field ] as $sex) {
293
-                    if (isset($this->_validators[ $field ]['shortcodes'][ $sex ])) {
294
-                        unset($this->_validators[ $field ]['shortcodes'][ $sex ]);
291
+            if (isset($specific_excludes[$field])) {
292
+                foreach ($specific_excludes[$field] as $sex) {
293
+                    if (isset($this->_validators[$field]['shortcodes'][$sex])) {
294
+                        unset($this->_validators[$field]['shortcodes'][$sex]);
295 295
                     }
296 296
                 }
297 297
             }
298 298
 
299 299
             // hey! don't forget to include the type if present!
300
-            $this->_validators[ $field ]['type'] =
300
+            $this->_validators[$field]['type'] =
301 301
                 isset($config['type'])
302 302
                     ? $config['type']
303 303
                     : null;
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
     {
328 328
         // specific validator filter
329 329
         $shortcode_excludes = apply_filters(
330
-            'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
330
+            'FHEE__'.get_class($this).'__get_specific_shortcode_excludes;',
331 331
             $this->_specific_shortcode_excludes,
332 332
             $this->_context
333 333
         );
@@ -354,21 +354,21 @@  discard block
 block discarded – undo
354 354
         $template_fields = $this->_messenger->get_template_fields();
355 355
         // loop through the fields and check!
356 356
         foreach ($this->_fields as $field => $value) {
357
-            $this->_errors[ $field ] = [];
357
+            $this->_errors[$field] = [];
358 358
             $err_msg                 = '';
359 359
             $field_label             = '';
360 360
             // if field is not present in the _validators array then we continue
361
-            if (! isset($this->_validators[ $field ])) {
362
-                unset($this->_errors[ $field ]);
361
+            if ( ! isset($this->_validators[$field])) {
362
+                unset($this->_errors[$field]);
363 363
                 continue;
364 364
             }
365 365
 
366 366
             // get the translated field label!
367 367
             // first check if it's in the main fields list
368
-            if (isset($template_fields[ $field ])) {
368
+            if (isset($template_fields[$field])) {
369 369
                 // most likely the field is found in the 'extra' array.
370
-                $field_label = ! empty($template_fields[ $field ])
371
-                    ? $template_fields[ $field ]['label']
370
+                $field_label = ! empty($template_fields[$field])
371
+                    ? $template_fields[$field]['label']
372 372
                     : $field;
373 373
             }
374 374
 
@@ -392,20 +392,20 @@  discard block
 block discarded – undo
392 392
 
393 393
             // field is present. Let's validate shortcodes first (but only if shortcodes present).
394 394
             if (
395
-                isset($this->_validators[ $field ]['shortcodes'])
396
-                && ! empty($this->_validators[ $field ]['shortcodes'])
395
+                isset($this->_validators[$field]['shortcodes'])
396
+                && ! empty($this->_validators[$field]['shortcodes'])
397 397
             ) {
398
-                $invalid_shortcodes = $this->_invalid_shortcodes($value, $this->_validators[ $field ]['shortcodes']);
398
+                $invalid_shortcodes = $this->_invalid_shortcodes($value, $this->_validators[$field]['shortcodes']);
399 399
                 // if true then that means there is a returned error message
400 400
                 // that we'll need to add to the _errors array for this field.
401 401
                 if ($invalid_shortcodes) {
402
-                    $v_s     = array_keys($this->_validators[ $field ]['shortcodes']);
402
+                    $v_s     = array_keys($this->_validators[$field]['shortcodes']);
403 403
                     $err_msg = sprintf(
404 404
                         esc_html__(
405 405
                             '%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
406 406
                             'event_espresso'
407 407
                         ),
408
-                        '<strong>' . $field_label . '</strong>',
408
+                        '<strong>'.$field_label.'</strong>',
409 409
                         $invalid_shortcodes,
410 410
                         '<p>',
411 411
                         '</p >'
@@ -420,10 +420,10 @@  discard block
 block discarded – undo
420 420
             }
421 421
 
422 422
             // if there's a "type" to be validated then let's do that too.
423
-            if (isset($this->_validators[ $field ]['type']) && ! empty($this->_validators[ $field ]['type'])) {
424
-                switch ($this->_validators[ $field ]['type']) {
423
+            if (isset($this->_validators[$field]['type']) && ! empty($this->_validators[$field]['type'])) {
424
+                switch ($this->_validators[$field]['type']) {
425 425
                     case 'number':
426
-                        if (! is_numeric($value)) {
426
+                        if ( ! is_numeric($value)) {
427 427
                             $err_msg .= sprintf(
428 428
                                 esc_html__(
429 429
                                     '%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
                         break;
439 439
                     case 'email':
440 440
                         $valid_email = $this->_validate_email($value);
441
-                        if (! $valid_email) {
441
+                        if ( ! $valid_email) {
442 442
                             $err_msg .= htmlentities(
443 443
                                 sprintf(
444 444
                                     esc_html__(
@@ -456,18 +456,18 @@  discard block
 block discarded – undo
456 456
             }
457 457
 
458 458
             // if $err_msg isn't empty let's setup the _errors array for this field.
459
-            if (! empty($err_msg)) {
460
-                $this->_errors[ $field ]['msg'] = $err_msg;
459
+            if ( ! empty($err_msg)) {
460
+                $this->_errors[$field]['msg'] = $err_msg;
461 461
             } else {
462
-                unset($this->_errors[ $field ]);
462
+                unset($this->_errors[$field]);
463 463
             }
464 464
         }
465 465
 
466 466
         // if we have ANY errors, then we want to make sure we return the values
467 467
         // for ALL the fields so the user doesn't have to retype them all.
468
-        if (! empty($this->_errors)) {
468
+        if ( ! empty($this->_errors)) {
469 469
             foreach ($this->_fields as $field => $value) {
470
-                $this->_errors[ $field ]['value'] = stripslashes($value);
470
+                $this->_errors[$field]['value'] = stripslashes($value);
471 471
             }
472 472
         }
473 473
 
@@ -490,7 +490,7 @@  discard block
 block discarded – undo
490 490
     {
491 491
         $shortcodes = [];
492 492
         foreach ($groups as $group) {
493
-            $shortcodes = array_merge($shortcodes, $codes_from_objs[ $group ]);
493
+            $shortcodes = array_merge($shortcodes, $codes_from_objs[$group]);
494 494
         }
495 495
         return $shortcodes;
496 496
     }
@@ -520,8 +520,8 @@  discard block
 block discarded – undo
520 520
                 // strip the shortcode so we just have the BASE string (i.e. [ANSWER_*] )
521 521
                 $dynamic_sc = preg_replace('/(_\*+.+)/', '_*]', $code);
522 522
                 // does this exist in the $valid_shortcodes?  If so then unset.
523
-                if (isset($valid_shortcodes[ $dynamic_sc ])) {
524
-                    unset($diff[ $ind ]);
523
+                if (isset($valid_shortcodes[$dynamic_sc])) {
524
+                    unset($diff[$ind]);
525 525
                 }
526 526
             }
527 527
         }
@@ -532,7 +532,7 @@  discard block
 block discarded – undo
532 532
 
533 533
         // made it here? then let's assemble the error message
534 534
         $invalid_shortcodes = implode('</strong>,<strong>', $diff);
535
-        return '<strong>' . $invalid_shortcodes . '</strong>';
535
+        return '<strong>'.$invalid_shortcodes.'</strong>';
536 536
     }
537 537
 
538 538
 
@@ -568,7 +568,7 @@  discard block
 block discarded – undo
568 568
         // its possible that this message is being "turned off" for a particular context
569 569
 
570 570
 
571
-        if (! empty($or_val) && empty($value)) {
571
+        if ( ! empty($or_val) && empty($value)) {
572 572
             return $validate;
573 573
         }
574 574
 
@@ -627,8 +627,8 @@  discard block
 block discarded – undo
627 627
             '_MSGTYP' => '_message_type',
628 628
         ];
629 629
 
630
-        if (isset($expected_properties_map[ $property ])) {
631
-            return $this->{$expected_properties_map[ $property ]};
630
+        if (isset($expected_properties_map[$property])) {
631
+            return $this->{$expected_properties_map[$property]};
632 632
         }
633 633
 
634 634
         throw new Exception(
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelDataTranslator.php 2 patches
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -69,7 +69,7 @@  discard block
 block discarded – undo
69 69
         ) {
70 70
             $new_value_maybe_array = [];
71 71
             foreach ($original_value_maybe_array as $array_key => $array_item) {
72
-                $new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
72
+                $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
73 73
                     $field_obj,
74 74
                     $array_item,
75 75
                     $requested_version,
@@ -103,7 +103,7 @@  discard block
 block discarded – undo
103 103
         if (is_array($original_value_maybe_array)) {
104 104
             $new_value = [];
105 105
             foreach ($original_value_maybe_array as $key => $value) {
106
-                $new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
106
+                $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson(
107 107
                     $field_obj,
108 108
                     $value,
109 109
                     $request_version
@@ -244,7 +244,7 @@  discard block
 block discarded – undo
244 244
                 '0',
245 245
                 STR_PAD_LEFT
246 246
             );
247
-        return $original_timestamp . $offset_sign . $offset_string;
247
+        return $original_timestamp.$offset_sign.$offset_string;
248 248
     }
249 249
 
250 250
 
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
                     // first, check if its a MySQL timestamp in GMT
324 324
                     $datetime_obj = DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
325 325
                 }
326
-                if (! $datetime_obj instanceof DateTime) {
326
+                if ( ! $datetime_obj instanceof DateTime) {
327 327
                     // so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
328 328
                     $datetime_obj = $field_obj->prepare_for_set($original_value);
329 329
                 }
@@ -349,7 +349,7 @@  discard block
 block discarded – undo
349 349
                         $original_value,
350 350
                         $field_obj->get_name(),
351 351
                         $field_obj->get_model_name(),
352
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
352
+                        $field_obj->get_time_format().' '.$field_obj->get_time_format()
353 353
                     )
354 354
                 );
355 355
             }
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
         }
364 364
         // are we about to send an object? just don't. We have no good way to represent it in JSON.
365 365
         // can't just check using is_object() because that missed PHP incomplete objects
366
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
366
+        if ( ! ModelDataTranslator::isRepresentableInJson($new_value)) {
367 367
             $new_value = [
368 368
                 'error_code'    => 'php_object_not_return',
369 369
                 'error_message' => esc_html__(
@@ -414,7 +414,7 @@  discard block
 block discarded – undo
414 414
             if ($query_param_meta->getField() instanceof EE_Model_Field_Base) {
415 415
                 $translated_value = $query_param_meta->determineConditionsQueryParameterValue();
416 416
                 if (
417
-                    (isset($query_param_for_models[ $query_param_meta->getQueryParamKey() ])
417
+                    (isset($query_param_for_models[$query_param_meta->getQueryParamKey()])
418 418
                      && $query_param_meta->isGmtField())
419 419
                     || $translated_value === null
420 420
                 ) {
@@ -423,11 +423,11 @@  discard block
 block discarded – undo
423 423
                     // OR we couldn't create a translated value from their input
424 424
                     continue;
425 425
                 }
426
-                $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $translated_value;
426
+                $query_param_for_models[$query_param_meta->getQueryParamKey()] = $translated_value;
427 427
             } else {
428 428
                 $nested_query_params = $query_param_meta->determineNestedConditionQueryParameters();
429 429
                 if ($nested_query_params) {
430
-                    $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $nested_query_params;
430
+                    $query_param_for_models[$query_param_meta->getQueryParamKey()] = $nested_query_params;
431 431
                 }
432 432
             }
433 433
         }
@@ -457,7 +457,7 @@  discard block
 block discarded – undo
457 457
      */
458 458
     public static function removeGmtFromFieldName($field_name)
459 459
     {
460
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
460
+        if ( ! ModelDataTranslator::isGmtDateFieldName($field_name)) {
461 461
             return $field_name;
462 462
         }
463 463
         $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
     {
501 501
         $new_array = [];
502 502
         foreach ($field_names as $key => $field_name) {
503
-            $new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
503
+            $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
504 504
         }
505 505
         return $new_array;
506 506
     }
@@ -517,7 +517,7 @@  discard block
 block discarded – undo
517 517
     {
518 518
         $new_array = [];
519 519
         foreach ($field_names_as_keys as $field_name => $value) {
520
-            $new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
520
+            $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
521 521
         }
522 522
         return $new_array;
523 523
     }
@@ -613,10 +613,10 @@  discard block
 block discarded – undo
613 613
                         $requested_version
614 614
                     );
615 615
                 }
616
-                $query_param_for_models[ $query_param_key ] = $translated_value;
616
+                $query_param_for_models[$query_param_key] = $translated_value;
617 617
             } else {
618 618
                 // so it's not for a field, assume it's a logic query param key
619
-                $query_param_for_models[ $query_param_key ] =
619
+                $query_param_for_models[$query_param_key] =
620 620
                     ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
621 621
                         $query_param_value,
622 622
                         $model,
@@ -668,11 +668,11 @@  discard block
 block discarded – undo
668 668
             );
669 669
         }
670 670
         $number_of_parts       = count($query_param_parts);
671
-        $last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
671
+        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
672 672
         $field_name            = $last_query_param_part;
673 673
         if ($number_of_parts !== 1) {
674 674
             // the last part is the column name, and there are only 2parts. therefore...
675
-            $model = EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
675
+            $model = EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
676 676
         }
677 677
         try {
678 678
             return $model->field_settings_for($field_name, false);
Please login to merge, or discard this patch.
Indentation   +656 added lines, -656 removed lines patch added patch discarded remove patch
@@ -39,660 +39,660 @@
 block discarded – undo
39 39
 class ModelDataTranslator
40 40
 {
41 41
 
42
-    /**
43
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
44
-     * fields that COULD contain -1; so we use null
45
-     */
46
-    const EE_INF_IN_REST = null;
47
-
48
-
49
-    /**
50
-     * Prepares a possible array of input values from JSON for use by the models
51
-     *
52
-     * @param EE_Model_Field_Base $field_obj
53
-     * @param mixed               $original_value_maybe_array
54
-     * @param string              $requested_version
55
-     * @param string              $timezone_string treat values as being in this timezone
56
-     * @return mixed
57
-     * @throws RestException
58
-     * @throws EE_Error
59
-     */
60
-    public static function prepareFieldValuesFromJson(
61
-        $field_obj,
62
-        $original_value_maybe_array,
63
-        $requested_version,
64
-        $timezone_string = 'UTC'
65
-    ) {
66
-        if (
67
-            is_array($original_value_maybe_array)
68
-            && ! $field_obj instanceof EE_Serialized_Text_Field
69
-        ) {
70
-            $new_value_maybe_array = [];
71
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
72
-                $new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
73
-                    $field_obj,
74
-                    $array_item,
75
-                    $requested_version,
76
-                    $timezone_string
77
-                );
78
-            }
79
-        } else {
80
-            $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
81
-                $field_obj,
82
-                $original_value_maybe_array,
83
-                $requested_version,
84
-                $timezone_string
85
-            );
86
-        }
87
-        return $new_value_maybe_array;
88
-    }
89
-
90
-
91
-    /**
92
-     * Prepares an array of field values FOR use in JSON/REST API
93
-     *
94
-     * @param EE_Model_Field_Base $field_obj
95
-     * @param mixed               $original_value_maybe_array
96
-     * @param string              $request_version (eg 4.8.36)
97
-     * @return array
98
-     * @throws EE_Error
99
-     * @throws EE_Error
100
-     */
101
-    public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
102
-    {
103
-        if (is_array($original_value_maybe_array)) {
104
-            $new_value = [];
105
-            foreach ($original_value_maybe_array as $key => $value) {
106
-                $new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
107
-                    $field_obj,
108
-                    $value,
109
-                    $request_version
110
-                );
111
-            }
112
-        } else {
113
-            $new_value = ModelDataTranslator::prepareFieldValueForJson(
114
-                $field_obj,
115
-                $original_value_maybe_array,
116
-                $request_version
117
-            );
118
-        }
119
-        return $new_value;
120
-    }
121
-
122
-
123
-    /**
124
-     * Prepares incoming data from the json or request parameters for the models'
125
-     * "$query_params".
126
-     *
127
-     * @param EE_Model_Field_Base $field_obj
128
-     * @param mixed               $original_value
129
-     * @param string              $requested_version
130
-     * @param string              $timezone_string treat values as being in this timezone
131
-     * @return mixed
132
-     * @throws RestException
133
-     * @throws DomainException
134
-     * @throws EE_Error
135
-     */
136
-    public static function prepareFieldValueFromJson(
137
-        $field_obj,
138
-        $original_value,
139
-        $requested_version,
140
-        $timezone_string = 'UTC'
141
-    ) {
142
-        // check if they accidentally submitted an error value. If so throw an exception
143
-        if (
144
-            is_array($original_value)
145
-            && isset($original_value['error_code'], $original_value['error_message'])
146
-        ) {
147
-            throw new RestException(
148
-                'rest_submitted_error_value',
149
-                sprintf(
150
-                    esc_html__(
151
-                        'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
152
-                        'event_espresso'
153
-                    ),
154
-                    $field_obj->get_name()
155
-                ),
156
-                [
157
-                    'status' => 400,
158
-                ]
159
-            );
160
-        }
161
-        // double-check for serialized PHP. We never accept serialized PHP. No way Jose.
162
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
163
-        $timezone_string =
164
-            $timezone_string !== ''
165
-                ? $timezone_string
166
-                : get_option('timezone_string', '');
167
-        // walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
168
-        // way Jose.
169
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
170
-        if (
171
-            $field_obj instanceof EE_Infinite_Integer_Field
172
-            && in_array($original_value, [null, ''], true)
173
-        ) {
174
-            $new_value = EE_INF;
175
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
176
-            $new_value = rest_parse_date(
177
-                self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
178
-            );
179
-            if ($new_value === false) {
180
-                throw new RestException(
181
-                    'invalid_format_for_timestamp',
182
-                    sprintf(
183
-                        esc_html__(
184
-                            'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
185
-                            'event_espresso'
186
-                        ),
187
-                        'RFC3339',
188
-                        'ISO8601',
189
-                        $original_value
190
-                    ),
191
-                    [
192
-                        'status' => 400,
193
-                    ]
194
-                );
195
-            }
196
-        } elseif ($field_obj instanceof EE_Boolean_Field) {
197
-            // Interpreted the strings "false", "true", "on", "off" appropriately.
198
-            $new_value = filter_var($original_value, FILTER_VALIDATE_BOOLEAN);
199
-        } else {
200
-            $new_value = $original_value;
201
-        }
202
-        return $new_value;
203
-    }
204
-
205
-
206
-    /**
207
-     * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
208
-     * information via details obtained from the host site.
209
-     *
210
-     * @param string            $original_timestamp
211
-     * @param EE_Datetime_Field $datetime_field
212
-     * @param                   $timezone_string
213
-     * @return string
214
-     * @throws DomainException
215
-     */
216
-    private static function getTimestampWithTimezoneOffset(
217
-        $original_timestamp,
218
-        EE_Datetime_Field $datetime_field,
219
-        $timezone_string
220
-    ) {
221
-        // already have timezone information?
222
-        if (preg_match('/Z|([+-])(\d{2}:\d{2})/', $original_timestamp)) {
223
-            // yes, we're ignoring the timezone.
224
-            return $original_timestamp;
225
-        }
226
-        // need to append timezone
227
-        list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
228
-            $datetime_field->get_timezone_offset(
229
-                new DateTimeZone($timezone_string),
230
-                $original_timestamp
231
-            )
232
-        );
233
-        $offset_string =
234
-            str_pad(
235
-                floor($offset_secs / HOUR_IN_SECONDS),
236
-                2,
237
-                '0',
238
-                STR_PAD_LEFT
239
-            )
240
-            . ':'
241
-            . str_pad(
242
-                ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
243
-                2,
244
-                '0',
245
-                STR_PAD_LEFT
246
-            );
247
-        return $original_timestamp . $offset_sign . $offset_string;
248
-    }
249
-
250
-
251
-    /**
252
-     * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
253
-     * think that can happen). If $data is an array, recurses into its keys and values
254
-     *
255
-     * @param mixed $data
256
-     * @return void
257
-     * @throws RestException
258
-     */
259
-    public static function throwExceptionIfContainsSerializedData($data)
260
-    {
261
-        if (is_array($data)) {
262
-            foreach ($data as $key => $value) {
263
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
264
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
265
-            }
266
-        } else {
267
-            if (is_serialized($data) || is_object($data)) {
268
-                throw new RestException(
269
-                    'serialized_data_submission_prohibited',
270
-                    esc_html__(
271
-                    // @codingStandardsIgnoreStart
272
-                        'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
273
-                        // @codingStandardsIgnoreEnd
274
-                        'event_espresso'
275
-                    )
276
-                );
277
-            }
278
-        }
279
-    }
280
-
281
-
282
-    /**
283
-     * determines what's going on with them timezone strings
284
-     *
285
-     * @param int $timezone_offset
286
-     * @return array
287
-     */
288
-    private static function parseTimezoneOffset($timezone_offset)
289
-    {
290
-        $first_char = substr((string) $timezone_offset, 0, 1);
291
-        if ($first_char === '+' || $first_char === '-') {
292
-            $offset_sign = $first_char;
293
-            $offset_secs = substr((string) $timezone_offset, 1);
294
-        } else {
295
-            $offset_sign = '+';
296
-            $offset_secs = $timezone_offset;
297
-        }
298
-        return [$offset_sign, $offset_secs];
299
-    }
300
-
301
-
302
-    /**
303
-     * Prepares a field's value for display in the API
304
-     *
305
-     * @param EE_Model_Field_Base $field_obj
306
-     * @param mixed               $original_value
307
-     * @param string              $requested_version
308
-     * @return mixed
309
-     * @throws EE_Error
310
-     * @throws EE_Error
311
-     */
312
-    public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
313
-    {
314
-        if ($original_value === EE_INF) {
315
-            $new_value = ModelDataTranslator::EE_INF_IN_REST;
316
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
317
-            if (is_string($original_value)) {
318
-                // did they submit a string of a unix timestamp?
319
-                if (is_numeric($original_value)) {
320
-                    $datetime_obj = new DateTime();
321
-                    $datetime_obj->setTimestamp((int) $original_value);
322
-                } else {
323
-                    // first, check if its a MySQL timestamp in GMT
324
-                    $datetime_obj = DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
325
-                }
326
-                if (! $datetime_obj instanceof DateTime) {
327
-                    // so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
328
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
329
-                }
330
-                $original_value = $datetime_obj;
331
-            }
332
-            if ($original_value instanceof DateTime) {
333
-                $new_value = $original_value->format('Y-m-d H:i:s');
334
-            } elseif (is_int($original_value) || is_float($original_value)) {
335
-                $new_value = date('Y-m-d H:i:s', $original_value);
336
-            } elseif ($original_value === null || $original_value === '') {
337
-                $new_value = null;
338
-            } else {
339
-                // so it's not a datetime object, unix timestamp (as string or int),
340
-                // MySQL timestamp, or even a string in the field object's format. So no idea what it is
341
-                throw new EE_Error(
342
-                    sprintf(
343
-                        esc_html__(
344
-                        // @codingStandardsIgnoreStart
345
-                            'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
346
-                            // @codingStandardsIgnoreEnd
347
-                            'event_espresso'
348
-                        ),
349
-                        $original_value,
350
-                        $field_obj->get_name(),
351
-                        $field_obj->get_model_name(),
352
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
353
-                    )
354
-                );
355
-            }
356
-            if ($new_value !== null) {
357
-                // phpcs:disable PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
358
-                $new_value = mysql_to_rfc3339($new_value);
359
-                // phpcs:enable
360
-            }
361
-        } else {
362
-            $new_value = $original_value;
363
-        }
364
-        // are we about to send an object? just don't. We have no good way to represent it in JSON.
365
-        // can't just check using is_object() because that missed PHP incomplete objects
366
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
367
-            $new_value = [
368
-                'error_code'    => 'php_object_not_return',
369
-                'error_message' => esc_html__(
370
-                    'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
371
-                    'event_espresso'
372
-                ),
373
-            ];
374
-        }
375
-        return apply_filters(
376
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
377
-            $new_value,
378
-            $field_obj,
379
-            $original_value,
380
-            $requested_version
381
-        );
382
-    }
383
-
384
-
385
-    /**
386
-     * Prepares condition-query-parameters (like what's in where and having) from
387
-     * the format expected in the API to use in the models
388
-     *
389
-     * @param array    $inputted_query_params_of_this_type
390
-     * @param EEM_Base $model
391
-     * @param string   $requested_version
392
-     * @param boolean  $writing whether this data will be written to the DB, or if we're just building a query.
393
-     *                          If we're writing to the DB, we don't expect any operators, or any logic query
394
-     *                          parameters, and we also won't accept serialized data unless the current user has
395
-     *                          unfiltered_html.
396
-     * @return array
397
-     * @throws DomainException
398
-     * @throws EE_Error
399
-     * @throws RestException
400
-     * @throws InvalidDataTypeException
401
-     * @throws InvalidInterfaceException
402
-     * @throws InvalidArgumentException
403
-     */
404
-    public static function prepareConditionsQueryParamsForModels(
405
-        $inputted_query_params_of_this_type,
406
-        EEM_Base $model,
407
-        $requested_version,
408
-        $writing = false
409
-    ) {
410
-        $query_param_for_models = [];
411
-        $context                = new RestIncomingQueryParamContext($model, $requested_version, $writing);
412
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
413
-            $query_param_meta = new RestIncomingQueryParamMetadata($query_param_key, $query_param_value, $context);
414
-            if ($query_param_meta->getField() instanceof EE_Model_Field_Base) {
415
-                $translated_value = $query_param_meta->determineConditionsQueryParameterValue();
416
-                if (
417
-                    (isset($query_param_for_models[ $query_param_meta->getQueryParamKey() ])
418
-                     && $query_param_meta->isGmtField())
419
-                    || $translated_value === null
420
-                ) {
421
-                    // they have already provided a non-gmt field, ignore the gmt one. That's what WP core
422
-                    // currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
423
-                    // OR we couldn't create a translated value from their input
424
-                    continue;
425
-                }
426
-                $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $translated_value;
427
-            } else {
428
-                $nested_query_params = $query_param_meta->determineNestedConditionQueryParameters();
429
-                if ($nested_query_params) {
430
-                    $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $nested_query_params;
431
-                }
432
-            }
433
-        }
434
-        return $query_param_for_models;
435
-    }
436
-
437
-
438
-    /**
439
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
440
-     * gmt date field name
441
-     *
442
-     * @param string $field_name
443
-     * @return boolean
444
-     */
445
-    public static function isGmtDateFieldName($field_name)
446
-    {
447
-        $field_name = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name);
448
-        return substr($field_name, -4, 4) === '_gmt';
449
-    }
450
-
451
-
452
-    /**
453
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
454
-     *
455
-     * @param string $field_name
456
-     * @return string
457
-     */
458
-    public static function removeGmtFromFieldName($field_name)
459
-    {
460
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
461
-            return $field_name;
462
-        }
463
-        $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
464
-            $field_name
465
-        );
466
-        $query_param_sans_gmt_and_sans_stars = substr(
467
-            $query_param_sans_stars,
468
-            0,
469
-            strrpos(
470
-                $field_name,
471
-                '_gmt'
472
-            )
473
-        );
474
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
475
-    }
476
-
477
-
478
-    /**
479
-     * Takes a field name from the REST API and prepares it for the model querying
480
-     *
481
-     * @param string $field_name
482
-     * @return string
483
-     */
484
-    public static function prepareFieldNameFromJson($field_name)
485
-    {
486
-        if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
487
-            return ModelDataTranslator::removeGmtFromFieldName($field_name);
488
-        }
489
-        return $field_name;
490
-    }
491
-
492
-
493
-    /**
494
-     * Takes array of field names from REST API and prepares for models
495
-     *
496
-     * @param array $field_names
497
-     * @return array of field names (possibly include model prefixes)
498
-     */
499
-    public static function prepareFieldNamesFromJson(array $field_names)
500
-    {
501
-        $new_array = [];
502
-        foreach ($field_names as $key => $field_name) {
503
-            $new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
504
-        }
505
-        return $new_array;
506
-    }
507
-
508
-
509
-    /**
510
-     * Takes array where array keys are field names (possibly with model path prefixes)
511
-     * from the REST API and prepares them for model querying
512
-     *
513
-     * @param array $field_names_as_keys
514
-     * @return array
515
-     */
516
-    public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
517
-    {
518
-        $new_array = [];
519
-        foreach ($field_names_as_keys as $field_name => $value) {
520
-            $new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
521
-        }
522
-        return $new_array;
523
-    }
524
-
525
-
526
-    /**
527
-     * Prepares an array of model query params for use in the REST API
528
-     *
529
-     * @param array    $model_query_params
530
-     * @param EEM_Base $model
531
-     * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
532
-     *                                     REST API
533
-     * @return array which can be passed into the EE4 REST API when querying a model resource
534
-     * @throws EE_Error
535
-     * @throws ReflectionException
536
-     */
537
-    public static function prepareQueryParamsForRestApi(
538
-        array $model_query_params,
539
-        EEM_Base $model,
540
-        $requested_version = null
541
-    ) {
542
-        if ($requested_version === null) {
543
-            $requested_version = EED_Core_Rest_Api::latest_rest_api_version();
544
-        }
545
-        $rest_query_params = $model_query_params;
546
-        if (isset($model_query_params[0])) {
547
-            $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
548
-                $model_query_params[0],
549
-                $model,
550
-                $requested_version
551
-            );
552
-            unset($rest_query_params[0]);
553
-        }
554
-        if (isset($model_query_params['having'])) {
555
-            $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
556
-                $model_query_params['having'],
557
-                $model,
558
-                $requested_version
559
-            );
560
-        }
561
-        return apply_filters(
562
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
563
-            $rest_query_params,
564
-            $model_query_params,
565
-            $model,
566
-            $requested_version
567
-        );
568
-    }
569
-
570
-
571
-    /**
572
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
573
-     *
574
-     * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
575
-     * @param EEM_Base $model
576
-     * @param string   $requested_version                   eg "4.8.36"
577
-     * @return array ready for use in the rest api query params
578
-     * @throws EE_Error
579
-     * @throws RestException if somehow a PHP object were in the query params' values,*@throws
580
-     * @throws ReflectionException
581
-     *                                                      ReflectionException
582
-     *                                                      (which would be really unusual)
583
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
584
-     */
585
-    public static function prepareConditionsQueryParamsForRestApi(
586
-        $inputted_query_params_of_this_type,
587
-        EEM_Base $model,
588
-        $requested_version
589
-    ) {
590
-        $query_param_for_models = [];
591
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
592
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
593
-                ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
594
-                $model
595
-            );
596
-            if ($field instanceof EE_Model_Field_Base) {
597
-                // did they specify an operator?
598
-                if (is_array($query_param_value)) {
599
-                    $op               = $query_param_value[0];
600
-                    $translated_value = [$op];
601
-                    if (isset($query_param_value[1])) {
602
-                        $value               = $query_param_value[1];
603
-                        $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
604
-                            $field,
605
-                            $value,
606
-                            $requested_version
607
-                        );
608
-                    }
609
-                } else {
610
-                    $translated_value = ModelDataTranslator::prepareFieldValueForJson(
611
-                        $field,
612
-                        $query_param_value,
613
-                        $requested_version
614
-                    );
615
-                }
616
-                $query_param_for_models[ $query_param_key ] = $translated_value;
617
-            } else {
618
-                // so it's not for a field, assume it's a logic query param key
619
-                $query_param_for_models[ $query_param_key ] =
620
-                    ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
621
-                        $query_param_value,
622
-                        $model,
623
-                        $requested_version
624
-                    );
625
-            }
626
-        }
627
-        return $query_param_for_models;
628
-    }
629
-
630
-
631
-    /**
632
-     * @param $condition_query_param_key
633
-     * @return string
634
-     */
635
-    public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
636
-    {
637
-        $pos_of_star = strpos($condition_query_param_key, '*');
638
-        if ($pos_of_star === false) {
639
-            return $condition_query_param_key;
640
-        }
641
-        return substr($condition_query_param_key, 0, $pos_of_star);
642
-    }
643
-
644
-
645
-    /**
646
-     * Takes the input parameter and finds the model field that it indicates.
647
-     *
648
-     * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
649
-     * @param EEM_Base $model
650
-     * @return EE_Model_Field_Base
651
-     * @throws EE_Error
652
-     * @throws ReflectionException
653
-     */
654
-    public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
655
-    {
656
-        // ok, now proceed with deducing which part is the model's name, and which is the field's name
657
-        // which will help us find the database table and column
658
-        $query_param_parts = explode('.', $query_param_name);
659
-        if (empty($query_param_parts)) {
660
-            throw new EE_Error(
661
-                sprintf(
662
-                    esc_html__(
663
-                        '_extract_column_name is empty when trying to extract column and table name from %s',
664
-                        'event_espresso'
665
-                    ),
666
-                    $query_param_name
667
-                )
668
-            );
669
-        }
670
-        $number_of_parts       = count($query_param_parts);
671
-        $last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
672
-        $field_name            = $last_query_param_part;
673
-        if ($number_of_parts !== 1) {
674
-            // the last part is the column name, and there are only 2parts. therefore...
675
-            $model = EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
676
-        }
677
-        try {
678
-            return $model->field_settings_for($field_name, false);
679
-        } catch (EE_Error $e) {
680
-            return null;
681
-        }
682
-    }
683
-
684
-
685
-    /**
686
-     * Returns true if $data can be easily represented in JSON.
687
-     * Basically, objects and resources can't be represented in JSON easily.
688
-     *
689
-     * @param mixed $data
690
-     * @return bool
691
-     */
692
-    protected static function isRepresentableInJson($data)
693
-    {
694
-        return is_scalar($data)
695
-               || is_array($data)
696
-               || is_null($data);
697
-    }
42
+	/**
43
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
44
+	 * fields that COULD contain -1; so we use null
45
+	 */
46
+	const EE_INF_IN_REST = null;
47
+
48
+
49
+	/**
50
+	 * Prepares a possible array of input values from JSON for use by the models
51
+	 *
52
+	 * @param EE_Model_Field_Base $field_obj
53
+	 * @param mixed               $original_value_maybe_array
54
+	 * @param string              $requested_version
55
+	 * @param string              $timezone_string treat values as being in this timezone
56
+	 * @return mixed
57
+	 * @throws RestException
58
+	 * @throws EE_Error
59
+	 */
60
+	public static function prepareFieldValuesFromJson(
61
+		$field_obj,
62
+		$original_value_maybe_array,
63
+		$requested_version,
64
+		$timezone_string = 'UTC'
65
+	) {
66
+		if (
67
+			is_array($original_value_maybe_array)
68
+			&& ! $field_obj instanceof EE_Serialized_Text_Field
69
+		) {
70
+			$new_value_maybe_array = [];
71
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
72
+				$new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
73
+					$field_obj,
74
+					$array_item,
75
+					$requested_version,
76
+					$timezone_string
77
+				);
78
+			}
79
+		} else {
80
+			$new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
81
+				$field_obj,
82
+				$original_value_maybe_array,
83
+				$requested_version,
84
+				$timezone_string
85
+			);
86
+		}
87
+		return $new_value_maybe_array;
88
+	}
89
+
90
+
91
+	/**
92
+	 * Prepares an array of field values FOR use in JSON/REST API
93
+	 *
94
+	 * @param EE_Model_Field_Base $field_obj
95
+	 * @param mixed               $original_value_maybe_array
96
+	 * @param string              $request_version (eg 4.8.36)
97
+	 * @return array
98
+	 * @throws EE_Error
99
+	 * @throws EE_Error
100
+	 */
101
+	public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
102
+	{
103
+		if (is_array($original_value_maybe_array)) {
104
+			$new_value = [];
105
+			foreach ($original_value_maybe_array as $key => $value) {
106
+				$new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
107
+					$field_obj,
108
+					$value,
109
+					$request_version
110
+				);
111
+			}
112
+		} else {
113
+			$new_value = ModelDataTranslator::prepareFieldValueForJson(
114
+				$field_obj,
115
+				$original_value_maybe_array,
116
+				$request_version
117
+			);
118
+		}
119
+		return $new_value;
120
+	}
121
+
122
+
123
+	/**
124
+	 * Prepares incoming data from the json or request parameters for the models'
125
+	 * "$query_params".
126
+	 *
127
+	 * @param EE_Model_Field_Base $field_obj
128
+	 * @param mixed               $original_value
129
+	 * @param string              $requested_version
130
+	 * @param string              $timezone_string treat values as being in this timezone
131
+	 * @return mixed
132
+	 * @throws RestException
133
+	 * @throws DomainException
134
+	 * @throws EE_Error
135
+	 */
136
+	public static function prepareFieldValueFromJson(
137
+		$field_obj,
138
+		$original_value,
139
+		$requested_version,
140
+		$timezone_string = 'UTC'
141
+	) {
142
+		// check if they accidentally submitted an error value. If so throw an exception
143
+		if (
144
+			is_array($original_value)
145
+			&& isset($original_value['error_code'], $original_value['error_message'])
146
+		) {
147
+			throw new RestException(
148
+				'rest_submitted_error_value',
149
+				sprintf(
150
+					esc_html__(
151
+						'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
152
+						'event_espresso'
153
+					),
154
+					$field_obj->get_name()
155
+				),
156
+				[
157
+					'status' => 400,
158
+				]
159
+			);
160
+		}
161
+		// double-check for serialized PHP. We never accept serialized PHP. No way Jose.
162
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
163
+		$timezone_string =
164
+			$timezone_string !== ''
165
+				? $timezone_string
166
+				: get_option('timezone_string', '');
167
+		// walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
168
+		// way Jose.
169
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
170
+		if (
171
+			$field_obj instanceof EE_Infinite_Integer_Field
172
+			&& in_array($original_value, [null, ''], true)
173
+		) {
174
+			$new_value = EE_INF;
175
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
176
+			$new_value = rest_parse_date(
177
+				self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
178
+			);
179
+			if ($new_value === false) {
180
+				throw new RestException(
181
+					'invalid_format_for_timestamp',
182
+					sprintf(
183
+						esc_html__(
184
+							'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
185
+							'event_espresso'
186
+						),
187
+						'RFC3339',
188
+						'ISO8601',
189
+						$original_value
190
+					),
191
+					[
192
+						'status' => 400,
193
+					]
194
+				);
195
+			}
196
+		} elseif ($field_obj instanceof EE_Boolean_Field) {
197
+			// Interpreted the strings "false", "true", "on", "off" appropriately.
198
+			$new_value = filter_var($original_value, FILTER_VALIDATE_BOOLEAN);
199
+		} else {
200
+			$new_value = $original_value;
201
+		}
202
+		return $new_value;
203
+	}
204
+
205
+
206
+	/**
207
+	 * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
208
+	 * information via details obtained from the host site.
209
+	 *
210
+	 * @param string            $original_timestamp
211
+	 * @param EE_Datetime_Field $datetime_field
212
+	 * @param                   $timezone_string
213
+	 * @return string
214
+	 * @throws DomainException
215
+	 */
216
+	private static function getTimestampWithTimezoneOffset(
217
+		$original_timestamp,
218
+		EE_Datetime_Field $datetime_field,
219
+		$timezone_string
220
+	) {
221
+		// already have timezone information?
222
+		if (preg_match('/Z|([+-])(\d{2}:\d{2})/', $original_timestamp)) {
223
+			// yes, we're ignoring the timezone.
224
+			return $original_timestamp;
225
+		}
226
+		// need to append timezone
227
+		list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
228
+			$datetime_field->get_timezone_offset(
229
+				new DateTimeZone($timezone_string),
230
+				$original_timestamp
231
+			)
232
+		);
233
+		$offset_string =
234
+			str_pad(
235
+				floor($offset_secs / HOUR_IN_SECONDS),
236
+				2,
237
+				'0',
238
+				STR_PAD_LEFT
239
+			)
240
+			. ':'
241
+			. str_pad(
242
+				($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
243
+				2,
244
+				'0',
245
+				STR_PAD_LEFT
246
+			);
247
+		return $original_timestamp . $offset_sign . $offset_string;
248
+	}
249
+
250
+
251
+	/**
252
+	 * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
253
+	 * think that can happen). If $data is an array, recurses into its keys and values
254
+	 *
255
+	 * @param mixed $data
256
+	 * @return void
257
+	 * @throws RestException
258
+	 */
259
+	public static function throwExceptionIfContainsSerializedData($data)
260
+	{
261
+		if (is_array($data)) {
262
+			foreach ($data as $key => $value) {
263
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
264
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
265
+			}
266
+		} else {
267
+			if (is_serialized($data) || is_object($data)) {
268
+				throw new RestException(
269
+					'serialized_data_submission_prohibited',
270
+					esc_html__(
271
+					// @codingStandardsIgnoreStart
272
+						'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
273
+						// @codingStandardsIgnoreEnd
274
+						'event_espresso'
275
+					)
276
+				);
277
+			}
278
+		}
279
+	}
280
+
281
+
282
+	/**
283
+	 * determines what's going on with them timezone strings
284
+	 *
285
+	 * @param int $timezone_offset
286
+	 * @return array
287
+	 */
288
+	private static function parseTimezoneOffset($timezone_offset)
289
+	{
290
+		$first_char = substr((string) $timezone_offset, 0, 1);
291
+		if ($first_char === '+' || $first_char === '-') {
292
+			$offset_sign = $first_char;
293
+			$offset_secs = substr((string) $timezone_offset, 1);
294
+		} else {
295
+			$offset_sign = '+';
296
+			$offset_secs = $timezone_offset;
297
+		}
298
+		return [$offset_sign, $offset_secs];
299
+	}
300
+
301
+
302
+	/**
303
+	 * Prepares a field's value for display in the API
304
+	 *
305
+	 * @param EE_Model_Field_Base $field_obj
306
+	 * @param mixed               $original_value
307
+	 * @param string              $requested_version
308
+	 * @return mixed
309
+	 * @throws EE_Error
310
+	 * @throws EE_Error
311
+	 */
312
+	public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
313
+	{
314
+		if ($original_value === EE_INF) {
315
+			$new_value = ModelDataTranslator::EE_INF_IN_REST;
316
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
317
+			if (is_string($original_value)) {
318
+				// did they submit a string of a unix timestamp?
319
+				if (is_numeric($original_value)) {
320
+					$datetime_obj = new DateTime();
321
+					$datetime_obj->setTimestamp((int) $original_value);
322
+				} else {
323
+					// first, check if its a MySQL timestamp in GMT
324
+					$datetime_obj = DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
325
+				}
326
+				if (! $datetime_obj instanceof DateTime) {
327
+					// so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
328
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
329
+				}
330
+				$original_value = $datetime_obj;
331
+			}
332
+			if ($original_value instanceof DateTime) {
333
+				$new_value = $original_value->format('Y-m-d H:i:s');
334
+			} elseif (is_int($original_value) || is_float($original_value)) {
335
+				$new_value = date('Y-m-d H:i:s', $original_value);
336
+			} elseif ($original_value === null || $original_value === '') {
337
+				$new_value = null;
338
+			} else {
339
+				// so it's not a datetime object, unix timestamp (as string or int),
340
+				// MySQL timestamp, or even a string in the field object's format. So no idea what it is
341
+				throw new EE_Error(
342
+					sprintf(
343
+						esc_html__(
344
+						// @codingStandardsIgnoreStart
345
+							'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
346
+							// @codingStandardsIgnoreEnd
347
+							'event_espresso'
348
+						),
349
+						$original_value,
350
+						$field_obj->get_name(),
351
+						$field_obj->get_model_name(),
352
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
353
+					)
354
+				);
355
+			}
356
+			if ($new_value !== null) {
357
+				// phpcs:disable PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
358
+				$new_value = mysql_to_rfc3339($new_value);
359
+				// phpcs:enable
360
+			}
361
+		} else {
362
+			$new_value = $original_value;
363
+		}
364
+		// are we about to send an object? just don't. We have no good way to represent it in JSON.
365
+		// can't just check using is_object() because that missed PHP incomplete objects
366
+		if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
367
+			$new_value = [
368
+				'error_code'    => 'php_object_not_return',
369
+				'error_message' => esc_html__(
370
+					'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
371
+					'event_espresso'
372
+				),
373
+			];
374
+		}
375
+		return apply_filters(
376
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
377
+			$new_value,
378
+			$field_obj,
379
+			$original_value,
380
+			$requested_version
381
+		);
382
+	}
383
+
384
+
385
+	/**
386
+	 * Prepares condition-query-parameters (like what's in where and having) from
387
+	 * the format expected in the API to use in the models
388
+	 *
389
+	 * @param array    $inputted_query_params_of_this_type
390
+	 * @param EEM_Base $model
391
+	 * @param string   $requested_version
392
+	 * @param boolean  $writing whether this data will be written to the DB, or if we're just building a query.
393
+	 *                          If we're writing to the DB, we don't expect any operators, or any logic query
394
+	 *                          parameters, and we also won't accept serialized data unless the current user has
395
+	 *                          unfiltered_html.
396
+	 * @return array
397
+	 * @throws DomainException
398
+	 * @throws EE_Error
399
+	 * @throws RestException
400
+	 * @throws InvalidDataTypeException
401
+	 * @throws InvalidInterfaceException
402
+	 * @throws InvalidArgumentException
403
+	 */
404
+	public static function prepareConditionsQueryParamsForModels(
405
+		$inputted_query_params_of_this_type,
406
+		EEM_Base $model,
407
+		$requested_version,
408
+		$writing = false
409
+	) {
410
+		$query_param_for_models = [];
411
+		$context                = new RestIncomingQueryParamContext($model, $requested_version, $writing);
412
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
413
+			$query_param_meta = new RestIncomingQueryParamMetadata($query_param_key, $query_param_value, $context);
414
+			if ($query_param_meta->getField() instanceof EE_Model_Field_Base) {
415
+				$translated_value = $query_param_meta->determineConditionsQueryParameterValue();
416
+				if (
417
+					(isset($query_param_for_models[ $query_param_meta->getQueryParamKey() ])
418
+					 && $query_param_meta->isGmtField())
419
+					|| $translated_value === null
420
+				) {
421
+					// they have already provided a non-gmt field, ignore the gmt one. That's what WP core
422
+					// currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
423
+					// OR we couldn't create a translated value from their input
424
+					continue;
425
+				}
426
+				$query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $translated_value;
427
+			} else {
428
+				$nested_query_params = $query_param_meta->determineNestedConditionQueryParameters();
429
+				if ($nested_query_params) {
430
+					$query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $nested_query_params;
431
+				}
432
+			}
433
+		}
434
+		return $query_param_for_models;
435
+	}
436
+
437
+
438
+	/**
439
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
440
+	 * gmt date field name
441
+	 *
442
+	 * @param string $field_name
443
+	 * @return boolean
444
+	 */
445
+	public static function isGmtDateFieldName($field_name)
446
+	{
447
+		$field_name = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name);
448
+		return substr($field_name, -4, 4) === '_gmt';
449
+	}
450
+
451
+
452
+	/**
453
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
454
+	 *
455
+	 * @param string $field_name
456
+	 * @return string
457
+	 */
458
+	public static function removeGmtFromFieldName($field_name)
459
+	{
460
+		if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
461
+			return $field_name;
462
+		}
463
+		$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
464
+			$field_name
465
+		);
466
+		$query_param_sans_gmt_and_sans_stars = substr(
467
+			$query_param_sans_stars,
468
+			0,
469
+			strrpos(
470
+				$field_name,
471
+				'_gmt'
472
+			)
473
+		);
474
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
475
+	}
476
+
477
+
478
+	/**
479
+	 * Takes a field name from the REST API and prepares it for the model querying
480
+	 *
481
+	 * @param string $field_name
482
+	 * @return string
483
+	 */
484
+	public static function prepareFieldNameFromJson($field_name)
485
+	{
486
+		if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
487
+			return ModelDataTranslator::removeGmtFromFieldName($field_name);
488
+		}
489
+		return $field_name;
490
+	}
491
+
492
+
493
+	/**
494
+	 * Takes array of field names from REST API and prepares for models
495
+	 *
496
+	 * @param array $field_names
497
+	 * @return array of field names (possibly include model prefixes)
498
+	 */
499
+	public static function prepareFieldNamesFromJson(array $field_names)
500
+	{
501
+		$new_array = [];
502
+		foreach ($field_names as $key => $field_name) {
503
+			$new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
504
+		}
505
+		return $new_array;
506
+	}
507
+
508
+
509
+	/**
510
+	 * Takes array where array keys are field names (possibly with model path prefixes)
511
+	 * from the REST API and prepares them for model querying
512
+	 *
513
+	 * @param array $field_names_as_keys
514
+	 * @return array
515
+	 */
516
+	public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
517
+	{
518
+		$new_array = [];
519
+		foreach ($field_names_as_keys as $field_name => $value) {
520
+			$new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
521
+		}
522
+		return $new_array;
523
+	}
524
+
525
+
526
+	/**
527
+	 * Prepares an array of model query params for use in the REST API
528
+	 *
529
+	 * @param array    $model_query_params
530
+	 * @param EEM_Base $model
531
+	 * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
532
+	 *                                     REST API
533
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
534
+	 * @throws EE_Error
535
+	 * @throws ReflectionException
536
+	 */
537
+	public static function prepareQueryParamsForRestApi(
538
+		array $model_query_params,
539
+		EEM_Base $model,
540
+		$requested_version = null
541
+	) {
542
+		if ($requested_version === null) {
543
+			$requested_version = EED_Core_Rest_Api::latest_rest_api_version();
544
+		}
545
+		$rest_query_params = $model_query_params;
546
+		if (isset($model_query_params[0])) {
547
+			$rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
548
+				$model_query_params[0],
549
+				$model,
550
+				$requested_version
551
+			);
552
+			unset($rest_query_params[0]);
553
+		}
554
+		if (isset($model_query_params['having'])) {
555
+			$rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
556
+				$model_query_params['having'],
557
+				$model,
558
+				$requested_version
559
+			);
560
+		}
561
+		return apply_filters(
562
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
563
+			$rest_query_params,
564
+			$model_query_params,
565
+			$model,
566
+			$requested_version
567
+		);
568
+	}
569
+
570
+
571
+	/**
572
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
573
+	 *
574
+	 * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
575
+	 * @param EEM_Base $model
576
+	 * @param string   $requested_version                   eg "4.8.36"
577
+	 * @return array ready for use in the rest api query params
578
+	 * @throws EE_Error
579
+	 * @throws RestException if somehow a PHP object were in the query params' values,*@throws
580
+	 * @throws ReflectionException
581
+	 *                                                      ReflectionException
582
+	 *                                                      (which would be really unusual)
583
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
584
+	 */
585
+	public static function prepareConditionsQueryParamsForRestApi(
586
+		$inputted_query_params_of_this_type,
587
+		EEM_Base $model,
588
+		$requested_version
589
+	) {
590
+		$query_param_for_models = [];
591
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
592
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
593
+				ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
594
+				$model
595
+			);
596
+			if ($field instanceof EE_Model_Field_Base) {
597
+				// did they specify an operator?
598
+				if (is_array($query_param_value)) {
599
+					$op               = $query_param_value[0];
600
+					$translated_value = [$op];
601
+					if (isset($query_param_value[1])) {
602
+						$value               = $query_param_value[1];
603
+						$translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
604
+							$field,
605
+							$value,
606
+							$requested_version
607
+						);
608
+					}
609
+				} else {
610
+					$translated_value = ModelDataTranslator::prepareFieldValueForJson(
611
+						$field,
612
+						$query_param_value,
613
+						$requested_version
614
+					);
615
+				}
616
+				$query_param_for_models[ $query_param_key ] = $translated_value;
617
+			} else {
618
+				// so it's not for a field, assume it's a logic query param key
619
+				$query_param_for_models[ $query_param_key ] =
620
+					ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
621
+						$query_param_value,
622
+						$model,
623
+						$requested_version
624
+					);
625
+			}
626
+		}
627
+		return $query_param_for_models;
628
+	}
629
+
630
+
631
+	/**
632
+	 * @param $condition_query_param_key
633
+	 * @return string
634
+	 */
635
+	public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
636
+	{
637
+		$pos_of_star = strpos($condition_query_param_key, '*');
638
+		if ($pos_of_star === false) {
639
+			return $condition_query_param_key;
640
+		}
641
+		return substr($condition_query_param_key, 0, $pos_of_star);
642
+	}
643
+
644
+
645
+	/**
646
+	 * Takes the input parameter and finds the model field that it indicates.
647
+	 *
648
+	 * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
649
+	 * @param EEM_Base $model
650
+	 * @return EE_Model_Field_Base
651
+	 * @throws EE_Error
652
+	 * @throws ReflectionException
653
+	 */
654
+	public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
655
+	{
656
+		// ok, now proceed with deducing which part is the model's name, and which is the field's name
657
+		// which will help us find the database table and column
658
+		$query_param_parts = explode('.', $query_param_name);
659
+		if (empty($query_param_parts)) {
660
+			throw new EE_Error(
661
+				sprintf(
662
+					esc_html__(
663
+						'_extract_column_name is empty when trying to extract column and table name from %s',
664
+						'event_espresso'
665
+					),
666
+					$query_param_name
667
+				)
668
+			);
669
+		}
670
+		$number_of_parts       = count($query_param_parts);
671
+		$last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
672
+		$field_name            = $last_query_param_part;
673
+		if ($number_of_parts !== 1) {
674
+			// the last part is the column name, and there are only 2parts. therefore...
675
+			$model = EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
676
+		}
677
+		try {
678
+			return $model->field_settings_for($field_name, false);
679
+		} catch (EE_Error $e) {
680
+			return null;
681
+		}
682
+	}
683
+
684
+
685
+	/**
686
+	 * Returns true if $data can be easily represented in JSON.
687
+	 * Basically, objects and resources can't be represented in JSON easily.
688
+	 *
689
+	 * @param mixed $data
690
+	 * @return bool
691
+	 */
692
+	protected static function isRepresentableInJson($data)
693
+	{
694
+		return is_scalar($data)
695
+			   || is_array($data)
696
+			   || is_null($data);
697
+	}
698 698
 }
Please login to merge, or discard this patch.