Completed
Branch Gutenberg/master (0cafc4)
by
unknown
87:32 queued 73:04
created
admin_pages/general_settings/OrganizationSettings.php 1 patch
Indentation   +469 added lines, -469 removed lines patch added patch discarded remove patch
@@ -40,494 +40,494 @@
 block discarded – undo
40 40
 class OrganizationSettings extends FormHandler
41 41
 {
42 42
 
43
-    /**
44
-     * @var EE_Organization_Config
45
-     */
46
-    protected $organization_config;
43
+	/**
44
+	 * @var EE_Organization_Config
45
+	 */
46
+	protected $organization_config;
47 47
 
48
-    /**
49
-     * @var EE_Core_Config
50
-     */
51
-    protected $core_config;
48
+	/**
49
+	 * @var EE_Core_Config
50
+	 */
51
+	protected $core_config;
52 52
 
53 53
 
54
-    /**
55
-     * @var EE_Network_Core_Config
56
-     */
57
-    protected $network_core_config;
54
+	/**
55
+	 * @var EE_Network_Core_Config
56
+	 */
57
+	protected $network_core_config;
58 58
 
59
-    /**
60
-     * Form constructor.
61
-     *
62
-     * @param EE_Registry             $registry
63
-     * @param EE_Organization_Config  $organization_config
64
-     * @param EE_Core_Config          $core_config
65
-     * @param EE_Network_Core_Config $network_core_config
66
-     * @throws InvalidArgumentException
67
-     * @throws InvalidDataTypeException
68
-     * @throws DomainException
69
-     */
70
-    public function __construct(
71
-        EE_Registry $registry,
72
-        EE_Organization_Config $organization_config,
73
-        EE_Core_Config $core_config,
74
-        EE_Network_Core_Config $network_core_config
75
-    ) {
76
-        $this->organization_config = $organization_config;
77
-        $this->core_config = $core_config;
78
-        $this->network_core_config = $network_core_config;
79
-        parent::__construct(
80
-            esc_html__('Your Organization Settings', 'event_espresso'),
81
-            esc_html__('Your Organization Settings', 'event_espresso'),
82
-            'organization_settings',
83
-            '',
84
-            FormHandler::DO_NOT_SETUP_FORM,
85
-            $registry
86
-        );
87
-    }
59
+	/**
60
+	 * Form constructor.
61
+	 *
62
+	 * @param EE_Registry             $registry
63
+	 * @param EE_Organization_Config  $organization_config
64
+	 * @param EE_Core_Config          $core_config
65
+	 * @param EE_Network_Core_Config $network_core_config
66
+	 * @throws InvalidArgumentException
67
+	 * @throws InvalidDataTypeException
68
+	 * @throws DomainException
69
+	 */
70
+	public function __construct(
71
+		EE_Registry $registry,
72
+		EE_Organization_Config $organization_config,
73
+		EE_Core_Config $core_config,
74
+		EE_Network_Core_Config $network_core_config
75
+	) {
76
+		$this->organization_config = $organization_config;
77
+		$this->core_config = $core_config;
78
+		$this->network_core_config = $network_core_config;
79
+		parent::__construct(
80
+			esc_html__('Your Organization Settings', 'event_espresso'),
81
+			esc_html__('Your Organization Settings', 'event_espresso'),
82
+			'organization_settings',
83
+			'',
84
+			FormHandler::DO_NOT_SETUP_FORM,
85
+			$registry
86
+		);
87
+	}
88 88
 
89 89
 
90 90
 
91
-    /**
92
-     * creates and returns the actual form
93
-     *
94
-     * @return EE_Form_Section_Proper
95
-     * @throws EE_Error
96
-     */
97
-    public function generate()
98
-    {
99
-        $form = new EE_Form_Section_Proper(
100
-            array(
101
-                'name'            => 'organization_settings',
102
-                'html_id'         => 'organization_settings',
103
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
104
-                'subsections'     => array(
105
-                    'site_license_key_hdr' => new EE_Form_Section_HTML(
106
-                        EEH_HTML::h2(
107
-                            esc_html__('Your Event Espresso License Key', 'event_espresso')
108
-                            . ' '
109
-                            . EEH_HTML::span(
110
-                                EEH_Template::get_help_tab_link('site_license_key_info'),
111
-                                'help_tour_activation'
112
-                            ),
113
-                            '',
114
-                            'site-license-key-hdr'
115
-                        )
116
-                    ),
117
-                    'site_license_key'     => $this->getSiteLicenseKeyField(),
118
-                    'contact_information_hdr'        => new EE_Form_Section_HTML(
119
-                        EEH_HTML::h2(
120
-                            esc_html__('Contact Information', 'event_espresso')
121
-                            . ' '
122
-                            . EEH_HTML::span(EEH_Template::get_help_tab_link('contact_info_info')),
123
-                            '',
124
-                            'contact-information-hdr'
125
-                        )
126
-                    ),
127
-                    'organization_name'      => new EE_Text_Input(
128
-                        array(
129
-                            'html_name' => 'organization_name',
130
-                            'html_label_text' => esc_html__('Organization Name', 'event_espresso'),
131
-                            'html_help_text'  => esc_html__(
132
-                                'Displayed on all emails and invoices.',
133
-                                'event_espresso'
134
-                            ),
135
-                            'default'         => $this->organization_config->get_pretty('name'),
136
-                            'required'        => false,
137
-                        )
138
-                    ),
139
-                    'organization_address_1'      => new EE_Text_Input(
140
-                        array(
141
-                            'html_name' => 'organization_address_1',
142
-                            'html_label_text' => esc_html__('Street Address', 'event_espresso'),
143
-                            'default'         => $this->organization_config->get_pretty('address_1'),
144
-                            'required'        => false,
145
-                        )
146
-                    ),
147
-                    'organization_address_2'      => new EE_Text_Input(
148
-                        array(
149
-                            'html_name' => 'organization_address_2',
150
-                            'html_label_text' => esc_html__('Street Address 2', 'event_espresso'),
151
-                            'default'         => $this->organization_config->get_pretty('address_2'),
152
-                            'required'        => false,
153
-                        )
154
-                    ),
155
-                    'organization_city'      => new EE_Text_Input(
156
-                        array(
157
-                            'html_name' => 'organization_city',
158
-                            'html_label_text' => esc_html__('City', 'event_espresso'),
159
-                            'default'         => $this->organization_config->get_pretty('city'),
160
-                            'required'        => false,
161
-                        )
162
-                    ),
163
-                    'organization_state'      => new EE_State_Select_Input(
164
-                        null,
165
-                        array(
166
-                            'html_name' => 'organization_state',
167
-                            'html_label_text' => esc_html__('State/Province', 'event_espresso'),
168
-                            'default'         => $this->organization_config->STA_ID,
169
-                            'required'        => false,
170
-                        )
171
-                    ),
172
-                    'organization_country'      => new EE_Country_Select_Input(
173
-                        null,
174
-                        array(
175
-                            'html_name' => 'organization_country',
176
-                            'html_label_text' => esc_html__('Country', 'event_espresso'),
177
-                            'default'         => $this->organization_config->CNT_ISO,
178
-                            'required'        => false,
179
-                        )
180
-                    ),
181
-                    'organization_zip'      => new EE_Text_Input(
182
-                        array(
183
-                            'html_name' => 'organization_zip',
184
-                            'html_label_text' => esc_html__('Zip/Postal Code', 'event_espresso'),
185
-                            'default'         => $this->organization_config->get_pretty('zip'),
186
-                            'required'        => false,
187
-                        )
188
-                    ),
189
-                    'organization_email'      => new EE_Text_Input(
190
-                        array(
191
-                            'html_name' => 'organization_email',
192
-                            'html_label_text' => esc_html__('Primary Contact Email', 'event_espresso'),
193
-                            'html_help_text'  => sprintf(
194
-                                esc_html__(
195
-                                    'This is where notifications go to when you use the %1$s and %2$s shortcodes in the message templates.',
196
-                                    'event_espresso'
197
-                                ),
198
-                                '<code>[CO_FORMATTED_EMAIL]</code>',
199
-                                '<code>[CO_EMAIL]</code>'
200
-                            ),
201
-                            'default'         => $this->organization_config->get_pretty('email'),
202
-                            'required'        => false,
203
-                        )
204
-                    ),
205
-                    'organization_phone'      => new EE_Text_Input(
206
-                        array(
207
-                            'html_name' => 'organization_phone',
208
-                            'html_label_text' => esc_html__('Phone Number', 'event_espresso'),
209
-                            'html_help_text'  => esc_html__(
210
-                                'The phone number for your organization.',
211
-                                'event_espresso'
212
-                            ),
213
-                            'default'         => $this->organization_config->get_pretty('phone'),
214
-                            'required'        => false,
215
-                        )
216
-                    ),
217
-                    'organization_vat'      => new EE_Text_Input(
218
-                        array(
219
-                            'html_name' => 'organization_vat',
220
-                            'html_label_text' => esc_html__('VAT/Tax Number', 'event_espresso'),
221
-                            'html_help_text'  => esc_html__(
222
-                                'The VAT/Tax Number may be displayed on invoices and receipts.',
223
-                                'event_espresso'
224
-                            ),
225
-                            'default'         => $this->organization_config->get_pretty('vat'),
226
-                            'required'        => false,
227
-                        )
228
-                    ),
229
-                    'company_logo_hdr'        => new EE_Form_Section_HTML(
230
-                        EEH_HTML::h2(
231
-                            esc_html__('Company Logo', 'event_espresso')
232
-                            . ' '
233
-                            . EEH_HTML::span(EEH_Template::get_help_tab_link('organization_logo_info')),
234
-                            '',
235
-                            'company-logo-hdr'
236
-                        )
237
-                    ),
238
-                    'organization_logo_url'      => new EE_Admin_File_Uploader_Input(
239
-                        array(
240
-                            'html_name' => 'organization_logo_url',
241
-                            'html_label_text' => esc_html__('Upload New Logo', 'event_espresso'),
242
-                            'html_help_text'  => esc_html__(
243
-                                'Your logo will be used on custom invoices, tickets, certificates, and payment templates.',
244
-                                'event_espresso'
245
-                            ),
246
-                            'default'         => $this->organization_config->get_pretty('logo_url'),
247
-                            'required'        => false,
248
-                        )
249
-                    ),
250
-                    'social_links_hdr'        => new EE_Form_Section_HTML(
251
-                        EEH_HTML::h2(
252
-                            esc_html__('Social Links', 'event_espresso')
253
-                            . ' '
254
-                            . EEH_HTML::span(EEH_Template::get_help_tab_link('social_links_info'))
255
-                            . EEH_HTML::br()
256
-                            . EEH_HTML::p(
257
-                                esc_html__(
258
-                                    'Enter any links to social accounts for your organization here',
259
-                                    'event_espresso'
260
-                                ),
261
-                                '',
262
-                                'description'
263
-                            ),
264
-                            '',
265
-                            'social-links-hdr'
266
-                        )
267
-                    ),
268
-                    'organization_facebook'      => new EE_Text_Input(
269
-                        array(
270
-                            'html_name' => 'organization_facebook',
271
-                            'html_label_text' => esc_html__('Facebook', 'event_espresso'),
272
-                            'other_html_attributes' => ' placeholder="facebook.com/profile.name"',
273
-                            'default'         => $this->organization_config->get_pretty('facebook'),
274
-                            'required'        => false,
275
-                        )
276
-                    ),
277
-                    'organization_twitter'      => new EE_Text_Input(
278
-                        array(
279
-                            'html_name' => 'organization_twitter',
280
-                            'html_label_text' => esc_html__('Twitter', 'event_espresso'),
281
-                            'other_html_attributes' => ' placeholder="twitter.com/twitterhandle"',
282
-                            'default'         => $this->organization_config->get_pretty('twitter'),
283
-                            'required'        => false,
284
-                        )
285
-                    ),
286
-                    'organization_linkedin'      => new EE_Text_Input(
287
-                        array(
288
-                            'html_name' => 'organization_linkedin',
289
-                            'html_label_text' => esc_html__('LinkedIn', 'event_espresso'),
290
-                            'other_html_attributes' => ' placeholder="linkedin.com/in/profilename"',
291
-                            'default'         => $this->organization_config->get_pretty('linkedin'),
292
-                            'required'        => false,
293
-                        )
294
-                    ),
295
-                    'organization_pinterest'      => new EE_Text_Input(
296
-                        array(
297
-                            'html_name' => 'organization_pinterest',
298
-                            'html_label_text' => esc_html__('Pinterest', 'event_espresso'),
299
-                            'other_html_attributes' => ' placeholder="pinterest.com/profilename"',
300
-                            'default'         => $this->organization_config->get_pretty('pinterest'),
301
-                            'required'        => false,
302
-                        )
303
-                    ),
304
-                    'organization_google'      => new EE_Text_Input(
305
-                        array(
306
-                            'html_name' => 'organization_google',
307
-                            'html_label_text' => esc_html__('Google+', 'event_espresso'),
308
-                            'other_html_attributes' => ' placeholder="google.com/+profilename"',
309
-                            'default'         => $this->organization_config->get_pretty('google'),
310
-                            'required'        => false,
311
-                        )
312
-                    ),
313
-                    'organization_instagram'      => new EE_Text_Input(
314
-                        array(
315
-                            'html_name' => 'organization_instagram',
316
-                            'html_label_text' => esc_html__('Instagram', 'event_espresso'),
317
-                            'other_html_attributes' => ' placeholder="instagram.com/handle"',
318
-                            'default'         => $this->organization_config->get_pretty('instagram'),
319
-                            'required'        => false,
320
-                        )
321
-                    ),
322
-                ),
323
-            )
324
-        );
325
-        if (is_main_site()) {
326
-            $form->add_subsections(
327
-                array(
328
-                    'uxip_optin_hdr'  => new EE_Form_Section_HTML(
329
-                        $this->uxipOptinText()
330
-                    ),
331
-                    'ueip_optin' => new EE_Checkbox_Multi_Input(
332
-                        array(
333
-                            true => __('Yes! I want to help improve Event Espresso!', 'event_espresso')
334
-                        ),
335
-                        array(
336
-                            'html_name' => EE_Core_Config::OPTION_NAME_UXIP,
337
-                            'html_label_text' => esc_html__(
338
-                                'UXIP Opt In?',
339
-                                'event_espresso'
340
-                            ),
341
-                            'default'         => isset($this->core_config->ee_ueip_optin)
342
-                                ? filter_var($this->core_config->ee_ueip_optin, FILTER_VALIDATE_BOOLEAN)
343
-                                : false,
344
-                            'required'        => false,
345
-                        )
346
-                    ),
347
-                ),
348
-                'organization_instagram',
349
-                false
350
-            );
351
-        }
352
-        return $form;
353
-    }
91
+	/**
92
+	 * creates and returns the actual form
93
+	 *
94
+	 * @return EE_Form_Section_Proper
95
+	 * @throws EE_Error
96
+	 */
97
+	public function generate()
98
+	{
99
+		$form = new EE_Form_Section_Proper(
100
+			array(
101
+				'name'            => 'organization_settings',
102
+				'html_id'         => 'organization_settings',
103
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
104
+				'subsections'     => array(
105
+					'site_license_key_hdr' => new EE_Form_Section_HTML(
106
+						EEH_HTML::h2(
107
+							esc_html__('Your Event Espresso License Key', 'event_espresso')
108
+							. ' '
109
+							. EEH_HTML::span(
110
+								EEH_Template::get_help_tab_link('site_license_key_info'),
111
+								'help_tour_activation'
112
+							),
113
+							'',
114
+							'site-license-key-hdr'
115
+						)
116
+					),
117
+					'site_license_key'     => $this->getSiteLicenseKeyField(),
118
+					'contact_information_hdr'        => new EE_Form_Section_HTML(
119
+						EEH_HTML::h2(
120
+							esc_html__('Contact Information', 'event_espresso')
121
+							. ' '
122
+							. EEH_HTML::span(EEH_Template::get_help_tab_link('contact_info_info')),
123
+							'',
124
+							'contact-information-hdr'
125
+						)
126
+					),
127
+					'organization_name'      => new EE_Text_Input(
128
+						array(
129
+							'html_name' => 'organization_name',
130
+							'html_label_text' => esc_html__('Organization Name', 'event_espresso'),
131
+							'html_help_text'  => esc_html__(
132
+								'Displayed on all emails and invoices.',
133
+								'event_espresso'
134
+							),
135
+							'default'         => $this->organization_config->get_pretty('name'),
136
+							'required'        => false,
137
+						)
138
+					),
139
+					'organization_address_1'      => new EE_Text_Input(
140
+						array(
141
+							'html_name' => 'organization_address_1',
142
+							'html_label_text' => esc_html__('Street Address', 'event_espresso'),
143
+							'default'         => $this->organization_config->get_pretty('address_1'),
144
+							'required'        => false,
145
+						)
146
+					),
147
+					'organization_address_2'      => new EE_Text_Input(
148
+						array(
149
+							'html_name' => 'organization_address_2',
150
+							'html_label_text' => esc_html__('Street Address 2', 'event_espresso'),
151
+							'default'         => $this->organization_config->get_pretty('address_2'),
152
+							'required'        => false,
153
+						)
154
+					),
155
+					'organization_city'      => new EE_Text_Input(
156
+						array(
157
+							'html_name' => 'organization_city',
158
+							'html_label_text' => esc_html__('City', 'event_espresso'),
159
+							'default'         => $this->organization_config->get_pretty('city'),
160
+							'required'        => false,
161
+						)
162
+					),
163
+					'organization_state'      => new EE_State_Select_Input(
164
+						null,
165
+						array(
166
+							'html_name' => 'organization_state',
167
+							'html_label_text' => esc_html__('State/Province', 'event_espresso'),
168
+							'default'         => $this->organization_config->STA_ID,
169
+							'required'        => false,
170
+						)
171
+					),
172
+					'organization_country'      => new EE_Country_Select_Input(
173
+						null,
174
+						array(
175
+							'html_name' => 'organization_country',
176
+							'html_label_text' => esc_html__('Country', 'event_espresso'),
177
+							'default'         => $this->organization_config->CNT_ISO,
178
+							'required'        => false,
179
+						)
180
+					),
181
+					'organization_zip'      => new EE_Text_Input(
182
+						array(
183
+							'html_name' => 'organization_zip',
184
+							'html_label_text' => esc_html__('Zip/Postal Code', 'event_espresso'),
185
+							'default'         => $this->organization_config->get_pretty('zip'),
186
+							'required'        => false,
187
+						)
188
+					),
189
+					'organization_email'      => new EE_Text_Input(
190
+						array(
191
+							'html_name' => 'organization_email',
192
+							'html_label_text' => esc_html__('Primary Contact Email', 'event_espresso'),
193
+							'html_help_text'  => sprintf(
194
+								esc_html__(
195
+									'This is where notifications go to when you use the %1$s and %2$s shortcodes in the message templates.',
196
+									'event_espresso'
197
+								),
198
+								'<code>[CO_FORMATTED_EMAIL]</code>',
199
+								'<code>[CO_EMAIL]</code>'
200
+							),
201
+							'default'         => $this->organization_config->get_pretty('email'),
202
+							'required'        => false,
203
+						)
204
+					),
205
+					'organization_phone'      => new EE_Text_Input(
206
+						array(
207
+							'html_name' => 'organization_phone',
208
+							'html_label_text' => esc_html__('Phone Number', 'event_espresso'),
209
+							'html_help_text'  => esc_html__(
210
+								'The phone number for your organization.',
211
+								'event_espresso'
212
+							),
213
+							'default'         => $this->organization_config->get_pretty('phone'),
214
+							'required'        => false,
215
+						)
216
+					),
217
+					'organization_vat'      => new EE_Text_Input(
218
+						array(
219
+							'html_name' => 'organization_vat',
220
+							'html_label_text' => esc_html__('VAT/Tax Number', 'event_espresso'),
221
+							'html_help_text'  => esc_html__(
222
+								'The VAT/Tax Number may be displayed on invoices and receipts.',
223
+								'event_espresso'
224
+							),
225
+							'default'         => $this->organization_config->get_pretty('vat'),
226
+							'required'        => false,
227
+						)
228
+					),
229
+					'company_logo_hdr'        => new EE_Form_Section_HTML(
230
+						EEH_HTML::h2(
231
+							esc_html__('Company Logo', 'event_espresso')
232
+							. ' '
233
+							. EEH_HTML::span(EEH_Template::get_help_tab_link('organization_logo_info')),
234
+							'',
235
+							'company-logo-hdr'
236
+						)
237
+					),
238
+					'organization_logo_url'      => new EE_Admin_File_Uploader_Input(
239
+						array(
240
+							'html_name' => 'organization_logo_url',
241
+							'html_label_text' => esc_html__('Upload New Logo', 'event_espresso'),
242
+							'html_help_text'  => esc_html__(
243
+								'Your logo will be used on custom invoices, tickets, certificates, and payment templates.',
244
+								'event_espresso'
245
+							),
246
+							'default'         => $this->organization_config->get_pretty('logo_url'),
247
+							'required'        => false,
248
+						)
249
+					),
250
+					'social_links_hdr'        => new EE_Form_Section_HTML(
251
+						EEH_HTML::h2(
252
+							esc_html__('Social Links', 'event_espresso')
253
+							. ' '
254
+							. EEH_HTML::span(EEH_Template::get_help_tab_link('social_links_info'))
255
+							. EEH_HTML::br()
256
+							. EEH_HTML::p(
257
+								esc_html__(
258
+									'Enter any links to social accounts for your organization here',
259
+									'event_espresso'
260
+								),
261
+								'',
262
+								'description'
263
+							),
264
+							'',
265
+							'social-links-hdr'
266
+						)
267
+					),
268
+					'organization_facebook'      => new EE_Text_Input(
269
+						array(
270
+							'html_name' => 'organization_facebook',
271
+							'html_label_text' => esc_html__('Facebook', 'event_espresso'),
272
+							'other_html_attributes' => ' placeholder="facebook.com/profile.name"',
273
+							'default'         => $this->organization_config->get_pretty('facebook'),
274
+							'required'        => false,
275
+						)
276
+					),
277
+					'organization_twitter'      => new EE_Text_Input(
278
+						array(
279
+							'html_name' => 'organization_twitter',
280
+							'html_label_text' => esc_html__('Twitter', 'event_espresso'),
281
+							'other_html_attributes' => ' placeholder="twitter.com/twitterhandle"',
282
+							'default'         => $this->organization_config->get_pretty('twitter'),
283
+							'required'        => false,
284
+						)
285
+					),
286
+					'organization_linkedin'      => new EE_Text_Input(
287
+						array(
288
+							'html_name' => 'organization_linkedin',
289
+							'html_label_text' => esc_html__('LinkedIn', 'event_espresso'),
290
+							'other_html_attributes' => ' placeholder="linkedin.com/in/profilename"',
291
+							'default'         => $this->organization_config->get_pretty('linkedin'),
292
+							'required'        => false,
293
+						)
294
+					),
295
+					'organization_pinterest'      => new EE_Text_Input(
296
+						array(
297
+							'html_name' => 'organization_pinterest',
298
+							'html_label_text' => esc_html__('Pinterest', 'event_espresso'),
299
+							'other_html_attributes' => ' placeholder="pinterest.com/profilename"',
300
+							'default'         => $this->organization_config->get_pretty('pinterest'),
301
+							'required'        => false,
302
+						)
303
+					),
304
+					'organization_google'      => new EE_Text_Input(
305
+						array(
306
+							'html_name' => 'organization_google',
307
+							'html_label_text' => esc_html__('Google+', 'event_espresso'),
308
+							'other_html_attributes' => ' placeholder="google.com/+profilename"',
309
+							'default'         => $this->organization_config->get_pretty('google'),
310
+							'required'        => false,
311
+						)
312
+					),
313
+					'organization_instagram'      => new EE_Text_Input(
314
+						array(
315
+							'html_name' => 'organization_instagram',
316
+							'html_label_text' => esc_html__('Instagram', 'event_espresso'),
317
+							'other_html_attributes' => ' placeholder="instagram.com/handle"',
318
+							'default'         => $this->organization_config->get_pretty('instagram'),
319
+							'required'        => false,
320
+						)
321
+					),
322
+				),
323
+			)
324
+		);
325
+		if (is_main_site()) {
326
+			$form->add_subsections(
327
+				array(
328
+					'uxip_optin_hdr'  => new EE_Form_Section_HTML(
329
+						$this->uxipOptinText()
330
+					),
331
+					'ueip_optin' => new EE_Checkbox_Multi_Input(
332
+						array(
333
+							true => __('Yes! I want to help improve Event Espresso!', 'event_espresso')
334
+						),
335
+						array(
336
+							'html_name' => EE_Core_Config::OPTION_NAME_UXIP,
337
+							'html_label_text' => esc_html__(
338
+								'UXIP Opt In?',
339
+								'event_espresso'
340
+							),
341
+							'default'         => isset($this->core_config->ee_ueip_optin)
342
+								? filter_var($this->core_config->ee_ueip_optin, FILTER_VALIDATE_BOOLEAN)
343
+								: false,
344
+							'required'        => false,
345
+						)
346
+					),
347
+				),
348
+				'organization_instagram',
349
+				false
350
+			);
351
+		}
352
+		return $form;
353
+	}
354 354
 
355 355
 
356
-    /**
357
-     * takes the generated form and displays it along with ony other non-form HTML that may be required
358
-     * returns a string of HTML that can be directly echoed in a template
359
-     *
360
-     * @return string
361
-     * @throws EE_Error
362
-     * @throws InvalidArgumentException
363
-     * @throws InvalidDataTypeException
364
-     * @throws InvalidInterfaceException
365
-     * @throws LogicException
366
-     */
367
-    public function display()
368
-    {
369
-        $this->form()->enqueue_js();
370
-        return parent::display();
371
-    }
356
+	/**
357
+	 * takes the generated form and displays it along with ony other non-form HTML that may be required
358
+	 * returns a string of HTML that can be directly echoed in a template
359
+	 *
360
+	 * @return string
361
+	 * @throws EE_Error
362
+	 * @throws InvalidArgumentException
363
+	 * @throws InvalidDataTypeException
364
+	 * @throws InvalidInterfaceException
365
+	 * @throws LogicException
366
+	 */
367
+	public function display()
368
+	{
369
+		$this->form()->enqueue_js();
370
+		return parent::display();
371
+	}
372 372
 
373 373
 
374
-    /**
375
-     * handles processing the form submission
376
-     * returns true or false depending on whether the form was processed successfully or not
377
-     *
378
-     * @param array $form_data
379
-     * @return bool
380
-     * @throws InvalidFormSubmissionException
381
-     * @throws EE_Error
382
-     * @throws LogicException
383
-     * @throws InvalidArgumentException
384
-     * @throws InvalidDataTypeException
385
-     */
386
-    public function process($form_data = array())
387
-    {
388
-        // process form
389
-        $valid_data = (array) parent::process($form_data);
390
-        if (empty($valid_data)) {
391
-            return false;
392
-        }
374
+	/**
375
+	 * handles processing the form submission
376
+	 * returns true or false depending on whether the form was processed successfully or not
377
+	 *
378
+	 * @param array $form_data
379
+	 * @return bool
380
+	 * @throws InvalidFormSubmissionException
381
+	 * @throws EE_Error
382
+	 * @throws LogicException
383
+	 * @throws InvalidArgumentException
384
+	 * @throws InvalidDataTypeException
385
+	 */
386
+	public function process($form_data = array())
387
+	{
388
+		// process form
389
+		$valid_data = (array) parent::process($form_data);
390
+		if (empty($valid_data)) {
391
+			return false;
392
+		}
393 393
 
394
-        if (is_main_site()) {
395
-            $this->network_core_config->site_license_key = isset($form_data['ee_site_license_key'])
396
-                ? sanitize_text_field($form_data['ee_site_license_key'])
397
-                : $this->network_core_config->site_license_key;
398
-        }
399
-        $this->organization_config->name = isset($form_data['organization_name'])
400
-            ? sanitize_text_field($form_data['organization_name'])
401
-            : $this->organization_config->name;
402
-        $this->organization_config->address_1 = isset($form_data['organization_address_1'])
403
-            ? sanitize_text_field($form_data['organization_address_1'])
404
-            : $this->organization_config->address_1;
405
-        $this->organization_config->address_2 = isset($form_data['organization_address_2'])
406
-            ? sanitize_text_field($form_data['organization_address_2'])
407
-            : $this->organization_config->address_2;
408
-        $this->organization_config->city = isset($form_data['organization_city'])
409
-            ? sanitize_text_field($form_data['organization_city'])
410
-            : $this->organization_config->city;
411
-        $this->organization_config->STA_ID = isset($form_data['organization_state'])
412
-            ? absint($form_data['organization_state'])
413
-            : $this->organization_config->STA_ID;
414
-        $this->organization_config->CNT_ISO = isset($form_data['organization_country'])
415
-            ? sanitize_text_field($form_data['organization_country'])
416
-            : $this->organization_config->CNT_ISO;
417
-        $this->organization_config->zip = isset($form_data['organization_zip'])
418
-            ? sanitize_text_field($form_data['organization_zip'])
419
-            : $this->organization_config->zip;
420
-        $this->organization_config->email = isset($form_data['organization_email'])
421
-            ? sanitize_email($form_data['organization_email'])
422
-            : $this->organization_config->email;
423
-        $this->organization_config->vat = isset($form_data['organization_vat'])
424
-            ? sanitize_text_field($form_data['organization_vat'])
425
-            : $this->organization_config->vat;
426
-        $this->organization_config->phone = isset($form_data['organization_phone'])
427
-            ? sanitize_text_field($form_data['organization_phone'])
428
-            : $this->organization_config->phone;
429
-        $this->organization_config->logo_url = isset($form_data['organization_logo_url'])
430
-            ? esc_url_raw($form_data['organization_logo_url'])
431
-            : $this->organization_config->logo_url;
432
-        $this->organization_config->facebook = isset($form_data['organization_facebook'])
433
-            ? esc_url_raw($form_data['organization_facebook'])
434
-            : $this->organization_config->facebook;
435
-        $this->organization_config->twitter = isset($form_data['organization_twitter'])
436
-            ? esc_url_raw($form_data['organization_twitter'])
437
-            : $this->organization_config->twitter;
438
-        $this->organization_config->linkedin = isset($form_data['organization_linkedin'])
439
-            ? esc_url_raw($form_data['organization_linkedin'])
440
-            : $this->organization_config->linkedin;
441
-        $this->organization_config->pinterest = isset($form_data['organization_pinterest'])
442
-            ? esc_url_raw($form_data['organization_pinterest'])
443
-            : $this->organization_config->pinterest;
444
-        $this->organization_config->google = isset($form_data['organization_google'])
445
-            ? esc_url_raw($form_data['organization_google'])
446
-            : $this->organization_config->google;
447
-        $this->organization_config->instagram = isset($form_data['organization_instagram'])
448
-            ? esc_url_raw($form_data['organization_instagram'])
449
-            : $this->organization_config->instagram;
450
-        $this->core_config->ee_ueip_optin = isset($form_data[ EE_Core_Config::OPTION_NAME_UXIP ][0])
451
-            ? filter_var($form_data[ EE_Core_Config::OPTION_NAME_UXIP ][0], FILTER_VALIDATE_BOOLEAN)
452
-            : false;
453
-        $this->core_config->ee_ueip_has_notified = true;
394
+		if (is_main_site()) {
395
+			$this->network_core_config->site_license_key = isset($form_data['ee_site_license_key'])
396
+				? sanitize_text_field($form_data['ee_site_license_key'])
397
+				: $this->network_core_config->site_license_key;
398
+		}
399
+		$this->organization_config->name = isset($form_data['organization_name'])
400
+			? sanitize_text_field($form_data['organization_name'])
401
+			: $this->organization_config->name;
402
+		$this->organization_config->address_1 = isset($form_data['organization_address_1'])
403
+			? sanitize_text_field($form_data['organization_address_1'])
404
+			: $this->organization_config->address_1;
405
+		$this->organization_config->address_2 = isset($form_data['organization_address_2'])
406
+			? sanitize_text_field($form_data['organization_address_2'])
407
+			: $this->organization_config->address_2;
408
+		$this->organization_config->city = isset($form_data['organization_city'])
409
+			? sanitize_text_field($form_data['organization_city'])
410
+			: $this->organization_config->city;
411
+		$this->organization_config->STA_ID = isset($form_data['organization_state'])
412
+			? absint($form_data['organization_state'])
413
+			: $this->organization_config->STA_ID;
414
+		$this->organization_config->CNT_ISO = isset($form_data['organization_country'])
415
+			? sanitize_text_field($form_data['organization_country'])
416
+			: $this->organization_config->CNT_ISO;
417
+		$this->organization_config->zip = isset($form_data['organization_zip'])
418
+			? sanitize_text_field($form_data['organization_zip'])
419
+			: $this->organization_config->zip;
420
+		$this->organization_config->email = isset($form_data['organization_email'])
421
+			? sanitize_email($form_data['organization_email'])
422
+			: $this->organization_config->email;
423
+		$this->organization_config->vat = isset($form_data['organization_vat'])
424
+			? sanitize_text_field($form_data['organization_vat'])
425
+			: $this->organization_config->vat;
426
+		$this->organization_config->phone = isset($form_data['organization_phone'])
427
+			? sanitize_text_field($form_data['organization_phone'])
428
+			: $this->organization_config->phone;
429
+		$this->organization_config->logo_url = isset($form_data['organization_logo_url'])
430
+			? esc_url_raw($form_data['organization_logo_url'])
431
+			: $this->organization_config->logo_url;
432
+		$this->organization_config->facebook = isset($form_data['organization_facebook'])
433
+			? esc_url_raw($form_data['organization_facebook'])
434
+			: $this->organization_config->facebook;
435
+		$this->organization_config->twitter = isset($form_data['organization_twitter'])
436
+			? esc_url_raw($form_data['organization_twitter'])
437
+			: $this->organization_config->twitter;
438
+		$this->organization_config->linkedin = isset($form_data['organization_linkedin'])
439
+			? esc_url_raw($form_data['organization_linkedin'])
440
+			: $this->organization_config->linkedin;
441
+		$this->organization_config->pinterest = isset($form_data['organization_pinterest'])
442
+			? esc_url_raw($form_data['organization_pinterest'])
443
+			: $this->organization_config->pinterest;
444
+		$this->organization_config->google = isset($form_data['organization_google'])
445
+			? esc_url_raw($form_data['organization_google'])
446
+			: $this->organization_config->google;
447
+		$this->organization_config->instagram = isset($form_data['organization_instagram'])
448
+			? esc_url_raw($form_data['organization_instagram'])
449
+			: $this->organization_config->instagram;
450
+		$this->core_config->ee_ueip_optin = isset($form_data[ EE_Core_Config::OPTION_NAME_UXIP ][0])
451
+			? filter_var($form_data[ EE_Core_Config::OPTION_NAME_UXIP ][0], FILTER_VALIDATE_BOOLEAN)
452
+			: false;
453
+		$this->core_config->ee_ueip_has_notified = true;
454 454
 
455
-        $this->registry->CFG->currency = new EE_Currency_Config(
456
-            $this->organization_config->CNT_ISO
457
-        );
458
-        return true;
459
-    }
455
+		$this->registry->CFG->currency = new EE_Currency_Config(
456
+			$this->organization_config->CNT_ISO
457
+		);
458
+		return true;
459
+	}
460 460
 
461 461
 
462
-    /**
463
-     * @return string
464
-     */
465
-    private function uxipOptinText()
466
-    {
467
-        ob_start();
468
-        Stats::optinText(false);
469
-        return ob_get_clean();
470
-    }
462
+	/**
463
+	 * @return string
464
+	 */
465
+	private function uxipOptinText()
466
+	{
467
+		ob_start();
468
+		Stats::optinText(false);
469
+		return ob_get_clean();
470
+	}
471 471
 
472 472
 
473
-    /**
474
-     * Return whether the site license key has been verified or not.
475
-     * @return bool
476
-     */
477
-    private function licenseKeyVerified()
478
-    {
479
-        if (empty($this->network_core_config->site_license_key)) {
480
-            return false;
481
-        }
482
-        $ver_option_key = 'puvererr_' . basename(EE_PLUGIN_BASENAME);
483
-        $verify_fail = get_option($ver_option_key, false);
484
-        return $verify_fail === false
485
-                  || (! empty($this->network_core_config->site_license_key)
486
-                        && $verify_fail === false
487
-                  );
488
-    }
473
+	/**
474
+	 * Return whether the site license key has been verified or not.
475
+	 * @return bool
476
+	 */
477
+	private function licenseKeyVerified()
478
+	{
479
+		if (empty($this->network_core_config->site_license_key)) {
480
+			return false;
481
+		}
482
+		$ver_option_key = 'puvererr_' . basename(EE_PLUGIN_BASENAME);
483
+		$verify_fail = get_option($ver_option_key, false);
484
+		return $verify_fail === false
485
+				  || (! empty($this->network_core_config->site_license_key)
486
+						&& $verify_fail === false
487
+				  );
488
+	}
489 489
 
490 490
 
491
-    /**
492
-     * @return EE_Text_Input
493
-     */
494
-    private function getSiteLicenseKeyField()
495
-    {
496
-        $text_input = new EE_Text_Input(
497
-            array(
498
-                'html_name' => 'ee_site_license_key',
499
-                'html_id' => 'site_license_key',
500
-                'html_label_text' => esc_html__('Support License Key', 'event_espresso'),
501
-                /** phpcs:disable WordPress.WP.I18n.UnorderedPlaceholdersText */
502
-                'html_help_text'  => sprintf(
503
-                    esc_html__(
504
-                        'Adding a valid Support License Key will enable automatic update notifications and backend updates for Event Espresso Core and any installed add-ons. If this is a Development or Test site, %sDO NOT%s enter your Support License Key.',
505
-                        'event_espresso'
506
-                    ),
507
-                    '<strong>',
508
-                    '</strong>'
509
-                ),
510
-                /** phpcs:enable */
511
-                'default'         => isset($this->network_core_config->site_license_key)
512
-                    ? $this->network_core_config->site_license_key
513
-                    : '',
514
-                'required'        => false,
515
-                'form_html_filter' => new VsprintfFilter(
516
-                    '%2$s %1$s',
517
-                    array($this->getValidationIndicator())
518
-                )
519
-            )
520
-        );
521
-        return $text_input;
522
-    }
491
+	/**
492
+	 * @return EE_Text_Input
493
+	 */
494
+	private function getSiteLicenseKeyField()
495
+	{
496
+		$text_input = new EE_Text_Input(
497
+			array(
498
+				'html_name' => 'ee_site_license_key',
499
+				'html_id' => 'site_license_key',
500
+				'html_label_text' => esc_html__('Support License Key', 'event_espresso'),
501
+				/** phpcs:disable WordPress.WP.I18n.UnorderedPlaceholdersText */
502
+				'html_help_text'  => sprintf(
503
+					esc_html__(
504
+						'Adding a valid Support License Key will enable automatic update notifications and backend updates for Event Espresso Core and any installed add-ons. If this is a Development or Test site, %sDO NOT%s enter your Support License Key.',
505
+						'event_espresso'
506
+					),
507
+					'<strong>',
508
+					'</strong>'
509
+				),
510
+				/** phpcs:enable */
511
+				'default'         => isset($this->network_core_config->site_license_key)
512
+					? $this->network_core_config->site_license_key
513
+					: '',
514
+				'required'        => false,
515
+				'form_html_filter' => new VsprintfFilter(
516
+					'%2$s %1$s',
517
+					array($this->getValidationIndicator())
518
+				)
519
+			)
520
+		);
521
+		return $text_input;
522
+	}
523 523
 
524 524
 
525
-    /**
526
-     * @return string
527
-     */
528
-    private function getValidationIndicator()
529
-    {
530
-        $verified_class = $this->licenseKeyVerified() ? 'ee-icon-color-ee-green' : 'ee-icon-color-ee-red';
531
-        return '<span class="dashicons dashicons-admin-network ' . $verified_class . ' ee-icon-size-20"></span>';
532
-    }
525
+	/**
526
+	 * @return string
527
+	 */
528
+	private function getValidationIndicator()
529
+	{
530
+		$verified_class = $this->licenseKeyVerified() ? 'ee-icon-color-ee-green' : 'ee-icon-color-ee-red';
531
+		return '<span class="dashicons dashicons-admin-network ' . $verified_class . ' ee-icon-size-20"></span>';
532
+	}
533 533
 }
Please login to merge, or discard this patch.
core/libraries/plugin_api/EE_Register_Addon.lib.php 2 patches
Indentation   +1161 added lines, -1161 removed lines patch added patch discarded remove patch
@@ -22,1225 +22,1225 @@
 block discarded – undo
22 22
 class EE_Register_Addon implements EEI_Plugin_API
23 23
 {
24 24
 
25
-    /**
26
-     * possibly truncated version of the EE core version string
27
-     *
28
-     * @var string
29
-     */
30
-    protected static $_core_version = '';
25
+	/**
26
+	 * possibly truncated version of the EE core version string
27
+	 *
28
+	 * @var string
29
+	 */
30
+	protected static $_core_version = '';
31 31
 
32
-    /**
33
-     * Holds values for registered addons
34
-     *
35
-     * @var array
36
-     */
37
-    protected static $_settings = array();
32
+	/**
33
+	 * Holds values for registered addons
34
+	 *
35
+	 * @var array
36
+	 */
37
+	protected static $_settings = array();
38 38
 
39
-    /**
40
-     * @var  array $_incompatible_addons keys are addon SLUGS
41
-     * (first argument passed to EE_Register_Addon::register()), keys are
42
-     * their MINIMUM VERSION (with all 5 parts. Eg 1.2.3.rc.004).
43
-     * Generally this should be used sparingly, as we don't want to muddle up
44
-     * EE core with knowledge of ALL the addons out there.
45
-     * If you want NO versions of an addon to run with a certain version of core,
46
-     * it's usually best to define the addon's "min_core_version" as part of its call
47
-     * to EE_Register_Addon::register(), rather than using this array with a super high value for its
48
-     * minimum plugin version.
49
-     * @access    protected
50
-     */
51
-    protected static $_incompatible_addons = array(
52
-        'Multi_Event_Registration' => '2.0.11.rc.002',
53
-        'Promotions'               => '1.0.0.rc.084',
54
-    );
39
+	/**
40
+	 * @var  array $_incompatible_addons keys are addon SLUGS
41
+	 * (first argument passed to EE_Register_Addon::register()), keys are
42
+	 * their MINIMUM VERSION (with all 5 parts. Eg 1.2.3.rc.004).
43
+	 * Generally this should be used sparingly, as we don't want to muddle up
44
+	 * EE core with knowledge of ALL the addons out there.
45
+	 * If you want NO versions of an addon to run with a certain version of core,
46
+	 * it's usually best to define the addon's "min_core_version" as part of its call
47
+	 * to EE_Register_Addon::register(), rather than using this array with a super high value for its
48
+	 * minimum plugin version.
49
+	 * @access    protected
50
+	 */
51
+	protected static $_incompatible_addons = array(
52
+		'Multi_Event_Registration' => '2.0.11.rc.002',
53
+		'Promotions'               => '1.0.0.rc.084',
54
+	);
55 55
 
56 56
 
57
-    /**
58
-     * We should always be comparing core to a version like '4.3.0.rc.000',
59
-     * not just '4.3.0'.
60
-     * So if the addon developer doesn't provide that full version string,
61
-     * fill in the blanks for them
62
-     *
63
-     * @param string $min_core_version
64
-     * @return string always like '4.3.0.rc.000'
65
-     */
66
-    protected static function _effective_version($min_core_version)
67
-    {
68
-        // versions: 4 . 3 . 1 . p . 123
69
-        // offsets:    0 . 1 . 2 . 3 . 4
70
-        $version_parts = explode('.', $min_core_version);
71
-        // check they specified the micro version (after 2nd period)
72
-        if (! isset($version_parts[2])) {
73
-            $version_parts[2] = '0';
74
-        }
75
-        // if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
76
-        // soon we can assume that's 'rc', but this current version is 'alpha'
77
-        if (! isset($version_parts[3])) {
78
-            $version_parts[3] = 'dev';
79
-        }
80
-        if (! isset($version_parts[4])) {
81
-            $version_parts[4] = '000';
82
-        }
83
-        return implode('.', $version_parts);
84
-    }
57
+	/**
58
+	 * We should always be comparing core to a version like '4.3.0.rc.000',
59
+	 * not just '4.3.0'.
60
+	 * So if the addon developer doesn't provide that full version string,
61
+	 * fill in the blanks for them
62
+	 *
63
+	 * @param string $min_core_version
64
+	 * @return string always like '4.3.0.rc.000'
65
+	 */
66
+	protected static function _effective_version($min_core_version)
67
+	{
68
+		// versions: 4 . 3 . 1 . p . 123
69
+		// offsets:    0 . 1 . 2 . 3 . 4
70
+		$version_parts = explode('.', $min_core_version);
71
+		// check they specified the micro version (after 2nd period)
72
+		if (! isset($version_parts[2])) {
73
+			$version_parts[2] = '0';
74
+		}
75
+		// if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
76
+		// soon we can assume that's 'rc', but this current version is 'alpha'
77
+		if (! isset($version_parts[3])) {
78
+			$version_parts[3] = 'dev';
79
+		}
80
+		if (! isset($version_parts[4])) {
81
+			$version_parts[4] = '000';
82
+		}
83
+		return implode('.', $version_parts);
84
+	}
85 85
 
86 86
 
87
-    /**
88
-     * Returns whether or not the min core version requirement of the addon is met
89
-     *
90
-     * @param string $min_core_version    the minimum core version required by the addon
91
-     * @param string $actual_core_version the actual core version, optional
92
-     * @return boolean
93
-     */
94
-    public static function _meets_min_core_version_requirement(
95
-        $min_core_version,
96
-        $actual_core_version = EVENT_ESPRESSO_VERSION
97
-    ) {
98
-        return version_compare(
99
-            self::_effective_version($actual_core_version),
100
-            self::_effective_version($min_core_version),
101
-            '>='
102
-        );
103
-    }
87
+	/**
88
+	 * Returns whether or not the min core version requirement of the addon is met
89
+	 *
90
+	 * @param string $min_core_version    the minimum core version required by the addon
91
+	 * @param string $actual_core_version the actual core version, optional
92
+	 * @return boolean
93
+	 */
94
+	public static function _meets_min_core_version_requirement(
95
+		$min_core_version,
96
+		$actual_core_version = EVENT_ESPRESSO_VERSION
97
+	) {
98
+		return version_compare(
99
+			self::_effective_version($actual_core_version),
100
+			self::_effective_version($min_core_version),
101
+			'>='
102
+		);
103
+	}
104 104
 
105 105
 
106
-    /**
107
-     * Method for registering new EE_Addons.
108
-     * Should be called AFTER AHEE__EE_System__load_espresso_addons but BEFORE
109
-     * AHEE__EE_System___detect_if_activation_or_upgrade__begin in order to register all its components. However, it
110
-     * may also be called after the 'activate_plugin' action (when an addon is activated), because an activating addon
111
-     * won't be loaded by WP until after AHEE__EE_System__load_espresso_addons has fired. If its called after
112
-     * 'activate_plugin', it registers the addon still, but its components are not registered
113
-     * (they shouldn't be needed anyways, because it's just an activation request and they won't have a chance to do
114
-     * anything anyways). Instead, it just sets the newly-activated addon's activation indicator wp option and returns
115
-     * (so that we can detect that the addon has activated on the subsequent request)
116
-     *
117
-     * @since    4.3.0
118
-     * @param string                  $addon_name                       [Required] the EE_Addon's name.
119
-     * @param  array                  $setup_args                       {
120
-     *                                                                  An array of arguments provided for registering
121
-     *                                                                  the message type.
122
-     * @type  string                  $class_name                       the addon's main file name.
123
-     *                                                                  If left blank, generated from the addon name,
124
-     *                                                                  changes something like "calendar" to
125
-     *                                                                  "EE_Calendar"
126
-     * @type string                   $min_core_version                 the minimum version of EE Core that the
127
-     *                                                                  addon will work with. eg "4.8.1.rc.084"
128
-     * @type string                   $version                          the "software" version for the addon. eg
129
-     *                                                                  "1.0.0.p" for a first stable release, or
130
-     *                                                                  "1.0.0.rc.043" for a version in progress
131
-     * @type string                   $main_file_path                   the full server path to the main file
132
-     *                                                                  loaded directly by WP
133
-     * @type DomainInterface $domain                                    child class of
134
-     *                                                                  EventEspresso\core\domain\DomainBase
135
-     * @type string                   $domain_fqcn                      Fully Qualified Class Name
136
-     *                                                                  for the addon's Domain class
137
-     *                                                                  (see EventEspresso\core\domain\Domain)
138
-     * @type string                   $admin_path                       full server path to the folder where the
139
-     *                                                                  addon\'s admin files reside
140
-     * @type string                   $admin_callback                   a method to be called when the EE Admin is
141
-     *                                                                  first invoked, can be used for hooking into
142
-     *                                                                  any admin page
143
-     * @type string                   $config_section                   the section name for this addon's
144
-     *                                                                  configuration settings section
145
-     *                                                                  (defaults to "addons")
146
-     * @type string                   $config_class                     the class name for this addon's
147
-     *                                                                  configuration settings object
148
-     * @type string                   $config_name                      the class name for this addon's
149
-     *                                                                  configuration settings object
150
-     * @type string                   $autoloader_paths                 [Required] an array of class names and the full
151
-     *                                                                  server paths to those files.
152
-     * @type string                   $autoloader_folders               an array of  "full server paths" for any
153
-     *                                                                  folders containing classes that might be
154
-     *                                                                  invoked by the addon
155
-     * @type string                   $dms_paths                        [Required] an array of full server paths to
156
-     *                                                                  folders that contain data migration scripts.
157
-     *                                                                  The key should be the EE_Addon class name that
158
-     *                                                                  this set of data migration scripts belongs to.
159
-     *                                                                  If the EE_Addon class is namespaced, then this
160
-     *                                                                  needs to be the Fully Qualified Class Name
161
-     * @type string                   $module_paths                     an array of full server paths to any
162
-     *                                                                  EED_Modules used by the addon
163
-     * @type string                   $shortcode_paths                  an array of full server paths to folders
164
-     *                                                                  that contain EES_Shortcodes
165
-     * @type string                   $widget_paths                     an array of full server paths to folders
166
-     *                                                                  that contain WP_Widgets
167
-     * @type string                   $pue_options
168
-     * @type array                    $capabilities                     an array indexed by role name
169
-     *                                                                  (i.e administrator,author ) and the values
170
-     *                                                                  are an array of caps to add to the role.
171
-     *                                                                  'administrator' => array(
172
-     *                                                                  'read_addon',
173
-     *                                                                  'edit_addon',
174
-     *                                                                  etc.
175
-     *                                                                  ).
176
-     * @type EE_Meta_Capability_Map[] $capability_maps                  an array of EE_Meta_Capability_Map object
177
-     *                                                                  for any addons that need to register any
178
-     *                                                                  special meta mapped capabilities.  Should
179
-     *                                                                  be indexed where the key is the
180
-     *                                                                  EE_Meta_Capability_Map class name and the
181
-     *                                                                  values are the arguments sent to the class.
182
-     * @type array                    $model_paths                      array of folders containing DB models
183
-     * @see      EE_Register_Model
184
-     * @type array                    $class_paths                      array of folders containing DB classes
185
-     * @see      EE_Register_Model
186
-     * @type array                    $model_extension_paths            array of folders containing DB model
187
-     *                                                                  extensions
188
-     * @see      EE_Register_Model_Extension
189
-     * @type array                    $class_extension_paths            array of folders containing DB class
190
-     *                                                                  extensions
191
-     * @see      EE_Register_Model_Extension
192
-     * @type array message_types {
193
-     *                                                                  An array of message types with the key as
194
-     *                                                                  the message type name and the values as
195
-     *                                                                  below:
196
-     * @type string                   $mtfilename                       [Required] The filename of the message type
197
-     *                                                                  being registered. This will be the main
198
-     *                                                                  EE_{Message Type Name}_message_type class.
199
-     *                                                                  for example:
200
-     *                                                                  EE_Declined_Registration_message_type.class.php
201
-     * @type array                    $autoloadpaths                    [Required] An array of paths to add to the
202
-     *                                                                  messages autoloader for the new message type.
203
-     * @type array                    $messengers_to_activate_with      An array of messengers that this message
204
-     *                                                                  type should activate with. Each value in
205
-     *                                                                  the
206
-     *                                                                  array
207
-     *                                                                  should match the name property of a
208
-     *                                                                  EE_messenger. Optional.
209
-     * @type array                    $messengers_to_validate_with      An array of messengers that this message
210
-     *                                                                  type should validate with. Each value in
211
-     *                                                                  the
212
-     *                                                                  array
213
-     *                                                                  should match the name property of an
214
-     *                                                                  EE_messenger.
215
-     *                                                                  Optional.
216
-     *                                                                  }
217
-     * @type array                    $custom_post_types
218
-     * @type array                    $custom_taxonomies
219
-     * @type array                    $payment_method_paths             each element is the folder containing the
220
-     *                                                                  EE_PMT_Base child class
221
-     *                                                                  (eg,
222
-     *                                                                  '/wp-content/plugins/my_plugin/Payomatic/'
223
-     *                                                                  which contains the files
224
-     *                                                                  EE_PMT_Payomatic.pm.php)
225
-     * @type array                    $default_terms
226
-     * @type array                    $namespace                        {
227
-     *                                                                  An array with two items for registering the
228
-     *                                                                  addon's namespace. (If, for some reason, you
229
-     *                                                                  require additional namespaces,
230
-     *                                                                  use
231
-     *                                                                  EventEspresso\core\Psr4Autoloader::addNamespace()
232
-     *                                                                  directly)
233
-     * @see      EventEspresso\core\Psr4Autoloader::addNamespace()
234
-     * @type string                   $FQNS                             the namespace prefix
235
-     * @type string                   $DIR                              a base directory for class files in the
236
-     *                                                                  namespace.
237
-     *                                                                  }
238
-     *                                                                  }
239
-     * @type string                   $privacy_policies                 FQNSs (namespaces, each of which contains only
240
-     *                                                                  privacy policy classes) or FQCNs (specific
241
-     *                                                                  classnames of privacy policy classes)
242
-     * @type string                   $personal_data_exporters          FQNSs (namespaces, each of which contains only
243
-     *                                                                  privacy policy classes) or FQCNs (specific
244
-     *                                                                  classnames of privacy policy classes)
245
-     * @type string                   $personal_data_erasers            FQNSs (namespaces, each of which contains only
246
-     *                                                                  privacy policy classes) or FQCNs (specific
247
-     *                                                                  classnames of privacy policy classes)
248
-     * @return void
249
-     * @throws DomainException
250
-     * @throws EE_Error
251
-     * @throws InvalidArgumentException
252
-     * @throws ReflectionException
253
-     * @throws InvalidDataTypeException
254
-     * @throws InvalidInterfaceException
255
-     */
256
-    public static function register($addon_name = '', $setup_args = array())
257
-    {
258
-        // required fields MUST be present, so let's make sure they are.
259
-        EE_Register_Addon::_verify_parameters($addon_name, $setup_args);
260
-        // get class name for addon
261
-        $class_name = EE_Register_Addon::_parse_class_name($addon_name, $setup_args);
262
-        // setup $_settings array from incoming values.
263
-        $addon_settings = EE_Register_Addon::_get_addon_settings($class_name, $setup_args);
264
-        // setup PUE
265
-        EE_Register_Addon::_parse_pue_options($addon_name, $class_name, $setup_args);
266
-        // does this addon work with this version of core or WordPress ?
267
-        if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
268
-            return;
269
-        }
270
-        // register namespaces
271
-        EE_Register_Addon::_setup_namespaces($addon_settings);
272
-        // check if this is an activation request
273
-        if (EE_Register_Addon::_addon_activation($addon_name, $addon_settings)) {
274
-            // dont bother setting up the rest of the addon atm
275
-            return;
276
-        }
277
-        // we need cars
278
-        EE_Register_Addon::_setup_autoloaders($addon_name);
279
-        // register new models and extensions
280
-        EE_Register_Addon::_register_models_and_extensions($addon_name);
281
-        // setup DMS
282
-        EE_Register_Addon::_register_data_migration_scripts($addon_name);
283
-        // if config_class is present let's register config.
284
-        EE_Register_Addon::_register_config($addon_name);
285
-        // register admin pages
286
-        EE_Register_Addon::_register_admin_pages($addon_name);
287
-        // add to list of modules to be registered
288
-        EE_Register_Addon::_register_modules($addon_name);
289
-        // add to list of shortcodes to be registered
290
-        EE_Register_Addon::_register_shortcodes($addon_name);
291
-        // add to list of widgets to be registered
292
-        EE_Register_Addon::_register_widgets($addon_name);
293
-        // register capability related stuff.
294
-        EE_Register_Addon::_register_capabilities($addon_name);
295
-        // any message type to register?
296
-        EE_Register_Addon::_register_message_types($addon_name);
297
-        // any custom post type/ custom capabilities or default terms to register
298
-        EE_Register_Addon::_register_custom_post_types($addon_name);
299
-        // and any payment methods
300
-        EE_Register_Addon::_register_payment_methods($addon_name);
301
-        // and privacy policy generators
302
-        EE_Register_Addon::registerPrivacyPolicies($addon_name);
303
-        // and privacy policy generators
304
-        EE_Register_Addon::registerPersonalDataExporters($addon_name);
305
-        // and privacy policy generators
306
-        EE_Register_Addon::registerPersonalDataErasers($addon_name);
307
-        // load and instantiate main addon class
308
-        $addon = EE_Register_Addon::_load_and_init_addon_class($addon_name);
309
-        // delay calling after_registration hook on each addon until after all add-ons have been registered.
310
-        add_action('AHEE__EE_System__load_espresso_addons__complete', array($addon, 'after_registration'), 999);
311
-    }
106
+	/**
107
+	 * Method for registering new EE_Addons.
108
+	 * Should be called AFTER AHEE__EE_System__load_espresso_addons but BEFORE
109
+	 * AHEE__EE_System___detect_if_activation_or_upgrade__begin in order to register all its components. However, it
110
+	 * may also be called after the 'activate_plugin' action (when an addon is activated), because an activating addon
111
+	 * won't be loaded by WP until after AHEE__EE_System__load_espresso_addons has fired. If its called after
112
+	 * 'activate_plugin', it registers the addon still, but its components are not registered
113
+	 * (they shouldn't be needed anyways, because it's just an activation request and they won't have a chance to do
114
+	 * anything anyways). Instead, it just sets the newly-activated addon's activation indicator wp option and returns
115
+	 * (so that we can detect that the addon has activated on the subsequent request)
116
+	 *
117
+	 * @since    4.3.0
118
+	 * @param string                  $addon_name                       [Required] the EE_Addon's name.
119
+	 * @param  array                  $setup_args                       {
120
+	 *                                                                  An array of arguments provided for registering
121
+	 *                                                                  the message type.
122
+	 * @type  string                  $class_name                       the addon's main file name.
123
+	 *                                                                  If left blank, generated from the addon name,
124
+	 *                                                                  changes something like "calendar" to
125
+	 *                                                                  "EE_Calendar"
126
+	 * @type string                   $min_core_version                 the minimum version of EE Core that the
127
+	 *                                                                  addon will work with. eg "4.8.1.rc.084"
128
+	 * @type string                   $version                          the "software" version for the addon. eg
129
+	 *                                                                  "1.0.0.p" for a first stable release, or
130
+	 *                                                                  "1.0.0.rc.043" for a version in progress
131
+	 * @type string                   $main_file_path                   the full server path to the main file
132
+	 *                                                                  loaded directly by WP
133
+	 * @type DomainInterface $domain                                    child class of
134
+	 *                                                                  EventEspresso\core\domain\DomainBase
135
+	 * @type string                   $domain_fqcn                      Fully Qualified Class Name
136
+	 *                                                                  for the addon's Domain class
137
+	 *                                                                  (see EventEspresso\core\domain\Domain)
138
+	 * @type string                   $admin_path                       full server path to the folder where the
139
+	 *                                                                  addon\'s admin files reside
140
+	 * @type string                   $admin_callback                   a method to be called when the EE Admin is
141
+	 *                                                                  first invoked, can be used for hooking into
142
+	 *                                                                  any admin page
143
+	 * @type string                   $config_section                   the section name for this addon's
144
+	 *                                                                  configuration settings section
145
+	 *                                                                  (defaults to "addons")
146
+	 * @type string                   $config_class                     the class name for this addon's
147
+	 *                                                                  configuration settings object
148
+	 * @type string                   $config_name                      the class name for this addon's
149
+	 *                                                                  configuration settings object
150
+	 * @type string                   $autoloader_paths                 [Required] an array of class names and the full
151
+	 *                                                                  server paths to those files.
152
+	 * @type string                   $autoloader_folders               an array of  "full server paths" for any
153
+	 *                                                                  folders containing classes that might be
154
+	 *                                                                  invoked by the addon
155
+	 * @type string                   $dms_paths                        [Required] an array of full server paths to
156
+	 *                                                                  folders that contain data migration scripts.
157
+	 *                                                                  The key should be the EE_Addon class name that
158
+	 *                                                                  this set of data migration scripts belongs to.
159
+	 *                                                                  If the EE_Addon class is namespaced, then this
160
+	 *                                                                  needs to be the Fully Qualified Class Name
161
+	 * @type string                   $module_paths                     an array of full server paths to any
162
+	 *                                                                  EED_Modules used by the addon
163
+	 * @type string                   $shortcode_paths                  an array of full server paths to folders
164
+	 *                                                                  that contain EES_Shortcodes
165
+	 * @type string                   $widget_paths                     an array of full server paths to folders
166
+	 *                                                                  that contain WP_Widgets
167
+	 * @type string                   $pue_options
168
+	 * @type array                    $capabilities                     an array indexed by role name
169
+	 *                                                                  (i.e administrator,author ) and the values
170
+	 *                                                                  are an array of caps to add to the role.
171
+	 *                                                                  'administrator' => array(
172
+	 *                                                                  'read_addon',
173
+	 *                                                                  'edit_addon',
174
+	 *                                                                  etc.
175
+	 *                                                                  ).
176
+	 * @type EE_Meta_Capability_Map[] $capability_maps                  an array of EE_Meta_Capability_Map object
177
+	 *                                                                  for any addons that need to register any
178
+	 *                                                                  special meta mapped capabilities.  Should
179
+	 *                                                                  be indexed where the key is the
180
+	 *                                                                  EE_Meta_Capability_Map class name and the
181
+	 *                                                                  values are the arguments sent to the class.
182
+	 * @type array                    $model_paths                      array of folders containing DB models
183
+	 * @see      EE_Register_Model
184
+	 * @type array                    $class_paths                      array of folders containing DB classes
185
+	 * @see      EE_Register_Model
186
+	 * @type array                    $model_extension_paths            array of folders containing DB model
187
+	 *                                                                  extensions
188
+	 * @see      EE_Register_Model_Extension
189
+	 * @type array                    $class_extension_paths            array of folders containing DB class
190
+	 *                                                                  extensions
191
+	 * @see      EE_Register_Model_Extension
192
+	 * @type array message_types {
193
+	 *                                                                  An array of message types with the key as
194
+	 *                                                                  the message type name and the values as
195
+	 *                                                                  below:
196
+	 * @type string                   $mtfilename                       [Required] The filename of the message type
197
+	 *                                                                  being registered. This will be the main
198
+	 *                                                                  EE_{Message Type Name}_message_type class.
199
+	 *                                                                  for example:
200
+	 *                                                                  EE_Declined_Registration_message_type.class.php
201
+	 * @type array                    $autoloadpaths                    [Required] An array of paths to add to the
202
+	 *                                                                  messages autoloader for the new message type.
203
+	 * @type array                    $messengers_to_activate_with      An array of messengers that this message
204
+	 *                                                                  type should activate with. Each value in
205
+	 *                                                                  the
206
+	 *                                                                  array
207
+	 *                                                                  should match the name property of a
208
+	 *                                                                  EE_messenger. Optional.
209
+	 * @type array                    $messengers_to_validate_with      An array of messengers that this message
210
+	 *                                                                  type should validate with. Each value in
211
+	 *                                                                  the
212
+	 *                                                                  array
213
+	 *                                                                  should match the name property of an
214
+	 *                                                                  EE_messenger.
215
+	 *                                                                  Optional.
216
+	 *                                                                  }
217
+	 * @type array                    $custom_post_types
218
+	 * @type array                    $custom_taxonomies
219
+	 * @type array                    $payment_method_paths             each element is the folder containing the
220
+	 *                                                                  EE_PMT_Base child class
221
+	 *                                                                  (eg,
222
+	 *                                                                  '/wp-content/plugins/my_plugin/Payomatic/'
223
+	 *                                                                  which contains the files
224
+	 *                                                                  EE_PMT_Payomatic.pm.php)
225
+	 * @type array                    $default_terms
226
+	 * @type array                    $namespace                        {
227
+	 *                                                                  An array with two items for registering the
228
+	 *                                                                  addon's namespace. (If, for some reason, you
229
+	 *                                                                  require additional namespaces,
230
+	 *                                                                  use
231
+	 *                                                                  EventEspresso\core\Psr4Autoloader::addNamespace()
232
+	 *                                                                  directly)
233
+	 * @see      EventEspresso\core\Psr4Autoloader::addNamespace()
234
+	 * @type string                   $FQNS                             the namespace prefix
235
+	 * @type string                   $DIR                              a base directory for class files in the
236
+	 *                                                                  namespace.
237
+	 *                                                                  }
238
+	 *                                                                  }
239
+	 * @type string                   $privacy_policies                 FQNSs (namespaces, each of which contains only
240
+	 *                                                                  privacy policy classes) or FQCNs (specific
241
+	 *                                                                  classnames of privacy policy classes)
242
+	 * @type string                   $personal_data_exporters          FQNSs (namespaces, each of which contains only
243
+	 *                                                                  privacy policy classes) or FQCNs (specific
244
+	 *                                                                  classnames of privacy policy classes)
245
+	 * @type string                   $personal_data_erasers            FQNSs (namespaces, each of which contains only
246
+	 *                                                                  privacy policy classes) or FQCNs (specific
247
+	 *                                                                  classnames of privacy policy classes)
248
+	 * @return void
249
+	 * @throws DomainException
250
+	 * @throws EE_Error
251
+	 * @throws InvalidArgumentException
252
+	 * @throws ReflectionException
253
+	 * @throws InvalidDataTypeException
254
+	 * @throws InvalidInterfaceException
255
+	 */
256
+	public static function register($addon_name = '', $setup_args = array())
257
+	{
258
+		// required fields MUST be present, so let's make sure they are.
259
+		EE_Register_Addon::_verify_parameters($addon_name, $setup_args);
260
+		// get class name for addon
261
+		$class_name = EE_Register_Addon::_parse_class_name($addon_name, $setup_args);
262
+		// setup $_settings array from incoming values.
263
+		$addon_settings = EE_Register_Addon::_get_addon_settings($class_name, $setup_args);
264
+		// setup PUE
265
+		EE_Register_Addon::_parse_pue_options($addon_name, $class_name, $setup_args);
266
+		// does this addon work with this version of core or WordPress ?
267
+		if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
268
+			return;
269
+		}
270
+		// register namespaces
271
+		EE_Register_Addon::_setup_namespaces($addon_settings);
272
+		// check if this is an activation request
273
+		if (EE_Register_Addon::_addon_activation($addon_name, $addon_settings)) {
274
+			// dont bother setting up the rest of the addon atm
275
+			return;
276
+		}
277
+		// we need cars
278
+		EE_Register_Addon::_setup_autoloaders($addon_name);
279
+		// register new models and extensions
280
+		EE_Register_Addon::_register_models_and_extensions($addon_name);
281
+		// setup DMS
282
+		EE_Register_Addon::_register_data_migration_scripts($addon_name);
283
+		// if config_class is present let's register config.
284
+		EE_Register_Addon::_register_config($addon_name);
285
+		// register admin pages
286
+		EE_Register_Addon::_register_admin_pages($addon_name);
287
+		// add to list of modules to be registered
288
+		EE_Register_Addon::_register_modules($addon_name);
289
+		// add to list of shortcodes to be registered
290
+		EE_Register_Addon::_register_shortcodes($addon_name);
291
+		// add to list of widgets to be registered
292
+		EE_Register_Addon::_register_widgets($addon_name);
293
+		// register capability related stuff.
294
+		EE_Register_Addon::_register_capabilities($addon_name);
295
+		// any message type to register?
296
+		EE_Register_Addon::_register_message_types($addon_name);
297
+		// any custom post type/ custom capabilities or default terms to register
298
+		EE_Register_Addon::_register_custom_post_types($addon_name);
299
+		// and any payment methods
300
+		EE_Register_Addon::_register_payment_methods($addon_name);
301
+		// and privacy policy generators
302
+		EE_Register_Addon::registerPrivacyPolicies($addon_name);
303
+		// and privacy policy generators
304
+		EE_Register_Addon::registerPersonalDataExporters($addon_name);
305
+		// and privacy policy generators
306
+		EE_Register_Addon::registerPersonalDataErasers($addon_name);
307
+		// load and instantiate main addon class
308
+		$addon = EE_Register_Addon::_load_and_init_addon_class($addon_name);
309
+		// delay calling after_registration hook on each addon until after all add-ons have been registered.
310
+		add_action('AHEE__EE_System__load_espresso_addons__complete', array($addon, 'after_registration'), 999);
311
+	}
312 312
 
313 313
 
314
-    /**
315
-     * @param string $addon_name
316
-     * @param array  $setup_args
317
-     * @return void
318
-     * @throws EE_Error
319
-     */
320
-    private static function _verify_parameters($addon_name, array $setup_args)
321
-    {
322
-        // required fields MUST be present, so let's make sure they are.
323
-        if (empty($addon_name) || ! is_array($setup_args)) {
324
-            throw new EE_Error(
325
-                __(
326
-                    'In order to register an EE_Addon with EE_Register_Addon::register(), you must include the "addon_name" (the name of the addon), and an array of arguments.',
327
-                    'event_espresso'
328
-                )
329
-            );
330
-        }
331
-        if (! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
332
-            throw new EE_Error(
333
-                sprintf(
334
-                    __(
335
-                        'When registering an addon, you didn\'t provide the "main_file_path", which is the full path to the main file loaded directly by Wordpress. You only provided %s',
336
-                        'event_espresso'
337
-                    ),
338
-                    implode(',', array_keys($setup_args))
339
-                )
340
-            );
341
-        }
342
-        // check that addon has not already been registered with that name
343
-        if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
344
-            throw new EE_Error(
345
-                sprintf(
346
-                    __(
347
-                        'An EE_Addon with the name "%s" has already been registered and each EE_Addon requires a unique name.',
348
-                        'event_espresso'
349
-                    ),
350
-                    $addon_name
351
-                )
352
-            );
353
-        }
354
-    }
314
+	/**
315
+	 * @param string $addon_name
316
+	 * @param array  $setup_args
317
+	 * @return void
318
+	 * @throws EE_Error
319
+	 */
320
+	private static function _verify_parameters($addon_name, array $setup_args)
321
+	{
322
+		// required fields MUST be present, so let's make sure they are.
323
+		if (empty($addon_name) || ! is_array($setup_args)) {
324
+			throw new EE_Error(
325
+				__(
326
+					'In order to register an EE_Addon with EE_Register_Addon::register(), you must include the "addon_name" (the name of the addon), and an array of arguments.',
327
+					'event_espresso'
328
+				)
329
+			);
330
+		}
331
+		if (! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
332
+			throw new EE_Error(
333
+				sprintf(
334
+					__(
335
+						'When registering an addon, you didn\'t provide the "main_file_path", which is the full path to the main file loaded directly by Wordpress. You only provided %s',
336
+						'event_espresso'
337
+					),
338
+					implode(',', array_keys($setup_args))
339
+				)
340
+			);
341
+		}
342
+		// check that addon has not already been registered with that name
343
+		if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
344
+			throw new EE_Error(
345
+				sprintf(
346
+					__(
347
+						'An EE_Addon with the name "%s" has already been registered and each EE_Addon requires a unique name.',
348
+						'event_espresso'
349
+					),
350
+					$addon_name
351
+				)
352
+			);
353
+		}
354
+	}
355 355
 
356 356
 
357
-    /**
358
-     * @param string $addon_name
359
-     * @param array  $setup_args
360
-     * @return string
361
-     */
362
-    private static function _parse_class_name($addon_name, array $setup_args)
363
-    {
364
-        if (empty($setup_args['class_name'])) {
365
-            // generate one by first separating name with spaces
366
-            $class_name = str_replace(array('-', '_'), ' ', trim($addon_name));
367
-            // capitalize, then replace spaces with underscores
368
-            $class_name = str_replace(' ', '_', ucwords($class_name));
369
-        } else {
370
-            $class_name = $setup_args['class_name'];
371
-        }
372
-        // check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
373
-        return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
374
-            ? $class_name
375
-            : 'EE_' . $class_name;
376
-    }
357
+	/**
358
+	 * @param string $addon_name
359
+	 * @param array  $setup_args
360
+	 * @return string
361
+	 */
362
+	private static function _parse_class_name($addon_name, array $setup_args)
363
+	{
364
+		if (empty($setup_args['class_name'])) {
365
+			// generate one by first separating name with spaces
366
+			$class_name = str_replace(array('-', '_'), ' ', trim($addon_name));
367
+			// capitalize, then replace spaces with underscores
368
+			$class_name = str_replace(' ', '_', ucwords($class_name));
369
+		} else {
370
+			$class_name = $setup_args['class_name'];
371
+		}
372
+		// check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
373
+		return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
374
+			? $class_name
375
+			: 'EE_' . $class_name;
376
+	}
377 377
 
378 378
 
379
-    /**
380
-     * @param string $class_name
381
-     * @param array  $setup_args
382
-     * @return array
383
-     */
384
-    private static function _get_addon_settings($class_name, array $setup_args)
385
-    {
386
-        // setup $_settings array from incoming values.
387
-        $addon_settings = array(
388
-            // generated from the addon name, changes something like "calendar" to "EE_Calendar"
389
-            'class_name'            => $class_name,
390
-            // the addon slug for use in URLs, etc
391
-            'plugin_slug'           => isset($setup_args['plugin_slug'])
392
-                ? (string) $setup_args['plugin_slug']
393
-                : '',
394
-            // page slug to be used when generating the "Settings" link on the WP plugin page
395
-            'plugin_action_slug'    => isset($setup_args['plugin_action_slug'])
396
-                ? (string) $setup_args['plugin_action_slug']
397
-                : '',
398
-            // the "software" version for the addon
399
-            'version'               => isset($setup_args['version'])
400
-                ? (string) $setup_args['version']
401
-                : '',
402
-            // the minimum version of EE Core that the addon will work with
403
-            'min_core_version'      => isset($setup_args['min_core_version'])
404
-                ? (string) $setup_args['min_core_version']
405
-                : '',
406
-            // the minimum version of WordPress that the addon will work with
407
-            'min_wp_version'        => isset($setup_args['min_wp_version'])
408
-                ? (string) $setup_args['min_wp_version']
409
-                : EE_MIN_WP_VER_REQUIRED,
410
-            // full server path to main file (file loaded directly by WP)
411
-            'main_file_path'        => isset($setup_args['main_file_path'])
412
-                ? (string) $setup_args['main_file_path']
413
-                : '',
414
-            // instance of \EventEspresso\core\domain\DomainInterface
415
-            'domain'                => isset($setup_args['domain']) && $setup_args['domain'] instanceof DomainInterface
416
-                ? $setup_args['domain']
417
-                : null,
418
-            // Fully Qualified Class Name for the addon's Domain class
419
-            'domain_fqcn'           => isset($setup_args['domain_fqcn'])
420
-                ? (string) $setup_args['domain_fqcn']
421
-                : '',
422
-            // path to folder containing files for integrating with the EE core admin and/or setting up EE admin pages
423
-            'admin_path'            => isset($setup_args['admin_path'])
424
-                ? (string) $setup_args['admin_path'] : '',
425
-            // a method to be called when the EE Admin is first invoked, can be used for hooking into any admin page
426
-            'admin_callback'        => isset($setup_args['admin_callback'])
427
-                ? (string) $setup_args['admin_callback']
428
-                : '',
429
-            // the section name for this addon's configuration settings section (defaults to "addons")
430
-            'config_section'        => isset($setup_args['config_section'])
431
-                ? (string) $setup_args['config_section']
432
-                : 'addons',
433
-            // the class name for this addon's configuration settings object
434
-            'config_class'          => isset($setup_args['config_class'])
435
-                ? (string) $setup_args['config_class'] : '',
436
-            // the name given to the config for this addons' configuration settings object (optional)
437
-            'config_name'           => isset($setup_args['config_name'])
438
-                ? (string) $setup_args['config_name'] : '',
439
-            // an array of "class names" => "full server paths" for any classes that might be invoked by the addon
440
-            'autoloader_paths'      => isset($setup_args['autoloader_paths'])
441
-                ? (array) $setup_args['autoloader_paths']
442
-                : array(),
443
-            // an array of  "full server paths" for any folders containing classes that might be invoked by the addon
444
-            'autoloader_folders'    => isset($setup_args['autoloader_folders'])
445
-                ? (array) $setup_args['autoloader_folders']
446
-                : array(),
447
-            // array of full server paths to any EE_DMS data migration scripts used by the addon.
448
-            // The key should be the EE_Addon class name that this set of data migration scripts belongs to.
449
-            // If the EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
450
-            'dms_paths'             => isset($setup_args['dms_paths'])
451
-                ? (array) $setup_args['dms_paths']
452
-                : array(),
453
-            // array of full server paths to any EED_Modules used by the addon
454
-            'module_paths'          => isset($setup_args['module_paths'])
455
-                ? (array) $setup_args['module_paths']
456
-                : array(),
457
-            // array of full server paths to any EES_Shortcodes used by the addon
458
-            'shortcode_paths'       => isset($setup_args['shortcode_paths'])
459
-                ? (array) $setup_args['shortcode_paths']
460
-                : array(),
461
-            'shortcode_fqcns'       => isset($setup_args['shortcode_fqcns'])
462
-                ? (array) $setup_args['shortcode_fqcns']
463
-                : array(),
464
-            // array of full server paths to any WP_Widgets used by the addon
465
-            'widget_paths'          => isset($setup_args['widget_paths'])
466
-                ? (array) $setup_args['widget_paths']
467
-                : array(),
468
-            // array of PUE options used by the addon
469
-            'pue_options'           => isset($setup_args['pue_options'])
470
-                ? (array) $setup_args['pue_options']
471
-                : array(),
472
-            'message_types'         => isset($setup_args['message_types'])
473
-                ? (array) $setup_args['message_types']
474
-                : array(),
475
-            'capabilities'          => isset($setup_args['capabilities'])
476
-                ? (array) $setup_args['capabilities']
477
-                : array(),
478
-            'capability_maps'       => isset($setup_args['capability_maps'])
479
-                ? (array) $setup_args['capability_maps']
480
-                : array(),
481
-            'model_paths'           => isset($setup_args['model_paths'])
482
-                ? (array) $setup_args['model_paths']
483
-                : array(),
484
-            'class_paths'           => isset($setup_args['class_paths'])
485
-                ? (array) $setup_args['class_paths']
486
-                : array(),
487
-            'model_extension_paths' => isset($setup_args['model_extension_paths'])
488
-                ? (array) $setup_args['model_extension_paths']
489
-                : array(),
490
-            'class_extension_paths' => isset($setup_args['class_extension_paths'])
491
-                ? (array) $setup_args['class_extension_paths']
492
-                : array(),
493
-            'custom_post_types'     => isset($setup_args['custom_post_types'])
494
-                ? (array) $setup_args['custom_post_types']
495
-                : array(),
496
-            'custom_taxonomies'     => isset($setup_args['custom_taxonomies'])
497
-                ? (array) $setup_args['custom_taxonomies']
498
-                : array(),
499
-            'payment_method_paths'  => isset($setup_args['payment_method_paths'])
500
-                ? (array) $setup_args['payment_method_paths']
501
-                : array(),
502
-            'default_terms'         => isset($setup_args['default_terms'])
503
-                ? (array) $setup_args['default_terms']
504
-                : array(),
505
-            // if not empty, inserts a new table row after this plugin's row on the WP Plugins page
506
-            // that can be used for adding upgrading/marketing info
507
-            'plugins_page_row'      => isset($setup_args['plugins_page_row'])
508
-                ? $setup_args['plugins_page_row']
509
-                : '',
510
-            'namespace'             => isset(
511
-                $setup_args['namespace']['FQNS'],
512
-                $setup_args['namespace']['DIR']
513
-            )
514
-                ? (array) $setup_args['namespace']
515
-                : array(),
516
-            'privacy_policies'      => isset($setup_args['privacy_policies'])
517
-                ? (array) $setup_args['privacy_policies']
518
-                : '',
519
-        );
520
-        // if plugin_action_slug is NOT set, but an admin page path IS set,
521
-        // then let's just use the plugin_slug since that will be used for linking to the admin page
522
-        $addon_settings['plugin_action_slug'] = empty($addon_settings['plugin_action_slug'])
523
-                                                && ! empty($addon_settings['admin_path'])
524
-            ? $addon_settings['plugin_slug']
525
-            : $addon_settings['plugin_action_slug'];
526
-        // full server path to main file (file loaded directly by WP)
527
-        $addon_settings['plugin_basename'] = plugin_basename($addon_settings['main_file_path']);
528
-        return $addon_settings;
529
-    }
379
+	/**
380
+	 * @param string $class_name
381
+	 * @param array  $setup_args
382
+	 * @return array
383
+	 */
384
+	private static function _get_addon_settings($class_name, array $setup_args)
385
+	{
386
+		// setup $_settings array from incoming values.
387
+		$addon_settings = array(
388
+			// generated from the addon name, changes something like "calendar" to "EE_Calendar"
389
+			'class_name'            => $class_name,
390
+			// the addon slug for use in URLs, etc
391
+			'plugin_slug'           => isset($setup_args['plugin_slug'])
392
+				? (string) $setup_args['plugin_slug']
393
+				: '',
394
+			// page slug to be used when generating the "Settings" link on the WP plugin page
395
+			'plugin_action_slug'    => isset($setup_args['plugin_action_slug'])
396
+				? (string) $setup_args['plugin_action_slug']
397
+				: '',
398
+			// the "software" version for the addon
399
+			'version'               => isset($setup_args['version'])
400
+				? (string) $setup_args['version']
401
+				: '',
402
+			// the minimum version of EE Core that the addon will work with
403
+			'min_core_version'      => isset($setup_args['min_core_version'])
404
+				? (string) $setup_args['min_core_version']
405
+				: '',
406
+			// the minimum version of WordPress that the addon will work with
407
+			'min_wp_version'        => isset($setup_args['min_wp_version'])
408
+				? (string) $setup_args['min_wp_version']
409
+				: EE_MIN_WP_VER_REQUIRED,
410
+			// full server path to main file (file loaded directly by WP)
411
+			'main_file_path'        => isset($setup_args['main_file_path'])
412
+				? (string) $setup_args['main_file_path']
413
+				: '',
414
+			// instance of \EventEspresso\core\domain\DomainInterface
415
+			'domain'                => isset($setup_args['domain']) && $setup_args['domain'] instanceof DomainInterface
416
+				? $setup_args['domain']
417
+				: null,
418
+			// Fully Qualified Class Name for the addon's Domain class
419
+			'domain_fqcn'           => isset($setup_args['domain_fqcn'])
420
+				? (string) $setup_args['domain_fqcn']
421
+				: '',
422
+			// path to folder containing files for integrating with the EE core admin and/or setting up EE admin pages
423
+			'admin_path'            => isset($setup_args['admin_path'])
424
+				? (string) $setup_args['admin_path'] : '',
425
+			// a method to be called when the EE Admin is first invoked, can be used for hooking into any admin page
426
+			'admin_callback'        => isset($setup_args['admin_callback'])
427
+				? (string) $setup_args['admin_callback']
428
+				: '',
429
+			// the section name for this addon's configuration settings section (defaults to "addons")
430
+			'config_section'        => isset($setup_args['config_section'])
431
+				? (string) $setup_args['config_section']
432
+				: 'addons',
433
+			// the class name for this addon's configuration settings object
434
+			'config_class'          => isset($setup_args['config_class'])
435
+				? (string) $setup_args['config_class'] : '',
436
+			// the name given to the config for this addons' configuration settings object (optional)
437
+			'config_name'           => isset($setup_args['config_name'])
438
+				? (string) $setup_args['config_name'] : '',
439
+			// an array of "class names" => "full server paths" for any classes that might be invoked by the addon
440
+			'autoloader_paths'      => isset($setup_args['autoloader_paths'])
441
+				? (array) $setup_args['autoloader_paths']
442
+				: array(),
443
+			// an array of  "full server paths" for any folders containing classes that might be invoked by the addon
444
+			'autoloader_folders'    => isset($setup_args['autoloader_folders'])
445
+				? (array) $setup_args['autoloader_folders']
446
+				: array(),
447
+			// array of full server paths to any EE_DMS data migration scripts used by the addon.
448
+			// The key should be the EE_Addon class name that this set of data migration scripts belongs to.
449
+			// If the EE_Addon class is namespaced, then this needs to be the Fully Qualified Class Name
450
+			'dms_paths'             => isset($setup_args['dms_paths'])
451
+				? (array) $setup_args['dms_paths']
452
+				: array(),
453
+			// array of full server paths to any EED_Modules used by the addon
454
+			'module_paths'          => isset($setup_args['module_paths'])
455
+				? (array) $setup_args['module_paths']
456
+				: array(),
457
+			// array of full server paths to any EES_Shortcodes used by the addon
458
+			'shortcode_paths'       => isset($setup_args['shortcode_paths'])
459
+				? (array) $setup_args['shortcode_paths']
460
+				: array(),
461
+			'shortcode_fqcns'       => isset($setup_args['shortcode_fqcns'])
462
+				? (array) $setup_args['shortcode_fqcns']
463
+				: array(),
464
+			// array of full server paths to any WP_Widgets used by the addon
465
+			'widget_paths'          => isset($setup_args['widget_paths'])
466
+				? (array) $setup_args['widget_paths']
467
+				: array(),
468
+			// array of PUE options used by the addon
469
+			'pue_options'           => isset($setup_args['pue_options'])
470
+				? (array) $setup_args['pue_options']
471
+				: array(),
472
+			'message_types'         => isset($setup_args['message_types'])
473
+				? (array) $setup_args['message_types']
474
+				: array(),
475
+			'capabilities'          => isset($setup_args['capabilities'])
476
+				? (array) $setup_args['capabilities']
477
+				: array(),
478
+			'capability_maps'       => isset($setup_args['capability_maps'])
479
+				? (array) $setup_args['capability_maps']
480
+				: array(),
481
+			'model_paths'           => isset($setup_args['model_paths'])
482
+				? (array) $setup_args['model_paths']
483
+				: array(),
484
+			'class_paths'           => isset($setup_args['class_paths'])
485
+				? (array) $setup_args['class_paths']
486
+				: array(),
487
+			'model_extension_paths' => isset($setup_args['model_extension_paths'])
488
+				? (array) $setup_args['model_extension_paths']
489
+				: array(),
490
+			'class_extension_paths' => isset($setup_args['class_extension_paths'])
491
+				? (array) $setup_args['class_extension_paths']
492
+				: array(),
493
+			'custom_post_types'     => isset($setup_args['custom_post_types'])
494
+				? (array) $setup_args['custom_post_types']
495
+				: array(),
496
+			'custom_taxonomies'     => isset($setup_args['custom_taxonomies'])
497
+				? (array) $setup_args['custom_taxonomies']
498
+				: array(),
499
+			'payment_method_paths'  => isset($setup_args['payment_method_paths'])
500
+				? (array) $setup_args['payment_method_paths']
501
+				: array(),
502
+			'default_terms'         => isset($setup_args['default_terms'])
503
+				? (array) $setup_args['default_terms']
504
+				: array(),
505
+			// if not empty, inserts a new table row after this plugin's row on the WP Plugins page
506
+			// that can be used for adding upgrading/marketing info
507
+			'plugins_page_row'      => isset($setup_args['plugins_page_row'])
508
+				? $setup_args['plugins_page_row']
509
+				: '',
510
+			'namespace'             => isset(
511
+				$setup_args['namespace']['FQNS'],
512
+				$setup_args['namespace']['DIR']
513
+			)
514
+				? (array) $setup_args['namespace']
515
+				: array(),
516
+			'privacy_policies'      => isset($setup_args['privacy_policies'])
517
+				? (array) $setup_args['privacy_policies']
518
+				: '',
519
+		);
520
+		// if plugin_action_slug is NOT set, but an admin page path IS set,
521
+		// then let's just use the plugin_slug since that will be used for linking to the admin page
522
+		$addon_settings['plugin_action_slug'] = empty($addon_settings['plugin_action_slug'])
523
+												&& ! empty($addon_settings['admin_path'])
524
+			? $addon_settings['plugin_slug']
525
+			: $addon_settings['plugin_action_slug'];
526
+		// full server path to main file (file loaded directly by WP)
527
+		$addon_settings['plugin_basename'] = plugin_basename($addon_settings['main_file_path']);
528
+		return $addon_settings;
529
+	}
530 530
 
531 531
 
532
-    /**
533
-     * @param string $addon_name
534
-     * @param array  $addon_settings
535
-     * @return boolean
536
-     */
537
-    private static function _addon_is_compatible($addon_name, array $addon_settings)
538
-    {
539
-        global $wp_version;
540
-        $incompatibility_message = '';
541
-        // check whether this addon version is compatible with EE core
542
-        if (isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
543
-            && ! self::_meets_min_core_version_requirement(
544
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
545
-                $addon_settings['version']
546
-            )
547
-        ) {
548
-            $incompatibility_message = sprintf(
549
-                __(
550
-                    '%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon is not compatible with this version of Event Espresso.%2$sPlease upgrade your "%1$s" addon to version %3$s or newer to resolve this issue.',
551
-                    'event_espresso'
552
-                ),
553
-                $addon_name,
554
-                '<br />',
555
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
556
-                '<span style="font-weight: bold; color: #D54E21;">',
557
-                '</span><br />'
558
-            );
559
-        } elseif (! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
560
-        ) {
561
-            $incompatibility_message = sprintf(
562
-                __(
563
-                    '%5$sIMPORTANT!%6$sThe Event Espresso "%1$s" addon requires Event Espresso Core version "%2$s" or higher in order to run.%4$sYour version of Event Espresso Core is currently at "%3$s". Please upgrade Event Espresso Core first and then re-activate "%1$s".',
564
-                    'event_espresso'
565
-                ),
566
-                $addon_name,
567
-                self::_effective_version($addon_settings['min_core_version']),
568
-                self::_effective_version(espresso_version()),
569
-                '<br />',
570
-                '<span style="font-weight: bold; color: #D54E21;">',
571
-                '</span><br />'
572
-            );
573
-        } elseif (version_compare($wp_version, $addon_settings['min_wp_version'], '<')) {
574
-            $incompatibility_message = sprintf(
575
-                __(
576
-                    '%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon requires WordPress version "%2$s" or greater.%3$sPlease update your version of WordPress to use the "%1$s" addon and to keep your site secure.',
577
-                    'event_espresso'
578
-                ),
579
-                $addon_name,
580
-                $addon_settings['min_wp_version'],
581
-                '<br />',
582
-                '<span style="font-weight: bold; color: #D54E21;">',
583
-                '</span><br />'
584
-            );
585
-        }
586
-        if (! empty($incompatibility_message)) {
587
-            // remove 'activate' from the REQUEST
588
-            // so WP doesn't erroneously tell the user the plugin activated fine when it didn't
589
-            unset($_GET['activate'], $_REQUEST['activate']);
590
-            if (current_user_can('activate_plugins')) {
591
-                // show an error message indicating the plugin didn't activate properly
592
-                EE_Error::add_error($incompatibility_message, __FILE__, __FUNCTION__, __LINE__);
593
-            }
594
-            // BAIL FROM THE ADDON REGISTRATION PROCESS
595
-            return false;
596
-        }
597
-        // addon IS compatible
598
-        return true;
599
-    }
532
+	/**
533
+	 * @param string $addon_name
534
+	 * @param array  $addon_settings
535
+	 * @return boolean
536
+	 */
537
+	private static function _addon_is_compatible($addon_name, array $addon_settings)
538
+	{
539
+		global $wp_version;
540
+		$incompatibility_message = '';
541
+		// check whether this addon version is compatible with EE core
542
+		if (isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
543
+			&& ! self::_meets_min_core_version_requirement(
544
+				EE_Register_Addon::$_incompatible_addons[ $addon_name ],
545
+				$addon_settings['version']
546
+			)
547
+		) {
548
+			$incompatibility_message = sprintf(
549
+				__(
550
+					'%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon is not compatible with this version of Event Espresso.%2$sPlease upgrade your "%1$s" addon to version %3$s or newer to resolve this issue.',
551
+					'event_espresso'
552
+				),
553
+				$addon_name,
554
+				'<br />',
555
+				EE_Register_Addon::$_incompatible_addons[ $addon_name ],
556
+				'<span style="font-weight: bold; color: #D54E21;">',
557
+				'</span><br />'
558
+			);
559
+		} elseif (! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
560
+		) {
561
+			$incompatibility_message = sprintf(
562
+				__(
563
+					'%5$sIMPORTANT!%6$sThe Event Espresso "%1$s" addon requires Event Espresso Core version "%2$s" or higher in order to run.%4$sYour version of Event Espresso Core is currently at "%3$s". Please upgrade Event Espresso Core first and then re-activate "%1$s".',
564
+					'event_espresso'
565
+				),
566
+				$addon_name,
567
+				self::_effective_version($addon_settings['min_core_version']),
568
+				self::_effective_version(espresso_version()),
569
+				'<br />',
570
+				'<span style="font-weight: bold; color: #D54E21;">',
571
+				'</span><br />'
572
+			);
573
+		} elseif (version_compare($wp_version, $addon_settings['min_wp_version'], '<')) {
574
+			$incompatibility_message = sprintf(
575
+				__(
576
+					'%4$sIMPORTANT!%5$sThe Event Espresso "%1$s" addon requires WordPress version "%2$s" or greater.%3$sPlease update your version of WordPress to use the "%1$s" addon and to keep your site secure.',
577
+					'event_espresso'
578
+				),
579
+				$addon_name,
580
+				$addon_settings['min_wp_version'],
581
+				'<br />',
582
+				'<span style="font-weight: bold; color: #D54E21;">',
583
+				'</span><br />'
584
+			);
585
+		}
586
+		if (! empty($incompatibility_message)) {
587
+			// remove 'activate' from the REQUEST
588
+			// so WP doesn't erroneously tell the user the plugin activated fine when it didn't
589
+			unset($_GET['activate'], $_REQUEST['activate']);
590
+			if (current_user_can('activate_plugins')) {
591
+				// show an error message indicating the plugin didn't activate properly
592
+				EE_Error::add_error($incompatibility_message, __FILE__, __FUNCTION__, __LINE__);
593
+			}
594
+			// BAIL FROM THE ADDON REGISTRATION PROCESS
595
+			return false;
596
+		}
597
+		// addon IS compatible
598
+		return true;
599
+	}
600 600
 
601 601
 
602
-    /**
603
-     * if plugin update engine is being used for auto-updates,
604
-     * then let's set that up now before going any further so that ALL addons can be updated
605
-     * (not needed if PUE is not being used)
606
-     *
607
-     * @param string $addon_name
608
-     * @param string $class_name
609
-     * @param array  $setup_args
610
-     * @return void
611
-     */
612
-    private static function _parse_pue_options($addon_name, $class_name, array $setup_args)
613
-    {
614
-        if (! empty($setup_args['pue_options'])) {
615
-            self::$_settings[ $addon_name ]['pue_options'] = array(
616
-                'pue_plugin_slug' => isset($setup_args['pue_options']['pue_plugin_slug'])
617
-                    ? (string) $setup_args['pue_options']['pue_plugin_slug']
618
-                    : 'espresso_' . strtolower($class_name),
619
-                'plugin_basename' => isset($setup_args['pue_options']['plugin_basename'])
620
-                    ? (string) $setup_args['pue_options']['plugin_basename']
621
-                    : plugin_basename($setup_args['main_file_path']),
622
-                'checkPeriod'     => isset($setup_args['pue_options']['checkPeriod'])
623
-                    ? (string) $setup_args['pue_options']['checkPeriod']
624
-                    : '24',
625
-                'use_wp_update'   => isset($setup_args['pue_options']['use_wp_update'])
626
-                    ? (string) $setup_args['pue_options']['use_wp_update']
627
-                    : false,
628
-            );
629
-            add_action(
630
-                'AHEE__EE_System__brew_espresso__after_pue_init',
631
-                array('EE_Register_Addon', 'load_pue_update')
632
-            );
633
-        }
634
-    }
602
+	/**
603
+	 * if plugin update engine is being used for auto-updates,
604
+	 * then let's set that up now before going any further so that ALL addons can be updated
605
+	 * (not needed if PUE is not being used)
606
+	 *
607
+	 * @param string $addon_name
608
+	 * @param string $class_name
609
+	 * @param array  $setup_args
610
+	 * @return void
611
+	 */
612
+	private static function _parse_pue_options($addon_name, $class_name, array $setup_args)
613
+	{
614
+		if (! empty($setup_args['pue_options'])) {
615
+			self::$_settings[ $addon_name ]['pue_options'] = array(
616
+				'pue_plugin_slug' => isset($setup_args['pue_options']['pue_plugin_slug'])
617
+					? (string) $setup_args['pue_options']['pue_plugin_slug']
618
+					: 'espresso_' . strtolower($class_name),
619
+				'plugin_basename' => isset($setup_args['pue_options']['plugin_basename'])
620
+					? (string) $setup_args['pue_options']['plugin_basename']
621
+					: plugin_basename($setup_args['main_file_path']),
622
+				'checkPeriod'     => isset($setup_args['pue_options']['checkPeriod'])
623
+					? (string) $setup_args['pue_options']['checkPeriod']
624
+					: '24',
625
+				'use_wp_update'   => isset($setup_args['pue_options']['use_wp_update'])
626
+					? (string) $setup_args['pue_options']['use_wp_update']
627
+					: false,
628
+			);
629
+			add_action(
630
+				'AHEE__EE_System__brew_espresso__after_pue_init',
631
+				array('EE_Register_Addon', 'load_pue_update')
632
+			);
633
+		}
634
+	}
635 635
 
636 636
 
637
-    /**
638
-     * register namespaces right away before any other files or classes get loaded, but AFTER the version checks
639
-     *
640
-     * @param array $addon_settings
641
-     * @return void
642
-     */
643
-    private static function _setup_namespaces(array $addon_settings)
644
-    {
645
-        //
646
-        if (isset(
647
-            $addon_settings['namespace']['FQNS'],
648
-            $addon_settings['namespace']['DIR']
649
-        )) {
650
-            EE_Psr4AutoloaderInit::psr4_loader()->addNamespace(
651
-                $addon_settings['namespace']['FQNS'],
652
-                $addon_settings['namespace']['DIR']
653
-            );
654
-        }
655
-    }
637
+	/**
638
+	 * register namespaces right away before any other files or classes get loaded, but AFTER the version checks
639
+	 *
640
+	 * @param array $addon_settings
641
+	 * @return void
642
+	 */
643
+	private static function _setup_namespaces(array $addon_settings)
644
+	{
645
+		//
646
+		if (isset(
647
+			$addon_settings['namespace']['FQNS'],
648
+			$addon_settings['namespace']['DIR']
649
+		)) {
650
+			EE_Psr4AutoloaderInit::psr4_loader()->addNamespace(
651
+				$addon_settings['namespace']['FQNS'],
652
+				$addon_settings['namespace']['DIR']
653
+			);
654
+		}
655
+	}
656 656
 
657 657
 
658
-    /**
659
-     * @param string $addon_name
660
-     * @param array  $addon_settings
661
-     * @return bool
662
-     * @throws EE_Error
663
-     * @throws InvalidArgumentException
664
-     * @throws ReflectionException
665
-     * @throws InvalidDataTypeException
666
-     * @throws InvalidInterfaceException
667
-     */
668
-    private static function _addon_activation($addon_name, array $addon_settings)
669
-    {
670
-        // this is an activation request
671
-        if (did_action(
672
-            'activate_plugin'
673
-        )) {// to find if THIS is the addon that was activated, just check if we have already registered it or not
674
-            // (as the newly-activated addon wasn't around the first time addons were registered).
675
-            // Note: the presence of pue_options in the addon registration options will initialize the $_settings
676
-            // property for the add-on, but the add-on is only partially initialized.  Hence, the additional check.
677
-            if (! isset(self::$_settings[ $addon_name ])
678
-                || (isset(self::$_settings[ $addon_name ])
679
-                    && ! isset(self::$_settings[ $addon_name ]['class_name'])
680
-                )
681
-            ) {
682
-                self::$_settings[ $addon_name ] = $addon_settings;
683
-                $addon = self::_load_and_init_addon_class($addon_name);
684
-                $addon->set_activation_indicator_option();
685
-                // dont bother setting up the rest of the addon.
686
-                // we know it was just activated and the request will end soon
687
-            }
688
-            return true;
689
-        }
690
-        // make sure this was called in the right place!
691
-        if (! did_action('AHEE__EE_System__load_espresso_addons')
692
-            || did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
693
-        ) {
694
-            EE_Error::doing_it_wrong(
695
-                __METHOD__,
696
-                sprintf(
697
-                    __(
698
-                        'An attempt to register an EE_Addon named "%s" has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register addons.',
699
-                        'event_espresso'
700
-                    ),
701
-                    $addon_name
702
-                ),
703
-                '4.3.0'
704
-            );
705
-        }
706
-        // make sure addon settings are set correctly without overwriting anything existing
707
-        if (isset(self::$_settings[ $addon_name ])) {
708
-            self::$_settings[ $addon_name ] += $addon_settings;
709
-        } else {
710
-            self::$_settings[ $addon_name ] = $addon_settings;
711
-        }
712
-        return false;
713
-    }
658
+	/**
659
+	 * @param string $addon_name
660
+	 * @param array  $addon_settings
661
+	 * @return bool
662
+	 * @throws EE_Error
663
+	 * @throws InvalidArgumentException
664
+	 * @throws ReflectionException
665
+	 * @throws InvalidDataTypeException
666
+	 * @throws InvalidInterfaceException
667
+	 */
668
+	private static function _addon_activation($addon_name, array $addon_settings)
669
+	{
670
+		// this is an activation request
671
+		if (did_action(
672
+			'activate_plugin'
673
+		)) {// to find if THIS is the addon that was activated, just check if we have already registered it or not
674
+			// (as the newly-activated addon wasn't around the first time addons were registered).
675
+			// Note: the presence of pue_options in the addon registration options will initialize the $_settings
676
+			// property for the add-on, but the add-on is only partially initialized.  Hence, the additional check.
677
+			if (! isset(self::$_settings[ $addon_name ])
678
+				|| (isset(self::$_settings[ $addon_name ])
679
+					&& ! isset(self::$_settings[ $addon_name ]['class_name'])
680
+				)
681
+			) {
682
+				self::$_settings[ $addon_name ] = $addon_settings;
683
+				$addon = self::_load_and_init_addon_class($addon_name);
684
+				$addon->set_activation_indicator_option();
685
+				// dont bother setting up the rest of the addon.
686
+				// we know it was just activated and the request will end soon
687
+			}
688
+			return true;
689
+		}
690
+		// make sure this was called in the right place!
691
+		if (! did_action('AHEE__EE_System__load_espresso_addons')
692
+			|| did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
693
+		) {
694
+			EE_Error::doing_it_wrong(
695
+				__METHOD__,
696
+				sprintf(
697
+					__(
698
+						'An attempt to register an EE_Addon named "%s" has failed because it was not registered at the correct time.  Please use the "AHEE__EE_System__load_espresso_addons" hook to register addons.',
699
+						'event_espresso'
700
+					),
701
+					$addon_name
702
+				),
703
+				'4.3.0'
704
+			);
705
+		}
706
+		// make sure addon settings are set correctly without overwriting anything existing
707
+		if (isset(self::$_settings[ $addon_name ])) {
708
+			self::$_settings[ $addon_name ] += $addon_settings;
709
+		} else {
710
+			self::$_settings[ $addon_name ] = $addon_settings;
711
+		}
712
+		return false;
713
+	}
714 714
 
715 715
 
716
-    /**
717
-     * @param string $addon_name
718
-     * @return void
719
-     * @throws EE_Error
720
-     */
721
-    private static function _setup_autoloaders($addon_name)
722
-    {
723
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
724
-            // setup autoloader for single file
725
-            EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
726
-        }
727
-        // setup autoloaders for folders
728
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
729
-            foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
730
-                EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
731
-            }
732
-        }
733
-    }
716
+	/**
717
+	 * @param string $addon_name
718
+	 * @return void
719
+	 * @throws EE_Error
720
+	 */
721
+	private static function _setup_autoloaders($addon_name)
722
+	{
723
+		if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
724
+			// setup autoloader for single file
725
+			EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
726
+		}
727
+		// setup autoloaders for folders
728
+		if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
729
+			foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
730
+				EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
731
+			}
732
+		}
733
+	}
734 734
 
735 735
 
736
-    /**
737
-     * register new models and extensions
738
-     *
739
-     * @param string $addon_name
740
-     * @return void
741
-     * @throws EE_Error
742
-     */
743
-    private static function _register_models_and_extensions($addon_name)
744
-    {
745
-        // register new models
746
-        if (! empty(self::$_settings[ $addon_name ]['model_paths'])
747
-            || ! empty(self::$_settings[ $addon_name ]['class_paths'])
748
-        ) {
749
-            EE_Register_Model::register(
750
-                $addon_name,
751
-                array(
752
-                    'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
753
-                    'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
754
-                )
755
-            );
756
-        }
757
-        // register model extensions
758
-        if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
759
-            || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
760
-        ) {
761
-            EE_Register_Model_Extensions::register(
762
-                $addon_name,
763
-                array(
764
-                    'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
765
-                    'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
766
-                )
767
-            );
768
-        }
769
-    }
736
+	/**
737
+	 * register new models and extensions
738
+	 *
739
+	 * @param string $addon_name
740
+	 * @return void
741
+	 * @throws EE_Error
742
+	 */
743
+	private static function _register_models_and_extensions($addon_name)
744
+	{
745
+		// register new models
746
+		if (! empty(self::$_settings[ $addon_name ]['model_paths'])
747
+			|| ! empty(self::$_settings[ $addon_name ]['class_paths'])
748
+		) {
749
+			EE_Register_Model::register(
750
+				$addon_name,
751
+				array(
752
+					'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
753
+					'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
754
+				)
755
+			);
756
+		}
757
+		// register model extensions
758
+		if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
759
+			|| ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
760
+		) {
761
+			EE_Register_Model_Extensions::register(
762
+				$addon_name,
763
+				array(
764
+					'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
765
+					'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
766
+				)
767
+			);
768
+		}
769
+	}
770 770
 
771 771
 
772
-    /**
773
-     * @param string $addon_name
774
-     * @return void
775
-     * @throws EE_Error
776
-     */
777
-    private static function _register_data_migration_scripts($addon_name)
778
-    {
779
-        // setup DMS
780
-        if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
781
-            EE_Register_Data_Migration_Scripts::register(
782
-                $addon_name,
783
-                array('dms_paths' => self::$_settings[ $addon_name ]['dms_paths'])
784
-            );
785
-        }
786
-    }
772
+	/**
773
+	 * @param string $addon_name
774
+	 * @return void
775
+	 * @throws EE_Error
776
+	 */
777
+	private static function _register_data_migration_scripts($addon_name)
778
+	{
779
+		// setup DMS
780
+		if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
781
+			EE_Register_Data_Migration_Scripts::register(
782
+				$addon_name,
783
+				array('dms_paths' => self::$_settings[ $addon_name ]['dms_paths'])
784
+			);
785
+		}
786
+	}
787 787
 
788 788
 
789
-    /**
790
-     * @param string $addon_name
791
-     * @return void
792
-     * @throws EE_Error
793
-     */
794
-    private static function _register_config($addon_name)
795
-    {
796
-        // if config_class is present let's register config.
797
-        if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
798
-            EE_Register_Config::register(
799
-                self::$_settings[ $addon_name ]['config_class'],
800
-                array(
801
-                    'config_section' => self::$_settings[ $addon_name ]['config_section'],
802
-                    'config_name'    => self::$_settings[ $addon_name ]['config_name'],
803
-                )
804
-            );
805
-        }
806
-    }
789
+	/**
790
+	 * @param string $addon_name
791
+	 * @return void
792
+	 * @throws EE_Error
793
+	 */
794
+	private static function _register_config($addon_name)
795
+	{
796
+		// if config_class is present let's register config.
797
+		if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
798
+			EE_Register_Config::register(
799
+				self::$_settings[ $addon_name ]['config_class'],
800
+				array(
801
+					'config_section' => self::$_settings[ $addon_name ]['config_section'],
802
+					'config_name'    => self::$_settings[ $addon_name ]['config_name'],
803
+				)
804
+			);
805
+		}
806
+	}
807 807
 
808 808
 
809
-    /**
810
-     * @param string $addon_name
811
-     * @return void
812
-     * @throws EE_Error
813
-     */
814
-    private static function _register_admin_pages($addon_name)
815
-    {
816
-        if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
817
-            EE_Register_Admin_Page::register(
818
-                $addon_name,
819
-                array('page_path' => self::$_settings[ $addon_name ]['admin_path'])
820
-            );
821
-        }
822
-    }
809
+	/**
810
+	 * @param string $addon_name
811
+	 * @return void
812
+	 * @throws EE_Error
813
+	 */
814
+	private static function _register_admin_pages($addon_name)
815
+	{
816
+		if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
817
+			EE_Register_Admin_Page::register(
818
+				$addon_name,
819
+				array('page_path' => self::$_settings[ $addon_name ]['admin_path'])
820
+			);
821
+		}
822
+	}
823 823
 
824 824
 
825
-    /**
826
-     * @param string $addon_name
827
-     * @return void
828
-     * @throws EE_Error
829
-     */
830
-    private static function _register_modules($addon_name)
831
-    {
832
-        if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
833
-            EE_Register_Module::register(
834
-                $addon_name,
835
-                array('module_paths' => self::$_settings[ $addon_name ]['module_paths'])
836
-            );
837
-        }
838
-    }
825
+	/**
826
+	 * @param string $addon_name
827
+	 * @return void
828
+	 * @throws EE_Error
829
+	 */
830
+	private static function _register_modules($addon_name)
831
+	{
832
+		if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
833
+			EE_Register_Module::register(
834
+				$addon_name,
835
+				array('module_paths' => self::$_settings[ $addon_name ]['module_paths'])
836
+			);
837
+		}
838
+	}
839 839
 
840 840
 
841
-    /**
842
-     * @param string $addon_name
843
-     * @return void
844
-     * @throws EE_Error
845
-     */
846
-    private static function _register_shortcodes($addon_name)
847
-    {
848
-        if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
849
-            || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
850
-        ) {
851
-            EE_Register_Shortcode::register(
852
-                $addon_name,
853
-                array(
854
-                    'shortcode_paths' => isset(self::$_settings[ $addon_name ]['shortcode_paths'])
855
-                        ? self::$_settings[ $addon_name ]['shortcode_paths']
856
-                        : array(),
857
-                    'shortcode_fqcns' => isset(self::$_settings[ $addon_name ]['shortcode_fqcns'])
858
-                        ? self::$_settings[ $addon_name ]['shortcode_fqcns']
859
-                        : array(),
860
-                )
861
-            );
862
-        }
863
-    }
841
+	/**
842
+	 * @param string $addon_name
843
+	 * @return void
844
+	 * @throws EE_Error
845
+	 */
846
+	private static function _register_shortcodes($addon_name)
847
+	{
848
+		if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
849
+			|| ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
850
+		) {
851
+			EE_Register_Shortcode::register(
852
+				$addon_name,
853
+				array(
854
+					'shortcode_paths' => isset(self::$_settings[ $addon_name ]['shortcode_paths'])
855
+						? self::$_settings[ $addon_name ]['shortcode_paths']
856
+						: array(),
857
+					'shortcode_fqcns' => isset(self::$_settings[ $addon_name ]['shortcode_fqcns'])
858
+						? self::$_settings[ $addon_name ]['shortcode_fqcns']
859
+						: array(),
860
+				)
861
+			);
862
+		}
863
+	}
864 864
 
865 865
 
866
-    /**
867
-     * @param string $addon_name
868
-     * @return void
869
-     * @throws EE_Error
870
-     */
871
-    private static function _register_widgets($addon_name)
872
-    {
873
-        if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
874
-            EE_Register_Widget::register(
875
-                $addon_name,
876
-                array('widget_paths' => self::$_settings[ $addon_name ]['widget_paths'])
877
-            );
878
-        }
879
-    }
866
+	/**
867
+	 * @param string $addon_name
868
+	 * @return void
869
+	 * @throws EE_Error
870
+	 */
871
+	private static function _register_widgets($addon_name)
872
+	{
873
+		if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
874
+			EE_Register_Widget::register(
875
+				$addon_name,
876
+				array('widget_paths' => self::$_settings[ $addon_name ]['widget_paths'])
877
+			);
878
+		}
879
+	}
880 880
 
881 881
 
882
-    /**
883
-     * @param string $addon_name
884
-     * @return void
885
-     * @throws EE_Error
886
-     */
887
-    private static function _register_capabilities($addon_name)
888
-    {
889
-        if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
890
-            EE_Register_Capabilities::register(
891
-                $addon_name,
892
-                array(
893
-                    'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
894
-                    'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
895
-                )
896
-            );
897
-        }
898
-    }
882
+	/**
883
+	 * @param string $addon_name
884
+	 * @return void
885
+	 * @throws EE_Error
886
+	 */
887
+	private static function _register_capabilities($addon_name)
888
+	{
889
+		if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
890
+			EE_Register_Capabilities::register(
891
+				$addon_name,
892
+				array(
893
+					'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
894
+					'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
895
+				)
896
+			);
897
+		}
898
+	}
899 899
 
900 900
 
901
-    /**
902
-     * @param string $addon_name
903
-     * @return void
904
-     * @throws EE_Error
905
-     */
906
-    private static function _register_message_types($addon_name)
907
-    {
908
-        if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
909
-            add_action(
910
-                'EE_Brewing_Regular___messages_caf',
911
-                array('EE_Register_Addon', 'register_message_types')
912
-            );
913
-        }
914
-    }
901
+	/**
902
+	 * @param string $addon_name
903
+	 * @return void
904
+	 * @throws EE_Error
905
+	 */
906
+	private static function _register_message_types($addon_name)
907
+	{
908
+		if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
909
+			add_action(
910
+				'EE_Brewing_Regular___messages_caf',
911
+				array('EE_Register_Addon', 'register_message_types')
912
+			);
913
+		}
914
+	}
915 915
 
916 916
 
917
-    /**
918
-     * @param string $addon_name
919
-     * @return void
920
-     * @throws EE_Error
921
-     */
922
-    private static function _register_custom_post_types($addon_name)
923
-    {
924
-        if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])
925
-            || ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
926
-        ) {
927
-            EE_Register_CPT::register(
928
-                $addon_name,
929
-                array(
930
-                    'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
931
-                    'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
932
-                    'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
933
-                )
934
-            );
935
-        }
936
-    }
917
+	/**
918
+	 * @param string $addon_name
919
+	 * @return void
920
+	 * @throws EE_Error
921
+	 */
922
+	private static function _register_custom_post_types($addon_name)
923
+	{
924
+		if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])
925
+			|| ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
926
+		) {
927
+			EE_Register_CPT::register(
928
+				$addon_name,
929
+				array(
930
+					'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
931
+					'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
932
+					'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
933
+				)
934
+			);
935
+		}
936
+	}
937 937
 
938 938
 
939
-    /**
940
-     * @param string $addon_name
941
-     * @return void
942
-     * @throws InvalidArgumentException
943
-     * @throws InvalidInterfaceException
944
-     * @throws InvalidDataTypeException
945
-     * @throws DomainException
946
-     * @throws EE_Error
947
-     */
948
-    private static function _register_payment_methods($addon_name)
949
-    {
950
-        if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
951
-            EE_Register_Payment_Method::register(
952
-                $addon_name,
953
-                array('payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths'])
954
-            );
955
-        }
956
-    }
939
+	/**
940
+	 * @param string $addon_name
941
+	 * @return void
942
+	 * @throws InvalidArgumentException
943
+	 * @throws InvalidInterfaceException
944
+	 * @throws InvalidDataTypeException
945
+	 * @throws DomainException
946
+	 * @throws EE_Error
947
+	 */
948
+	private static function _register_payment_methods($addon_name)
949
+	{
950
+		if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
951
+			EE_Register_Payment_Method::register(
952
+				$addon_name,
953
+				array('payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths'])
954
+			);
955
+		}
956
+	}
957 957
 
958 958
 
959
-    /**
960
-     * @param string $addon_name
961
-     * @return void
962
-     * @throws InvalidArgumentException
963
-     * @throws InvalidInterfaceException
964
-     * @throws InvalidDataTypeException
965
-     * @throws DomainException
966
-     * @throws EE_Error
967
-     */
968
-    private static function registerPrivacyPolicies($addon_name)
969
-    {
970
-        if (! empty(self::$_settings[ $addon_name ]['privacy_policies'])) {
971
-            EE_Register_Privacy_Policy::register(
972
-                $addon_name,
973
-                self::$_settings[ $addon_name ]['privacy_policies']
974
-            );
975
-        }
976
-    }
959
+	/**
960
+	 * @param string $addon_name
961
+	 * @return void
962
+	 * @throws InvalidArgumentException
963
+	 * @throws InvalidInterfaceException
964
+	 * @throws InvalidDataTypeException
965
+	 * @throws DomainException
966
+	 * @throws EE_Error
967
+	 */
968
+	private static function registerPrivacyPolicies($addon_name)
969
+	{
970
+		if (! empty(self::$_settings[ $addon_name ]['privacy_policies'])) {
971
+			EE_Register_Privacy_Policy::register(
972
+				$addon_name,
973
+				self::$_settings[ $addon_name ]['privacy_policies']
974
+			);
975
+		}
976
+	}
977 977
 
978 978
 
979
-    /**
980
-     * @param string $addon_name
981
-     * @return void
982
-     */
983
-    private static function registerPersonalDataExporters($addon_name)
984
-    {
985
-        if (! empty(self::$_settings[ $addon_name ]['personal_data_exporters'])) {
986
-            EE_Register_Personal_Data_Eraser::register(
987
-                $addon_name,
988
-                self::$_settings[ $addon_name ]['personal_data_exporters']
989
-            );
990
-        }
991
-    }
979
+	/**
980
+	 * @param string $addon_name
981
+	 * @return void
982
+	 */
983
+	private static function registerPersonalDataExporters($addon_name)
984
+	{
985
+		if (! empty(self::$_settings[ $addon_name ]['personal_data_exporters'])) {
986
+			EE_Register_Personal_Data_Eraser::register(
987
+				$addon_name,
988
+				self::$_settings[ $addon_name ]['personal_data_exporters']
989
+			);
990
+		}
991
+	}
992 992
 
993 993
 
994
-    /**
995
-     * @param string $addon_name
996
-     * @return void
997
-     */
998
-    private static function registerPersonalDataErasers($addon_name)
999
-    {
1000
-        if (! empty(self::$_settings[ $addon_name ]['personal_data_erasers'])) {
1001
-            EE_Register_Personal_Data_Eraser::register(
1002
-                $addon_name,
1003
-                self::$_settings[ $addon_name ]['personal_data_erasers']
1004
-            );
1005
-        }
1006
-    }
994
+	/**
995
+	 * @param string $addon_name
996
+	 * @return void
997
+	 */
998
+	private static function registerPersonalDataErasers($addon_name)
999
+	{
1000
+		if (! empty(self::$_settings[ $addon_name ]['personal_data_erasers'])) {
1001
+			EE_Register_Personal_Data_Eraser::register(
1002
+				$addon_name,
1003
+				self::$_settings[ $addon_name ]['personal_data_erasers']
1004
+			);
1005
+		}
1006
+	}
1007 1007
 
1008 1008
 
1009
-    /**
1010
-     * Loads and instantiates the EE_Addon class and adds it onto the registry
1011
-     *
1012
-     * @param string $addon_name
1013
-     * @return EE_Addon
1014
-     * @throws InvalidArgumentException
1015
-     * @throws InvalidInterfaceException
1016
-     * @throws InvalidDataTypeException
1017
-     * @throws ReflectionException
1018
-     * @throws EE_Error
1019
-     */
1020
-    private static function _load_and_init_addon_class($addon_name)
1021
-    {
1022
-        $loader = EventEspresso\core\services\loaders\LoaderFactory::getLoader();
1023
-        $addon = $loader->getShared(
1024
-            self::$_settings[ $addon_name ]['class_name'],
1025
-            array('EE_Registry::create(addon)' => true)
1026
-        );
1027
-        // setter inject dep map if required
1028
-        if ($addon instanceof RequiresDependencyMapInterface && $addon->dependencyMap() === null) {
1029
-            $addon->setDependencyMap($loader->getShared('EE_Dependency_Map'));
1030
-        }
1031
-        // setter inject domain if required
1032
-        if ($addon instanceof RequiresDomainInterface
1033
-            && $addon->domain() === null
1034
-        ) {
1035
-            // using supplied Domain object
1036
-            $domain = self::$_settings[ $addon_name ]['domain'] instanceof DomainInterface
1037
-                ? self::$_settings[ $addon_name ]['domain']
1038
-                : null;
1039
-            // or construct one using Domain FQCN
1040
-            if ($domain === null && self::$_settings[ $addon_name ]['domain_fqcn'] !== '') {
1041
-                $domain = $loader->getShared(
1042
-                    self::$_settings[ $addon_name ]['domain_fqcn'],
1043
-                    array(
1044
-                        new EventEspresso\core\domain\values\FilePath(
1045
-                            self::$_settings[ $addon_name ]['main_file_path']
1046
-                        ),
1047
-                        EventEspresso\core\domain\values\Version::fromString(
1048
-                            self::$_settings[ $addon_name ]['version']
1049
-                        ),
1050
-                    )
1051
-                );
1052
-            }
1053
-            if ($domain instanceof DomainInterface) {
1054
-                $addon->setDomain($domain);
1055
-            }
1056
-        }
1057
-        $addon->set_name($addon_name);
1058
-        $addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
1059
-        $addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
1060
-        $addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
1061
-        $addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
1062
-        $addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
1063
-        $addon->set_version(self::$_settings[ $addon_name ]['version']);
1064
-        $addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
1065
-        $addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
1066
-        $addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
1067
-        $addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
1068
-        // unfortunately this can't be hooked in upon construction, because we don't have
1069
-        // the plugin mainfile's path upon construction.
1070
-        register_deactivation_hook($addon->get_main_plugin_file(), array($addon, 'deactivation'));
1071
-        // call any additional admin_callback functions during load_admin_controller hook
1072
-        if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
1073
-            add_action(
1074
-                'AHEE__EE_System__load_controllers__load_admin_controllers',
1075
-                array($addon, self::$_settings[ $addon_name ]['admin_callback'])
1076
-            );
1077
-        }
1078
-        return $addon;
1079
-    }
1009
+	/**
1010
+	 * Loads and instantiates the EE_Addon class and adds it onto the registry
1011
+	 *
1012
+	 * @param string $addon_name
1013
+	 * @return EE_Addon
1014
+	 * @throws InvalidArgumentException
1015
+	 * @throws InvalidInterfaceException
1016
+	 * @throws InvalidDataTypeException
1017
+	 * @throws ReflectionException
1018
+	 * @throws EE_Error
1019
+	 */
1020
+	private static function _load_and_init_addon_class($addon_name)
1021
+	{
1022
+		$loader = EventEspresso\core\services\loaders\LoaderFactory::getLoader();
1023
+		$addon = $loader->getShared(
1024
+			self::$_settings[ $addon_name ]['class_name'],
1025
+			array('EE_Registry::create(addon)' => true)
1026
+		);
1027
+		// setter inject dep map if required
1028
+		if ($addon instanceof RequiresDependencyMapInterface && $addon->dependencyMap() === null) {
1029
+			$addon->setDependencyMap($loader->getShared('EE_Dependency_Map'));
1030
+		}
1031
+		// setter inject domain if required
1032
+		if ($addon instanceof RequiresDomainInterface
1033
+			&& $addon->domain() === null
1034
+		) {
1035
+			// using supplied Domain object
1036
+			$domain = self::$_settings[ $addon_name ]['domain'] instanceof DomainInterface
1037
+				? self::$_settings[ $addon_name ]['domain']
1038
+				: null;
1039
+			// or construct one using Domain FQCN
1040
+			if ($domain === null && self::$_settings[ $addon_name ]['domain_fqcn'] !== '') {
1041
+				$domain = $loader->getShared(
1042
+					self::$_settings[ $addon_name ]['domain_fqcn'],
1043
+					array(
1044
+						new EventEspresso\core\domain\values\FilePath(
1045
+							self::$_settings[ $addon_name ]['main_file_path']
1046
+						),
1047
+						EventEspresso\core\domain\values\Version::fromString(
1048
+							self::$_settings[ $addon_name ]['version']
1049
+						),
1050
+					)
1051
+				);
1052
+			}
1053
+			if ($domain instanceof DomainInterface) {
1054
+				$addon->setDomain($domain);
1055
+			}
1056
+		}
1057
+		$addon->set_name($addon_name);
1058
+		$addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
1059
+		$addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
1060
+		$addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
1061
+		$addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
1062
+		$addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
1063
+		$addon->set_version(self::$_settings[ $addon_name ]['version']);
1064
+		$addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
1065
+		$addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
1066
+		$addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
1067
+		$addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
1068
+		// unfortunately this can't be hooked in upon construction, because we don't have
1069
+		// the plugin mainfile's path upon construction.
1070
+		register_deactivation_hook($addon->get_main_plugin_file(), array($addon, 'deactivation'));
1071
+		// call any additional admin_callback functions during load_admin_controller hook
1072
+		if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
1073
+			add_action(
1074
+				'AHEE__EE_System__load_controllers__load_admin_controllers',
1075
+				array($addon, self::$_settings[ $addon_name ]['admin_callback'])
1076
+			);
1077
+		}
1078
+		return $addon;
1079
+	}
1080 1080
 
1081 1081
 
1082
-    /**
1083
-     *    load_pue_update - Update notifications
1084
-     *
1085
-     * @return void
1086
-     * @throws InvalidArgumentException
1087
-     * @throws InvalidDataTypeException
1088
-     * @throws InvalidInterfaceException
1089
-     */
1090
-    public static function load_pue_update()
1091
-    {
1092
-        // load PUE client
1093
-        require_once EE_THIRD_PARTY . 'pue' . DS . 'pue-client.php';
1094
-        $license_server = defined('PUE_UPDATES_ENDPOINT') ? PUE_UPDATES_ENDPOINT : 'https://eventespresso.com';
1095
-        // cycle thru settings
1096
-        foreach (self::$_settings as $settings) {
1097
-            if (! empty($settings['pue_options'])) {
1098
-                // initiate the class and start the plugin update engine!
1099
-                new PluginUpdateEngineChecker(
1100
-                    // host file URL
1101
-                    $license_server,
1102
-                    // plugin slug(s)
1103
-                    array(
1104
-                        'premium'    => array('p' => $settings['pue_options']['pue_plugin_slug']),
1105
-                        'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'] . '-pr'),
1106
-                    ),
1107
-                    // options
1108
-                    array(
1109
-                        'apikey'            => EE_Registry::instance()->NET_CFG->core->site_license_key,
1110
-                        'lang_domain'       => 'event_espresso',
1111
-                        'checkPeriod'       => $settings['pue_options']['checkPeriod'],
1112
-                        'option_key'        => 'ee_site_license_key',
1113
-                        'options_page_slug' => 'event_espresso',
1114
-                        'plugin_basename'   => $settings['pue_options']['plugin_basename'],
1115
-                        // if use_wp_update is TRUE it means you want FREE versions of the plugin to be updated from WP
1116
-                        'use_wp_update'     => $settings['pue_options']['use_wp_update'],
1117
-                    )
1118
-                );
1119
-            }
1120
-        }
1121
-    }
1082
+	/**
1083
+	 *    load_pue_update - Update notifications
1084
+	 *
1085
+	 * @return void
1086
+	 * @throws InvalidArgumentException
1087
+	 * @throws InvalidDataTypeException
1088
+	 * @throws InvalidInterfaceException
1089
+	 */
1090
+	public static function load_pue_update()
1091
+	{
1092
+		// load PUE client
1093
+		require_once EE_THIRD_PARTY . 'pue' . DS . 'pue-client.php';
1094
+		$license_server = defined('PUE_UPDATES_ENDPOINT') ? PUE_UPDATES_ENDPOINT : 'https://eventespresso.com';
1095
+		// cycle thru settings
1096
+		foreach (self::$_settings as $settings) {
1097
+			if (! empty($settings['pue_options'])) {
1098
+				// initiate the class and start the plugin update engine!
1099
+				new PluginUpdateEngineChecker(
1100
+					// host file URL
1101
+					$license_server,
1102
+					// plugin slug(s)
1103
+					array(
1104
+						'premium'    => array('p' => $settings['pue_options']['pue_plugin_slug']),
1105
+						'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'] . '-pr'),
1106
+					),
1107
+					// options
1108
+					array(
1109
+						'apikey'            => EE_Registry::instance()->NET_CFG->core->site_license_key,
1110
+						'lang_domain'       => 'event_espresso',
1111
+						'checkPeriod'       => $settings['pue_options']['checkPeriod'],
1112
+						'option_key'        => 'ee_site_license_key',
1113
+						'options_page_slug' => 'event_espresso',
1114
+						'plugin_basename'   => $settings['pue_options']['plugin_basename'],
1115
+						// if use_wp_update is TRUE it means you want FREE versions of the plugin to be updated from WP
1116
+						'use_wp_update'     => $settings['pue_options']['use_wp_update'],
1117
+					)
1118
+				);
1119
+			}
1120
+		}
1121
+	}
1122 1122
 
1123 1123
 
1124
-    /**
1125
-     * Callback for EE_Brewing_Regular__messages_caf hook used to register message types.
1126
-     *
1127
-     * @since 4.4.0
1128
-     * @return void
1129
-     * @throws EE_Error
1130
-     */
1131
-    public static function register_message_types()
1132
-    {
1133
-        foreach (self::$_settings as $addon_name => $settings) {
1134
-            if (! empty($settings['message_types'])) {
1135
-                foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1136
-                    EE_Register_Message_Type::register($message_type, $message_type_settings);
1137
-                }
1138
-            }
1139
-        }
1140
-    }
1124
+	/**
1125
+	 * Callback for EE_Brewing_Regular__messages_caf hook used to register message types.
1126
+	 *
1127
+	 * @since 4.4.0
1128
+	 * @return void
1129
+	 * @throws EE_Error
1130
+	 */
1131
+	public static function register_message_types()
1132
+	{
1133
+		foreach (self::$_settings as $addon_name => $settings) {
1134
+			if (! empty($settings['message_types'])) {
1135
+				foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1136
+					EE_Register_Message_Type::register($message_type, $message_type_settings);
1137
+				}
1138
+			}
1139
+		}
1140
+	}
1141 1141
 
1142 1142
 
1143
-    /**
1144
-     * This deregisters an addon that was previously registered with a specific addon_name.
1145
-     *
1146
-     * @since    4.3.0
1147
-     * @param string $addon_name the name for the addon that was previously registered
1148
-     * @throws DomainException
1149
-     * @throws EE_Error
1150
-     * @throws InvalidArgumentException
1151
-     * @throws InvalidDataTypeException
1152
-     * @throws InvalidInterfaceException
1153
-     */
1154
-    public static function deregister($addon_name = null)
1155
-    {
1156
-        if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1157
-            try {
1158
-                do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1159
-                $class_name = self::$_settings[ $addon_name ]['class_name'];
1160
-                if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1161
-                    // setup DMS
1162
-                    EE_Register_Data_Migration_Scripts::deregister($addon_name);
1163
-                }
1164
-                if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1165
-                    // register admin page
1166
-                    EE_Register_Admin_Page::deregister($addon_name);
1167
-                }
1168
-                if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1169
-                    // add to list of modules to be registered
1170
-                    EE_Register_Module::deregister($addon_name);
1171
-                }
1172
-                if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1173
-                    || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1174
-                ) {
1175
-                    // add to list of shortcodes to be registered
1176
-                    EE_Register_Shortcode::deregister($addon_name);
1177
-                }
1178
-                if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1179
-                    // if config_class present let's register config.
1180
-                    EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1181
-                }
1182
-                if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1183
-                    // add to list of widgets to be registered
1184
-                    EE_Register_Widget::deregister($addon_name);
1185
-                }
1186
-                if (! empty(self::$_settings[ $addon_name ]['model_paths'])
1187
-                    || ! empty(self::$_settings[ $addon_name ]['class_paths'])
1188
-                ) {
1189
-                    // add to list of shortcodes to be registered
1190
-                    EE_Register_Model::deregister($addon_name);
1191
-                }
1192
-                if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1193
-                    || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1194
-                ) {
1195
-                    // add to list of shortcodes to be registered
1196
-                    EE_Register_Model_Extensions::deregister($addon_name);
1197
-                }
1198
-                if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1199
-                    foreach ((array) self::$_settings[ $addon_name ]['message_types'] as $message_type => $message_type_settings) {
1200
-                        EE_Register_Message_Type::deregister($message_type);
1201
-                    }
1202
-                }
1203
-                // deregister capabilities for addon
1204
-                if (! empty(self::$_settings[ $addon_name ]['capabilities'])
1205
-                    || ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1206
-                ) {
1207
-                    EE_Register_Capabilities::deregister($addon_name);
1208
-                }
1209
-                // deregister custom_post_types for addon
1210
-                if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1211
-                    EE_Register_CPT::deregister($addon_name);
1212
-                }
1213
-                if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1214
-                    EE_Register_Payment_Method::deregister($addon_name);
1215
-                }
1216
-                $addon = EE_Registry::instance()->getAddon($class_name);
1217
-                if ($addon instanceof EE_Addon) {
1218
-                    remove_action(
1219
-                        'deactivate_' . $addon->get_main_plugin_file_basename(),
1220
-                        array($addon, 'deactivation')
1221
-                    );
1222
-                    remove_action(
1223
-                        'AHEE__EE_System__perform_activations_upgrades_and_migrations',
1224
-                        array($addon, 'initialize_db_if_no_migrations_required')
1225
-                    );
1226
-                    // remove `after_registration` call
1227
-                    remove_action(
1228
-                        'AHEE__EE_System__load_espresso_addons__complete',
1229
-                        array($addon, 'after_registration'),
1230
-                        999
1231
-                    );
1232
-                }
1233
-                EE_Registry::instance()->removeAddon($class_name);
1234
-            } catch (OutOfBoundsException $addon_not_yet_registered_exception) {
1235
-                // the add-on was not yet registered in the registry,
1236
-                // so RegistryContainer::__get() throws this exception.
1237
-                // also no need to worry about this or log it,
1238
-                // it's ok to deregister an add-on before its registered in the registry
1239
-            } catch (Exception $e) {
1240
-                new ExceptionLogger($e);
1241
-            }
1242
-            unset(self::$_settings[ $addon_name ]);
1243
-            do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1244
-        }
1245
-    }
1143
+	/**
1144
+	 * This deregisters an addon that was previously registered with a specific addon_name.
1145
+	 *
1146
+	 * @since    4.3.0
1147
+	 * @param string $addon_name the name for the addon that was previously registered
1148
+	 * @throws DomainException
1149
+	 * @throws EE_Error
1150
+	 * @throws InvalidArgumentException
1151
+	 * @throws InvalidDataTypeException
1152
+	 * @throws InvalidInterfaceException
1153
+	 */
1154
+	public static function deregister($addon_name = null)
1155
+	{
1156
+		if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1157
+			try {
1158
+				do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1159
+				$class_name = self::$_settings[ $addon_name ]['class_name'];
1160
+				if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1161
+					// setup DMS
1162
+					EE_Register_Data_Migration_Scripts::deregister($addon_name);
1163
+				}
1164
+				if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1165
+					// register admin page
1166
+					EE_Register_Admin_Page::deregister($addon_name);
1167
+				}
1168
+				if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1169
+					// add to list of modules to be registered
1170
+					EE_Register_Module::deregister($addon_name);
1171
+				}
1172
+				if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1173
+					|| ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1174
+				) {
1175
+					// add to list of shortcodes to be registered
1176
+					EE_Register_Shortcode::deregister($addon_name);
1177
+				}
1178
+				if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1179
+					// if config_class present let's register config.
1180
+					EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1181
+				}
1182
+				if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1183
+					// add to list of widgets to be registered
1184
+					EE_Register_Widget::deregister($addon_name);
1185
+				}
1186
+				if (! empty(self::$_settings[ $addon_name ]['model_paths'])
1187
+					|| ! empty(self::$_settings[ $addon_name ]['class_paths'])
1188
+				) {
1189
+					// add to list of shortcodes to be registered
1190
+					EE_Register_Model::deregister($addon_name);
1191
+				}
1192
+				if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1193
+					|| ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1194
+				) {
1195
+					// add to list of shortcodes to be registered
1196
+					EE_Register_Model_Extensions::deregister($addon_name);
1197
+				}
1198
+				if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1199
+					foreach ((array) self::$_settings[ $addon_name ]['message_types'] as $message_type => $message_type_settings) {
1200
+						EE_Register_Message_Type::deregister($message_type);
1201
+					}
1202
+				}
1203
+				// deregister capabilities for addon
1204
+				if (! empty(self::$_settings[ $addon_name ]['capabilities'])
1205
+					|| ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1206
+				) {
1207
+					EE_Register_Capabilities::deregister($addon_name);
1208
+				}
1209
+				// deregister custom_post_types for addon
1210
+				if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1211
+					EE_Register_CPT::deregister($addon_name);
1212
+				}
1213
+				if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1214
+					EE_Register_Payment_Method::deregister($addon_name);
1215
+				}
1216
+				$addon = EE_Registry::instance()->getAddon($class_name);
1217
+				if ($addon instanceof EE_Addon) {
1218
+					remove_action(
1219
+						'deactivate_' . $addon->get_main_plugin_file_basename(),
1220
+						array($addon, 'deactivation')
1221
+					);
1222
+					remove_action(
1223
+						'AHEE__EE_System__perform_activations_upgrades_and_migrations',
1224
+						array($addon, 'initialize_db_if_no_migrations_required')
1225
+					);
1226
+					// remove `after_registration` call
1227
+					remove_action(
1228
+						'AHEE__EE_System__load_espresso_addons__complete',
1229
+						array($addon, 'after_registration'),
1230
+						999
1231
+					);
1232
+				}
1233
+				EE_Registry::instance()->removeAddon($class_name);
1234
+			} catch (OutOfBoundsException $addon_not_yet_registered_exception) {
1235
+				// the add-on was not yet registered in the registry,
1236
+				// so RegistryContainer::__get() throws this exception.
1237
+				// also no need to worry about this or log it,
1238
+				// it's ok to deregister an add-on before its registered in the registry
1239
+			} catch (Exception $e) {
1240
+				new ExceptionLogger($e);
1241
+			}
1242
+			unset(self::$_settings[ $addon_name ]);
1243
+			do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1244
+		}
1245
+	}
1246 1246
 }
Please login to merge, or discard this patch.
Spacing   +115 added lines, -115 removed lines patch added patch discarded remove patch
@@ -69,15 +69,15 @@  discard block
 block discarded – undo
69 69
         // offsets:    0 . 1 . 2 . 3 . 4
70 70
         $version_parts = explode('.', $min_core_version);
71 71
         // check they specified the micro version (after 2nd period)
72
-        if (! isset($version_parts[2])) {
72
+        if ( ! isset($version_parts[2])) {
73 73
             $version_parts[2] = '0';
74 74
         }
75 75
         // if they didn't specify the 'p', or 'rc' part. Just assume the lowest possible
76 76
         // soon we can assume that's 'rc', but this current version is 'alpha'
77
-        if (! isset($version_parts[3])) {
77
+        if ( ! isset($version_parts[3])) {
78 78
             $version_parts[3] = 'dev';
79 79
         }
80
-        if (! isset($version_parts[4])) {
80
+        if ( ! isset($version_parts[4])) {
81 81
             $version_parts[4] = '000';
82 82
         }
83 83
         return implode('.', $version_parts);
@@ -264,7 +264,7 @@  discard block
 block discarded – undo
264 264
         // setup PUE
265 265
         EE_Register_Addon::_parse_pue_options($addon_name, $class_name, $setup_args);
266 266
         // does this addon work with this version of core or WordPress ?
267
-        if (! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
267
+        if ( ! EE_Register_Addon::_addon_is_compatible($addon_name, $addon_settings)) {
268 268
             return;
269 269
         }
270 270
         // register namespaces
@@ -328,7 +328,7 @@  discard block
 block discarded – undo
328 328
                 )
329 329
             );
330 330
         }
331
-        if (! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
331
+        if ( ! isset($setup_args['main_file_path']) || empty($setup_args['main_file_path'])) {
332 332
             throw new EE_Error(
333 333
                 sprintf(
334 334
                     __(
@@ -340,7 +340,7 @@  discard block
 block discarded – undo
340 340
             );
341 341
         }
342 342
         // check that addon has not already been registered with that name
343
-        if (isset(self::$_settings[ $addon_name ]) && ! did_action('activate_plugin')) {
343
+        if (isset(self::$_settings[$addon_name]) && ! did_action('activate_plugin')) {
344 344
             throw new EE_Error(
345 345
                 sprintf(
346 346
                     __(
@@ -372,7 +372,7 @@  discard block
 block discarded – undo
372 372
         // check if classname is fully  qualified or is a legacy classname already prefixed with 'EE_'
373 373
         return strpos($class_name, '\\') || strpos($class_name, 'EE_') === 0
374 374
             ? $class_name
375
-            : 'EE_' . $class_name;
375
+            : 'EE_'.$class_name;
376 376
     }
377 377
 
378 378
 
@@ -539,9 +539,9 @@  discard block
 block discarded – undo
539 539
         global $wp_version;
540 540
         $incompatibility_message = '';
541 541
         // check whether this addon version is compatible with EE core
542
-        if (isset(EE_Register_Addon::$_incompatible_addons[ $addon_name ])
542
+        if (isset(EE_Register_Addon::$_incompatible_addons[$addon_name])
543 543
             && ! self::_meets_min_core_version_requirement(
544
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
544
+                EE_Register_Addon::$_incompatible_addons[$addon_name],
545 545
                 $addon_settings['version']
546 546
             )
547 547
         ) {
@@ -552,11 +552,11 @@  discard block
 block discarded – undo
552 552
                 ),
553 553
                 $addon_name,
554 554
                 '<br />',
555
-                EE_Register_Addon::$_incompatible_addons[ $addon_name ],
555
+                EE_Register_Addon::$_incompatible_addons[$addon_name],
556 556
                 '<span style="font-weight: bold; color: #D54E21;">',
557 557
                 '</span><br />'
558 558
             );
559
-        } elseif (! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
559
+        } elseif ( ! self::_meets_min_core_version_requirement($addon_settings['min_core_version'], espresso_version())
560 560
         ) {
561 561
             $incompatibility_message = sprintf(
562 562
                 __(
@@ -583,7 +583,7 @@  discard block
 block discarded – undo
583 583
                 '</span><br />'
584 584
             );
585 585
         }
586
-        if (! empty($incompatibility_message)) {
586
+        if ( ! empty($incompatibility_message)) {
587 587
             // remove 'activate' from the REQUEST
588 588
             // so WP doesn't erroneously tell the user the plugin activated fine when it didn't
589 589
             unset($_GET['activate'], $_REQUEST['activate']);
@@ -611,11 +611,11 @@  discard block
 block discarded – undo
611 611
      */
612 612
     private static function _parse_pue_options($addon_name, $class_name, array $setup_args)
613 613
     {
614
-        if (! empty($setup_args['pue_options'])) {
615
-            self::$_settings[ $addon_name ]['pue_options'] = array(
614
+        if ( ! empty($setup_args['pue_options'])) {
615
+            self::$_settings[$addon_name]['pue_options'] = array(
616 616
                 'pue_plugin_slug' => isset($setup_args['pue_options']['pue_plugin_slug'])
617 617
                     ? (string) $setup_args['pue_options']['pue_plugin_slug']
618
-                    : 'espresso_' . strtolower($class_name),
618
+                    : 'espresso_'.strtolower($class_name),
619 619
                 'plugin_basename' => isset($setup_args['pue_options']['plugin_basename'])
620 620
                     ? (string) $setup_args['pue_options']['plugin_basename']
621 621
                     : plugin_basename($setup_args['main_file_path']),
@@ -674,12 +674,12 @@  discard block
 block discarded – undo
674 674
             // (as the newly-activated addon wasn't around the first time addons were registered).
675 675
             // Note: the presence of pue_options in the addon registration options will initialize the $_settings
676 676
             // property for the add-on, but the add-on is only partially initialized.  Hence, the additional check.
677
-            if (! isset(self::$_settings[ $addon_name ])
678
-                || (isset(self::$_settings[ $addon_name ])
679
-                    && ! isset(self::$_settings[ $addon_name ]['class_name'])
677
+            if ( ! isset(self::$_settings[$addon_name])
678
+                || (isset(self::$_settings[$addon_name])
679
+                    && ! isset(self::$_settings[$addon_name]['class_name'])
680 680
                 )
681 681
             ) {
682
-                self::$_settings[ $addon_name ] = $addon_settings;
682
+                self::$_settings[$addon_name] = $addon_settings;
683 683
                 $addon = self::_load_and_init_addon_class($addon_name);
684 684
                 $addon->set_activation_indicator_option();
685 685
                 // dont bother setting up the rest of the addon.
@@ -688,7 +688,7 @@  discard block
 block discarded – undo
688 688
             return true;
689 689
         }
690 690
         // make sure this was called in the right place!
691
-        if (! did_action('AHEE__EE_System__load_espresso_addons')
691
+        if ( ! did_action('AHEE__EE_System__load_espresso_addons')
692 692
             || did_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin')
693 693
         ) {
694 694
             EE_Error::doing_it_wrong(
@@ -704,10 +704,10 @@  discard block
 block discarded – undo
704 704
             );
705 705
         }
706 706
         // make sure addon settings are set correctly without overwriting anything existing
707
-        if (isset(self::$_settings[ $addon_name ])) {
708
-            self::$_settings[ $addon_name ] += $addon_settings;
707
+        if (isset(self::$_settings[$addon_name])) {
708
+            self::$_settings[$addon_name] += $addon_settings;
709 709
         } else {
710
-            self::$_settings[ $addon_name ] = $addon_settings;
710
+            self::$_settings[$addon_name] = $addon_settings;
711 711
         }
712 712
         return false;
713 713
     }
@@ -720,13 +720,13 @@  discard block
 block discarded – undo
720 720
      */
721 721
     private static function _setup_autoloaders($addon_name)
722 722
     {
723
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_paths'])) {
723
+        if ( ! empty(self::$_settings[$addon_name]['autoloader_paths'])) {
724 724
             // setup autoloader for single file
725
-            EEH_Autoloader::instance()->register_autoloader(self::$_settings[ $addon_name ]['autoloader_paths']);
725
+            EEH_Autoloader::instance()->register_autoloader(self::$_settings[$addon_name]['autoloader_paths']);
726 726
         }
727 727
         // setup autoloaders for folders
728
-        if (! empty(self::$_settings[ $addon_name ]['autoloader_folders'])) {
729
-            foreach ((array) self::$_settings[ $addon_name ]['autoloader_folders'] as $autoloader_folder) {
728
+        if ( ! empty(self::$_settings[$addon_name]['autoloader_folders'])) {
729
+            foreach ((array) self::$_settings[$addon_name]['autoloader_folders'] as $autoloader_folder) {
730 730
                 EEH_Autoloader::register_autoloaders_for_each_file_in_folder($autoloader_folder);
731 731
             }
732 732
         }
@@ -743,26 +743,26 @@  discard block
 block discarded – undo
743 743
     private static function _register_models_and_extensions($addon_name)
744 744
     {
745 745
         // register new models
746
-        if (! empty(self::$_settings[ $addon_name ]['model_paths'])
747
-            || ! empty(self::$_settings[ $addon_name ]['class_paths'])
746
+        if ( ! empty(self::$_settings[$addon_name]['model_paths'])
747
+            || ! empty(self::$_settings[$addon_name]['class_paths'])
748 748
         ) {
749 749
             EE_Register_Model::register(
750 750
                 $addon_name,
751 751
                 array(
752
-                    'model_paths' => self::$_settings[ $addon_name ]['model_paths'],
753
-                    'class_paths' => self::$_settings[ $addon_name ]['class_paths'],
752
+                    'model_paths' => self::$_settings[$addon_name]['model_paths'],
753
+                    'class_paths' => self::$_settings[$addon_name]['class_paths'],
754 754
                 )
755 755
             );
756 756
         }
757 757
         // register model extensions
758
-        if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
759
-            || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
758
+        if ( ! empty(self::$_settings[$addon_name]['model_extension_paths'])
759
+            || ! empty(self::$_settings[$addon_name]['class_extension_paths'])
760 760
         ) {
761 761
             EE_Register_Model_Extensions::register(
762 762
                 $addon_name,
763 763
                 array(
764
-                    'model_extension_paths' => self::$_settings[ $addon_name ]['model_extension_paths'],
765
-                    'class_extension_paths' => self::$_settings[ $addon_name ]['class_extension_paths'],
764
+                    'model_extension_paths' => self::$_settings[$addon_name]['model_extension_paths'],
765
+                    'class_extension_paths' => self::$_settings[$addon_name]['class_extension_paths'],
766 766
                 )
767 767
             );
768 768
         }
@@ -777,10 +777,10 @@  discard block
 block discarded – undo
777 777
     private static function _register_data_migration_scripts($addon_name)
778 778
     {
779 779
         // setup DMS
780
-        if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
780
+        if ( ! empty(self::$_settings[$addon_name]['dms_paths'])) {
781 781
             EE_Register_Data_Migration_Scripts::register(
782 782
                 $addon_name,
783
-                array('dms_paths' => self::$_settings[ $addon_name ]['dms_paths'])
783
+                array('dms_paths' => self::$_settings[$addon_name]['dms_paths'])
784 784
             );
785 785
         }
786 786
     }
@@ -794,12 +794,12 @@  discard block
 block discarded – undo
794 794
     private static function _register_config($addon_name)
795 795
     {
796 796
         // if config_class is present let's register config.
797
-        if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
797
+        if ( ! empty(self::$_settings[$addon_name]['config_class'])) {
798 798
             EE_Register_Config::register(
799
-                self::$_settings[ $addon_name ]['config_class'],
799
+                self::$_settings[$addon_name]['config_class'],
800 800
                 array(
801
-                    'config_section' => self::$_settings[ $addon_name ]['config_section'],
802
-                    'config_name'    => self::$_settings[ $addon_name ]['config_name'],
801
+                    'config_section' => self::$_settings[$addon_name]['config_section'],
802
+                    'config_name'    => self::$_settings[$addon_name]['config_name'],
803 803
                 )
804 804
             );
805 805
         }
@@ -813,10 +813,10 @@  discard block
 block discarded – undo
813 813
      */
814 814
     private static function _register_admin_pages($addon_name)
815 815
     {
816
-        if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
816
+        if ( ! empty(self::$_settings[$addon_name]['admin_path'])) {
817 817
             EE_Register_Admin_Page::register(
818 818
                 $addon_name,
819
-                array('page_path' => self::$_settings[ $addon_name ]['admin_path'])
819
+                array('page_path' => self::$_settings[$addon_name]['admin_path'])
820 820
             );
821 821
         }
822 822
     }
@@ -829,10 +829,10 @@  discard block
 block discarded – undo
829 829
      */
830 830
     private static function _register_modules($addon_name)
831 831
     {
832
-        if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
832
+        if ( ! empty(self::$_settings[$addon_name]['module_paths'])) {
833 833
             EE_Register_Module::register(
834 834
                 $addon_name,
835
-                array('module_paths' => self::$_settings[ $addon_name ]['module_paths'])
835
+                array('module_paths' => self::$_settings[$addon_name]['module_paths'])
836 836
             );
837 837
         }
838 838
     }
@@ -845,17 +845,17 @@  discard block
 block discarded – undo
845 845
      */
846 846
     private static function _register_shortcodes($addon_name)
847 847
     {
848
-        if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
849
-            || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
848
+        if ( ! empty(self::$_settings[$addon_name]['shortcode_paths'])
849
+            || ! empty(self::$_settings[$addon_name]['shortcode_fqcns'])
850 850
         ) {
851 851
             EE_Register_Shortcode::register(
852 852
                 $addon_name,
853 853
                 array(
854
-                    'shortcode_paths' => isset(self::$_settings[ $addon_name ]['shortcode_paths'])
855
-                        ? self::$_settings[ $addon_name ]['shortcode_paths']
854
+                    'shortcode_paths' => isset(self::$_settings[$addon_name]['shortcode_paths'])
855
+                        ? self::$_settings[$addon_name]['shortcode_paths']
856 856
                         : array(),
857
-                    'shortcode_fqcns' => isset(self::$_settings[ $addon_name ]['shortcode_fqcns'])
858
-                        ? self::$_settings[ $addon_name ]['shortcode_fqcns']
857
+                    'shortcode_fqcns' => isset(self::$_settings[$addon_name]['shortcode_fqcns'])
858
+                        ? self::$_settings[$addon_name]['shortcode_fqcns']
859 859
                         : array(),
860 860
                 )
861 861
             );
@@ -870,10 +870,10 @@  discard block
 block discarded – undo
870 870
      */
871 871
     private static function _register_widgets($addon_name)
872 872
     {
873
-        if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
873
+        if ( ! empty(self::$_settings[$addon_name]['widget_paths'])) {
874 874
             EE_Register_Widget::register(
875 875
                 $addon_name,
876
-                array('widget_paths' => self::$_settings[ $addon_name ]['widget_paths'])
876
+                array('widget_paths' => self::$_settings[$addon_name]['widget_paths'])
877 877
             );
878 878
         }
879 879
     }
@@ -886,12 +886,12 @@  discard block
 block discarded – undo
886 886
      */
887 887
     private static function _register_capabilities($addon_name)
888 888
     {
889
-        if (! empty(self::$_settings[ $addon_name ]['capabilities'])) {
889
+        if ( ! empty(self::$_settings[$addon_name]['capabilities'])) {
890 890
             EE_Register_Capabilities::register(
891 891
                 $addon_name,
892 892
                 array(
893
-                    'capabilities'    => self::$_settings[ $addon_name ]['capabilities'],
894
-                    'capability_maps' => self::$_settings[ $addon_name ]['capability_maps'],
893
+                    'capabilities'    => self::$_settings[$addon_name]['capabilities'],
894
+                    'capability_maps' => self::$_settings[$addon_name]['capability_maps'],
895 895
                 )
896 896
             );
897 897
         }
@@ -905,7 +905,7 @@  discard block
 block discarded – undo
905 905
      */
906 906
     private static function _register_message_types($addon_name)
907 907
     {
908
-        if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
908
+        if ( ! empty(self::$_settings[$addon_name]['message_types'])) {
909 909
             add_action(
910 910
                 'EE_Brewing_Regular___messages_caf',
911 911
                 array('EE_Register_Addon', 'register_message_types')
@@ -921,15 +921,15 @@  discard block
 block discarded – undo
921 921
      */
922 922
     private static function _register_custom_post_types($addon_name)
923 923
     {
924
-        if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])
925
-            || ! empty(self::$_settings[ $addon_name ]['custom_taxonomies'])
924
+        if ( ! empty(self::$_settings[$addon_name]['custom_post_types'])
925
+            || ! empty(self::$_settings[$addon_name]['custom_taxonomies'])
926 926
         ) {
927 927
             EE_Register_CPT::register(
928 928
                 $addon_name,
929 929
                 array(
930
-                    'cpts'          => self::$_settings[ $addon_name ]['custom_post_types'],
931
-                    'cts'           => self::$_settings[ $addon_name ]['custom_taxonomies'],
932
-                    'default_terms' => self::$_settings[ $addon_name ]['default_terms'],
930
+                    'cpts'          => self::$_settings[$addon_name]['custom_post_types'],
931
+                    'cts'           => self::$_settings[$addon_name]['custom_taxonomies'],
932
+                    'default_terms' => self::$_settings[$addon_name]['default_terms'],
933 933
                 )
934 934
             );
935 935
         }
@@ -947,10 +947,10 @@  discard block
 block discarded – undo
947 947
      */
948 948
     private static function _register_payment_methods($addon_name)
949 949
     {
950
-        if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
950
+        if ( ! empty(self::$_settings[$addon_name]['payment_method_paths'])) {
951 951
             EE_Register_Payment_Method::register(
952 952
                 $addon_name,
953
-                array('payment_method_paths' => self::$_settings[ $addon_name ]['payment_method_paths'])
953
+                array('payment_method_paths' => self::$_settings[$addon_name]['payment_method_paths'])
954 954
             );
955 955
         }
956 956
     }
@@ -967,10 +967,10 @@  discard block
 block discarded – undo
967 967
      */
968 968
     private static function registerPrivacyPolicies($addon_name)
969 969
     {
970
-        if (! empty(self::$_settings[ $addon_name ]['privacy_policies'])) {
970
+        if ( ! empty(self::$_settings[$addon_name]['privacy_policies'])) {
971 971
             EE_Register_Privacy_Policy::register(
972 972
                 $addon_name,
973
-                self::$_settings[ $addon_name ]['privacy_policies']
973
+                self::$_settings[$addon_name]['privacy_policies']
974 974
             );
975 975
         }
976 976
     }
@@ -982,10 +982,10 @@  discard block
 block discarded – undo
982 982
      */
983 983
     private static function registerPersonalDataExporters($addon_name)
984 984
     {
985
-        if (! empty(self::$_settings[ $addon_name ]['personal_data_exporters'])) {
985
+        if ( ! empty(self::$_settings[$addon_name]['personal_data_exporters'])) {
986 986
             EE_Register_Personal_Data_Eraser::register(
987 987
                 $addon_name,
988
-                self::$_settings[ $addon_name ]['personal_data_exporters']
988
+                self::$_settings[$addon_name]['personal_data_exporters']
989 989
             );
990 990
         }
991 991
     }
@@ -997,10 +997,10 @@  discard block
 block discarded – undo
997 997
      */
998 998
     private static function registerPersonalDataErasers($addon_name)
999 999
     {
1000
-        if (! empty(self::$_settings[ $addon_name ]['personal_data_erasers'])) {
1000
+        if ( ! empty(self::$_settings[$addon_name]['personal_data_erasers'])) {
1001 1001
             EE_Register_Personal_Data_Eraser::register(
1002 1002
                 $addon_name,
1003
-                self::$_settings[ $addon_name ]['personal_data_erasers']
1003
+                self::$_settings[$addon_name]['personal_data_erasers']
1004 1004
             );
1005 1005
         }
1006 1006
     }
@@ -1021,7 +1021,7 @@  discard block
 block discarded – undo
1021 1021
     {
1022 1022
         $loader = EventEspresso\core\services\loaders\LoaderFactory::getLoader();
1023 1023
         $addon = $loader->getShared(
1024
-            self::$_settings[ $addon_name ]['class_name'],
1024
+            self::$_settings[$addon_name]['class_name'],
1025 1025
             array('EE_Registry::create(addon)' => true)
1026 1026
         );
1027 1027
         // setter inject dep map if required
@@ -1033,19 +1033,19 @@  discard block
 block discarded – undo
1033 1033
             && $addon->domain() === null
1034 1034
         ) {
1035 1035
             // using supplied Domain object
1036
-            $domain = self::$_settings[ $addon_name ]['domain'] instanceof DomainInterface
1037
-                ? self::$_settings[ $addon_name ]['domain']
1036
+            $domain = self::$_settings[$addon_name]['domain'] instanceof DomainInterface
1037
+                ? self::$_settings[$addon_name]['domain']
1038 1038
                 : null;
1039 1039
             // or construct one using Domain FQCN
1040
-            if ($domain === null && self::$_settings[ $addon_name ]['domain_fqcn'] !== '') {
1040
+            if ($domain === null && self::$_settings[$addon_name]['domain_fqcn'] !== '') {
1041 1041
                 $domain = $loader->getShared(
1042
-                    self::$_settings[ $addon_name ]['domain_fqcn'],
1042
+                    self::$_settings[$addon_name]['domain_fqcn'],
1043 1043
                     array(
1044 1044
                         new EventEspresso\core\domain\values\FilePath(
1045
-                            self::$_settings[ $addon_name ]['main_file_path']
1045
+                            self::$_settings[$addon_name]['main_file_path']
1046 1046
                         ),
1047 1047
                         EventEspresso\core\domain\values\Version::fromString(
1048
-                            self::$_settings[ $addon_name ]['version']
1048
+                            self::$_settings[$addon_name]['version']
1049 1049
                         ),
1050 1050
                     )
1051 1051
                 );
@@ -1055,24 +1055,24 @@  discard block
 block discarded – undo
1055 1055
             }
1056 1056
         }
1057 1057
         $addon->set_name($addon_name);
1058
-        $addon->set_plugin_slug(self::$_settings[ $addon_name ]['plugin_slug']);
1059
-        $addon->set_plugin_basename(self::$_settings[ $addon_name ]['plugin_basename']);
1060
-        $addon->set_main_plugin_file(self::$_settings[ $addon_name ]['main_file_path']);
1061
-        $addon->set_plugin_action_slug(self::$_settings[ $addon_name ]['plugin_action_slug']);
1062
-        $addon->set_plugins_page_row(self::$_settings[ $addon_name ]['plugins_page_row']);
1063
-        $addon->set_version(self::$_settings[ $addon_name ]['version']);
1064
-        $addon->set_min_core_version(self::_effective_version(self::$_settings[ $addon_name ]['min_core_version']));
1065
-        $addon->set_config_section(self::$_settings[ $addon_name ]['config_section']);
1066
-        $addon->set_config_class(self::$_settings[ $addon_name ]['config_class']);
1067
-        $addon->set_config_name(self::$_settings[ $addon_name ]['config_name']);
1058
+        $addon->set_plugin_slug(self::$_settings[$addon_name]['plugin_slug']);
1059
+        $addon->set_plugin_basename(self::$_settings[$addon_name]['plugin_basename']);
1060
+        $addon->set_main_plugin_file(self::$_settings[$addon_name]['main_file_path']);
1061
+        $addon->set_plugin_action_slug(self::$_settings[$addon_name]['plugin_action_slug']);
1062
+        $addon->set_plugins_page_row(self::$_settings[$addon_name]['plugins_page_row']);
1063
+        $addon->set_version(self::$_settings[$addon_name]['version']);
1064
+        $addon->set_min_core_version(self::_effective_version(self::$_settings[$addon_name]['min_core_version']));
1065
+        $addon->set_config_section(self::$_settings[$addon_name]['config_section']);
1066
+        $addon->set_config_class(self::$_settings[$addon_name]['config_class']);
1067
+        $addon->set_config_name(self::$_settings[$addon_name]['config_name']);
1068 1068
         // unfortunately this can't be hooked in upon construction, because we don't have
1069 1069
         // the plugin mainfile's path upon construction.
1070 1070
         register_deactivation_hook($addon->get_main_plugin_file(), array($addon, 'deactivation'));
1071 1071
         // call any additional admin_callback functions during load_admin_controller hook
1072
-        if (! empty(self::$_settings[ $addon_name ]['admin_callback'])) {
1072
+        if ( ! empty(self::$_settings[$addon_name]['admin_callback'])) {
1073 1073
             add_action(
1074 1074
                 'AHEE__EE_System__load_controllers__load_admin_controllers',
1075
-                array($addon, self::$_settings[ $addon_name ]['admin_callback'])
1075
+                array($addon, self::$_settings[$addon_name]['admin_callback'])
1076 1076
             );
1077 1077
         }
1078 1078
         return $addon;
@@ -1090,11 +1090,11 @@  discard block
 block discarded – undo
1090 1090
     public static function load_pue_update()
1091 1091
     {
1092 1092
         // load PUE client
1093
-        require_once EE_THIRD_PARTY . 'pue' . DS . 'pue-client.php';
1093
+        require_once EE_THIRD_PARTY.'pue'.DS.'pue-client.php';
1094 1094
         $license_server = defined('PUE_UPDATES_ENDPOINT') ? PUE_UPDATES_ENDPOINT : 'https://eventespresso.com';
1095 1095
         // cycle thru settings
1096 1096
         foreach (self::$_settings as $settings) {
1097
-            if (! empty($settings['pue_options'])) {
1097
+            if ( ! empty($settings['pue_options'])) {
1098 1098
                 // initiate the class and start the plugin update engine!
1099 1099
                 new PluginUpdateEngineChecker(
1100 1100
                     // host file URL
@@ -1102,7 +1102,7 @@  discard block
 block discarded – undo
1102 1102
                     // plugin slug(s)
1103 1103
                     array(
1104 1104
                         'premium'    => array('p' => $settings['pue_options']['pue_plugin_slug']),
1105
-                        'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'] . '-pr'),
1105
+                        'prerelease' => array('beta' => $settings['pue_options']['pue_plugin_slug'].'-pr'),
1106 1106
                     ),
1107 1107
                     // options
1108 1108
                     array(
@@ -1131,7 +1131,7 @@  discard block
 block discarded – undo
1131 1131
     public static function register_message_types()
1132 1132
     {
1133 1133
         foreach (self::$_settings as $addon_name => $settings) {
1134
-            if (! empty($settings['message_types'])) {
1134
+            if ( ! empty($settings['message_types'])) {
1135 1135
                 foreach ((array) $settings['message_types'] as $message_type => $message_type_settings) {
1136 1136
                     EE_Register_Message_Type::register($message_type, $message_type_settings);
1137 1137
                 }
@@ -1153,70 +1153,70 @@  discard block
 block discarded – undo
1153 1153
      */
1154 1154
     public static function deregister($addon_name = null)
1155 1155
     {
1156
-        if (isset(self::$_settings[ $addon_name ]['class_name'])) {
1156
+        if (isset(self::$_settings[$addon_name]['class_name'])) {
1157 1157
             try {
1158 1158
                 do_action('AHEE__EE_Register_Addon__deregister__before', $addon_name);
1159
-                $class_name = self::$_settings[ $addon_name ]['class_name'];
1160
-                if (! empty(self::$_settings[ $addon_name ]['dms_paths'])) {
1159
+                $class_name = self::$_settings[$addon_name]['class_name'];
1160
+                if ( ! empty(self::$_settings[$addon_name]['dms_paths'])) {
1161 1161
                     // setup DMS
1162 1162
                     EE_Register_Data_Migration_Scripts::deregister($addon_name);
1163 1163
                 }
1164
-                if (! empty(self::$_settings[ $addon_name ]['admin_path'])) {
1164
+                if ( ! empty(self::$_settings[$addon_name]['admin_path'])) {
1165 1165
                     // register admin page
1166 1166
                     EE_Register_Admin_Page::deregister($addon_name);
1167 1167
                 }
1168
-                if (! empty(self::$_settings[ $addon_name ]['module_paths'])) {
1168
+                if ( ! empty(self::$_settings[$addon_name]['module_paths'])) {
1169 1169
                     // add to list of modules to be registered
1170 1170
                     EE_Register_Module::deregister($addon_name);
1171 1171
                 }
1172
-                if (! empty(self::$_settings[ $addon_name ]['shortcode_paths'])
1173
-                    || ! empty(self::$_settings[ $addon_name ]['shortcode_fqcns'])
1172
+                if ( ! empty(self::$_settings[$addon_name]['shortcode_paths'])
1173
+                    || ! empty(self::$_settings[$addon_name]['shortcode_fqcns'])
1174 1174
                 ) {
1175 1175
                     // add to list of shortcodes to be registered
1176 1176
                     EE_Register_Shortcode::deregister($addon_name);
1177 1177
                 }
1178
-                if (! empty(self::$_settings[ $addon_name ]['config_class'])) {
1178
+                if ( ! empty(self::$_settings[$addon_name]['config_class'])) {
1179 1179
                     // if config_class present let's register config.
1180
-                    EE_Register_Config::deregister(self::$_settings[ $addon_name ]['config_class']);
1180
+                    EE_Register_Config::deregister(self::$_settings[$addon_name]['config_class']);
1181 1181
                 }
1182
-                if (! empty(self::$_settings[ $addon_name ]['widget_paths'])) {
1182
+                if ( ! empty(self::$_settings[$addon_name]['widget_paths'])) {
1183 1183
                     // add to list of widgets to be registered
1184 1184
                     EE_Register_Widget::deregister($addon_name);
1185 1185
                 }
1186
-                if (! empty(self::$_settings[ $addon_name ]['model_paths'])
1187
-                    || ! empty(self::$_settings[ $addon_name ]['class_paths'])
1186
+                if ( ! empty(self::$_settings[$addon_name]['model_paths'])
1187
+                    || ! empty(self::$_settings[$addon_name]['class_paths'])
1188 1188
                 ) {
1189 1189
                     // add to list of shortcodes to be registered
1190 1190
                     EE_Register_Model::deregister($addon_name);
1191 1191
                 }
1192
-                if (! empty(self::$_settings[ $addon_name ]['model_extension_paths'])
1193
-                    || ! empty(self::$_settings[ $addon_name ]['class_extension_paths'])
1192
+                if ( ! empty(self::$_settings[$addon_name]['model_extension_paths'])
1193
+                    || ! empty(self::$_settings[$addon_name]['class_extension_paths'])
1194 1194
                 ) {
1195 1195
                     // add to list of shortcodes to be registered
1196 1196
                     EE_Register_Model_Extensions::deregister($addon_name);
1197 1197
                 }
1198
-                if (! empty(self::$_settings[ $addon_name ]['message_types'])) {
1199
-                    foreach ((array) self::$_settings[ $addon_name ]['message_types'] as $message_type => $message_type_settings) {
1198
+                if ( ! empty(self::$_settings[$addon_name]['message_types'])) {
1199
+                    foreach ((array) self::$_settings[$addon_name]['message_types'] as $message_type => $message_type_settings) {
1200 1200
                         EE_Register_Message_Type::deregister($message_type);
1201 1201
                     }
1202 1202
                 }
1203 1203
                 // deregister capabilities for addon
1204
-                if (! empty(self::$_settings[ $addon_name ]['capabilities'])
1205
-                    || ! empty(self::$_settings[ $addon_name ]['capability_maps'])
1204
+                if ( ! empty(self::$_settings[$addon_name]['capabilities'])
1205
+                    || ! empty(self::$_settings[$addon_name]['capability_maps'])
1206 1206
                 ) {
1207 1207
                     EE_Register_Capabilities::deregister($addon_name);
1208 1208
                 }
1209 1209
                 // deregister custom_post_types for addon
1210
-                if (! empty(self::$_settings[ $addon_name ]['custom_post_types'])) {
1210
+                if ( ! empty(self::$_settings[$addon_name]['custom_post_types'])) {
1211 1211
                     EE_Register_CPT::deregister($addon_name);
1212 1212
                 }
1213
-                if (! empty(self::$_settings[ $addon_name ]['payment_method_paths'])) {
1213
+                if ( ! empty(self::$_settings[$addon_name]['payment_method_paths'])) {
1214 1214
                     EE_Register_Payment_Method::deregister($addon_name);
1215 1215
                 }
1216 1216
                 $addon = EE_Registry::instance()->getAddon($class_name);
1217 1217
                 if ($addon instanceof EE_Addon) {
1218 1218
                     remove_action(
1219
-                        'deactivate_' . $addon->get_main_plugin_file_basename(),
1219
+                        'deactivate_'.$addon->get_main_plugin_file_basename(),
1220 1220
                         array($addon, 'deactivation')
1221 1221
                     );
1222 1222
                     remove_action(
@@ -1239,7 +1239,7 @@  discard block
 block discarded – undo
1239 1239
             } catch (Exception $e) {
1240 1240
                 new ExceptionLogger($e);
1241 1241
             }
1242
-            unset(self::$_settings[ $addon_name ]);
1242
+            unset(self::$_settings[$addon_name]);
1243 1243
             do_action('AHEE__EE_Register_Addon__deregister__after', $addon_name);
1244 1244
         }
1245 1245
     }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Spacing   +55 added lines, -55 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
         $controller = new Read();
65 65
         try {
66 66
             $controller->setRequestedVersion($version);
67
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
67
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
68 68
                 return $controller->sendResponse(
69 69
                     new WP_Error(
70 70
                         'endpoint_parsing_error',
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
         $controller = new Read();
103 103
         try {
104 104
             $controller->setRequestedVersion($version);
105
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
105
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
106 106
                 return array();
107 107
             }
108 108
             // get the model for this version
@@ -159,11 +159,11 @@  discard block
 block discarded – undo
159 159
      */
160 160
     protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
161 161
     {
162
-        if (isset($schema['properties'][ $field_name ]['default'])) {
163
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
164
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
162
+        if (isset($schema['properties'][$field_name]['default'])) {
163
+            if (is_array($schema['properties'][$field_name]['default'])) {
164
+                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
165 165
                     if ($default_key === 'raw') {
166
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
166
+                        $schema['properties'][$field_name]['default'][$default_key] =
167 167
                             ModelDataTranslator::prepareFieldValueForJson(
168 168
                                 $field,
169 169
                                 $default_value,
@@ -172,9 +172,9 @@  discard block
 block discarded – undo
172 172
                     }
173 173
                 }
174 174
             } else {
175
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
175
+                $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson(
176 176
                     $field,
177
-                    $schema['properties'][ $field_name ]['default'],
177
+                    $schema['properties'][$field_name]['default'],
178 178
                     $this->getModelVersionInfo()->requestedVersion()
179 179
                 );
180 180
             }
@@ -196,9 +196,9 @@  discard block
 block discarded – undo
196 196
     protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
197 197
     {
198 198
         if ($field instanceof EE_Datetime_Field) {
199
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
199
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
200 200
             // modify the description
201
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
201
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
202 202
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
203 203
                 wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
204 204
             );
@@ -238,7 +238,7 @@  discard block
 block discarded – undo
238 238
         $controller = new Read();
239 239
         try {
240 240
             $controller->setRequestedVersion($version);
241
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
241
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
242 242
                 return $controller->sendResponse(
243 243
                     new WP_Error(
244 244
                         'endpoint_parsing_error',
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
         $controller = new Read();
284 284
         try {
285 285
             $controller->setRequestedVersion($version);
286
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
286
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
287 287
                 return $controller->sendResponse(
288 288
                     new WP_Error(
289 289
                         'endpoint_parsing_error',
@@ -298,7 +298,7 @@  discard block
 block discarded – undo
298 298
                 );
299 299
             }
300 300
             $main_model = $controller->getModelVersionInfo()->loadModel($model_name);
301
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
301
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
302 302
                 return $controller->sendResponse(
303 303
                     new WP_Error(
304 304
                         'endpoint_parsing_error',
@@ -335,7 +335,7 @@  discard block
 block discarded – undo
335 335
     public function getEntitiesFromModel($model, $request)
336 336
     {
337 337
         $query_params = $this->createModelQueryParams($model, $request->get_params());
338
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
338
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
339 339
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
340 340
             return new WP_Error(
341 341
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -347,7 +347,7 @@  discard block
 block discarded – undo
347 347
                 array('status' => 403)
348 348
             );
349 349
         }
350
-        if (! $request->get_header('no_rest_headers')) {
350
+        if ( ! $request->get_header('no_rest_headers')) {
351 351
             $this->setHeadersFromQueryParams($model, $query_params);
352 352
         }
353 353
         /** @type array $results */
@@ -382,7 +382,7 @@  discard block
 block discarded – undo
382 382
         $context = $this->validateContext($request->get_param('caps'));
383 383
         $model = $relation->get_this_model();
384 384
         $related_model = $relation->get_other_model();
385
-        if (! isset($primary_model_query_params[0])) {
385
+        if ( ! isset($primary_model_query_params[0])) {
386 386
             $primary_model_query_params[0] = array();
387 387
         }
388 388
         // check if they can access the 1st model object
@@ -399,7 +399,7 @@  discard block
 block discarded – undo
399 399
         $restricted_query_params['caps'] = $context;
400 400
         $this->setDebugInfo('main model query params', $restricted_query_params);
401 401
         $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
402
-        if (! (
402
+        if ( ! (
403 403
             Capabilities::currentUserHasPartialAccessTo($related_model, $context)
404 404
             && $model->exists($restricted_query_params)
405 405
         )
@@ -432,13 +432,13 @@  discard block
 block discarded – undo
432 432
         }
433 433
         $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
434 434
         foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
435
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
435
+            $query_params[0][$relation->get_this_model()->get_this_model_name()
436 436
                               . '.'
437
-                              . $where_condition_key ] = $where_condition_value;
437
+                              . $where_condition_key] = $where_condition_value;
438 438
         }
439 439
         $query_params['default_where_conditions'] = 'none';
440 440
         $query_params['caps'] = $context;
441
-        if (! $request->get_header('no_rest_headers')) {
441
+        if ( ! $request->get_header('no_rest_headers')) {
442 442
             $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
443 443
         }
444 444
         /** @type array $results */
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
      */
490 490
     public function getEntitiesFromRelation($id, $relation, $request)
491 491
     {
492
-        if (! $relation->get_this_model()->has_primary_key_field()) {
492
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
493 493
             throw new EE_Error(
494 494
                 sprintf(
495 495
                     __(
@@ -531,7 +531,7 @@  discard block
 block discarded – undo
531 531
             Capabilities::getMissingPermissionsString($model, $query_params['caps'])
532 532
         );
533 533
         // normally the limit to a 2-part array, where the 2nd item is the limit
534
-        if (! isset($query_params['limit'])) {
534
+        if ( ! isset($query_params['limit'])) {
535 535
             $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
536 536
         }
537 537
         if (is_array($query_params['limit'])) {
@@ -564,7 +564,7 @@  discard block
 block discarded – undo
564 564
      */
565 565
     public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
566 566
     {
567
-        if (! $rest_request instanceof WP_REST_Request) {
567
+        if ( ! $rest_request instanceof WP_REST_Request) {
568 568
             // ok so this was called in the old style, where the 3rd arg was
569 569
             // $include, and the 4th arg was $context
570 570
             // now setup the request just to avoid fatal errors, although we won't be able
@@ -645,8 +645,8 @@  discard block
 block discarded – undo
645 645
         if ($do_chevy_shuffle) {
646 646
             global $post;
647 647
             $old_post = $post;
648
-            $post = get_post($result[ $model->primary_key_name() ]);
649
-            if (! $post instanceof \WP_Post) {
648
+            $post = get_post($result[$model->primary_key_name()]);
649
+            if ( ! $post instanceof \WP_Post) {
650 650
                 // well that's weird, because $result is what we JUST fetched from the database
651 651
                 throw new RestException(
652 652
                     'error_fetching_post_from_database_results',
@@ -656,7 +656,7 @@  discard block
 block discarded – undo
656 656
                     )
657 657
                 );
658 658
             }
659
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
659
+            $model_object_classname = 'EE_'.$model->get_this_model_name();
660 660
             $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
661 661
                 $model_object_classname,
662 662
                 $result,
@@ -667,13 +667,13 @@  discard block
 block discarded – undo
667 667
         foreach ($result as $field_name => $field_value) {
668 668
             $field_obj = $model->field_settings_for($field_name);
669 669
             if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
670
-                unset($result[ $field_name ]);
670
+                unset($result[$field_name]);
671 671
             } elseif ($this->isSubclassOfOne(
672 672
                 $field_obj,
673 673
                 $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
674 674
             )
675 675
             ) {
676
-                $result[ $field_name ] = array(
676
+                $result[$field_name] = array(
677 677
                     'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
678 678
                     'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
679 679
                 );
@@ -682,7 +682,7 @@  discard block
 block discarded – undo
682 682
                 $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
683 683
             )
684 684
             ) {
685
-                $result[ $field_name ] = array(
685
+                $result[$field_name] = array(
686 686
                     'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
687 687
                     'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
688 688
                 );
@@ -709,10 +709,10 @@  discard block
 block discarded – undo
709 709
                         $this->getModelVersionInfo()->requestedVersion()
710 710
                     );
711 711
                 }
712
-                $result[ $field_name . '_gmt' ] = $gmt_date;
713
-                $result[ $field_name ] = $local_date;
712
+                $result[$field_name.'_gmt'] = $gmt_date;
713
+                $result[$field_name] = $local_date;
714 714
             } else {
715
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
715
+                $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
716 716
             }
717 717
         }
718 718
         if ($do_chevy_shuffle) {
@@ -764,7 +764,7 @@  discard block
 block discarded – undo
764 764
     protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
765 765
     {
766 766
         if ($model instanceof EEM_CPT_Base) {
767
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
767
+            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
768 768
         }
769 769
         return $entity_array;
770 770
     }
@@ -789,7 +789,7 @@  discard block
 block discarded – undo
789 789
                     'href' => $this->getVersionedLinkTo(
790 790
                         EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
791 791
                         . '/'
792
-                        . $entity_array[ $model->primary_key_name() ]
792
+                        . $entity_array[$model->primary_key_name()]
793 793
                     ),
794 794
                 ),
795 795
             );
@@ -805,12 +805,12 @@  discard block
 block discarded – undo
805 805
         if ($model->has_primary_key_field()) {
806 806
             foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
807 807
                 $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
808
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
808
+                $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = array(
809 809
                     array(
810 810
                         'href'   => $this->getVersionedLinkTo(
811 811
                             EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
812 812
                             . '/'
813
-                            . $entity_array[ $model->primary_key_name() ]
813
+                            . $entity_array[$model->primary_key_name()]
814 814
                             . '/'
815 815
                             . $related_model_part
816 816
                         ),
@@ -839,13 +839,13 @@  discard block
 block discarded – undo
839 839
         $db_row = array()
840 840
     ) {
841 841
         // if $db_row not included, hope the entity array has what we need
842
-        if (! $db_row) {
842
+        if ( ! $db_row) {
843 843
             $db_row = $entity_array;
844 844
         }
845 845
         $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
846 846
         $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
847 847
         // if they passed in * or didn't specify any includes, return everything
848
-        if (! in_array('*', $includes_for_this_model)
848
+        if ( ! in_array('*', $includes_for_this_model)
849 849
             && ! empty($includes_for_this_model)
850 850
         ) {
851 851
             if ($model->has_primary_key_field()) {
@@ -891,7 +891,7 @@  discard block
 block discarded – undo
891 891
                     $relation_obj,
892 892
                     $pretend_related_request
893 893
                 );
894
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
894
+                $entity_array[Read::getRelatedEntityName($relation_name, $relation_obj)] = $related_results
895 895
                                                                                              instanceof
896 896
                                                                                              WP_Error
897 897
                     ? null
@@ -1023,7 +1023,7 @@  discard block
 block discarded – undo
1023 1023
      */
1024 1024
     public function validateContext($context)
1025 1025
     {
1026
-        if (! $context) {
1026
+        if ( ! $context) {
1027 1027
             $context = EEM_Base::caps_read;
1028 1028
         }
1029 1029
         $valid_contexts = EEM_Base::valid_cap_contexts();
@@ -1048,7 +1048,7 @@  discard block
 block discarded – undo
1048 1048
             EEM_Base::default_where_conditions_minimum_all,
1049 1049
             EEM_Base::default_where_conditions_minimum_others,
1050 1050
         );
1051
-        if (! $default_query_params) {
1051
+        if ( ! $default_query_params) {
1052 1052
             $default_query_params = EEM_Base::default_where_conditions_all;
1053 1053
         }
1054 1054
         if (in_array(
@@ -1131,14 +1131,14 @@  discard block
 block discarded – undo
1131 1131
         }
1132 1132
         if (isset($query_parameters['limit'])) {
1133 1133
             // limit should be either a string like '23' or '23,43', or an array with two items in it
1134
-            if (! is_array($query_parameters['limit'])) {
1134
+            if ( ! is_array($query_parameters['limit'])) {
1135 1135
                 $limit_array = explode(',', (string) $query_parameters['limit']);
1136 1136
             } else {
1137 1137
                 $limit_array = $query_parameters['limit'];
1138 1138
             }
1139 1139
             $sanitized_limit = array();
1140 1140
             foreach ($limit_array as $key => $limit_part) {
1141
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1141
+                if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1142 1142
                     throw new EE_Error(
1143 1143
                         sprintf(
1144 1144
                             __(
@@ -1184,9 +1184,9 @@  discard block
 block discarded – undo
1184 1184
         $model_ready_query_params = array();
1185 1185
         foreach ($query_params as $key => $value) {
1186 1186
             if (is_array($value)) {
1187
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1187
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1188 1188
             } else {
1189
-                $model_ready_query_params[ $key ] = $value;
1189
+                $model_ready_query_params[$key] = $value;
1190 1190
             }
1191 1191
         }
1192 1192
         return $model_ready_query_params;
@@ -1204,9 +1204,9 @@  discard block
 block discarded – undo
1204 1204
         $model_ready_query_params = array();
1205 1205
         foreach ($query_params as $key => $value) {
1206 1206
             if (is_array($value)) {
1207
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1207
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1208 1208
             } else {
1209
-                $model_ready_query_params[ $key ] = $value;
1209
+                $model_ready_query_params[$key] = $value;
1210 1210
             }
1211 1211
         }
1212 1212
         return $model_ready_query_params;
@@ -1238,17 +1238,17 @@  discard block
 block discarded – undo
1238 1238
         foreach ($exploded_contents as $item) {
1239 1239
             $item = trim($item);
1240 1240
             // if no prefix was provided, so we look for items with no "." in them
1241
-            if (! $prefix) {
1241
+            if ( ! $prefix) {
1242 1242
                 // does this item have a period?
1243 1243
                 if (strpos($item, '.') === false) {
1244 1244
                     // if not, then its what we're looking for
1245 1245
                     $contents_with_prefix[] = $item;
1246 1246
                 }
1247
-            } elseif (strpos($item, $prefix . '.') === 0) {
1247
+            } elseif (strpos($item, $prefix.'.') === 0) {
1248 1248
                 // this item has the prefix and a period, grab it
1249 1249
                 $contents_with_prefix[] = substr(
1250 1250
                     $item,
1251
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1251
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1252 1252
                 );
1253 1253
             } elseif ($item === $prefix) {
1254 1254
                 // this item is JUST the prefix
@@ -1287,9 +1287,9 @@  discard block
 block discarded – undo
1287 1287
         if ($model_name) {
1288 1288
             foreach ($includes as $field_to_include) {
1289 1289
                 $field_to_include = trim($field_to_include);
1290
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1290
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1291 1291
                     // found the model name at the exact start
1292
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1292
+                    $field_sans_model_name = str_replace($model_name.'.', '', $field_to_include);
1293 1293
                     $extracted_fields_to_include[] = $field_sans_model_name;
1294 1294
                 } elseif ($field_to_include == $model_name) {
1295 1295
                     $extracted_fields_to_include[] = '*';
@@ -1329,7 +1329,7 @@  discard block
 block discarded – undo
1329 1329
         $restricted_query_params['caps'] = $context;
1330 1330
         $this->setDebugInfo('model query params', $restricted_query_params);
1331 1331
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1332
-        if (! empty($model_rows)) {
1332
+        if ( ! empty($model_rows)) {
1333 1333
             return $this->createEntityFromWpdbResult(
1334 1334
                 $model,
1335 1335
                 array_shift($model_rows),
@@ -1339,10 +1339,10 @@  discard block
 block discarded – undo
1339 1339
             // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1340 1340
             $lowercase_model_name = strtolower($model->get_this_model_name());
1341 1341
             $model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1342
-            if (! empty($model_rows_found_sans_restrictions)) {
1342
+            if ( ! empty($model_rows_found_sans_restrictions)) {
1343 1343
                 // you got shafted- it existed but we didn't want to tell you!
1344 1344
                 return new WP_Error(
1345
-                    'rest_user_cannot_' . $context,
1345
+                    'rest_user_cannot_'.$context,
1346 1346
                     sprintf(
1347 1347
                         __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1348 1348
                         $context,
Please login to merge, or discard this patch.
Indentation   +1333 added lines, -1333 removed lines patch added patch discarded remove patch
@@ -35,1337 +35,1337 @@
 block discarded – undo
35 35
 {
36 36
 
37 37
 
38
-    /**
39
-     * @var CalculatedModelFields
40
-     */
41
-    protected $fields_calculator;
42
-
43
-
44
-    /**
45
-     * Read constructor.
46
-     */
47
-    public function __construct()
48
-    {
49
-        parent::__construct();
50
-        $this->fields_calculator = new CalculatedModelFields();
51
-    }
52
-
53
-
54
-    /**
55
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
56
-     *
57
-     * @param WP_REST_Request $request
58
-     * @param string          $version
59
-     * @param string          $model_name
60
-     * @return \WP_REST_Response|WP_Error
61
-     */
62
-    public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
63
-    {
64
-        $controller = new Read();
65
-        try {
66
-            $controller->setRequestedVersion($version);
67
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
68
-                return $controller->sendResponse(
69
-                    new WP_Error(
70
-                        'endpoint_parsing_error',
71
-                        sprintf(
72
-                            __(
73
-                                'There is no model for endpoint %s. Please contact event espresso support',
74
-                                'event_espresso'
75
-                            ),
76
-                            $model_name
77
-                        )
78
-                    )
79
-                );
80
-            }
81
-            return $controller->sendResponse(
82
-                $controller->getEntitiesFromModel(
83
-                    $controller->getModelVersionInfo()->loadModel($model_name),
84
-                    $request
85
-                )
86
-            );
87
-        } catch (Exception $e) {
88
-            return $controller->sendResponse($e);
89
-        }
90
-    }
91
-
92
-
93
-    /**
94
-     * Prepares and returns schema for any OPTIONS request.
95
-     *
96
-     * @param string $version    The API endpoint version being used.
97
-     * @param string $model_name Something like `Event` or `Registration`
98
-     * @return array
99
-     */
100
-    public static function handleSchemaRequest($version, $model_name)
101
-    {
102
-        $controller = new Read();
103
-        try {
104
-            $controller->setRequestedVersion($version);
105
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
106
-                return array();
107
-            }
108
-            // get the model for this version
109
-            $model = $controller->getModelVersionInfo()->loadModel($model_name);
110
-            $model_schema = new JsonModelSchema($model);
111
-            return $model_schema->getModelSchemaForRelations(
112
-                $controller->getModelVersionInfo()->relationSettings($model),
113
-                $controller->customizeSchemaForRestResponse(
114
-                    $model,
115
-                    $model_schema->getModelSchemaForFields(
116
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
117
-                        $model_schema->getInitialSchemaStructure()
118
-                    )
119
-                )
120
-            );
121
-        } catch (Exception $e) {
122
-            return array();
123
-        }
124
-    }
125
-
126
-
127
-    /**
128
-     * This loops through each field in the given schema for the model and does the following:
129
-     * - add any extra fields that are REST API specific and related to existing fields.
130
-     * - transform default values into the correct format for a REST API response.
131
-     *
132
-     * @param EEM_Base $model
133
-     * @param array    $schema
134
-     * @return array  The final schema.
135
-     */
136
-    protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
137
-    {
138
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
139
-            $schema = $this->translateDefaultsForRestResponse(
140
-                $field_name,
141
-                $field,
142
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
143
-            );
144
-        }
145
-        return $schema;
146
-    }
147
-
148
-
149
-    /**
150
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
151
-     * response.
152
-     *
153
-     * @param                      $field_name
154
-     * @param EE_Model_Field_Base  $field
155
-     * @param array                $schema
156
-     * @return array
157
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
158
-     * did, let's know about it ASAP, so let the exception bubble up)
159
-     */
160
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
161
-    {
162
-        if (isset($schema['properties'][ $field_name ]['default'])) {
163
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
164
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
165
-                    if ($default_key === 'raw') {
166
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
167
-                            ModelDataTranslator::prepareFieldValueForJson(
168
-                                $field,
169
-                                $default_value,
170
-                                $this->getModelVersionInfo()->requestedVersion()
171
-                            );
172
-                    }
173
-                }
174
-            } else {
175
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
176
-                    $field,
177
-                    $schema['properties'][ $field_name ]['default'],
178
-                    $this->getModelVersionInfo()->requestedVersion()
179
-                );
180
-            }
181
-        }
182
-        return $schema;
183
-    }
184
-
185
-
186
-    /**
187
-     * Adds additional fields to the schema
188
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
189
-     * needs to be added to the schema.
190
-     *
191
-     * @param                      $field_name
192
-     * @param EE_Model_Field_Base  $field
193
-     * @param array                $schema
194
-     * @return array
195
-     */
196
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
197
-    {
198
-        if ($field instanceof EE_Datetime_Field) {
199
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
200
-            // modify the description
201
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
202
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
203
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
204
-            );
205
-        }
206
-        return $schema;
207
-    }
208
-
209
-
210
-    /**
211
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
212
-     *
213
-     * @return string
214
-     */
215
-    protected function getRouteFromRequest()
216
-    {
217
-        if (isset($GLOBALS['wp'])
218
-            && $GLOBALS['wp'] instanceof \WP
219
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
220
-        ) {
221
-            return $GLOBALS['wp']->query_vars['rest_route'];
222
-        } else {
223
-            return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
224
-        }
225
-    }
226
-
227
-
228
-    /**
229
-     * Gets a single entity related to the model indicated in the path and its id
230
-     *
231
-     * @param WP_REST_Request $request
232
-     * @param string          $version
233
-     * @param string          $model_name
234
-     * @return \WP_REST_Response|WP_Error
235
-     */
236
-    public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
237
-    {
238
-        $controller = new Read();
239
-        try {
240
-            $controller->setRequestedVersion($version);
241
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
242
-                return $controller->sendResponse(
243
-                    new WP_Error(
244
-                        'endpoint_parsing_error',
245
-                        sprintf(
246
-                            __(
247
-                                'There is no model for endpoint %s. Please contact event espresso support',
248
-                                'event_espresso'
249
-                            ),
250
-                            $model_name
251
-                        )
252
-                    )
253
-                );
254
-            }
255
-            return $controller->sendResponse(
256
-                $controller->getEntityFromModel(
257
-                    $controller->getModelVersionInfo()->loadModel($model_name),
258
-                    $request
259
-                )
260
-            );
261
-        } catch (Exception $e) {
262
-            return $controller->sendResponse($e);
263
-        }
264
-    }
265
-
266
-
267
-    /**
268
-     * Gets all the related entities (or if its a belongs-to relation just the one)
269
-     * to the item with the given id
270
-     *
271
-     * @param WP_REST_Request $request
272
-     * @param string          $version
273
-     * @param string          $model_name
274
-     * @param string          $related_model_name
275
-     * @return \WP_REST_Response|WP_Error
276
-     */
277
-    public static function handleRequestGetRelated(
278
-        WP_REST_Request $request,
279
-        $version,
280
-        $model_name,
281
-        $related_model_name
282
-    ) {
283
-        $controller = new Read();
284
-        try {
285
-            $controller->setRequestedVersion($version);
286
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
287
-                return $controller->sendResponse(
288
-                    new WP_Error(
289
-                        'endpoint_parsing_error',
290
-                        sprintf(
291
-                            __(
292
-                                'There is no model for endpoint %s. Please contact event espresso support',
293
-                                'event_espresso'
294
-                            ),
295
-                            $model_name
296
-                        )
297
-                    )
298
-                );
299
-            }
300
-            $main_model = $controller->getModelVersionInfo()->loadModel($model_name);
301
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
302
-                return $controller->sendResponse(
303
-                    new WP_Error(
304
-                        'endpoint_parsing_error',
305
-                        sprintf(
306
-                            __(
307
-                                'There is no model for endpoint %s. Please contact event espresso support',
308
-                                'event_espresso'
309
-                            ),
310
-                            $related_model_name
311
-                        )
312
-                    )
313
-                );
314
-            }
315
-            return $controller->sendResponse(
316
-                $controller->getEntitiesFromRelation(
317
-                    $request->get_param('id'),
318
-                    $main_model->related_settings_for($related_model_name),
319
-                    $request
320
-                )
321
-            );
322
-        } catch (Exception $e) {
323
-            return $controller->sendResponse($e);
324
-        }
325
-    }
326
-
327
-
328
-    /**
329
-     * Gets a collection for the given model and filters
330
-     *
331
-     * @param EEM_Base        $model
332
-     * @param WP_REST_Request $request
333
-     * @return array|WP_Error
334
-     */
335
-    public function getEntitiesFromModel($model, $request)
336
-    {
337
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
338
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
339
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
340
-            return new WP_Error(
341
-                sprintf('rest_%s_cannot_list', $model_name_plural),
342
-                sprintf(
343
-                    __('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
344
-                    $model_name_plural,
345
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
346
-                ),
347
-                array('status' => 403)
348
-            );
349
-        }
350
-        if (! $request->get_header('no_rest_headers')) {
351
-            $this->setHeadersFromQueryParams($model, $query_params);
352
-        }
353
-        /** @type array $results */
354
-        $results = $model->get_all_wpdb_results($query_params);
355
-        $nice_results = array();
356
-        foreach ($results as $result) {
357
-            $nice_results[] = $this->createEntityFromWpdbResult(
358
-                $model,
359
-                $result,
360
-                $request
361
-            );
362
-        }
363
-        return $nice_results;
364
-    }
365
-
366
-
367
-    /**
368
-     * Gets the collection for given relation object
369
-     * The same as Read::get_entities_from_model(), except if the relation
370
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
371
-     * the join-model-object into the results
372
-     *
373
-     * @param array                   $primary_model_query_params query params for finding the item from which
374
-     *                                                            relations will be based
375
-     * @param \EE_Model_Relation_Base $relation
376
-     * @param WP_REST_Request         $request
377
-     * @return WP_Error|array
378
-     * @throws RestException
379
-     */
380
-    protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
381
-    {
382
-        $context = $this->validateContext($request->get_param('caps'));
383
-        $model = $relation->get_this_model();
384
-        $related_model = $relation->get_other_model();
385
-        if (! isset($primary_model_query_params[0])) {
386
-            $primary_model_query_params[0] = array();
387
-        }
388
-        // check if they can access the 1st model object
389
-        $primary_model_query_params = array(
390
-            0       => $primary_model_query_params[0],
391
-            'limit' => 1,
392
-        );
393
-        if ($model instanceof \EEM_Soft_Delete_Base) {
394
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
395
-                $primary_model_query_params
396
-            );
397
-        }
398
-        $restricted_query_params = $primary_model_query_params;
399
-        $restricted_query_params['caps'] = $context;
400
-        $this->setDebugInfo('main model query params', $restricted_query_params);
401
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
402
-        if (! (
403
-            Capabilities::currentUserHasPartialAccessTo($related_model, $context)
404
-            && $model->exists($restricted_query_params)
405
-        )
406
-        ) {
407
-            if ($relation instanceof EE_Belongs_To_Relation) {
408
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
409
-            } else {
410
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
411
-                    $related_model->get_this_model_name()
412
-                );
413
-            }
414
-            return new WP_Error(
415
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
416
-                sprintf(
417
-                    __(
418
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
419
-                        'event_espresso'
420
-                    ),
421
-                    $related_model_name_maybe_plural,
422
-                    $relation->get_this_model()->get_this_model_name(),
423
-                    implode(
424
-                        ',',
425
-                        array_keys(
426
-                            Capabilities::getMissingPermissions($related_model, $context)
427
-                        )
428
-                    )
429
-                ),
430
-                array('status' => 403)
431
-            );
432
-        }
433
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
434
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
435
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
436
-                              . '.'
437
-                              . $where_condition_key ] = $where_condition_value;
438
-        }
439
-        $query_params['default_where_conditions'] = 'none';
440
-        $query_params['caps'] = $context;
441
-        if (! $request->get_header('no_rest_headers')) {
442
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
443
-        }
444
-        /** @type array $results */
445
-        $results = $relation->get_other_model()->get_all_wpdb_results($query_params);
446
-        $nice_results = array();
447
-        foreach ($results as $result) {
448
-            $nice_result = $this->createEntityFromWpdbResult(
449
-                $relation->get_other_model(),
450
-                $result,
451
-                $request
452
-            );
453
-            if ($relation instanceof \EE_HABTM_Relation) {
454
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
455
-                // if there are conflicts we prefer the properties from the main model
456
-                $join_model_result = $this->createEntityFromWpdbResult(
457
-                    $relation->get_join_model(),
458
-                    $result,
459
-                    $request
460
-                );
461
-                $joined_result = array_merge($nice_result, $join_model_result);
462
-                // but keep the meta stuff from the main model
463
-                if (isset($nice_result['meta'])) {
464
-                    $joined_result['meta'] = $nice_result['meta'];
465
-                }
466
-                $nice_result = $joined_result;
467
-            }
468
-            $nice_results[] = $nice_result;
469
-        }
470
-        if ($relation instanceof EE_Belongs_To_Relation) {
471
-            return array_shift($nice_results);
472
-        } else {
473
-            return $nice_results;
474
-        }
475
-    }
476
-
477
-
478
-    /**
479
-     * Gets the collection for given relation object
480
-     * The same as Read::get_entities_from_model(), except if the relation
481
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
482
-     * the join-model-object into the results
483
-     *
484
-     * @param string                  $id the ID of the thing we are fetching related stuff from
485
-     * @param \EE_Model_Relation_Base $relation
486
-     * @param WP_REST_Request         $request
487
-     * @return array|WP_Error
488
-     * @throws EE_Error
489
-     */
490
-    public function getEntitiesFromRelation($id, $relation, $request)
491
-    {
492
-        if (! $relation->get_this_model()->has_primary_key_field()) {
493
-            throw new EE_Error(
494
-                sprintf(
495
-                    __(
496
-                    // @codingStandardsIgnoreStart
497
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
498
-                        // @codingStandardsIgnoreEnd
499
-                        'event_espresso'
500
-                    ),
501
-                    $relation->get_this_model()->get_this_model_name()
502
-                )
503
-            );
504
-        }
505
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
506
-            array(
507
-                array(
508
-                    $relation->get_this_model()->primary_key_name() => $id,
509
-                ),
510
-            ),
511
-            $relation,
512
-            $request
513
-        );
514
-    }
515
-
516
-
517
-    /**
518
-     * Sets the headers that are based on the model and query params,
519
-     * like the total records. This should only be called on the original request
520
-     * from the client, not on subsequent internal
521
-     *
522
-     * @param EEM_Base $model
523
-     * @param array    $query_params
524
-     * @return void
525
-     */
526
-    protected function setHeadersFromQueryParams($model, $query_params)
527
-    {
528
-        $this->setDebugInfo('model query params', $query_params);
529
-        $this->setDebugInfo(
530
-            'missing caps',
531
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
532
-        );
533
-        // normally the limit to a 2-part array, where the 2nd item is the limit
534
-        if (! isset($query_params['limit'])) {
535
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
536
-        }
537
-        if (is_array($query_params['limit'])) {
538
-            $limit_parts = $query_params['limit'];
539
-        } else {
540
-            $limit_parts = explode(',', $query_params['limit']);
541
-            if (count($limit_parts) == 1) {
542
-                $limit_parts = array(0, $limit_parts[0]);
543
-            }
544
-        }
545
-        // remove the group by and having parts of the query, as those will
546
-        // make the sql query return an array of values, instead of just a single value
547
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
548
-        $count = $model->count($query_params, null, true);
549
-        $pages = $count / $limit_parts[1];
550
-        $this->setResponseHeader('Total', $count, false);
551
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
552
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
553
-    }
554
-
555
-
556
-    /**
557
-     * Changes database results into REST API entities
558
-     *
559
-     * @param EEM_Base        $model
560
-     * @param array           $db_row     like results from $wpdb->get_results()
561
-     * @param WP_REST_Request $rest_request
562
-     * @param string          $deprecated no longer used
563
-     * @return array ready for being converted into json for sending to client
564
-     */
565
-    public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
566
-    {
567
-        if (! $rest_request instanceof WP_REST_Request) {
568
-            // ok so this was called in the old style, where the 3rd arg was
569
-            // $include, and the 4th arg was $context
570
-            // now setup the request just to avoid fatal errors, although we won't be able
571
-            // to truly make use of it because it's kinda devoid of info
572
-            $rest_request = new WP_REST_Request();
573
-            $rest_request->set_param('include', $rest_request);
574
-            $rest_request->set_param('caps', $deprecated);
575
-        }
576
-        if ($rest_request->get_param('caps') == null) {
577
-            $rest_request->set_param('caps', EEM_Base::caps_read);
578
-        }
579
-        $entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
580
-        $entity_array = $this->addExtraFields($model, $db_row, $entity_array);
581
-        $entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
582
-        $entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request);
583
-        $entity_array = apply_filters(
584
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
585
-            $entity_array,
586
-            $model,
587
-            $rest_request->get_param('caps'),
588
-            $rest_request,
589
-            $this
590
-        );
591
-        $entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row);
592
-        $entity_array = apply_filters(
593
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
594
-            $entity_array,
595
-            $model,
596
-            $rest_request->get_param('caps'),
597
-            $rest_request,
598
-            $this
599
-        );
600
-        $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
601
-            $entity_array,
602
-            $model,
603
-            $rest_request->get_param('caps'),
604
-            $this->getModelVersionInfo(),
605
-            $model->get_index_primary_key_string(
606
-                $model->deduce_fields_n_values_from_cols_n_values($db_row)
607
-            )
608
-        );
609
-        $this->setDebugInfo(
610
-            'inaccessible fields',
611
-            array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
612
-        );
613
-        return apply_filters(
614
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
615
-            $result_without_inaccessible_fields,
616
-            $model,
617
-            $rest_request->get_param('caps')
618
-        );
619
-    }
620
-
621
-
622
-    /**
623
-     * Creates a REST entity array (JSON object we're going to return in the response, but
624
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
625
-     * from $wpdb->get_row( $sql, ARRAY_A)
626
-     *
627
-     * @param EEM_Base $model
628
-     * @param array    $db_row
629
-     * @return array entity mostly ready for converting to JSON and sending in the response
630
-     */
631
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
632
-    {
633
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
634
-        $result = array_intersect_key(
635
-            $result,
636
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
637
-        );
638
-        // if this is a CPT, we need to set the global $post to it,
639
-        // otherwise shortcodes etc won't work properly while rendering it
640
-        if ($model instanceof \EEM_CPT_Base) {
641
-            $do_chevy_shuffle = true;
642
-        } else {
643
-            $do_chevy_shuffle = false;
644
-        }
645
-        if ($do_chevy_shuffle) {
646
-            global $post;
647
-            $old_post = $post;
648
-            $post = get_post($result[ $model->primary_key_name() ]);
649
-            if (! $post instanceof \WP_Post) {
650
-                // well that's weird, because $result is what we JUST fetched from the database
651
-                throw new RestException(
652
-                    'error_fetching_post_from_database_results',
653
-                    esc_html__(
654
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
655
-                        'event_espresso'
656
-                    )
657
-                );
658
-            }
659
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
660
-            $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
661
-                $model_object_classname,
662
-                $result,
663
-                false,
664
-                false
665
-            );
666
-        }
667
-        foreach ($result as $field_name => $field_value) {
668
-            $field_obj = $model->field_settings_for($field_name);
669
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
670
-                unset($result[ $field_name ]);
671
-            } elseif ($this->isSubclassOfOne(
672
-                $field_obj,
673
-                $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
674
-            )
675
-            ) {
676
-                $result[ $field_name ] = array(
677
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
678
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
679
-                );
680
-            } elseif ($this->isSubclassOfOne(
681
-                $field_obj,
682
-                $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
683
-            )
684
-            ) {
685
-                $result[ $field_name ] = array(
686
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
687
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
688
-                );
689
-            } elseif ($field_obj instanceof \EE_Datetime_Field) {
690
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
691
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
692
-                if (is_null($field_value)) {
693
-                    $field_value = $field_obj->getDefaultDateTimeObj();
694
-                }
695
-                if (is_null($field_value)) {
696
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
697
-                        $field_obj,
698
-                        $field_value,
699
-                        $this->getModelVersionInfo()->requestedVersion()
700
-                    );
701
-                } else {
702
-                    $timezone = $field_value->getTimezone();
703
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
704
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
705
-                        $field_obj,
706
-                        $field_value,
707
-                        $this->getModelVersionInfo()->requestedVersion()
708
-                    );
709
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
710
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
711
-                        $field_obj,
712
-                        $field_value,
713
-                        $this->getModelVersionInfo()->requestedVersion()
714
-                    );
715
-                }
716
-                $result[ $field_name . '_gmt' ] = $gmt_date;
717
-                $result[ $field_name ] = $local_date;
718
-            } else {
719
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
720
-            }
721
-        }
722
-        if ($do_chevy_shuffle) {
723
-            $post = $old_post;
724
-        }
725
-        return $result;
726
-    }
727
-
728
-
729
-    /**
730
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
731
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
732
-     * representation using $field_obj->prepare_for_set_from_db())
733
-     *
734
-     * @param EE_Model_Field_Base $field_obj
735
-     * @param mixed               $value  as it's stored on a model object
736
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
737
-     * @return mixed
738
-     * @throws ObjectDetectedException if $value contains a PHP object
739
-     */
740
-    protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
741
-    {
742
-        $value = $field_obj->prepare_for_set_from_db($value);
743
-        switch ($format) {
744
-            case 'pretty':
745
-                $value = $field_obj->prepare_for_pretty_echoing($value);
746
-                break;
747
-            case 'normal':
748
-            default:
749
-                $value = $field_obj->prepare_for_get($value);
750
-                break;
751
-        }
752
-        return ModelDataTranslator::prepareFieldValuesForJson(
753
-            $field_obj,
754
-            $value,
755
-            $this->getModelVersionInfo()->requestedVersion()
756
-        );
757
-    }
758
-
759
-
760
-    /**
761
-     * Adds a few extra fields to the entity response
762
-     *
763
-     * @param EEM_Base $model
764
-     * @param array    $db_row
765
-     * @param array    $entity_array
766
-     * @return array modified entity
767
-     */
768
-    protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
769
-    {
770
-        if ($model instanceof EEM_CPT_Base) {
771
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
772
-        }
773
-        return $entity_array;
774
-    }
775
-
776
-
777
-    /**
778
-     * Gets links we want to add to the response
779
-     *
780
-     * @global \WP_REST_Server $wp_rest_server
781
-     * @param EEM_Base         $model
782
-     * @param array            $db_row
783
-     * @param array            $entity_array
784
-     * @return array the _links item in the entity
785
-     */
786
-    protected function getEntityLinks($model, $db_row, $entity_array)
787
-    {
788
-        // add basic links
789
-        $links = array();
790
-        if ($model->has_primary_key_field()) {
791
-            $links['self'] = array(
792
-                array(
793
-                    'href' => $this->getVersionedLinkTo(
794
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
795
-                        . '/'
796
-                        . $entity_array[ $model->primary_key_name() ]
797
-                    ),
798
-                ),
799
-            );
800
-        }
801
-        $links['collection'] = array(
802
-            array(
803
-                'href' => $this->getVersionedLinkTo(
804
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
805
-                ),
806
-            ),
807
-        );
808
-        // add links to related models
809
-        if ($model->has_primary_key_field()) {
810
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
811
-                $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
812
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
813
-                    array(
814
-                        'href'   => $this->getVersionedLinkTo(
815
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
816
-                            . '/'
817
-                            . $entity_array[ $model->primary_key_name() ]
818
-                            . '/'
819
-                            . $related_model_part
820
-                        ),
821
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
822
-                    ),
823
-                );
824
-            }
825
-        }
826
-        return $links;
827
-    }
828
-
829
-
830
-    /**
831
-     * Adds the included models indicated in the request to the entity provided
832
-     *
833
-     * @param EEM_Base        $model
834
-     * @param WP_REST_Request $rest_request
835
-     * @param array           $entity_array
836
-     * @param array           $db_row
837
-     * @return array the modified entity
838
-     */
839
-    protected function includeRequestedModels(
840
-        EEM_Base $model,
841
-        WP_REST_Request $rest_request,
842
-        $entity_array,
843
-        $db_row = array()
844
-    ) {
845
-        // if $db_row not included, hope the entity array has what we need
846
-        if (! $db_row) {
847
-            $db_row = $entity_array;
848
-        }
849
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
850
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
851
-        // if they passed in * or didn't specify any includes, return everything
852
-        if (! in_array('*', $includes_for_this_model)
853
-            && ! empty($includes_for_this_model)
854
-        ) {
855
-            if ($model->has_primary_key_field()) {
856
-                // always include the primary key. ya just gotta know that at least
857
-                $includes_for_this_model[] = $model->primary_key_name();
858
-            }
859
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
860
-                $includes_for_this_model[] = '_calculated_fields';
861
-            }
862
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
863
-        }
864
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
865
-        foreach ($relation_settings as $relation_name => $relation_obj) {
866
-            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
867
-                $rest_request->get_param('include'),
868
-                $relation_name
869
-            );
870
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
871
-                $rest_request->get_param('calculate'),
872
-                $relation_name
873
-            );
874
-            // did they specify they wanted to include a related model, or
875
-            // specific fields from a related model?
876
-            // or did they specify to calculate a field from a related model?
877
-            if ($related_fields_to_include || $related_fields_to_calculate) {
878
-                // if so, we should include at least some part of the related model
879
-                $pretend_related_request = new WP_REST_Request();
880
-                $pretend_related_request->set_query_params(
881
-                    array(
882
-                        'caps'      => $rest_request->get_param('caps'),
883
-                        'include'   => $related_fields_to_include,
884
-                        'calculate' => $related_fields_to_calculate,
885
-                    )
886
-                );
887
-                $pretend_related_request->add_header('no_rest_headers', true);
888
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
889
-                    $model->get_index_primary_key_string(
890
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
891
-                    )
892
-                );
893
-                $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
894
-                    $primary_model_query_params,
895
-                    $relation_obj,
896
-                    $pretend_related_request
897
-                );
898
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
899
-                                                                                             instanceof
900
-                                                                                             WP_Error
901
-                    ? null
902
-                    : $related_results;
903
-            }
904
-        }
905
-        return $entity_array;
906
-    }
907
-
908
-
909
-    /**
910
-     * Returns a new array with all the names of models removed. Eg
911
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
912
-     *
913
-     * @param array $arr
914
-     * @return array
915
-     */
916
-    private function removeModelNamesFromArray($arr)
917
-    {
918
-        return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
919
-    }
920
-
921
-
922
-    /**
923
-     * Gets the calculated fields for the response
924
-     *
925
-     * @param EEM_Base        $model
926
-     * @param array           $wpdb_row
927
-     * @param WP_REST_Request $rest_request
928
-     * @return \stdClass the _calculations item in the entity
929
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
930
-     * did, let's know about it ASAP, so let the exception bubble up)
931
-     */
932
-    protected function getEntityCalculations($model, $wpdb_row, $rest_request)
933
-    {
934
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
935
-            $rest_request->get_param('calculate'),
936
-            ''
937
-        );
938
-        // note: setting calculate=* doesn't do anything
939
-        $calculated_fields_to_return = new \stdClass();
940
-        foreach ($calculated_fields as $field_to_calculate) {
941
-            try {
942
-                $calculated_fields_to_return->$field_to_calculate = ModelDataTranslator::prepareFieldValueForJson(
943
-                    null,
944
-                    $this->fields_calculator->retrieveCalculatedFieldValue(
945
-                        $model,
946
-                        $field_to_calculate,
947
-                        $wpdb_row,
948
-                        $rest_request,
949
-                        $this
950
-                    ),
951
-                    $this->getModelVersionInfo()->requestedVersion()
952
-                );
953
-            } catch (RestException $e) {
954
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
955
-                $this->setResponseHeader(
956
-                    'Notices-Field-Calculation-Errors['
957
-                    . $e->getStringCode()
958
-                    . ']['
959
-                    . $model->get_this_model_name()
960
-                    . ']['
961
-                    . $field_to_calculate
962
-                    . ']',
963
-                    $e->getMessage(),
964
-                    true
965
-                );
966
-            }
967
-        }
968
-        return $calculated_fields_to_return;
969
-    }
970
-
971
-
972
-    /**
973
-     * Gets the full URL to the resource, taking the requested version into account
974
-     *
975
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
976
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
977
-     */
978
-    public function getVersionedLinkTo($link_part_after_version_and_slash)
979
-    {
980
-        return rest_url(
981
-            EED_Core_Rest_Api::get_versioned_route_to(
982
-                $link_part_after_version_and_slash,
983
-                $this->getModelVersionInfo()->requestedVersion()
984
-            )
985
-        );
986
-    }
987
-
988
-
989
-    /**
990
-     * Gets the correct lowercase name for the relation in the API according
991
-     * to the relation's type
992
-     *
993
-     * @param string                  $relation_name
994
-     * @param \EE_Model_Relation_Base $relation_obj
995
-     * @return string
996
-     */
997
-    public static function getRelatedEntityName($relation_name, $relation_obj)
998
-    {
999
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1000
-            return strtolower($relation_name);
1001
-        } else {
1002
-            return EEH_Inflector::pluralize_and_lower($relation_name);
1003
-        }
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * Gets the one model object with the specified id for the specified model
1009
-     *
1010
-     * @param EEM_Base        $model
1011
-     * @param WP_REST_Request $request
1012
-     * @return array|WP_Error
1013
-     */
1014
-    public function getEntityFromModel($model, $request)
1015
-    {
1016
-        $context = $this->validateContext($request->get_param('caps'));
1017
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1018
-    }
1019
-
1020
-
1021
-    /**
1022
-     * If a context is provided which isn't valid, maybe it was added in a future
1023
-     * version so just treat it as a default read
1024
-     *
1025
-     * @param string $context
1026
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1027
-     */
1028
-    public function validateContext($context)
1029
-    {
1030
-        if (! $context) {
1031
-            $context = EEM_Base::caps_read;
1032
-        }
1033
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1034
-        if (in_array($context, $valid_contexts)) {
1035
-            return $context;
1036
-        } else {
1037
-            return EEM_Base::caps_read;
1038
-        }
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * Verifies the passed in value is an allowable default where conditions value.
1044
-     *
1045
-     * @param $default_query_params
1046
-     * @return string
1047
-     */
1048
-    public function validateDefaultQueryParams($default_query_params)
1049
-    {
1050
-        $valid_default_where_conditions_for_api_calls = array(
1051
-            EEM_Base::default_where_conditions_all,
1052
-            EEM_Base::default_where_conditions_minimum_all,
1053
-            EEM_Base::default_where_conditions_minimum_others,
1054
-        );
1055
-        if (! $default_query_params) {
1056
-            $default_query_params = EEM_Base::default_where_conditions_all;
1057
-        }
1058
-        if (in_array(
1059
-            $default_query_params,
1060
-            $valid_default_where_conditions_for_api_calls,
1061
-            true
1062
-        )) {
1063
-            return $default_query_params;
1064
-        } else {
1065
-            return EEM_Base::default_where_conditions_all;
1066
-        }
1067
-    }
1068
-
1069
-
1070
-    /**
1071
-     * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1072
-     * Note: right now the query parameter keys for fields (and related fields)
1073
-     * can be left as-is, but it's quite possible this will change someday.
1074
-     * Also, this method's contents might be candidate for moving to Model_Data_Translator
1075
-     *
1076
-     * @param EEM_Base $model
1077
-     * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1078
-     * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1079
-     *                                    that absolutely no results should be returned
1080
-     * @throws EE_Error
1081
-     * @throws RestException
1082
-     */
1083
-    public function createModelQueryParams($model, $query_parameters)
1084
-    {
1085
-        $model_query_params = array();
1086
-        if (isset($query_parameters['where'])) {
1087
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1088
-                $query_parameters['where'],
1089
-                $model,
1090
-                $this->getModelVersionInfo()->requestedVersion()
1091
-            );
1092
-        }
1093
-        if (isset($query_parameters['order_by'])) {
1094
-            $order_by = $query_parameters['order_by'];
1095
-        } elseif (isset($query_parameters['orderby'])) {
1096
-            $order_by = $query_parameters['orderby'];
1097
-        } else {
1098
-            $order_by = null;
1099
-        }
1100
-        if ($order_by !== null) {
1101
-            if (is_array($order_by)) {
1102
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1103
-            } else {
1104
-                // it's a single item
1105
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1106
-            }
1107
-            $model_query_params['order_by'] = $order_by;
1108
-        }
1109
-        if (isset($query_parameters['group_by'])) {
1110
-            $group_by = $query_parameters['group_by'];
1111
-        } elseif (isset($query_parameters['groupby'])) {
1112
-            $group_by = $query_parameters['groupby'];
1113
-        } else {
1114
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1115
-        }
1116
-        // make sure they're all real names
1117
-        if (is_array($group_by)) {
1118
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1119
-        }
1120
-        if ($group_by !== null) {
1121
-            $model_query_params['group_by'] = $group_by;
1122
-        }
1123
-        if (isset($query_parameters['having'])) {
1124
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1125
-                $query_parameters['having'],
1126
-                $model,
1127
-                $this->getModelVersionInfo()->requestedVersion()
1128
-            );
1129
-        }
1130
-        if (isset($query_parameters['order'])) {
1131
-            $model_query_params['order'] = $query_parameters['order'];
1132
-        }
1133
-        if (isset($query_parameters['mine'])) {
1134
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1135
-        }
1136
-        if (isset($query_parameters['limit'])) {
1137
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1138
-            if (! is_array($query_parameters['limit'])) {
1139
-                $limit_array = explode(',', (string) $query_parameters['limit']);
1140
-            } else {
1141
-                $limit_array = $query_parameters['limit'];
1142
-            }
1143
-            $sanitized_limit = array();
1144
-            foreach ($limit_array as $key => $limit_part) {
1145
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1146
-                    throw new EE_Error(
1147
-                        sprintf(
1148
-                            __(
1149
-                            // @codingStandardsIgnoreStart
1150
-                                'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1151
-                                // @codingStandardsIgnoreEnd
1152
-                                'event_espresso'
1153
-                            ),
1154
-                            wp_json_encode($query_parameters['limit'])
1155
-                        )
1156
-                    );
1157
-                }
1158
-                $sanitized_limit[] = (int) $limit_part;
1159
-            }
1160
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1161
-        } else {
1162
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1163
-        }
1164
-        if (isset($query_parameters['caps'])) {
1165
-            $model_query_params['caps'] = $this->validateContext($query_parameters['caps']);
1166
-        } else {
1167
-            $model_query_params['caps'] = EEM_Base::caps_read;
1168
-        }
1169
-        if (isset($query_parameters['default_where_conditions'])) {
1170
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1171
-                $query_parameters['default_where_conditions']
1172
-            );
1173
-        }
1174
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1175
-    }
1176
-
1177
-
1178
-    /**
1179
-     * Changes the REST-style query params for use in the models
1180
-     *
1181
-     * @deprecated
1182
-     * @param EEM_Base $model
1183
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1184
-     * @return array
1185
-     */
1186
-    public function prepareRestQueryParamsKeyForModels($model, $query_params)
1187
-    {
1188
-        $model_ready_query_params = array();
1189
-        foreach ($query_params as $key => $value) {
1190
-            if (is_array($value)) {
1191
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1192
-            } else {
1193
-                $model_ready_query_params[ $key ] = $value;
1194
-            }
1195
-        }
1196
-        return $model_ready_query_params;
1197
-    }
1198
-
1199
-
1200
-    /**
1201
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1202
-     * @param $model
1203
-     * @param $query_params
1204
-     * @return array
1205
-     */
1206
-    public function prepareRestQueryParamsValuesForModels($model, $query_params)
1207
-    {
1208
-        $model_ready_query_params = array();
1209
-        foreach ($query_params as $key => $value) {
1210
-            if (is_array($value)) {
1211
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1212
-            } else {
1213
-                $model_ready_query_params[ $key ] = $value;
1214
-            }
1215
-        }
1216
-        return $model_ready_query_params;
1217
-    }
1218
-
1219
-
1220
-    /**
1221
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1222
-     * If no prefix is specified, returns items with no period.
1223
-     *
1224
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1225
-     * @param string       $prefix            "Event" or "foobar"
1226
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1227
-     *                                        we only return strings starting with that and a period; if no prefix was
1228
-     *                                        specified we return all items containing NO periods
1229
-     */
1230
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1231
-    {
1232
-        if (is_string($string_to_explode)) {
1233
-            $exploded_contents = explode(',', $string_to_explode);
1234
-        } elseif (is_array($string_to_explode)) {
1235
-            $exploded_contents = $string_to_explode;
1236
-        } else {
1237
-            $exploded_contents = array();
1238
-        }
1239
-        // if the string was empty, we want an empty array
1240
-        $exploded_contents = array_filter($exploded_contents);
1241
-        $contents_with_prefix = array();
1242
-        foreach ($exploded_contents as $item) {
1243
-            $item = trim($item);
1244
-            // if no prefix was provided, so we look for items with no "." in them
1245
-            if (! $prefix) {
1246
-                // does this item have a period?
1247
-                if (strpos($item, '.') === false) {
1248
-                    // if not, then its what we're looking for
1249
-                    $contents_with_prefix[] = $item;
1250
-                }
1251
-            } elseif (strpos($item, $prefix . '.') === 0) {
1252
-                // this item has the prefix and a period, grab it
1253
-                $contents_with_prefix[] = substr(
1254
-                    $item,
1255
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1256
-                );
1257
-            } elseif ($item === $prefix) {
1258
-                // this item is JUST the prefix
1259
-                // so let's grab everything after, which is a blank string
1260
-                $contents_with_prefix[] = '';
1261
-            }
1262
-        }
1263
-        return $contents_with_prefix;
1264
-    }
1265
-
1266
-
1267
-    /**
1268
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1269
-     * Deprecated because its return values were really quite confusing- sometimes it returned
1270
-     * an empty array (when the include string was blank or '*') or sometimes it returned
1271
-     * array('*') (when you provided a model and a model of that kind was found).
1272
-     * Parses the $include_string so we fetch all the field names relating to THIS model
1273
-     * (ie have NO period in them), or for the provided model (ie start with the model
1274
-     * name and then a period).
1275
-     * @param string $include_string @see Read:handle_request_get_all
1276
-     * @param string $model_name
1277
-     * @return array of fields for this model. If $model_name is provided, then
1278
-     *                               the fields for that model, with the model's name removed from each.
1279
-     *                               If $include_string was blank or '*' returns an empty array
1280
-     */
1281
-    public function extractIncludesForThisModel($include_string, $model_name = null)
1282
-    {
1283
-        if (is_array($include_string)) {
1284
-            $include_string = implode(',', $include_string);
1285
-        }
1286
-        if ($include_string === '*' || $include_string === '') {
1287
-            return array();
1288
-        }
1289
-        $includes = explode(',', $include_string);
1290
-        $extracted_fields_to_include = array();
1291
-        if ($model_name) {
1292
-            foreach ($includes as $field_to_include) {
1293
-                $field_to_include = trim($field_to_include);
1294
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1295
-                    // found the model name at the exact start
1296
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1297
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1298
-                } elseif ($field_to_include == $model_name) {
1299
-                    $extracted_fields_to_include[] = '*';
1300
-                }
1301
-            }
1302
-        } else {
1303
-            // look for ones with no period
1304
-            foreach ($includes as $field_to_include) {
1305
-                $field_to_include = trim($field_to_include);
1306
-                if (strpos($field_to_include, '.') === false
1307
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1308
-                ) {
1309
-                    $extracted_fields_to_include[] = $field_to_include;
1310
-                }
1311
-            }
1312
-        }
1313
-        return $extracted_fields_to_include;
1314
-    }
1315
-
1316
-
1317
-    /**
1318
-     * Gets the single item using the model according to the request in the context given, otherwise
1319
-     * returns that it's inaccessible to the current user
1320
-     *
1321
-     * @param EEM_Base        $model
1322
-     * @param WP_REST_Request $request
1323
-     * @param null            $context
1324
-     * @return array|WP_Error
1325
-     */
1326
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1327
-    {
1328
-        $query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1329
-        if ($model instanceof \EEM_Soft_Delete_Base) {
1330
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1331
-        }
1332
-        $restricted_query_params = $query_params;
1333
-        $restricted_query_params['caps'] = $context;
1334
-        $this->setDebugInfo('model query params', $restricted_query_params);
1335
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1336
-        if (! empty($model_rows)) {
1337
-            return $this->createEntityFromWpdbResult(
1338
-                $model,
1339
-                array_shift($model_rows),
1340
-                $request
1341
-            );
1342
-        } else {
1343
-            // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1344
-            $lowercase_model_name = strtolower($model->get_this_model_name());
1345
-            $model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1346
-            if (! empty($model_rows_found_sans_restrictions)) {
1347
-                // you got shafted- it existed but we didn't want to tell you!
1348
-                return new WP_Error(
1349
-                    'rest_user_cannot_' . $context,
1350
-                    sprintf(
1351
-                        __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1352
-                        $context,
1353
-                        strtolower($model->get_this_model_name()),
1354
-                        Capabilities::getMissingPermissionsString(
1355
-                            $model,
1356
-                            $context
1357
-                        )
1358
-                    ),
1359
-                    array('status' => 403)
1360
-                );
1361
-            } else {
1362
-                // it's not you. It just doesn't exist
1363
-                return new WP_Error(
1364
-                    sprintf('rest_%s_invalid_id', $lowercase_model_name),
1365
-                    sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1366
-                    array('status' => 404)
1367
-                );
1368
-            }
1369
-        }
1370
-    }
38
+	/**
39
+	 * @var CalculatedModelFields
40
+	 */
41
+	protected $fields_calculator;
42
+
43
+
44
+	/**
45
+	 * Read constructor.
46
+	 */
47
+	public function __construct()
48
+	{
49
+		parent::__construct();
50
+		$this->fields_calculator = new CalculatedModelFields();
51
+	}
52
+
53
+
54
+	/**
55
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
56
+	 *
57
+	 * @param WP_REST_Request $request
58
+	 * @param string          $version
59
+	 * @param string          $model_name
60
+	 * @return \WP_REST_Response|WP_Error
61
+	 */
62
+	public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
63
+	{
64
+		$controller = new Read();
65
+		try {
66
+			$controller->setRequestedVersion($version);
67
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
68
+				return $controller->sendResponse(
69
+					new WP_Error(
70
+						'endpoint_parsing_error',
71
+						sprintf(
72
+							__(
73
+								'There is no model for endpoint %s. Please contact event espresso support',
74
+								'event_espresso'
75
+							),
76
+							$model_name
77
+						)
78
+					)
79
+				);
80
+			}
81
+			return $controller->sendResponse(
82
+				$controller->getEntitiesFromModel(
83
+					$controller->getModelVersionInfo()->loadModel($model_name),
84
+					$request
85
+				)
86
+			);
87
+		} catch (Exception $e) {
88
+			return $controller->sendResponse($e);
89
+		}
90
+	}
91
+
92
+
93
+	/**
94
+	 * Prepares and returns schema for any OPTIONS request.
95
+	 *
96
+	 * @param string $version    The API endpoint version being used.
97
+	 * @param string $model_name Something like `Event` or `Registration`
98
+	 * @return array
99
+	 */
100
+	public static function handleSchemaRequest($version, $model_name)
101
+	{
102
+		$controller = new Read();
103
+		try {
104
+			$controller->setRequestedVersion($version);
105
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
106
+				return array();
107
+			}
108
+			// get the model for this version
109
+			$model = $controller->getModelVersionInfo()->loadModel($model_name);
110
+			$model_schema = new JsonModelSchema($model);
111
+			return $model_schema->getModelSchemaForRelations(
112
+				$controller->getModelVersionInfo()->relationSettings($model),
113
+				$controller->customizeSchemaForRestResponse(
114
+					$model,
115
+					$model_schema->getModelSchemaForFields(
116
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
117
+						$model_schema->getInitialSchemaStructure()
118
+					)
119
+				)
120
+			);
121
+		} catch (Exception $e) {
122
+			return array();
123
+		}
124
+	}
125
+
126
+
127
+	/**
128
+	 * This loops through each field in the given schema for the model and does the following:
129
+	 * - add any extra fields that are REST API specific and related to existing fields.
130
+	 * - transform default values into the correct format for a REST API response.
131
+	 *
132
+	 * @param EEM_Base $model
133
+	 * @param array    $schema
134
+	 * @return array  The final schema.
135
+	 */
136
+	protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
137
+	{
138
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
139
+			$schema = $this->translateDefaultsForRestResponse(
140
+				$field_name,
141
+				$field,
142
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
143
+			);
144
+		}
145
+		return $schema;
146
+	}
147
+
148
+
149
+	/**
150
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
151
+	 * response.
152
+	 *
153
+	 * @param                      $field_name
154
+	 * @param EE_Model_Field_Base  $field
155
+	 * @param array                $schema
156
+	 * @return array
157
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
158
+	 * did, let's know about it ASAP, so let the exception bubble up)
159
+	 */
160
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
161
+	{
162
+		if (isset($schema['properties'][ $field_name ]['default'])) {
163
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
164
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
165
+					if ($default_key === 'raw') {
166
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
167
+							ModelDataTranslator::prepareFieldValueForJson(
168
+								$field,
169
+								$default_value,
170
+								$this->getModelVersionInfo()->requestedVersion()
171
+							);
172
+					}
173
+				}
174
+			} else {
175
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
176
+					$field,
177
+					$schema['properties'][ $field_name ]['default'],
178
+					$this->getModelVersionInfo()->requestedVersion()
179
+				);
180
+			}
181
+		}
182
+		return $schema;
183
+	}
184
+
185
+
186
+	/**
187
+	 * Adds additional fields to the schema
188
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
189
+	 * needs to be added to the schema.
190
+	 *
191
+	 * @param                      $field_name
192
+	 * @param EE_Model_Field_Base  $field
193
+	 * @param array                $schema
194
+	 * @return array
195
+	 */
196
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
197
+	{
198
+		if ($field instanceof EE_Datetime_Field) {
199
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
200
+			// modify the description
201
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
202
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
203
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
204
+			);
205
+		}
206
+		return $schema;
207
+	}
208
+
209
+
210
+	/**
211
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
212
+	 *
213
+	 * @return string
214
+	 */
215
+	protected function getRouteFromRequest()
216
+	{
217
+		if (isset($GLOBALS['wp'])
218
+			&& $GLOBALS['wp'] instanceof \WP
219
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
220
+		) {
221
+			return $GLOBALS['wp']->query_vars['rest_route'];
222
+		} else {
223
+			return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
224
+		}
225
+	}
226
+
227
+
228
+	/**
229
+	 * Gets a single entity related to the model indicated in the path and its id
230
+	 *
231
+	 * @param WP_REST_Request $request
232
+	 * @param string          $version
233
+	 * @param string          $model_name
234
+	 * @return \WP_REST_Response|WP_Error
235
+	 */
236
+	public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
237
+	{
238
+		$controller = new Read();
239
+		try {
240
+			$controller->setRequestedVersion($version);
241
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
242
+				return $controller->sendResponse(
243
+					new WP_Error(
244
+						'endpoint_parsing_error',
245
+						sprintf(
246
+							__(
247
+								'There is no model for endpoint %s. Please contact event espresso support',
248
+								'event_espresso'
249
+							),
250
+							$model_name
251
+						)
252
+					)
253
+				);
254
+			}
255
+			return $controller->sendResponse(
256
+				$controller->getEntityFromModel(
257
+					$controller->getModelVersionInfo()->loadModel($model_name),
258
+					$request
259
+				)
260
+			);
261
+		} catch (Exception $e) {
262
+			return $controller->sendResponse($e);
263
+		}
264
+	}
265
+
266
+
267
+	/**
268
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
269
+	 * to the item with the given id
270
+	 *
271
+	 * @param WP_REST_Request $request
272
+	 * @param string          $version
273
+	 * @param string          $model_name
274
+	 * @param string          $related_model_name
275
+	 * @return \WP_REST_Response|WP_Error
276
+	 */
277
+	public static function handleRequestGetRelated(
278
+		WP_REST_Request $request,
279
+		$version,
280
+		$model_name,
281
+		$related_model_name
282
+	) {
283
+		$controller = new Read();
284
+		try {
285
+			$controller->setRequestedVersion($version);
286
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
287
+				return $controller->sendResponse(
288
+					new WP_Error(
289
+						'endpoint_parsing_error',
290
+						sprintf(
291
+							__(
292
+								'There is no model for endpoint %s. Please contact event espresso support',
293
+								'event_espresso'
294
+							),
295
+							$model_name
296
+						)
297
+					)
298
+				);
299
+			}
300
+			$main_model = $controller->getModelVersionInfo()->loadModel($model_name);
301
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($related_model_name)) {
302
+				return $controller->sendResponse(
303
+					new WP_Error(
304
+						'endpoint_parsing_error',
305
+						sprintf(
306
+							__(
307
+								'There is no model for endpoint %s. Please contact event espresso support',
308
+								'event_espresso'
309
+							),
310
+							$related_model_name
311
+						)
312
+					)
313
+				);
314
+			}
315
+			return $controller->sendResponse(
316
+				$controller->getEntitiesFromRelation(
317
+					$request->get_param('id'),
318
+					$main_model->related_settings_for($related_model_name),
319
+					$request
320
+				)
321
+			);
322
+		} catch (Exception $e) {
323
+			return $controller->sendResponse($e);
324
+		}
325
+	}
326
+
327
+
328
+	/**
329
+	 * Gets a collection for the given model and filters
330
+	 *
331
+	 * @param EEM_Base        $model
332
+	 * @param WP_REST_Request $request
333
+	 * @return array|WP_Error
334
+	 */
335
+	public function getEntitiesFromModel($model, $request)
336
+	{
337
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
338
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
339
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
340
+			return new WP_Error(
341
+				sprintf('rest_%s_cannot_list', $model_name_plural),
342
+				sprintf(
343
+					__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
344
+					$model_name_plural,
345
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
346
+				),
347
+				array('status' => 403)
348
+			);
349
+		}
350
+		if (! $request->get_header('no_rest_headers')) {
351
+			$this->setHeadersFromQueryParams($model, $query_params);
352
+		}
353
+		/** @type array $results */
354
+		$results = $model->get_all_wpdb_results($query_params);
355
+		$nice_results = array();
356
+		foreach ($results as $result) {
357
+			$nice_results[] = $this->createEntityFromWpdbResult(
358
+				$model,
359
+				$result,
360
+				$request
361
+			);
362
+		}
363
+		return $nice_results;
364
+	}
365
+
366
+
367
+	/**
368
+	 * Gets the collection for given relation object
369
+	 * The same as Read::get_entities_from_model(), except if the relation
370
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
371
+	 * the join-model-object into the results
372
+	 *
373
+	 * @param array                   $primary_model_query_params query params for finding the item from which
374
+	 *                                                            relations will be based
375
+	 * @param \EE_Model_Relation_Base $relation
376
+	 * @param WP_REST_Request         $request
377
+	 * @return WP_Error|array
378
+	 * @throws RestException
379
+	 */
380
+	protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
381
+	{
382
+		$context = $this->validateContext($request->get_param('caps'));
383
+		$model = $relation->get_this_model();
384
+		$related_model = $relation->get_other_model();
385
+		if (! isset($primary_model_query_params[0])) {
386
+			$primary_model_query_params[0] = array();
387
+		}
388
+		// check if they can access the 1st model object
389
+		$primary_model_query_params = array(
390
+			0       => $primary_model_query_params[0],
391
+			'limit' => 1,
392
+		);
393
+		if ($model instanceof \EEM_Soft_Delete_Base) {
394
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
395
+				$primary_model_query_params
396
+			);
397
+		}
398
+		$restricted_query_params = $primary_model_query_params;
399
+		$restricted_query_params['caps'] = $context;
400
+		$this->setDebugInfo('main model query params', $restricted_query_params);
401
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
402
+		if (! (
403
+			Capabilities::currentUserHasPartialAccessTo($related_model, $context)
404
+			&& $model->exists($restricted_query_params)
405
+		)
406
+		) {
407
+			if ($relation instanceof EE_Belongs_To_Relation) {
408
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
409
+			} else {
410
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
411
+					$related_model->get_this_model_name()
412
+				);
413
+			}
414
+			return new WP_Error(
415
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
416
+				sprintf(
417
+					__(
418
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
419
+						'event_espresso'
420
+					),
421
+					$related_model_name_maybe_plural,
422
+					$relation->get_this_model()->get_this_model_name(),
423
+					implode(
424
+						',',
425
+						array_keys(
426
+							Capabilities::getMissingPermissions($related_model, $context)
427
+						)
428
+					)
429
+				),
430
+				array('status' => 403)
431
+			);
432
+		}
433
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
434
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
435
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
436
+							  . '.'
437
+							  . $where_condition_key ] = $where_condition_value;
438
+		}
439
+		$query_params['default_where_conditions'] = 'none';
440
+		$query_params['caps'] = $context;
441
+		if (! $request->get_header('no_rest_headers')) {
442
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
443
+		}
444
+		/** @type array $results */
445
+		$results = $relation->get_other_model()->get_all_wpdb_results($query_params);
446
+		$nice_results = array();
447
+		foreach ($results as $result) {
448
+			$nice_result = $this->createEntityFromWpdbResult(
449
+				$relation->get_other_model(),
450
+				$result,
451
+				$request
452
+			);
453
+			if ($relation instanceof \EE_HABTM_Relation) {
454
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
455
+				// if there are conflicts we prefer the properties from the main model
456
+				$join_model_result = $this->createEntityFromWpdbResult(
457
+					$relation->get_join_model(),
458
+					$result,
459
+					$request
460
+				);
461
+				$joined_result = array_merge($nice_result, $join_model_result);
462
+				// but keep the meta stuff from the main model
463
+				if (isset($nice_result['meta'])) {
464
+					$joined_result['meta'] = $nice_result['meta'];
465
+				}
466
+				$nice_result = $joined_result;
467
+			}
468
+			$nice_results[] = $nice_result;
469
+		}
470
+		if ($relation instanceof EE_Belongs_To_Relation) {
471
+			return array_shift($nice_results);
472
+		} else {
473
+			return $nice_results;
474
+		}
475
+	}
476
+
477
+
478
+	/**
479
+	 * Gets the collection for given relation object
480
+	 * The same as Read::get_entities_from_model(), except if the relation
481
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
482
+	 * the join-model-object into the results
483
+	 *
484
+	 * @param string                  $id the ID of the thing we are fetching related stuff from
485
+	 * @param \EE_Model_Relation_Base $relation
486
+	 * @param WP_REST_Request         $request
487
+	 * @return array|WP_Error
488
+	 * @throws EE_Error
489
+	 */
490
+	public function getEntitiesFromRelation($id, $relation, $request)
491
+	{
492
+		if (! $relation->get_this_model()->has_primary_key_field()) {
493
+			throw new EE_Error(
494
+				sprintf(
495
+					__(
496
+					// @codingStandardsIgnoreStart
497
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
498
+						// @codingStandardsIgnoreEnd
499
+						'event_espresso'
500
+					),
501
+					$relation->get_this_model()->get_this_model_name()
502
+				)
503
+			);
504
+		}
505
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
506
+			array(
507
+				array(
508
+					$relation->get_this_model()->primary_key_name() => $id,
509
+				),
510
+			),
511
+			$relation,
512
+			$request
513
+		);
514
+	}
515
+
516
+
517
+	/**
518
+	 * Sets the headers that are based on the model and query params,
519
+	 * like the total records. This should only be called on the original request
520
+	 * from the client, not on subsequent internal
521
+	 *
522
+	 * @param EEM_Base $model
523
+	 * @param array    $query_params
524
+	 * @return void
525
+	 */
526
+	protected function setHeadersFromQueryParams($model, $query_params)
527
+	{
528
+		$this->setDebugInfo('model query params', $query_params);
529
+		$this->setDebugInfo(
530
+			'missing caps',
531
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
532
+		);
533
+		// normally the limit to a 2-part array, where the 2nd item is the limit
534
+		if (! isset($query_params['limit'])) {
535
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
536
+		}
537
+		if (is_array($query_params['limit'])) {
538
+			$limit_parts = $query_params['limit'];
539
+		} else {
540
+			$limit_parts = explode(',', $query_params['limit']);
541
+			if (count($limit_parts) == 1) {
542
+				$limit_parts = array(0, $limit_parts[0]);
543
+			}
544
+		}
545
+		// remove the group by and having parts of the query, as those will
546
+		// make the sql query return an array of values, instead of just a single value
547
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
548
+		$count = $model->count($query_params, null, true);
549
+		$pages = $count / $limit_parts[1];
550
+		$this->setResponseHeader('Total', $count, false);
551
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
552
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
553
+	}
554
+
555
+
556
+	/**
557
+	 * Changes database results into REST API entities
558
+	 *
559
+	 * @param EEM_Base        $model
560
+	 * @param array           $db_row     like results from $wpdb->get_results()
561
+	 * @param WP_REST_Request $rest_request
562
+	 * @param string          $deprecated no longer used
563
+	 * @return array ready for being converted into json for sending to client
564
+	 */
565
+	public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
566
+	{
567
+		if (! $rest_request instanceof WP_REST_Request) {
568
+			// ok so this was called in the old style, where the 3rd arg was
569
+			// $include, and the 4th arg was $context
570
+			// now setup the request just to avoid fatal errors, although we won't be able
571
+			// to truly make use of it because it's kinda devoid of info
572
+			$rest_request = new WP_REST_Request();
573
+			$rest_request->set_param('include', $rest_request);
574
+			$rest_request->set_param('caps', $deprecated);
575
+		}
576
+		if ($rest_request->get_param('caps') == null) {
577
+			$rest_request->set_param('caps', EEM_Base::caps_read);
578
+		}
579
+		$entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
580
+		$entity_array = $this->addExtraFields($model, $db_row, $entity_array);
581
+		$entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
582
+		$entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request);
583
+		$entity_array = apply_filters(
584
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
585
+			$entity_array,
586
+			$model,
587
+			$rest_request->get_param('caps'),
588
+			$rest_request,
589
+			$this
590
+		);
591
+		$entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row);
592
+		$entity_array = apply_filters(
593
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
594
+			$entity_array,
595
+			$model,
596
+			$rest_request->get_param('caps'),
597
+			$rest_request,
598
+			$this
599
+		);
600
+		$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
601
+			$entity_array,
602
+			$model,
603
+			$rest_request->get_param('caps'),
604
+			$this->getModelVersionInfo(),
605
+			$model->get_index_primary_key_string(
606
+				$model->deduce_fields_n_values_from_cols_n_values($db_row)
607
+			)
608
+		);
609
+		$this->setDebugInfo(
610
+			'inaccessible fields',
611
+			array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
612
+		);
613
+		return apply_filters(
614
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
615
+			$result_without_inaccessible_fields,
616
+			$model,
617
+			$rest_request->get_param('caps')
618
+		);
619
+	}
620
+
621
+
622
+	/**
623
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
624
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
625
+	 * from $wpdb->get_row( $sql, ARRAY_A)
626
+	 *
627
+	 * @param EEM_Base $model
628
+	 * @param array    $db_row
629
+	 * @return array entity mostly ready for converting to JSON and sending in the response
630
+	 */
631
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
632
+	{
633
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
634
+		$result = array_intersect_key(
635
+			$result,
636
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
637
+		);
638
+		// if this is a CPT, we need to set the global $post to it,
639
+		// otherwise shortcodes etc won't work properly while rendering it
640
+		if ($model instanceof \EEM_CPT_Base) {
641
+			$do_chevy_shuffle = true;
642
+		} else {
643
+			$do_chevy_shuffle = false;
644
+		}
645
+		if ($do_chevy_shuffle) {
646
+			global $post;
647
+			$old_post = $post;
648
+			$post = get_post($result[ $model->primary_key_name() ]);
649
+			if (! $post instanceof \WP_Post) {
650
+				// well that's weird, because $result is what we JUST fetched from the database
651
+				throw new RestException(
652
+					'error_fetching_post_from_database_results',
653
+					esc_html__(
654
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
655
+						'event_espresso'
656
+					)
657
+				);
658
+			}
659
+			$model_object_classname = 'EE_' . $model->get_this_model_name();
660
+			$post->{$model_object_classname} = \EE_Registry::instance()->load_class(
661
+				$model_object_classname,
662
+				$result,
663
+				false,
664
+				false
665
+			);
666
+		}
667
+		foreach ($result as $field_name => $field_value) {
668
+			$field_obj = $model->field_settings_for($field_name);
669
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
670
+				unset($result[ $field_name ]);
671
+			} elseif ($this->isSubclassOfOne(
672
+				$field_obj,
673
+				$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
674
+			)
675
+			) {
676
+				$result[ $field_name ] = array(
677
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
678
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
679
+				);
680
+			} elseif ($this->isSubclassOfOne(
681
+				$field_obj,
682
+				$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
683
+			)
684
+			) {
685
+				$result[ $field_name ] = array(
686
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
687
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
688
+				);
689
+			} elseif ($field_obj instanceof \EE_Datetime_Field) {
690
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
691
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
692
+				if (is_null($field_value)) {
693
+					$field_value = $field_obj->getDefaultDateTimeObj();
694
+				}
695
+				if (is_null($field_value)) {
696
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
697
+						$field_obj,
698
+						$field_value,
699
+						$this->getModelVersionInfo()->requestedVersion()
700
+					);
701
+				} else {
702
+					$timezone = $field_value->getTimezone();
703
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
704
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
705
+						$field_obj,
706
+						$field_value,
707
+						$this->getModelVersionInfo()->requestedVersion()
708
+					);
709
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
710
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
711
+						$field_obj,
712
+						$field_value,
713
+						$this->getModelVersionInfo()->requestedVersion()
714
+					);
715
+				}
716
+				$result[ $field_name . '_gmt' ] = $gmt_date;
717
+				$result[ $field_name ] = $local_date;
718
+			} else {
719
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
720
+			}
721
+		}
722
+		if ($do_chevy_shuffle) {
723
+			$post = $old_post;
724
+		}
725
+		return $result;
726
+	}
727
+
728
+
729
+	/**
730
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
731
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
732
+	 * representation using $field_obj->prepare_for_set_from_db())
733
+	 *
734
+	 * @param EE_Model_Field_Base $field_obj
735
+	 * @param mixed               $value  as it's stored on a model object
736
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
737
+	 * @return mixed
738
+	 * @throws ObjectDetectedException if $value contains a PHP object
739
+	 */
740
+	protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
741
+	{
742
+		$value = $field_obj->prepare_for_set_from_db($value);
743
+		switch ($format) {
744
+			case 'pretty':
745
+				$value = $field_obj->prepare_for_pretty_echoing($value);
746
+				break;
747
+			case 'normal':
748
+			default:
749
+				$value = $field_obj->prepare_for_get($value);
750
+				break;
751
+		}
752
+		return ModelDataTranslator::prepareFieldValuesForJson(
753
+			$field_obj,
754
+			$value,
755
+			$this->getModelVersionInfo()->requestedVersion()
756
+		);
757
+	}
758
+
759
+
760
+	/**
761
+	 * Adds a few extra fields to the entity response
762
+	 *
763
+	 * @param EEM_Base $model
764
+	 * @param array    $db_row
765
+	 * @param array    $entity_array
766
+	 * @return array modified entity
767
+	 */
768
+	protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
769
+	{
770
+		if ($model instanceof EEM_CPT_Base) {
771
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
772
+		}
773
+		return $entity_array;
774
+	}
775
+
776
+
777
+	/**
778
+	 * Gets links we want to add to the response
779
+	 *
780
+	 * @global \WP_REST_Server $wp_rest_server
781
+	 * @param EEM_Base         $model
782
+	 * @param array            $db_row
783
+	 * @param array            $entity_array
784
+	 * @return array the _links item in the entity
785
+	 */
786
+	protected function getEntityLinks($model, $db_row, $entity_array)
787
+	{
788
+		// add basic links
789
+		$links = array();
790
+		if ($model->has_primary_key_field()) {
791
+			$links['self'] = array(
792
+				array(
793
+					'href' => $this->getVersionedLinkTo(
794
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
795
+						. '/'
796
+						. $entity_array[ $model->primary_key_name() ]
797
+					),
798
+				),
799
+			);
800
+		}
801
+		$links['collection'] = array(
802
+			array(
803
+				'href' => $this->getVersionedLinkTo(
804
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
805
+				),
806
+			),
807
+		);
808
+		// add links to related models
809
+		if ($model->has_primary_key_field()) {
810
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
811
+				$related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
812
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
813
+					array(
814
+						'href'   => $this->getVersionedLinkTo(
815
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
816
+							. '/'
817
+							. $entity_array[ $model->primary_key_name() ]
818
+							. '/'
819
+							. $related_model_part
820
+						),
821
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
822
+					),
823
+				);
824
+			}
825
+		}
826
+		return $links;
827
+	}
828
+
829
+
830
+	/**
831
+	 * Adds the included models indicated in the request to the entity provided
832
+	 *
833
+	 * @param EEM_Base        $model
834
+	 * @param WP_REST_Request $rest_request
835
+	 * @param array           $entity_array
836
+	 * @param array           $db_row
837
+	 * @return array the modified entity
838
+	 */
839
+	protected function includeRequestedModels(
840
+		EEM_Base $model,
841
+		WP_REST_Request $rest_request,
842
+		$entity_array,
843
+		$db_row = array()
844
+	) {
845
+		// if $db_row not included, hope the entity array has what we need
846
+		if (! $db_row) {
847
+			$db_row = $entity_array;
848
+		}
849
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
850
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
851
+		// if they passed in * or didn't specify any includes, return everything
852
+		if (! in_array('*', $includes_for_this_model)
853
+			&& ! empty($includes_for_this_model)
854
+		) {
855
+			if ($model->has_primary_key_field()) {
856
+				// always include the primary key. ya just gotta know that at least
857
+				$includes_for_this_model[] = $model->primary_key_name();
858
+			}
859
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
860
+				$includes_for_this_model[] = '_calculated_fields';
861
+			}
862
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
863
+		}
864
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
865
+		foreach ($relation_settings as $relation_name => $relation_obj) {
866
+			$related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
867
+				$rest_request->get_param('include'),
868
+				$relation_name
869
+			);
870
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
871
+				$rest_request->get_param('calculate'),
872
+				$relation_name
873
+			);
874
+			// did they specify they wanted to include a related model, or
875
+			// specific fields from a related model?
876
+			// or did they specify to calculate a field from a related model?
877
+			if ($related_fields_to_include || $related_fields_to_calculate) {
878
+				// if so, we should include at least some part of the related model
879
+				$pretend_related_request = new WP_REST_Request();
880
+				$pretend_related_request->set_query_params(
881
+					array(
882
+						'caps'      => $rest_request->get_param('caps'),
883
+						'include'   => $related_fields_to_include,
884
+						'calculate' => $related_fields_to_calculate,
885
+					)
886
+				);
887
+				$pretend_related_request->add_header('no_rest_headers', true);
888
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
889
+					$model->get_index_primary_key_string(
890
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
891
+					)
892
+				);
893
+				$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
894
+					$primary_model_query_params,
895
+					$relation_obj,
896
+					$pretend_related_request
897
+				);
898
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results
899
+																							 instanceof
900
+																							 WP_Error
901
+					? null
902
+					: $related_results;
903
+			}
904
+		}
905
+		return $entity_array;
906
+	}
907
+
908
+
909
+	/**
910
+	 * Returns a new array with all the names of models removed. Eg
911
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
912
+	 *
913
+	 * @param array $arr
914
+	 * @return array
915
+	 */
916
+	private function removeModelNamesFromArray($arr)
917
+	{
918
+		return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
919
+	}
920
+
921
+
922
+	/**
923
+	 * Gets the calculated fields for the response
924
+	 *
925
+	 * @param EEM_Base        $model
926
+	 * @param array           $wpdb_row
927
+	 * @param WP_REST_Request $rest_request
928
+	 * @return \stdClass the _calculations item in the entity
929
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
930
+	 * did, let's know about it ASAP, so let the exception bubble up)
931
+	 */
932
+	protected function getEntityCalculations($model, $wpdb_row, $rest_request)
933
+	{
934
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
935
+			$rest_request->get_param('calculate'),
936
+			''
937
+		);
938
+		// note: setting calculate=* doesn't do anything
939
+		$calculated_fields_to_return = new \stdClass();
940
+		foreach ($calculated_fields as $field_to_calculate) {
941
+			try {
942
+				$calculated_fields_to_return->$field_to_calculate = ModelDataTranslator::prepareFieldValueForJson(
943
+					null,
944
+					$this->fields_calculator->retrieveCalculatedFieldValue(
945
+						$model,
946
+						$field_to_calculate,
947
+						$wpdb_row,
948
+						$rest_request,
949
+						$this
950
+					),
951
+					$this->getModelVersionInfo()->requestedVersion()
952
+				);
953
+			} catch (RestException $e) {
954
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
955
+				$this->setResponseHeader(
956
+					'Notices-Field-Calculation-Errors['
957
+					. $e->getStringCode()
958
+					. ']['
959
+					. $model->get_this_model_name()
960
+					. ']['
961
+					. $field_to_calculate
962
+					. ']',
963
+					$e->getMessage(),
964
+					true
965
+				);
966
+			}
967
+		}
968
+		return $calculated_fields_to_return;
969
+	}
970
+
971
+
972
+	/**
973
+	 * Gets the full URL to the resource, taking the requested version into account
974
+	 *
975
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
976
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
977
+	 */
978
+	public function getVersionedLinkTo($link_part_after_version_and_slash)
979
+	{
980
+		return rest_url(
981
+			EED_Core_Rest_Api::get_versioned_route_to(
982
+				$link_part_after_version_and_slash,
983
+				$this->getModelVersionInfo()->requestedVersion()
984
+			)
985
+		);
986
+	}
987
+
988
+
989
+	/**
990
+	 * Gets the correct lowercase name for the relation in the API according
991
+	 * to the relation's type
992
+	 *
993
+	 * @param string                  $relation_name
994
+	 * @param \EE_Model_Relation_Base $relation_obj
995
+	 * @return string
996
+	 */
997
+	public static function getRelatedEntityName($relation_name, $relation_obj)
998
+	{
999
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1000
+			return strtolower($relation_name);
1001
+		} else {
1002
+			return EEH_Inflector::pluralize_and_lower($relation_name);
1003
+		}
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * Gets the one model object with the specified id for the specified model
1009
+	 *
1010
+	 * @param EEM_Base        $model
1011
+	 * @param WP_REST_Request $request
1012
+	 * @return array|WP_Error
1013
+	 */
1014
+	public function getEntityFromModel($model, $request)
1015
+	{
1016
+		$context = $this->validateContext($request->get_param('caps'));
1017
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1018
+	}
1019
+
1020
+
1021
+	/**
1022
+	 * If a context is provided which isn't valid, maybe it was added in a future
1023
+	 * version so just treat it as a default read
1024
+	 *
1025
+	 * @param string $context
1026
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1027
+	 */
1028
+	public function validateContext($context)
1029
+	{
1030
+		if (! $context) {
1031
+			$context = EEM_Base::caps_read;
1032
+		}
1033
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1034
+		if (in_array($context, $valid_contexts)) {
1035
+			return $context;
1036
+		} else {
1037
+			return EEM_Base::caps_read;
1038
+		}
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * Verifies the passed in value is an allowable default where conditions value.
1044
+	 *
1045
+	 * @param $default_query_params
1046
+	 * @return string
1047
+	 */
1048
+	public function validateDefaultQueryParams($default_query_params)
1049
+	{
1050
+		$valid_default_where_conditions_for_api_calls = array(
1051
+			EEM_Base::default_where_conditions_all,
1052
+			EEM_Base::default_where_conditions_minimum_all,
1053
+			EEM_Base::default_where_conditions_minimum_others,
1054
+		);
1055
+		if (! $default_query_params) {
1056
+			$default_query_params = EEM_Base::default_where_conditions_all;
1057
+		}
1058
+		if (in_array(
1059
+			$default_query_params,
1060
+			$valid_default_where_conditions_for_api_calls,
1061
+			true
1062
+		)) {
1063
+			return $default_query_params;
1064
+		} else {
1065
+			return EEM_Base::default_where_conditions_all;
1066
+		}
1067
+	}
1068
+
1069
+
1070
+	/**
1071
+	 * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1072
+	 * Note: right now the query parameter keys for fields (and related fields)
1073
+	 * can be left as-is, but it's quite possible this will change someday.
1074
+	 * Also, this method's contents might be candidate for moving to Model_Data_Translator
1075
+	 *
1076
+	 * @param EEM_Base $model
1077
+	 * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1078
+	 * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1079
+	 *                                    that absolutely no results should be returned
1080
+	 * @throws EE_Error
1081
+	 * @throws RestException
1082
+	 */
1083
+	public function createModelQueryParams($model, $query_parameters)
1084
+	{
1085
+		$model_query_params = array();
1086
+		if (isset($query_parameters['where'])) {
1087
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1088
+				$query_parameters['where'],
1089
+				$model,
1090
+				$this->getModelVersionInfo()->requestedVersion()
1091
+			);
1092
+		}
1093
+		if (isset($query_parameters['order_by'])) {
1094
+			$order_by = $query_parameters['order_by'];
1095
+		} elseif (isset($query_parameters['orderby'])) {
1096
+			$order_by = $query_parameters['orderby'];
1097
+		} else {
1098
+			$order_by = null;
1099
+		}
1100
+		if ($order_by !== null) {
1101
+			if (is_array($order_by)) {
1102
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1103
+			} else {
1104
+				// it's a single item
1105
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1106
+			}
1107
+			$model_query_params['order_by'] = $order_by;
1108
+		}
1109
+		if (isset($query_parameters['group_by'])) {
1110
+			$group_by = $query_parameters['group_by'];
1111
+		} elseif (isset($query_parameters['groupby'])) {
1112
+			$group_by = $query_parameters['groupby'];
1113
+		} else {
1114
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1115
+		}
1116
+		// make sure they're all real names
1117
+		if (is_array($group_by)) {
1118
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1119
+		}
1120
+		if ($group_by !== null) {
1121
+			$model_query_params['group_by'] = $group_by;
1122
+		}
1123
+		if (isset($query_parameters['having'])) {
1124
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1125
+				$query_parameters['having'],
1126
+				$model,
1127
+				$this->getModelVersionInfo()->requestedVersion()
1128
+			);
1129
+		}
1130
+		if (isset($query_parameters['order'])) {
1131
+			$model_query_params['order'] = $query_parameters['order'];
1132
+		}
1133
+		if (isset($query_parameters['mine'])) {
1134
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1135
+		}
1136
+		if (isset($query_parameters['limit'])) {
1137
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1138
+			if (! is_array($query_parameters['limit'])) {
1139
+				$limit_array = explode(',', (string) $query_parameters['limit']);
1140
+			} else {
1141
+				$limit_array = $query_parameters['limit'];
1142
+			}
1143
+			$sanitized_limit = array();
1144
+			foreach ($limit_array as $key => $limit_part) {
1145
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1146
+					throw new EE_Error(
1147
+						sprintf(
1148
+							__(
1149
+							// @codingStandardsIgnoreStart
1150
+								'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1151
+								// @codingStandardsIgnoreEnd
1152
+								'event_espresso'
1153
+							),
1154
+							wp_json_encode($query_parameters['limit'])
1155
+						)
1156
+					);
1157
+				}
1158
+				$sanitized_limit[] = (int) $limit_part;
1159
+			}
1160
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1161
+		} else {
1162
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1163
+		}
1164
+		if (isset($query_parameters['caps'])) {
1165
+			$model_query_params['caps'] = $this->validateContext($query_parameters['caps']);
1166
+		} else {
1167
+			$model_query_params['caps'] = EEM_Base::caps_read;
1168
+		}
1169
+		if (isset($query_parameters['default_where_conditions'])) {
1170
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1171
+				$query_parameters['default_where_conditions']
1172
+			);
1173
+		}
1174
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * Changes the REST-style query params for use in the models
1180
+	 *
1181
+	 * @deprecated
1182
+	 * @param EEM_Base $model
1183
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1184
+	 * @return array
1185
+	 */
1186
+	public function prepareRestQueryParamsKeyForModels($model, $query_params)
1187
+	{
1188
+		$model_ready_query_params = array();
1189
+		foreach ($query_params as $key => $value) {
1190
+			if (is_array($value)) {
1191
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1192
+			} else {
1193
+				$model_ready_query_params[ $key ] = $value;
1194
+			}
1195
+		}
1196
+		return $model_ready_query_params;
1197
+	}
1198
+
1199
+
1200
+	/**
1201
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1202
+	 * @param $model
1203
+	 * @param $query_params
1204
+	 * @return array
1205
+	 */
1206
+	public function prepareRestQueryParamsValuesForModels($model, $query_params)
1207
+	{
1208
+		$model_ready_query_params = array();
1209
+		foreach ($query_params as $key => $value) {
1210
+			if (is_array($value)) {
1211
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1212
+			} else {
1213
+				$model_ready_query_params[ $key ] = $value;
1214
+			}
1215
+		}
1216
+		return $model_ready_query_params;
1217
+	}
1218
+
1219
+
1220
+	/**
1221
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1222
+	 * If no prefix is specified, returns items with no period.
1223
+	 *
1224
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1225
+	 * @param string       $prefix            "Event" or "foobar"
1226
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1227
+	 *                                        we only return strings starting with that and a period; if no prefix was
1228
+	 *                                        specified we return all items containing NO periods
1229
+	 */
1230
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1231
+	{
1232
+		if (is_string($string_to_explode)) {
1233
+			$exploded_contents = explode(',', $string_to_explode);
1234
+		} elseif (is_array($string_to_explode)) {
1235
+			$exploded_contents = $string_to_explode;
1236
+		} else {
1237
+			$exploded_contents = array();
1238
+		}
1239
+		// if the string was empty, we want an empty array
1240
+		$exploded_contents = array_filter($exploded_contents);
1241
+		$contents_with_prefix = array();
1242
+		foreach ($exploded_contents as $item) {
1243
+			$item = trim($item);
1244
+			// if no prefix was provided, so we look for items with no "." in them
1245
+			if (! $prefix) {
1246
+				// does this item have a period?
1247
+				if (strpos($item, '.') === false) {
1248
+					// if not, then its what we're looking for
1249
+					$contents_with_prefix[] = $item;
1250
+				}
1251
+			} elseif (strpos($item, $prefix . '.') === 0) {
1252
+				// this item has the prefix and a period, grab it
1253
+				$contents_with_prefix[] = substr(
1254
+					$item,
1255
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1256
+				);
1257
+			} elseif ($item === $prefix) {
1258
+				// this item is JUST the prefix
1259
+				// so let's grab everything after, which is a blank string
1260
+				$contents_with_prefix[] = '';
1261
+			}
1262
+		}
1263
+		return $contents_with_prefix;
1264
+	}
1265
+
1266
+
1267
+	/**
1268
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1269
+	 * Deprecated because its return values were really quite confusing- sometimes it returned
1270
+	 * an empty array (when the include string was blank or '*') or sometimes it returned
1271
+	 * array('*') (when you provided a model and a model of that kind was found).
1272
+	 * Parses the $include_string so we fetch all the field names relating to THIS model
1273
+	 * (ie have NO period in them), or for the provided model (ie start with the model
1274
+	 * name and then a period).
1275
+	 * @param string $include_string @see Read:handle_request_get_all
1276
+	 * @param string $model_name
1277
+	 * @return array of fields for this model. If $model_name is provided, then
1278
+	 *                               the fields for that model, with the model's name removed from each.
1279
+	 *                               If $include_string was blank or '*' returns an empty array
1280
+	 */
1281
+	public function extractIncludesForThisModel($include_string, $model_name = null)
1282
+	{
1283
+		if (is_array($include_string)) {
1284
+			$include_string = implode(',', $include_string);
1285
+		}
1286
+		if ($include_string === '*' || $include_string === '') {
1287
+			return array();
1288
+		}
1289
+		$includes = explode(',', $include_string);
1290
+		$extracted_fields_to_include = array();
1291
+		if ($model_name) {
1292
+			foreach ($includes as $field_to_include) {
1293
+				$field_to_include = trim($field_to_include);
1294
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1295
+					// found the model name at the exact start
1296
+					$field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1297
+					$extracted_fields_to_include[] = $field_sans_model_name;
1298
+				} elseif ($field_to_include == $model_name) {
1299
+					$extracted_fields_to_include[] = '*';
1300
+				}
1301
+			}
1302
+		} else {
1303
+			// look for ones with no period
1304
+			foreach ($includes as $field_to_include) {
1305
+				$field_to_include = trim($field_to_include);
1306
+				if (strpos($field_to_include, '.') === false
1307
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1308
+				) {
1309
+					$extracted_fields_to_include[] = $field_to_include;
1310
+				}
1311
+			}
1312
+		}
1313
+		return $extracted_fields_to_include;
1314
+	}
1315
+
1316
+
1317
+	/**
1318
+	 * Gets the single item using the model according to the request in the context given, otherwise
1319
+	 * returns that it's inaccessible to the current user
1320
+	 *
1321
+	 * @param EEM_Base        $model
1322
+	 * @param WP_REST_Request $request
1323
+	 * @param null            $context
1324
+	 * @return array|WP_Error
1325
+	 */
1326
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1327
+	{
1328
+		$query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1329
+		if ($model instanceof \EEM_Soft_Delete_Base) {
1330
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1331
+		}
1332
+		$restricted_query_params = $query_params;
1333
+		$restricted_query_params['caps'] = $context;
1334
+		$this->setDebugInfo('model query params', $restricted_query_params);
1335
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1336
+		if (! empty($model_rows)) {
1337
+			return $this->createEntityFromWpdbResult(
1338
+				$model,
1339
+				array_shift($model_rows),
1340
+				$request
1341
+			);
1342
+		} else {
1343
+			// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1344
+			$lowercase_model_name = strtolower($model->get_this_model_name());
1345
+			$model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
1346
+			if (! empty($model_rows_found_sans_restrictions)) {
1347
+				// you got shafted- it existed but we didn't want to tell you!
1348
+				return new WP_Error(
1349
+					'rest_user_cannot_' . $context,
1350
+					sprintf(
1351
+						__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1352
+						$context,
1353
+						strtolower($model->get_this_model_name()),
1354
+						Capabilities::getMissingPermissionsString(
1355
+							$model,
1356
+							$context
1357
+						)
1358
+					),
1359
+					array('status' => 403)
1360
+				);
1361
+			} else {
1362
+				// it's not you. It just doesn't exist
1363
+				return new WP_Error(
1364
+					sprintf('rest_%s_invalid_id', $lowercase_model_name),
1365
+					sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1366
+					array('status' => 404)
1367
+				);
1368
+			}
1369
+		}
1370
+	}
1371 1371
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelDataTranslator.php 1 patch
Indentation   +832 added lines, -832 removed lines patch added patch discarded remove patch
@@ -32,836 +32,836 @@
 block discarded – undo
32 32
 class ModelDataTranslator
33 33
 {
34 34
 
35
-    /**
36
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
37
-     * fields that COULD contain -1; so we use null
38
-     */
39
-    const EE_INF_IN_REST = null;
40
-
41
-
42
-    /**
43
-     * Prepares a possible array of input values from JSON for use by the models
44
-     *
45
-     * @param EE_Model_Field_Base $field_obj
46
-     * @param mixed               $original_value_maybe_array
47
-     * @param string              $requested_version
48
-     * @param string              $timezone_string treat values as being in this timezone
49
-     * @return mixed
50
-     * @throws RestException
51
-     */
52
-    public static function prepareFieldValuesFromJson(
53
-        $field_obj,
54
-        $original_value_maybe_array,
55
-        $requested_version,
56
-        $timezone_string = 'UTC'
57
-    ) {
58
-        if (is_array($original_value_maybe_array)
59
-            && ! $field_obj instanceof EE_Serialized_Text_Field
60
-        ) {
61
-            $new_value_maybe_array = array();
62
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
63
-                $new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
64
-                    $field_obj,
65
-                    $array_item,
66
-                    $requested_version,
67
-                    $timezone_string
68
-                );
69
-            }
70
-        } else {
71
-            $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
72
-                $field_obj,
73
-                $original_value_maybe_array,
74
-                $requested_version,
75
-                $timezone_string
76
-            );
77
-        }
78
-        return $new_value_maybe_array;
79
-    }
80
-
81
-
82
-    /**
83
-     * Prepares an array of field values FOR use in JSON/REST API
84
-     *
85
-     * @param EE_Model_Field_Base $field_obj
86
-     * @param mixed               $original_value_maybe_array
87
-     * @param string              $request_version (eg 4.8.36)
88
-     * @return array
89
-     */
90
-    public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
91
-    {
92
-        if (is_array($original_value_maybe_array)) {
93
-            $new_value = array();
94
-            foreach ($original_value_maybe_array as $key => $value) {
95
-                $new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
96
-                    $field_obj,
97
-                    $value,
98
-                    $request_version
99
-                );
100
-            }
101
-        } else {
102
-            $new_value = ModelDataTranslator::prepareFieldValueForJson(
103
-                $field_obj,
104
-                $original_value_maybe_array,
105
-                $request_version
106
-            );
107
-        }
108
-        return $new_value;
109
-    }
110
-
111
-
112
-    /**
113
-     * Prepares incoming data from the json or $_REQUEST parameters for the models'
114
-     * "$query_params".
115
-     *
116
-     * @param EE_Model_Field_Base $field_obj
117
-     * @param mixed               $original_value
118
-     * @param string              $requested_version
119
-     * @param string              $timezone_string treat values as being in this timezone
120
-     * @return mixed
121
-     * @throws RestException
122
-     * @throws DomainException
123
-     * @throws EE_Error
124
-     */
125
-    public static function prepareFieldValueFromJson(
126
-        $field_obj,
127
-        $original_value,
128
-        $requested_version,
129
-        $timezone_string = 'UTC' // UTC
130
-    ) {
131
-        // check if they accidentally submitted an error value. If so throw an exception
132
-        if (is_array($original_value)
133
-            && isset($original_value['error_code'], $original_value['error_message'])) {
134
-            throw new RestException(
135
-                'rest_submitted_error_value',
136
-                sprintf(
137
-                    esc_html__(
138
-                        'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
139
-                        'event_espresso'
140
-                    ),
141
-                    $field_obj->get_name()
142
-                ),
143
-                array(
144
-                    'status' => 400,
145
-                )
146
-            );
147
-        }
148
-        // double-check for serialized PHP. We never accept serialized PHP. No way Jose.
149
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
150
-        $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
151
-        $new_value = null;
152
-        // walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
153
-        // way Jose.
154
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
155
-        if ($field_obj instanceof EE_Infinite_Integer_Field
156
-            && in_array($original_value, array(null, ''), true)
157
-        ) {
158
-            $new_value = EE_INF;
159
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
160
-            $new_value = rest_parse_date(
161
-                self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
162
-            );
163
-            if ($new_value === false) {
164
-                throw new RestException(
165
-                    'invalid_format_for_timestamp',
166
-                    sprintf(
167
-                        esc_html__(
168
-                            '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.',
169
-                            'event_espresso'
170
-                        ),
171
-                        'RFC3339',
172
-                        'ISO8601',
173
-                        $original_value
174
-                    ),
175
-                    array(
176
-                        'status' => 400,
177
-                    )
178
-                );
179
-            }
180
-        } else {
181
-            $new_value = $original_value;
182
-        }
183
-        return $new_value;
184
-    }
185
-
186
-
187
-    /**
188
-     * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
189
-     * information via details obtained from the host site.
190
-     *
191
-     * @param string            $original_timestamp
192
-     * @param EE_Datetime_Field $datetime_field
193
-     * @param                   $timezone_string
194
-     * @return string
195
-     * @throws DomainException
196
-     */
197
-    private static function getTimestampWithTimezoneOffset(
198
-        $original_timestamp,
199
-        EE_Datetime_Field $datetime_field,
200
-        $timezone_string
201
-    ) {
202
-        // already have timezone information?
203
-        if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
204
-            // yes, we're ignoring the timezone.
205
-            return $original_timestamp;
206
-        }
207
-        // need to append timezone
208
-        list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
209
-            $datetime_field->get_timezone_offset(
210
-                new \DateTimeZone($timezone_string),
211
-                $original_timestamp
212
-            )
213
-        );
214
-        $offset_string =
215
-            str_pad(
216
-                floor($offset_secs / HOUR_IN_SECONDS),
217
-                2,
218
-                '0',
219
-                STR_PAD_LEFT
220
-            )
221
-            . ':'
222
-            . str_pad(
223
-                ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
224
-                2,
225
-                '0',
226
-                STR_PAD_LEFT
227
-            );
228
-        return $original_timestamp . $offset_sign . $offset_string;
229
-    }
230
-
231
-
232
-    /**
233
-     * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
234
-     * think that can happen). If $data is an array, recurses into its keys and values
235
-     *
236
-     * @param mixed $data
237
-     * @throws RestException
238
-     * @return void
239
-     */
240
-    public static function throwExceptionIfContainsSerializedData($data)
241
-    {
242
-        if (is_array($data)) {
243
-            foreach ($data as $key => $value) {
244
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
245
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
246
-            }
247
-        } else {
248
-            if (is_serialized($data) || is_object($data)) {
249
-                throw new RestException(
250
-                    'serialized_data_submission_prohibited',
251
-                    esc_html__(
252
-                    // @codingStandardsIgnoreStart
253
-                        'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
254
-                        // @codingStandardsIgnoreEnd
255
-                        'event_espresso'
256
-                    )
257
-                );
258
-            }
259
-        }
260
-    }
261
-
262
-
263
-    /**
264
-     * determines what's going on with them timezone strings
265
-     *
266
-     * @param int $timezone_offset
267
-     * @return array
268
-     */
269
-    private static function parseTimezoneOffset($timezone_offset)
270
-    {
271
-        $first_char = substr((string) $timezone_offset, 0, 1);
272
-        if ($first_char === '+' || $first_char === '-') {
273
-            $offset_sign = $first_char;
274
-            $offset_secs = substr((string) $timezone_offset, 1);
275
-        } else {
276
-            $offset_sign = '+';
277
-            $offset_secs = $timezone_offset;
278
-        }
279
-        return array($offset_sign, $offset_secs);
280
-    }
281
-
282
-
283
-    /**
284
-     * Prepares a field's value for display in the API
285
-     *
286
-     * @param EE_Model_Field_Base $field_obj
287
-     * @param mixed               $original_value
288
-     * @param string              $requested_version
289
-     * @return mixed
290
-     */
291
-    public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
292
-    {
293
-        if ($original_value === EE_INF) {
294
-            $new_value = ModelDataTranslator::EE_INF_IN_REST;
295
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
296
-            if (is_string($original_value)) {
297
-                // did they submit a string of a unix timestamp?
298
-                if (is_numeric($original_value)) {
299
-                    $datetime_obj = new \DateTime();
300
-                    $datetime_obj->setTimestamp((int) $original_value);
301
-                } else {
302
-                    // first, check if its a MySQL timestamp in GMT
303
-                    $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
304
-                }
305
-                if (! $datetime_obj instanceof \DateTime) {
306
-                    // so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
307
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
308
-                }
309
-                $original_value = $datetime_obj;
310
-            }
311
-            if ($original_value instanceof \DateTime) {
312
-                $new_value = $original_value->format('Y-m-d H:i:s');
313
-            } elseif (is_int($original_value) || is_float($original_value)) {
314
-                $new_value = date('Y-m-d H:i:s', $original_value);
315
-            } elseif ($original_value === null || $original_value === '') {
316
-                $new_value = null;
317
-            } else {
318
-                // so it's not a datetime object, unix timestamp (as string or int),
319
-                // MySQL timestamp, or even a string in the field object's format. So no idea what it is
320
-                throw new \EE_Error(
321
-                    sprintf(
322
-                        esc_html__(
323
-                        // @codingStandardsIgnoreStart
324
-                            '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".',
325
-                            // @codingStandardsIgnoreEnd
326
-                            'event_espresso'
327
-                        ),
328
-                        $original_value,
329
-                        $field_obj->get_name(),
330
-                        $field_obj->get_model_name(),
331
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
332
-                    )
333
-                );
334
-            }
335
-            if ($new_value !== null) {
336
-                $new_value = mysql_to_rfc3339($new_value);
337
-            }
338
-        } else {
339
-            $new_value = $original_value;
340
-        }
341
-        // are we about to send an object? just don't. We have no good way to represent it in JSON.
342
-        // can't just check using is_object() because that missed PHP incomplete objects
343
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
344
-            $new_value = array(
345
-                'error_code'    => 'php_object_not_return',
346
-                'error_message' => esc_html__(
347
-                    'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
348
-                    'event_espresso'
349
-                ),
350
-            );
351
-        }
352
-        return apply_filters(
353
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
354
-            $new_value,
355
-            $field_obj,
356
-            $original_value,
357
-            $requested_version
358
-        );
359
-    }
360
-
361
-
362
-    /**
363
-     * Prepares condition-query-parameters (like what's in where and having) from
364
-     * the format expected in the API to use in the models
365
-     *
366
-     * @param array    $inputted_query_params_of_this_type
367
-     * @param EEM_Base $model
368
-     * @param string   $requested_version
369
-     * @param boolean  $writing whether this data will be written to the DB, or if we're just building a query.
370
-     *                          If we're writing to the DB, we don't expect any operators, or any logic query
371
-     *                          parameters, and we also won't accept serialized data unless the current user has
372
-     *                          unfiltered_html.
373
-     * @return array
374
-     * @throws DomainException
375
-     * @throws RestException
376
-     * @throws EE_Error
377
-     */
378
-    public static function prepareConditionsQueryParamsForModels(
379
-        $inputted_query_params_of_this_type,
380
-        EEM_Base $model,
381
-        $requested_version,
382
-        $writing = false
383
-    ) {
384
-        $query_param_for_models = array();
385
-        $valid_operators = $model->valid_operators();
386
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
387
-            $is_gmt_datetime_field = false;
388
-            $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
389
-                $query_param_key
390
-            );
391
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
392
-                $query_param_sans_stars,
393
-                $model
394
-            );
395
-            // double-check is it a *_gmt field?
396
-            if (! $field instanceof EE_Model_Field_Base
397
-                && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
398
-            ) {
399
-                // yep, take off '_gmt', and find the field
400
-                $query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
401
-                $field = ModelDataTranslator::deduceFieldFromQueryParam(
402
-                    $query_param_key,
403
-                    $model
404
-                );
405
-                $timezone = 'UTC';
406
-                $is_gmt_datetime_field = true;
407
-            } elseif ($field instanceof EE_Datetime_Field) {
408
-                // so it's not a GMT field. Set the timezone on the model to the default
409
-                $timezone = \EEH_DTT_Helper::get_valid_timezone_string();
410
-            } else {
411
-                // just keep using what's already set for the timezone
412
-                $timezone = $model->get_timezone();
413
-            }
414
-            if ($field instanceof EE_Model_Field_Base) {
415
-                if (! $writing && is_array($query_param_value)) {
416
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
417
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
418
-                            throw new RestException(
419
-                                'numerically_indexed_array_of_values_only',
420
-                                sprintf(
421
-                                    esc_html__(
422
-                                        'The array provided for the parameter "%1$s" should be numerically indexed.',
423
-                                        'event_espresso'
424
-                                    ),
425
-                                    $query_param_key
426
-                                ),
427
-                                array(
428
-                                    'status' => 400,
429
-                                )
430
-                            );
431
-                        }
432
-                    }
433
-                    // did they specify an operator?
434
-                    if (isset($query_param_value[0])
435
-                        && isset($valid_operators[ $query_param_value[0] ])
436
-                    ) {
437
-                        $op = $query_param_value[0];
438
-                        $translated_value = array($op);
439
-                        if (array_key_exists($op, $model->valid_in_style_operators())
440
-                            && isset($query_param_value[1])
441
-                            && ! isset($query_param_value[2])
442
-                        ) {
443
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
444
-                                $field,
445
-                                $query_param_value[1],
446
-                                $requested_version,
447
-                                $timezone
448
-                            );
449
-                        } elseif (array_key_exists($op, $model->valid_between_style_operators())
450
-                                  && isset($query_param_value[1])
451
-                                  && is_array($query_param_value[1])
452
-                                  && isset($query_param_key[1][0], $query_param_value[1][1])
453
-                                  && ! isset($query_param_value[1][2])
454
-                                  && ! isset($query_param_value[2])
455
-                        ) {
456
-                            $translated_value[] = array(
457
-                                ModelDataTranslator::prepareFieldValuesFromJson(
458
-                                    $field,
459
-                                    $query_param_value[1][0],
460
-                                    $requested_version,
461
-                                    $timezone
462
-                                ),
463
-                                ModelDataTranslator::prepareFieldValuesFromJson(
464
-                                    $field,
465
-                                    $query_param_value[1][1],
466
-                                    $requested_version,
467
-                                    $timezone
468
-                                )
469
-                            );
470
-                        } elseif (array_key_exists($op, $model->valid_like_style_operators())
471
-                                  && isset($query_param_value[1])
472
-                                  && ! isset($query_param_value[2])
473
-                        ) {
474
-                            // we want to leave this value mostly-as-is (eg don't force it to be a float
475
-                            // or a boolean or an enum value. Leave it as-is with wildcards etc)
476
-                            // but do verify it at least doesn't have any serialized data
477
-                            ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
478
-                            $translated_value[] = $query_param_value[1];
479
-                        } elseif (array_key_exists($op, $model->valid_null_style_operators())
480
-                                  && ! isset($query_param_value[1])) {
481
-                            // no arguments should have been provided, so don't look for any
482
-                        } elseif (isset($query_param_value[1])
483
-                                  && ! isset($query_param_value[2])
484
-                                  && ! array_key_exists(
485
-                                      $op,
486
-                                      array_merge(
487
-                                          $model->valid_in_style_operators(),
488
-                                          $model->valid_null_style_operators(),
489
-                                          $model->valid_like_style_operators(),
490
-                                          $model->valid_between_style_operators()
491
-                                      )
492
-                                  )
493
-                        ) {
494
-                            // it's a valid operator, but none of the exceptions. Treat it normally.
495
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
496
-                                $field,
497
-                                $query_param_value[1],
498
-                                $requested_version,
499
-                                $timezone
500
-                            );
501
-                        } else {
502
-                            // so they provided a valid operator, but wrong number of arguments
503
-                            if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
504
-                                throw new RestException(
505
-                                    'wrong_number_of_arguments',
506
-                                    sprintf(
507
-                                        esc_html__(
508
-                                            'The operator you provided, "%1$s" had the wrong number of arguments',
509
-                                            'event_espresso'
510
-                                        ),
511
-                                        $op
512
-                                    ),
513
-                                    array(
514
-                                        'status' => 400,
515
-                                    )
516
-                                );
517
-                            }
518
-                            $translated_value = null;
519
-                        }
520
-                    } else {
521
-                        // so they didn't provide a valid operator
522
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
523
-                            throw new RestException(
524
-                                'invalid_operator',
525
-                                sprintf(
526
-                                    esc_html__(
527
-                                        'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
528
-                                        'event_espresso'
529
-                                    ),
530
-                                    $query_param_key,
531
-                                    $query_param_value
532
-                                ),
533
-                                array(
534
-                                    'status' => 400,
535
-                                )
536
-                            );
537
-                        }
538
-                        // if we aren't in debug mode, then just try our best to fulfill the user's request
539
-                        $translated_value = null;
540
-                    }
541
-                } else {
542
-                    $translated_value = ModelDataTranslator::prepareFieldValueFromJson(
543
-                        $field,
544
-                        $query_param_value,
545
-                        $requested_version,
546
-                        $timezone
547
-                    );
548
-                }
549
-                if ((isset($query_param_for_models[ $query_param_key ]) && $is_gmt_datetime_field)
550
-                    || $translated_value === null
551
-                ) {
552
-                    // they have already provided a non-gmt field, ignore the gmt one. That's what WP core
553
-                    // currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
554
-                    // OR we couldn't create a translated value from their input
555
-                    continue;
556
-                }
557
-                $query_param_for_models[ $query_param_key ] = $translated_value;
558
-            } else {
559
-                // so this param doesn't correspond to a field eh?
560
-                if ($writing) {
561
-                    // always tell API clients about invalid parameters when they're creating data. Otherwise,
562
-                    // they are probably going to create invalid data
563
-                    throw new RestException(
564
-                        'invalid_field',
565
-                        sprintf(
566
-                            esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
567
-                            $query_param_key
568
-                        )
569
-                    );
570
-                } else {
571
-                    // so it's not for a field, is it a logic query param key?
572
-                    if (in_array(
573
-                        $query_param_sans_stars,
574
-                        $model->logic_query_param_keys()
575
-                    )) {
576
-                        $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
577
-                            $query_param_value,
578
-                            $model,
579
-                            $requested_version
580
-                        );
581
-                    } elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
582
-                        // only tell API clients they got it wrong if we're in debug mode
583
-                        // otherwise try our best ot fulfill their request by ignoring this invalid data
584
-                        throw new RestException(
585
-                            'invalid_parameter',
586
-                            sprintf(
587
-                                esc_html__(
588
-                                    'You provided an invalid parameter, with key "%1$s"',
589
-                                    'event_espresso'
590
-                                ),
591
-                                $query_param_sans_stars
592
-                            ),
593
-                            array(
594
-                                'status' => 400,
595
-                            )
596
-                        );
597
-                    }
598
-                }
599
-            }
600
-        }
601
-        return $query_param_for_models;
602
-    }
603
-
604
-
605
-    /**
606
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
607
-     * gmt date field name
608
-     *
609
-     * @param string $field_name
610
-     * @return boolean
611
-     */
612
-    public static function isGmtDateFieldName($field_name)
613
-    {
614
-        return substr(
615
-            ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
616
-            -4,
617
-            4
618
-        ) === '_gmt';
619
-    }
620
-
621
-
622
-    /**
623
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
624
-     *
625
-     * @param string $field_name
626
-     * @return string
627
-     */
628
-    public static function removeGmtFromFieldName($field_name)
629
-    {
630
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
631
-            return $field_name;
632
-        }
633
-        $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
634
-            $field_name
635
-        );
636
-        $query_param_sans_gmt_and_sans_stars = substr(
637
-            $query_param_sans_stars,
638
-            0,
639
-            strrpos(
640
-                $field_name,
641
-                '_gmt'
642
-            )
643
-        );
644
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
645
-    }
646
-
647
-
648
-    /**
649
-     * Takes a field name from the REST API and prepares it for the model querying
650
-     *
651
-     * @param string $field_name
652
-     * @return string
653
-     */
654
-    public static function prepareFieldNameFromJson($field_name)
655
-    {
656
-        if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
657
-            return ModelDataTranslator::removeGmtFromFieldName($field_name);
658
-        }
659
-        return $field_name;
660
-    }
661
-
662
-
663
-    /**
664
-     * Takes array of field names from REST API and prepares for models
665
-     *
666
-     * @param array $field_names
667
-     * @return array of field names (possibly include model prefixes)
668
-     */
669
-    public static function prepareFieldNamesFromJson(array $field_names)
670
-    {
671
-        $new_array = array();
672
-        foreach ($field_names as $key => $field_name) {
673
-            $new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
674
-        }
675
-        return $new_array;
676
-    }
677
-
678
-
679
-    /**
680
-     * Takes array where array keys are field names (possibly with model path prefixes)
681
-     * from the REST API and prepares them for model querying
682
-     *
683
-     * @param array $field_names_as_keys
684
-     * @return array
685
-     */
686
-    public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
687
-    {
688
-        $new_array = array();
689
-        foreach ($field_names_as_keys as $field_name => $value) {
690
-            $new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
691
-        }
692
-        return $new_array;
693
-    }
694
-
695
-
696
-    /**
697
-     * Prepares an array of model query params for use in the REST API
698
-     *
699
-     * @param array    $model_query_params
700
-     * @param EEM_Base $model
701
-     * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
702
-     *                                     REST API
703
-     * @return array which can be passed into the EE4 REST API when querying a model resource
704
-     * @throws EE_Error
705
-     */
706
-    public static function prepareQueryParamsForRestApi(
707
-        array $model_query_params,
708
-        EEM_Base $model,
709
-        $requested_version = null
710
-    ) {
711
-        if ($requested_version === null) {
712
-            $requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
713
-        }
714
-        $rest_query_params = $model_query_params;
715
-        if (isset($model_query_params[0])) {
716
-            $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
717
-                $model_query_params[0],
718
-                $model,
719
-                $requested_version
720
-            );
721
-            unset($rest_query_params[0]);
722
-        }
723
-        if (isset($model_query_params['having'])) {
724
-            $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
725
-                $model_query_params['having'],
726
-                $model,
727
-                $requested_version
728
-            );
729
-        }
730
-        return apply_filters(
731
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
732
-            $rest_query_params,
733
-            $model_query_params,
734
-            $model,
735
-            $requested_version
736
-        );
737
-    }
738
-
739
-
740
-    /**
741
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
742
-     *
743
-     * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
744
-     *                                                      passed into EEM_Base::get_all()
745
-     * @param EEM_Base $model
746
-     * @param string   $requested_version                   eg "4.8.36"
747
-     * @return array ready for use in the rest api query params
748
-     * @throws EE_Error
749
-     * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
750
-     *                                                      (which would be really unusual)
751
-     */
752
-    public static function prepareConditionsQueryParamsForRestApi(
753
-        $inputted_query_params_of_this_type,
754
-        EEM_Base $model,
755
-        $requested_version
756
-    ) {
757
-        $query_param_for_models = array();
758
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
759
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
760
-                ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
761
-                $model
762
-            );
763
-            if ($field instanceof EE_Model_Field_Base) {
764
-                // did they specify an operator?
765
-                if (is_array($query_param_value)) {
766
-                    $op = $query_param_value[0];
767
-                    $translated_value = array($op);
768
-                    if (isset($query_param_value[1])) {
769
-                        $value = $query_param_value[1];
770
-                        $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
771
-                            $field,
772
-                            $value,
773
-                            $requested_version
774
-                        );
775
-                    }
776
-                } else {
777
-                    $translated_value = ModelDataTranslator::prepareFieldValueForJson(
778
-                        $field,
779
-                        $query_param_value,
780
-                        $requested_version
781
-                    );
782
-                }
783
-                $query_param_for_models[ $query_param_key ] = $translated_value;
784
-            } else {
785
-                // so it's not for a field, assume it's a logic query param key
786
-                $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
787
-                    $query_param_value,
788
-                    $model,
789
-                    $requested_version
790
-                );
791
-            }
792
-        }
793
-        return $query_param_for_models;
794
-    }
795
-
796
-
797
-    /**
798
-     * @param $condition_query_param_key
799
-     * @return string
800
-     */
801
-    public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
802
-    {
803
-        $pos_of_star = strpos($condition_query_param_key, '*');
804
-        if ($pos_of_star === false) {
805
-            return $condition_query_param_key;
806
-        } else {
807
-            $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
808
-            return $condition_query_param_sans_star;
809
-        }
810
-    }
811
-
812
-
813
-    /**
814
-     * Takes the input parameter and finds the model field that it indicates.
815
-     *
816
-     * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
817
-     * @param EEM_Base $model
818
-     * @return EE_Model_Field_Base
819
-     * @throws EE_Error
820
-     */
821
-    public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
822
-    {
823
-        // ok, now proceed with deducing which part is the model's name, and which is the field's name
824
-        // which will help us find the database table and column
825
-        $query_param_parts = explode('.', $query_param_name);
826
-        if (empty($query_param_parts)) {
827
-            throw new EE_Error(
828
-                sprintf(
829
-                    __(
830
-                        '_extract_column_name is empty when trying to extract column and table name from %s',
831
-                        'event_espresso'
832
-                    ),
833
-                    $query_param_name
834
-                )
835
-            );
836
-        }
837
-        $number_of_parts = count($query_param_parts);
838
-        $last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
839
-        if ($number_of_parts === 1) {
840
-            $field_name = $last_query_param_part;
841
-        } else {// $number_of_parts >= 2
842
-            // the last part is the column name, and there are only 2parts. therefore...
843
-            $field_name = $last_query_param_part;
844
-            $model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
845
-        }
846
-        try {
847
-            return $model->field_settings_for($field_name, false);
848
-        } catch (EE_Error $e) {
849
-            return null;
850
-        }
851
-    }
852
-
853
-
854
-    /**
855
-     * Returns true if $data can be easily represented in JSON.
856
-     * Basically, objects and resources can't be represented in JSON easily.
857
-     *
858
-     * @param mixed $data
859
-     * @return bool
860
-     */
861
-    protected static function isRepresentableInJson($data)
862
-    {
863
-        return is_scalar($data)
864
-               || is_array($data)
865
-               || is_null($data);
866
-    }
35
+	/**
36
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
37
+	 * fields that COULD contain -1; so we use null
38
+	 */
39
+	const EE_INF_IN_REST = null;
40
+
41
+
42
+	/**
43
+	 * Prepares a possible array of input values from JSON for use by the models
44
+	 *
45
+	 * @param EE_Model_Field_Base $field_obj
46
+	 * @param mixed               $original_value_maybe_array
47
+	 * @param string              $requested_version
48
+	 * @param string              $timezone_string treat values as being in this timezone
49
+	 * @return mixed
50
+	 * @throws RestException
51
+	 */
52
+	public static function prepareFieldValuesFromJson(
53
+		$field_obj,
54
+		$original_value_maybe_array,
55
+		$requested_version,
56
+		$timezone_string = 'UTC'
57
+	) {
58
+		if (is_array($original_value_maybe_array)
59
+			&& ! $field_obj instanceof EE_Serialized_Text_Field
60
+		) {
61
+			$new_value_maybe_array = array();
62
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
63
+				$new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
64
+					$field_obj,
65
+					$array_item,
66
+					$requested_version,
67
+					$timezone_string
68
+				);
69
+			}
70
+		} else {
71
+			$new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
72
+				$field_obj,
73
+				$original_value_maybe_array,
74
+				$requested_version,
75
+				$timezone_string
76
+			);
77
+		}
78
+		return $new_value_maybe_array;
79
+	}
80
+
81
+
82
+	/**
83
+	 * Prepares an array of field values FOR use in JSON/REST API
84
+	 *
85
+	 * @param EE_Model_Field_Base $field_obj
86
+	 * @param mixed               $original_value_maybe_array
87
+	 * @param string              $request_version (eg 4.8.36)
88
+	 * @return array
89
+	 */
90
+	public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
91
+	{
92
+		if (is_array($original_value_maybe_array)) {
93
+			$new_value = array();
94
+			foreach ($original_value_maybe_array as $key => $value) {
95
+				$new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
96
+					$field_obj,
97
+					$value,
98
+					$request_version
99
+				);
100
+			}
101
+		} else {
102
+			$new_value = ModelDataTranslator::prepareFieldValueForJson(
103
+				$field_obj,
104
+				$original_value_maybe_array,
105
+				$request_version
106
+			);
107
+		}
108
+		return $new_value;
109
+	}
110
+
111
+
112
+	/**
113
+	 * Prepares incoming data from the json or $_REQUEST parameters for the models'
114
+	 * "$query_params".
115
+	 *
116
+	 * @param EE_Model_Field_Base $field_obj
117
+	 * @param mixed               $original_value
118
+	 * @param string              $requested_version
119
+	 * @param string              $timezone_string treat values as being in this timezone
120
+	 * @return mixed
121
+	 * @throws RestException
122
+	 * @throws DomainException
123
+	 * @throws EE_Error
124
+	 */
125
+	public static function prepareFieldValueFromJson(
126
+		$field_obj,
127
+		$original_value,
128
+		$requested_version,
129
+		$timezone_string = 'UTC' // UTC
130
+	) {
131
+		// check if they accidentally submitted an error value. If so throw an exception
132
+		if (is_array($original_value)
133
+			&& isset($original_value['error_code'], $original_value['error_message'])) {
134
+			throw new RestException(
135
+				'rest_submitted_error_value',
136
+				sprintf(
137
+					esc_html__(
138
+						'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
139
+						'event_espresso'
140
+					),
141
+					$field_obj->get_name()
142
+				),
143
+				array(
144
+					'status' => 400,
145
+				)
146
+			);
147
+		}
148
+		// double-check for serialized PHP. We never accept serialized PHP. No way Jose.
149
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
150
+		$timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
151
+		$new_value = null;
152
+		// walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
153
+		// way Jose.
154
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
155
+		if ($field_obj instanceof EE_Infinite_Integer_Field
156
+			&& in_array($original_value, array(null, ''), true)
157
+		) {
158
+			$new_value = EE_INF;
159
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
160
+			$new_value = rest_parse_date(
161
+				self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
162
+			);
163
+			if ($new_value === false) {
164
+				throw new RestException(
165
+					'invalid_format_for_timestamp',
166
+					sprintf(
167
+						esc_html__(
168
+							'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.',
169
+							'event_espresso'
170
+						),
171
+						'RFC3339',
172
+						'ISO8601',
173
+						$original_value
174
+					),
175
+					array(
176
+						'status' => 400,
177
+					)
178
+				);
179
+			}
180
+		} else {
181
+			$new_value = $original_value;
182
+		}
183
+		return $new_value;
184
+	}
185
+
186
+
187
+	/**
188
+	 * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
189
+	 * information via details obtained from the host site.
190
+	 *
191
+	 * @param string            $original_timestamp
192
+	 * @param EE_Datetime_Field $datetime_field
193
+	 * @param                   $timezone_string
194
+	 * @return string
195
+	 * @throws DomainException
196
+	 */
197
+	private static function getTimestampWithTimezoneOffset(
198
+		$original_timestamp,
199
+		EE_Datetime_Field $datetime_field,
200
+		$timezone_string
201
+	) {
202
+		// already have timezone information?
203
+		if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
204
+			// yes, we're ignoring the timezone.
205
+			return $original_timestamp;
206
+		}
207
+		// need to append timezone
208
+		list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
209
+			$datetime_field->get_timezone_offset(
210
+				new \DateTimeZone($timezone_string),
211
+				$original_timestamp
212
+			)
213
+		);
214
+		$offset_string =
215
+			str_pad(
216
+				floor($offset_secs / HOUR_IN_SECONDS),
217
+				2,
218
+				'0',
219
+				STR_PAD_LEFT
220
+			)
221
+			. ':'
222
+			. str_pad(
223
+				($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
224
+				2,
225
+				'0',
226
+				STR_PAD_LEFT
227
+			);
228
+		return $original_timestamp . $offset_sign . $offset_string;
229
+	}
230
+
231
+
232
+	/**
233
+	 * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
234
+	 * think that can happen). If $data is an array, recurses into its keys and values
235
+	 *
236
+	 * @param mixed $data
237
+	 * @throws RestException
238
+	 * @return void
239
+	 */
240
+	public static function throwExceptionIfContainsSerializedData($data)
241
+	{
242
+		if (is_array($data)) {
243
+			foreach ($data as $key => $value) {
244
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
245
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
246
+			}
247
+		} else {
248
+			if (is_serialized($data) || is_object($data)) {
249
+				throw new RestException(
250
+					'serialized_data_submission_prohibited',
251
+					esc_html__(
252
+					// @codingStandardsIgnoreStart
253
+						'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
254
+						// @codingStandardsIgnoreEnd
255
+						'event_espresso'
256
+					)
257
+				);
258
+			}
259
+		}
260
+	}
261
+
262
+
263
+	/**
264
+	 * determines what's going on with them timezone strings
265
+	 *
266
+	 * @param int $timezone_offset
267
+	 * @return array
268
+	 */
269
+	private static function parseTimezoneOffset($timezone_offset)
270
+	{
271
+		$first_char = substr((string) $timezone_offset, 0, 1);
272
+		if ($first_char === '+' || $first_char === '-') {
273
+			$offset_sign = $first_char;
274
+			$offset_secs = substr((string) $timezone_offset, 1);
275
+		} else {
276
+			$offset_sign = '+';
277
+			$offset_secs = $timezone_offset;
278
+		}
279
+		return array($offset_sign, $offset_secs);
280
+	}
281
+
282
+
283
+	/**
284
+	 * Prepares a field's value for display in the API
285
+	 *
286
+	 * @param EE_Model_Field_Base $field_obj
287
+	 * @param mixed               $original_value
288
+	 * @param string              $requested_version
289
+	 * @return mixed
290
+	 */
291
+	public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
292
+	{
293
+		if ($original_value === EE_INF) {
294
+			$new_value = ModelDataTranslator::EE_INF_IN_REST;
295
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
296
+			if (is_string($original_value)) {
297
+				// did they submit a string of a unix timestamp?
298
+				if (is_numeric($original_value)) {
299
+					$datetime_obj = new \DateTime();
300
+					$datetime_obj->setTimestamp((int) $original_value);
301
+				} else {
302
+					// first, check if its a MySQL timestamp in GMT
303
+					$datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
304
+				}
305
+				if (! $datetime_obj instanceof \DateTime) {
306
+					// so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
307
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
308
+				}
309
+				$original_value = $datetime_obj;
310
+			}
311
+			if ($original_value instanceof \DateTime) {
312
+				$new_value = $original_value->format('Y-m-d H:i:s');
313
+			} elseif (is_int($original_value) || is_float($original_value)) {
314
+				$new_value = date('Y-m-d H:i:s', $original_value);
315
+			} elseif ($original_value === null || $original_value === '') {
316
+				$new_value = null;
317
+			} else {
318
+				// so it's not a datetime object, unix timestamp (as string or int),
319
+				// MySQL timestamp, or even a string in the field object's format. So no idea what it is
320
+				throw new \EE_Error(
321
+					sprintf(
322
+						esc_html__(
323
+						// @codingStandardsIgnoreStart
324
+							'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".',
325
+							// @codingStandardsIgnoreEnd
326
+							'event_espresso'
327
+						),
328
+						$original_value,
329
+						$field_obj->get_name(),
330
+						$field_obj->get_model_name(),
331
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
332
+					)
333
+				);
334
+			}
335
+			if ($new_value !== null) {
336
+				$new_value = mysql_to_rfc3339($new_value);
337
+			}
338
+		} else {
339
+			$new_value = $original_value;
340
+		}
341
+		// are we about to send an object? just don't. We have no good way to represent it in JSON.
342
+		// can't just check using is_object() because that missed PHP incomplete objects
343
+		if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
344
+			$new_value = array(
345
+				'error_code'    => 'php_object_not_return',
346
+				'error_message' => esc_html__(
347
+					'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
348
+					'event_espresso'
349
+				),
350
+			);
351
+		}
352
+		return apply_filters(
353
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
354
+			$new_value,
355
+			$field_obj,
356
+			$original_value,
357
+			$requested_version
358
+		);
359
+	}
360
+
361
+
362
+	/**
363
+	 * Prepares condition-query-parameters (like what's in where and having) from
364
+	 * the format expected in the API to use in the models
365
+	 *
366
+	 * @param array    $inputted_query_params_of_this_type
367
+	 * @param EEM_Base $model
368
+	 * @param string   $requested_version
369
+	 * @param boolean  $writing whether this data will be written to the DB, or if we're just building a query.
370
+	 *                          If we're writing to the DB, we don't expect any operators, or any logic query
371
+	 *                          parameters, and we also won't accept serialized data unless the current user has
372
+	 *                          unfiltered_html.
373
+	 * @return array
374
+	 * @throws DomainException
375
+	 * @throws RestException
376
+	 * @throws EE_Error
377
+	 */
378
+	public static function prepareConditionsQueryParamsForModels(
379
+		$inputted_query_params_of_this_type,
380
+		EEM_Base $model,
381
+		$requested_version,
382
+		$writing = false
383
+	) {
384
+		$query_param_for_models = array();
385
+		$valid_operators = $model->valid_operators();
386
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
387
+			$is_gmt_datetime_field = false;
388
+			$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
389
+				$query_param_key
390
+			);
391
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
392
+				$query_param_sans_stars,
393
+				$model
394
+			);
395
+			// double-check is it a *_gmt field?
396
+			if (! $field instanceof EE_Model_Field_Base
397
+				&& ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
398
+			) {
399
+				// yep, take off '_gmt', and find the field
400
+				$query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
401
+				$field = ModelDataTranslator::deduceFieldFromQueryParam(
402
+					$query_param_key,
403
+					$model
404
+				);
405
+				$timezone = 'UTC';
406
+				$is_gmt_datetime_field = true;
407
+			} elseif ($field instanceof EE_Datetime_Field) {
408
+				// so it's not a GMT field. Set the timezone on the model to the default
409
+				$timezone = \EEH_DTT_Helper::get_valid_timezone_string();
410
+			} else {
411
+				// just keep using what's already set for the timezone
412
+				$timezone = $model->get_timezone();
413
+			}
414
+			if ($field instanceof EE_Model_Field_Base) {
415
+				if (! $writing && is_array($query_param_value)) {
416
+					if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
417
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
418
+							throw new RestException(
419
+								'numerically_indexed_array_of_values_only',
420
+								sprintf(
421
+									esc_html__(
422
+										'The array provided for the parameter "%1$s" should be numerically indexed.',
423
+										'event_espresso'
424
+									),
425
+									$query_param_key
426
+								),
427
+								array(
428
+									'status' => 400,
429
+								)
430
+							);
431
+						}
432
+					}
433
+					// did they specify an operator?
434
+					if (isset($query_param_value[0])
435
+						&& isset($valid_operators[ $query_param_value[0] ])
436
+					) {
437
+						$op = $query_param_value[0];
438
+						$translated_value = array($op);
439
+						if (array_key_exists($op, $model->valid_in_style_operators())
440
+							&& isset($query_param_value[1])
441
+							&& ! isset($query_param_value[2])
442
+						) {
443
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
444
+								$field,
445
+								$query_param_value[1],
446
+								$requested_version,
447
+								$timezone
448
+							);
449
+						} elseif (array_key_exists($op, $model->valid_between_style_operators())
450
+								  && isset($query_param_value[1])
451
+								  && is_array($query_param_value[1])
452
+								  && isset($query_param_key[1][0], $query_param_value[1][1])
453
+								  && ! isset($query_param_value[1][2])
454
+								  && ! isset($query_param_value[2])
455
+						) {
456
+							$translated_value[] = array(
457
+								ModelDataTranslator::prepareFieldValuesFromJson(
458
+									$field,
459
+									$query_param_value[1][0],
460
+									$requested_version,
461
+									$timezone
462
+								),
463
+								ModelDataTranslator::prepareFieldValuesFromJson(
464
+									$field,
465
+									$query_param_value[1][1],
466
+									$requested_version,
467
+									$timezone
468
+								)
469
+							);
470
+						} elseif (array_key_exists($op, $model->valid_like_style_operators())
471
+								  && isset($query_param_value[1])
472
+								  && ! isset($query_param_value[2])
473
+						) {
474
+							// we want to leave this value mostly-as-is (eg don't force it to be a float
475
+							// or a boolean or an enum value. Leave it as-is with wildcards etc)
476
+							// but do verify it at least doesn't have any serialized data
477
+							ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
478
+							$translated_value[] = $query_param_value[1];
479
+						} elseif (array_key_exists($op, $model->valid_null_style_operators())
480
+								  && ! isset($query_param_value[1])) {
481
+							// no arguments should have been provided, so don't look for any
482
+						} elseif (isset($query_param_value[1])
483
+								  && ! isset($query_param_value[2])
484
+								  && ! array_key_exists(
485
+									  $op,
486
+									  array_merge(
487
+										  $model->valid_in_style_operators(),
488
+										  $model->valid_null_style_operators(),
489
+										  $model->valid_like_style_operators(),
490
+										  $model->valid_between_style_operators()
491
+									  )
492
+								  )
493
+						) {
494
+							// it's a valid operator, but none of the exceptions. Treat it normally.
495
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
496
+								$field,
497
+								$query_param_value[1],
498
+								$requested_version,
499
+								$timezone
500
+							);
501
+						} else {
502
+							// so they provided a valid operator, but wrong number of arguments
503
+							if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
504
+								throw new RestException(
505
+									'wrong_number_of_arguments',
506
+									sprintf(
507
+										esc_html__(
508
+											'The operator you provided, "%1$s" had the wrong number of arguments',
509
+											'event_espresso'
510
+										),
511
+										$op
512
+									),
513
+									array(
514
+										'status' => 400,
515
+									)
516
+								);
517
+							}
518
+							$translated_value = null;
519
+						}
520
+					} else {
521
+						// so they didn't provide a valid operator
522
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
523
+							throw new RestException(
524
+								'invalid_operator',
525
+								sprintf(
526
+									esc_html__(
527
+										'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
528
+										'event_espresso'
529
+									),
530
+									$query_param_key,
531
+									$query_param_value
532
+								),
533
+								array(
534
+									'status' => 400,
535
+								)
536
+							);
537
+						}
538
+						// if we aren't in debug mode, then just try our best to fulfill the user's request
539
+						$translated_value = null;
540
+					}
541
+				} else {
542
+					$translated_value = ModelDataTranslator::prepareFieldValueFromJson(
543
+						$field,
544
+						$query_param_value,
545
+						$requested_version,
546
+						$timezone
547
+					);
548
+				}
549
+				if ((isset($query_param_for_models[ $query_param_key ]) && $is_gmt_datetime_field)
550
+					|| $translated_value === null
551
+				) {
552
+					// they have already provided a non-gmt field, ignore the gmt one. That's what WP core
553
+					// currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
554
+					// OR we couldn't create a translated value from their input
555
+					continue;
556
+				}
557
+				$query_param_for_models[ $query_param_key ] = $translated_value;
558
+			} else {
559
+				// so this param doesn't correspond to a field eh?
560
+				if ($writing) {
561
+					// always tell API clients about invalid parameters when they're creating data. Otherwise,
562
+					// they are probably going to create invalid data
563
+					throw new RestException(
564
+						'invalid_field',
565
+						sprintf(
566
+							esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
567
+							$query_param_key
568
+						)
569
+					);
570
+				} else {
571
+					// so it's not for a field, is it a logic query param key?
572
+					if (in_array(
573
+						$query_param_sans_stars,
574
+						$model->logic_query_param_keys()
575
+					)) {
576
+						$query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
577
+							$query_param_value,
578
+							$model,
579
+							$requested_version
580
+						);
581
+					} elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
582
+						// only tell API clients they got it wrong if we're in debug mode
583
+						// otherwise try our best ot fulfill their request by ignoring this invalid data
584
+						throw new RestException(
585
+							'invalid_parameter',
586
+							sprintf(
587
+								esc_html__(
588
+									'You provided an invalid parameter, with key "%1$s"',
589
+									'event_espresso'
590
+								),
591
+								$query_param_sans_stars
592
+							),
593
+							array(
594
+								'status' => 400,
595
+							)
596
+						);
597
+					}
598
+				}
599
+			}
600
+		}
601
+		return $query_param_for_models;
602
+	}
603
+
604
+
605
+	/**
606
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
607
+	 * gmt date field name
608
+	 *
609
+	 * @param string $field_name
610
+	 * @return boolean
611
+	 */
612
+	public static function isGmtDateFieldName($field_name)
613
+	{
614
+		return substr(
615
+			ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
616
+			-4,
617
+			4
618
+		) === '_gmt';
619
+	}
620
+
621
+
622
+	/**
623
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
624
+	 *
625
+	 * @param string $field_name
626
+	 * @return string
627
+	 */
628
+	public static function removeGmtFromFieldName($field_name)
629
+	{
630
+		if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
631
+			return $field_name;
632
+		}
633
+		$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
634
+			$field_name
635
+		);
636
+		$query_param_sans_gmt_and_sans_stars = substr(
637
+			$query_param_sans_stars,
638
+			0,
639
+			strrpos(
640
+				$field_name,
641
+				'_gmt'
642
+			)
643
+		);
644
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
645
+	}
646
+
647
+
648
+	/**
649
+	 * Takes a field name from the REST API and prepares it for the model querying
650
+	 *
651
+	 * @param string $field_name
652
+	 * @return string
653
+	 */
654
+	public static function prepareFieldNameFromJson($field_name)
655
+	{
656
+		if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
657
+			return ModelDataTranslator::removeGmtFromFieldName($field_name);
658
+		}
659
+		return $field_name;
660
+	}
661
+
662
+
663
+	/**
664
+	 * Takes array of field names from REST API and prepares for models
665
+	 *
666
+	 * @param array $field_names
667
+	 * @return array of field names (possibly include model prefixes)
668
+	 */
669
+	public static function prepareFieldNamesFromJson(array $field_names)
670
+	{
671
+		$new_array = array();
672
+		foreach ($field_names as $key => $field_name) {
673
+			$new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
674
+		}
675
+		return $new_array;
676
+	}
677
+
678
+
679
+	/**
680
+	 * Takes array where array keys are field names (possibly with model path prefixes)
681
+	 * from the REST API and prepares them for model querying
682
+	 *
683
+	 * @param array $field_names_as_keys
684
+	 * @return array
685
+	 */
686
+	public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
687
+	{
688
+		$new_array = array();
689
+		foreach ($field_names_as_keys as $field_name => $value) {
690
+			$new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
691
+		}
692
+		return $new_array;
693
+	}
694
+
695
+
696
+	/**
697
+	 * Prepares an array of model query params for use in the REST API
698
+	 *
699
+	 * @param array    $model_query_params
700
+	 * @param EEM_Base $model
701
+	 * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
702
+	 *                                     REST API
703
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
704
+	 * @throws EE_Error
705
+	 */
706
+	public static function prepareQueryParamsForRestApi(
707
+		array $model_query_params,
708
+		EEM_Base $model,
709
+		$requested_version = null
710
+	) {
711
+		if ($requested_version === null) {
712
+			$requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
713
+		}
714
+		$rest_query_params = $model_query_params;
715
+		if (isset($model_query_params[0])) {
716
+			$rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
717
+				$model_query_params[0],
718
+				$model,
719
+				$requested_version
720
+			);
721
+			unset($rest_query_params[0]);
722
+		}
723
+		if (isset($model_query_params['having'])) {
724
+			$rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
725
+				$model_query_params['having'],
726
+				$model,
727
+				$requested_version
728
+			);
729
+		}
730
+		return apply_filters(
731
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
732
+			$rest_query_params,
733
+			$model_query_params,
734
+			$model,
735
+			$requested_version
736
+		);
737
+	}
738
+
739
+
740
+	/**
741
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
742
+	 *
743
+	 * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
744
+	 *                                                      passed into EEM_Base::get_all()
745
+	 * @param EEM_Base $model
746
+	 * @param string   $requested_version                   eg "4.8.36"
747
+	 * @return array ready for use in the rest api query params
748
+	 * @throws EE_Error
749
+	 * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
750
+	 *                                                      (which would be really unusual)
751
+	 */
752
+	public static function prepareConditionsQueryParamsForRestApi(
753
+		$inputted_query_params_of_this_type,
754
+		EEM_Base $model,
755
+		$requested_version
756
+	) {
757
+		$query_param_for_models = array();
758
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
759
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
760
+				ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
761
+				$model
762
+			);
763
+			if ($field instanceof EE_Model_Field_Base) {
764
+				// did they specify an operator?
765
+				if (is_array($query_param_value)) {
766
+					$op = $query_param_value[0];
767
+					$translated_value = array($op);
768
+					if (isset($query_param_value[1])) {
769
+						$value = $query_param_value[1];
770
+						$translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
771
+							$field,
772
+							$value,
773
+							$requested_version
774
+						);
775
+					}
776
+				} else {
777
+					$translated_value = ModelDataTranslator::prepareFieldValueForJson(
778
+						$field,
779
+						$query_param_value,
780
+						$requested_version
781
+					);
782
+				}
783
+				$query_param_for_models[ $query_param_key ] = $translated_value;
784
+			} else {
785
+				// so it's not for a field, assume it's a logic query param key
786
+				$query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
787
+					$query_param_value,
788
+					$model,
789
+					$requested_version
790
+				);
791
+			}
792
+		}
793
+		return $query_param_for_models;
794
+	}
795
+
796
+
797
+	/**
798
+	 * @param $condition_query_param_key
799
+	 * @return string
800
+	 */
801
+	public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
802
+	{
803
+		$pos_of_star = strpos($condition_query_param_key, '*');
804
+		if ($pos_of_star === false) {
805
+			return $condition_query_param_key;
806
+		} else {
807
+			$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
808
+			return $condition_query_param_sans_star;
809
+		}
810
+	}
811
+
812
+
813
+	/**
814
+	 * Takes the input parameter and finds the model field that it indicates.
815
+	 *
816
+	 * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
817
+	 * @param EEM_Base $model
818
+	 * @return EE_Model_Field_Base
819
+	 * @throws EE_Error
820
+	 */
821
+	public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
822
+	{
823
+		// ok, now proceed with deducing which part is the model's name, and which is the field's name
824
+		// which will help us find the database table and column
825
+		$query_param_parts = explode('.', $query_param_name);
826
+		if (empty($query_param_parts)) {
827
+			throw new EE_Error(
828
+				sprintf(
829
+					__(
830
+						'_extract_column_name is empty when trying to extract column and table name from %s',
831
+						'event_espresso'
832
+					),
833
+					$query_param_name
834
+				)
835
+			);
836
+		}
837
+		$number_of_parts = count($query_param_parts);
838
+		$last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
839
+		if ($number_of_parts === 1) {
840
+			$field_name = $last_query_param_part;
841
+		} else {// $number_of_parts >= 2
842
+			// the last part is the column name, and there are only 2parts. therefore...
843
+			$field_name = $last_query_param_part;
844
+			$model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
845
+		}
846
+		try {
847
+			return $model->field_settings_for($field_name, false);
848
+		} catch (EE_Error $e) {
849
+			return null;
850
+		}
851
+	}
852
+
853
+
854
+	/**
855
+	 * Returns true if $data can be easily represented in JSON.
856
+	 * Basically, objects and resources can't be represented in JSON easily.
857
+	 *
858
+	 * @param mixed $data
859
+	 * @return bool
860
+	 */
861
+	protected static function isRepresentableInJson($data)
862
+	{
863
+		return is_scalar($data)
864
+			   || is_array($data)
865
+			   || is_null($data);
866
+	}
867 867
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelVersionInfo.php 1 patch
Indentation   +436 added lines, -436 removed lines patch added patch discarded remove patch
@@ -21,440 +21,440 @@
 block discarded – undo
21 21
 class ModelVersionInfo
22 22
 {
23 23
 
24
-    /**
25
-     * Constant used in the $_model_changes array to indicate that a model
26
-     * was completely new in this version
27
-     */
28
-    const MODEL_ADDED = 'model_added_in_this_version';
29
-
30
-    /**
31
-     * Top-level keys are versions (major and minor version numbers, eg "4.6")
32
-     * next-level keys are model names (eg "Event") that underwent some change in that version
33
-     * and the value is either Model_Version_Info::model_added (indicating the model is completely NEW in this version),
34
-     * or it's an array where the values are model field names,
35
-     * or API resource properties (ie, non-model fields that appear in REST API results)
36
-     * If a version is missing then we don't know anything about what changes it introduced from the previous version
37
-     *
38
-     * @var array
39
-     */
40
-    protected $model_changes = array();
41
-
42
-    /**
43
-     * top-level keys are version numbers,
44
-     * next-level keys are model CLASSNAMES (even parent classnames),
45
-     * and next-level keys are extra resource properties to attach to those models' resources,
46
-     * and next-level key-value pairs, where the keys are:
47
-     * 'raw', 'type', 'nullable', 'table_alias', 'table_column',  'always_available'
48
-     *
49
-     * @var array
50
-     */
51
-    protected $resource_changes = array();
52
-
53
-    /**
54
-     * @var string indicating what version of the API was requested
55
-     * (eg although core might be at version 4.8.11, they may have sent a request
56
-     * for 4.6)
57
-     */
58
-    protected $requested_version = null;
59
-
60
-    /**
61
-     * Keys are model names, values are their classnames.
62
-     * We cache this so we only need to calculate this once per request
63
-     *
64
-     * @var array
65
-     */
66
-    protected $cached_models_for_requested_version = null;
67
-
68
-    /**
69
-     * @var array
70
-     */
71
-    protected $cached_model_changes_between_requested_version_and_current = null;
72
-
73
-    /**
74
-     * @var array
75
-     */
76
-    protected $cached_resource_changes_between_requested_version_and_current = null;
77
-
78
-    /**
79
-     * 2d array where top-level keys are model names, 2nd-level keys are field names
80
-     * and values are the actual field objects
81
-     *
82
-     * @var array
83
-     */
84
-    protected $cached_fields_on_models = array();
85
-
86
-
87
-    /**
88
-     * Model_Version_Info constructor.
89
-     *
90
-     * @param string $requested_version
91
-     */
92
-    public function __construct($requested_version)
93
-    {
94
-        $this->requested_version = (string) $requested_version;
95
-        $this->model_changes = array(
96
-            '4.8.29' => array(
97
-                // first version where the REST API is in EE core, so no need
98
-                // to specify how its different from the previous
99
-            ),
100
-        );
101
-        // setup data for "extra" fields added onto resources which don't actually exist on models
102
-        $this->resource_changes = apply_filters(
103
-            'FHEE__Model_Version_Info___construct__extra_resource_properties_for_models',
104
-            array()
105
-        );
106
-        $defaults = array(
107
-            'raw'              => false,
108
-            'type'             => 'N/A',
109
-            'nullable'         => true,
110
-            'table_alias'      => 'N/A',
111
-            'table_column'     => 'N/A',
112
-            'always_available' => true,
113
-        );
114
-        foreach ($this->resource_changes as $version => $model_classnames) {
115
-            foreach ($model_classnames as $model_classname => $extra_fields) {
116
-                foreach ($extra_fields as $fieldname => $field_data) {
117
-                    $this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname;
118
-                    foreach ($defaults as $attribute => $default_value) {
119
-                        if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) {
120
-                            $this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value;
121
-                        }
122
-                    }
123
-                }
124
-            }
125
-        }
126
-    }
127
-
128
-
129
-    /**
130
-     * Returns a slice of Model_Version_Info::model_changes()'s array
131
-     * indicating exactly what changes happened between the current core version,
132
-     * and the version requested
133
-     *
134
-     * @return array
135
-     */
136
-    public function modelChangesBetweenRequestedVersionAndCurrent()
137
-    {
138
-        if ($this->cached_model_changes_between_requested_version_and_current === null) {
139
-            $model_changes = array();
140
-            foreach ($this->modelChanges() as $version => $models_changed_in_version) {
141
-                if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
142
-                    $model_changes[ $version ] = $models_changed_in_version;
143
-                }
144
-            }
145
-            $this->cached_model_changes_between_requested_version_and_current = $model_changes;
146
-        }
147
-        return $this->cached_model_changes_between_requested_version_and_current;
148
-    }
149
-
150
-
151
-    /**
152
-     * Returns a slice of Model_Version_Info::model_changes()'s array
153
-     * indicating exactly what changes happened between the current core version,
154
-     * and the version requested
155
-     *
156
-     * @return array
157
-     */
158
-    public function resourceChangesBetweenRequestedVersionAndCurrent()
159
-    {
160
-        if ($this->cached_resource_changes_between_requested_version_and_current === null) {
161
-            $resource_changes = array();
162
-            foreach ($this->resourceChanges() as $version => $model_classnames) {
163
-                if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
164
-                    $resource_changes[ $version ] = $model_classnames;
165
-                }
166
-            }
167
-            $this->cached_resource_changes_between_requested_version_and_current = $resource_changes;
168
-        }
169
-        return $this->cached_resource_changes_between_requested_version_and_current;
170
-    }
171
-
172
-
173
-    /**
174
-     * If a request was sent to 'wp-json/ee/v4.7/events' this would be '4.7'
175
-     *
176
-     * @return string like '4.6'
177
-     */
178
-    public function requestedVersion()
179
-    {
180
-        return $this->requested_version;
181
-    }
182
-
183
-
184
-    /**
185
-     * Returns an array describing how the models have changed in each version of core
186
-     * that supports the API (starting at 4.6)
187
-     * Top-level keys are versions (major and minor version numbers, eg "4.6")
188
-     * next-level keys are model names (eg "Event") that underwent some change in that version
189
-     * and the value is either NULL (indicating the model is completely NEW in this version),
190
-     * or it's an array where fields are value names.
191
-     * If a version is missing then we don't know anything about what changes it introduced from the previous version
192
-     *
193
-     * @return array
194
-     */
195
-    public function modelChanges()
196
-    {
197
-        return $this->model_changes;
198
-    }
199
-
200
-
201
-    /**
202
-     * Takes into account the requested version, and the current version, and
203
-     * what changed between the two, and tries to return.
204
-     * Analogous to EE_Registry::instance()->non_abstract_db_models
205
-     *
206
-     * @return array keys are model names, values are their classname
207
-     */
208
-    public function modelsForRequestedVersion()
209
-    {
210
-        if ($this->cached_models_for_requested_version === null) {
211
-            $all_models_in_current_version = EE_Registry::instance()->non_abstract_db_models;
212
-            foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) {
213
-                foreach ($models_changed as $model_name => $new_indicator_or_fields_added) {
214
-                    if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) {
215
-                        unset($all_models_in_current_version[ $model_name ]);
216
-                    }
217
-                }
218
-            }
219
-            $this->cached_models_for_requested_version = apply_filters(
220
-                'FHEE__EventEspresso_core_libraries_rest_api__models_for_requested_version',
221
-                $all_models_in_current_version,
222
-                $this
223
-            );
224
-        }
225
-        return $this->cached_models_for_requested_version;
226
-    }
227
-
228
-
229
-    /**
230
-     * Determines if this is a valid model name in the requested version.
231
-     * Similar to EE_Registry::instance()->is_model_name(), but takes the requested
232
-     * version's models into account
233
-     *
234
-     * @param string $model_name eg 'Event'
235
-     * @return boolean
236
-     */
237
-    public function isModelNameInThisVersion($model_name)
238
-    {
239
-        $model_names = $this->modelsForRequestedVersion();
240
-        if (isset($model_names[ $model_name ])) {
241
-            return true;
242
-        } else {
243
-            return false;
244
-        }
245
-    }
246
-
247
-
248
-    /**
249
-     * Wrapper for EE_Registry::instance()->load_model(), but takes the requested
250
-     * version's models into account
251
-     *
252
-     * @param string $model_name
253
-     * @return \EEM_Base
254
-     * @throws \EE_Error
255
-     */
256
-    public function loadModel($model_name)
257
-    {
258
-        if ($this->isModelNameInThisVersion($model_name)) {
259
-            return EE_Registry::instance()->load_model($model_name);
260
-        } else {
261
-            throw new \EE_Error(
262
-                sprintf(
263
-                    __(
264
-                        'Cannot load model "%1$s" because it does not exist in version %2$s of Event Espresso',
265
-                        'event_espresso'
266
-                    ),
267
-                    $model_name,
268
-                    $this->requestedVersion()
269
-                )
270
-            );
271
-        }
272
-    }
273
-
274
-
275
-    /**
276
-     * Gets all the fields that should exist on this model right now
277
-     *
278
-     * @param \EEM_Base $model
279
-     * @return array|\EE_Model_Field_Base[]
280
-     */
281
-    public function fieldsOnModelInThisVersion($model)
282
-    {
283
-        if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) {
284
-            // get all model changes between the requested version and current core version
285
-            $changes = $this->modelChangesBetweenRequestedVersionAndCurrent();
286
-            // fetch all fields currently on this model
287
-            $current_fields = $model->field_settings();
288
-            // remove all fields that have been added since
289
-            foreach ($changes as $version => $changes_in_version) {
290
-                if (isset($changes_in_version[ $model->get_this_model_name() ])
291
-                    && $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED
292
-                ) {
293
-                    $current_fields = array_diff_key(
294
-                        $current_fields,
295
-                        array_flip($changes_in_version[ $model->get_this_model_name() ])
296
-                    );
297
-                }
298
-            }
299
-            $this->cached_fields_on_models = $current_fields;
300
-        }
301
-        return $this->cached_fields_on_models;
302
-    }
303
-
304
-
305
-    /**
306
-     * Determines if $object is of one of the classes of $classes. Similar to
307
-     * in_array(), except this checks if $object is a subclass of the classnames provided
308
-     * in $classnames
309
-     *
310
-     * @param object $object
311
-     * @param array  $classnames
312
-     * @return boolean
313
-     */
314
-    public function isSubclassOfOne($object, $classnames)
315
-    {
316
-        foreach ($classnames as $classname) {
317
-            if (is_a($object, $classname)) {
318
-                return true;
319
-            }
320
-        }
321
-        return false;
322
-    }
323
-
324
-
325
-    /**
326
-     * Returns the list of model field classes that that the API basically ignores
327
-     *
328
-     * @return array
329
-     */
330
-    public function fieldsIgnored()
331
-    {
332
-        return apply_filters(
333
-            'FHEE__Controller_Model_Read_fields_ignored',
334
-            array()
335
-        );
336
-    }
337
-
338
-
339
-    /**
340
-     * If this field one that should be ignored by the API?
341
-     *
342
-     * @param EE_Model_Field_Base
343
-     * @return boolean
344
-     */
345
-    public function fieldIsIgnored($field_obj)
346
-    {
347
-        return $this->isSubclassOfOne($field_obj, $this->fieldsIgnored());
348
-    }
349
-
350
-
351
-    /**
352
-     * Returns the list of model field classes that have a "raw" and non-raw formats.
353
-     * Normally the "raw" versions are only accessible to those who can edit them.
354
-     *
355
-     * @return array an array of EE_Model_Field_Base child classnames
356
-     */
357
-    public function fieldsThatHaveRenderedFormat()
358
-    {
359
-        return apply_filters(
360
-            'FHEE__Controller_Model_Read__fields_raw',
361
-            array('EE_Post_Content_Field', 'EE_Full_HTML_Field')
362
-        );
363
-    }
364
-
365
-
366
-    /**
367
-     * If this field one that has a raw format
368
-     *
369
-     * @param EE_Model_Field_Base
370
-     * @return boolean
371
-     */
372
-    public function fieldHasRenderedFormat($field_obj)
373
-    {
374
-        return $this->isSubclassOfOne($field_obj, $this->fieldsThatHaveRenderedFormat());
375
-    }
376
-
377
-
378
-    /**
379
-     * Returns the list of model field classes that have a "_pretty" and non-pretty versions.
380
-     * The pretty version of the field is NOT query-able or editable, but requires no extra permissions
381
-     * to view
382
-     *
383
-     * @return array an array of EE_Model_Field_Base child classnames
384
-     */
385
-    public function fieldsThatHavePrettyFormat()
386
-    {
387
-        return apply_filters(
388
-            'FHEE__Controller_Model_Read__fields_pretty',
389
-            array('EE_Enum_Integer_Field', 'EE_Enum_Text_Field', 'EE_Money_Field')
390
-        );
391
-    }
392
-
393
-
394
-    /**
395
-     * If this field one that has a pretty equivalent
396
-     *
397
-     * @param EE_Model_Field_Base
398
-     * @return boolean
399
-     */
400
-    public function fieldHasPrettyFormat($field_obj)
401
-    {
402
-        return $this->isSubclassOfOne($field_obj, $this->fieldsThatHavePrettyFormat());
403
-    }
404
-
405
-
406
-    /**
407
-     * Returns an array describing what extra API resource properties have been added through the versions
408
-     *
409
-     * @return array @see $this->_extra_resource_properties_for_models
410
-     */
411
-    public function resourceChanges()
412
-    {
413
-        return $this->resource_changes;
414
-    }
415
-
416
-
417
-    /**
418
-     * Returns an array where keys are extra resource properties in this version of the API,
419
-     * and values are key-value pairs describing the new properties. @see Model_Version::_resource_changes
420
-     *
421
-     * @param \EEM_Base $model
422
-     * @return array
423
-     */
424
-    public function extraResourcePropertiesForModel($model)
425
-    {
426
-        $extra_properties = array();
427
-        foreach ($this->resourceChangesBetweenRequestedVersionAndCurrent() as $version => $model_classnames) {
428
-            foreach ($model_classnames as $model_classname => $properties_added_in_this_version) {
429
-                if (is_subclass_of($model, $model_classname)) {
430
-                    $extra_properties = array_merge($extra_properties, $properties_added_in_this_version);
431
-                }
432
-            }
433
-        }
434
-        return $extra_properties;
435
-    }
436
-
437
-
438
-    /**
439
-     * Gets all the related models for the specified model. It's good to use this
440
-     * in case this model didn't exist for this version or something
441
-     *
442
-     * @param \EEM_Base $model
443
-     * @return \EE_Model_Relation_Base[]
444
-     */
445
-    public function relationSettings(\EEM_Base $model)
446
-    {
447
-        $relations = array();
448
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
449
-            if ($this->isModelNameInThisVersion($relation_name)) {
450
-                $relations[ $relation_name ] = $relation_obj;
451
-            }
452
-        }
453
-        // filter the results, but use the old filter name
454
-        return apply_filters(
455
-            'FHEE__Read__create_entity_from_wpdb_result__related_models_to_include',
456
-            $relations,
457
-            $model
458
-        );
459
-    }
24
+	/**
25
+	 * Constant used in the $_model_changes array to indicate that a model
26
+	 * was completely new in this version
27
+	 */
28
+	const MODEL_ADDED = 'model_added_in_this_version';
29
+
30
+	/**
31
+	 * Top-level keys are versions (major and minor version numbers, eg "4.6")
32
+	 * next-level keys are model names (eg "Event") that underwent some change in that version
33
+	 * and the value is either Model_Version_Info::model_added (indicating the model is completely NEW in this version),
34
+	 * or it's an array where the values are model field names,
35
+	 * or API resource properties (ie, non-model fields that appear in REST API results)
36
+	 * If a version is missing then we don't know anything about what changes it introduced from the previous version
37
+	 *
38
+	 * @var array
39
+	 */
40
+	protected $model_changes = array();
41
+
42
+	/**
43
+	 * top-level keys are version numbers,
44
+	 * next-level keys are model CLASSNAMES (even parent classnames),
45
+	 * and next-level keys are extra resource properties to attach to those models' resources,
46
+	 * and next-level key-value pairs, where the keys are:
47
+	 * 'raw', 'type', 'nullable', 'table_alias', 'table_column',  'always_available'
48
+	 *
49
+	 * @var array
50
+	 */
51
+	protected $resource_changes = array();
52
+
53
+	/**
54
+	 * @var string indicating what version of the API was requested
55
+	 * (eg although core might be at version 4.8.11, they may have sent a request
56
+	 * for 4.6)
57
+	 */
58
+	protected $requested_version = null;
59
+
60
+	/**
61
+	 * Keys are model names, values are their classnames.
62
+	 * We cache this so we only need to calculate this once per request
63
+	 *
64
+	 * @var array
65
+	 */
66
+	protected $cached_models_for_requested_version = null;
67
+
68
+	/**
69
+	 * @var array
70
+	 */
71
+	protected $cached_model_changes_between_requested_version_and_current = null;
72
+
73
+	/**
74
+	 * @var array
75
+	 */
76
+	protected $cached_resource_changes_between_requested_version_and_current = null;
77
+
78
+	/**
79
+	 * 2d array where top-level keys are model names, 2nd-level keys are field names
80
+	 * and values are the actual field objects
81
+	 *
82
+	 * @var array
83
+	 */
84
+	protected $cached_fields_on_models = array();
85
+
86
+
87
+	/**
88
+	 * Model_Version_Info constructor.
89
+	 *
90
+	 * @param string $requested_version
91
+	 */
92
+	public function __construct($requested_version)
93
+	{
94
+		$this->requested_version = (string) $requested_version;
95
+		$this->model_changes = array(
96
+			'4.8.29' => array(
97
+				// first version where the REST API is in EE core, so no need
98
+				// to specify how its different from the previous
99
+			),
100
+		);
101
+		// setup data for "extra" fields added onto resources which don't actually exist on models
102
+		$this->resource_changes = apply_filters(
103
+			'FHEE__Model_Version_Info___construct__extra_resource_properties_for_models',
104
+			array()
105
+		);
106
+		$defaults = array(
107
+			'raw'              => false,
108
+			'type'             => 'N/A',
109
+			'nullable'         => true,
110
+			'table_alias'      => 'N/A',
111
+			'table_column'     => 'N/A',
112
+			'always_available' => true,
113
+		);
114
+		foreach ($this->resource_changes as $version => $model_classnames) {
115
+			foreach ($model_classnames as $model_classname => $extra_fields) {
116
+				foreach ($extra_fields as $fieldname => $field_data) {
117
+					$this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname;
118
+					foreach ($defaults as $attribute => $default_value) {
119
+						if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) {
120
+							$this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value;
121
+						}
122
+					}
123
+				}
124
+			}
125
+		}
126
+	}
127
+
128
+
129
+	/**
130
+	 * Returns a slice of Model_Version_Info::model_changes()'s array
131
+	 * indicating exactly what changes happened between the current core version,
132
+	 * and the version requested
133
+	 *
134
+	 * @return array
135
+	 */
136
+	public function modelChangesBetweenRequestedVersionAndCurrent()
137
+	{
138
+		if ($this->cached_model_changes_between_requested_version_and_current === null) {
139
+			$model_changes = array();
140
+			foreach ($this->modelChanges() as $version => $models_changed_in_version) {
141
+				if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
142
+					$model_changes[ $version ] = $models_changed_in_version;
143
+				}
144
+			}
145
+			$this->cached_model_changes_between_requested_version_and_current = $model_changes;
146
+		}
147
+		return $this->cached_model_changes_between_requested_version_and_current;
148
+	}
149
+
150
+
151
+	/**
152
+	 * Returns a slice of Model_Version_Info::model_changes()'s array
153
+	 * indicating exactly what changes happened between the current core version,
154
+	 * and the version requested
155
+	 *
156
+	 * @return array
157
+	 */
158
+	public function resourceChangesBetweenRequestedVersionAndCurrent()
159
+	{
160
+		if ($this->cached_resource_changes_between_requested_version_and_current === null) {
161
+			$resource_changes = array();
162
+			foreach ($this->resourceChanges() as $version => $model_classnames) {
163
+				if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
164
+					$resource_changes[ $version ] = $model_classnames;
165
+				}
166
+			}
167
+			$this->cached_resource_changes_between_requested_version_and_current = $resource_changes;
168
+		}
169
+		return $this->cached_resource_changes_between_requested_version_and_current;
170
+	}
171
+
172
+
173
+	/**
174
+	 * If a request was sent to 'wp-json/ee/v4.7/events' this would be '4.7'
175
+	 *
176
+	 * @return string like '4.6'
177
+	 */
178
+	public function requestedVersion()
179
+	{
180
+		return $this->requested_version;
181
+	}
182
+
183
+
184
+	/**
185
+	 * Returns an array describing how the models have changed in each version of core
186
+	 * that supports the API (starting at 4.6)
187
+	 * Top-level keys are versions (major and minor version numbers, eg "4.6")
188
+	 * next-level keys are model names (eg "Event") that underwent some change in that version
189
+	 * and the value is either NULL (indicating the model is completely NEW in this version),
190
+	 * or it's an array where fields are value names.
191
+	 * If a version is missing then we don't know anything about what changes it introduced from the previous version
192
+	 *
193
+	 * @return array
194
+	 */
195
+	public function modelChanges()
196
+	{
197
+		return $this->model_changes;
198
+	}
199
+
200
+
201
+	/**
202
+	 * Takes into account the requested version, and the current version, and
203
+	 * what changed between the two, and tries to return.
204
+	 * Analogous to EE_Registry::instance()->non_abstract_db_models
205
+	 *
206
+	 * @return array keys are model names, values are their classname
207
+	 */
208
+	public function modelsForRequestedVersion()
209
+	{
210
+		if ($this->cached_models_for_requested_version === null) {
211
+			$all_models_in_current_version = EE_Registry::instance()->non_abstract_db_models;
212
+			foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) {
213
+				foreach ($models_changed as $model_name => $new_indicator_or_fields_added) {
214
+					if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) {
215
+						unset($all_models_in_current_version[ $model_name ]);
216
+					}
217
+				}
218
+			}
219
+			$this->cached_models_for_requested_version = apply_filters(
220
+				'FHEE__EventEspresso_core_libraries_rest_api__models_for_requested_version',
221
+				$all_models_in_current_version,
222
+				$this
223
+			);
224
+		}
225
+		return $this->cached_models_for_requested_version;
226
+	}
227
+
228
+
229
+	/**
230
+	 * Determines if this is a valid model name in the requested version.
231
+	 * Similar to EE_Registry::instance()->is_model_name(), but takes the requested
232
+	 * version's models into account
233
+	 *
234
+	 * @param string $model_name eg 'Event'
235
+	 * @return boolean
236
+	 */
237
+	public function isModelNameInThisVersion($model_name)
238
+	{
239
+		$model_names = $this->modelsForRequestedVersion();
240
+		if (isset($model_names[ $model_name ])) {
241
+			return true;
242
+		} else {
243
+			return false;
244
+		}
245
+	}
246
+
247
+
248
+	/**
249
+	 * Wrapper for EE_Registry::instance()->load_model(), but takes the requested
250
+	 * version's models into account
251
+	 *
252
+	 * @param string $model_name
253
+	 * @return \EEM_Base
254
+	 * @throws \EE_Error
255
+	 */
256
+	public function loadModel($model_name)
257
+	{
258
+		if ($this->isModelNameInThisVersion($model_name)) {
259
+			return EE_Registry::instance()->load_model($model_name);
260
+		} else {
261
+			throw new \EE_Error(
262
+				sprintf(
263
+					__(
264
+						'Cannot load model "%1$s" because it does not exist in version %2$s of Event Espresso',
265
+						'event_espresso'
266
+					),
267
+					$model_name,
268
+					$this->requestedVersion()
269
+				)
270
+			);
271
+		}
272
+	}
273
+
274
+
275
+	/**
276
+	 * Gets all the fields that should exist on this model right now
277
+	 *
278
+	 * @param \EEM_Base $model
279
+	 * @return array|\EE_Model_Field_Base[]
280
+	 */
281
+	public function fieldsOnModelInThisVersion($model)
282
+	{
283
+		if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) {
284
+			// get all model changes between the requested version and current core version
285
+			$changes = $this->modelChangesBetweenRequestedVersionAndCurrent();
286
+			// fetch all fields currently on this model
287
+			$current_fields = $model->field_settings();
288
+			// remove all fields that have been added since
289
+			foreach ($changes as $version => $changes_in_version) {
290
+				if (isset($changes_in_version[ $model->get_this_model_name() ])
291
+					&& $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED
292
+				) {
293
+					$current_fields = array_diff_key(
294
+						$current_fields,
295
+						array_flip($changes_in_version[ $model->get_this_model_name() ])
296
+					);
297
+				}
298
+			}
299
+			$this->cached_fields_on_models = $current_fields;
300
+		}
301
+		return $this->cached_fields_on_models;
302
+	}
303
+
304
+
305
+	/**
306
+	 * Determines if $object is of one of the classes of $classes. Similar to
307
+	 * in_array(), except this checks if $object is a subclass of the classnames provided
308
+	 * in $classnames
309
+	 *
310
+	 * @param object $object
311
+	 * @param array  $classnames
312
+	 * @return boolean
313
+	 */
314
+	public function isSubclassOfOne($object, $classnames)
315
+	{
316
+		foreach ($classnames as $classname) {
317
+			if (is_a($object, $classname)) {
318
+				return true;
319
+			}
320
+		}
321
+		return false;
322
+	}
323
+
324
+
325
+	/**
326
+	 * Returns the list of model field classes that that the API basically ignores
327
+	 *
328
+	 * @return array
329
+	 */
330
+	public function fieldsIgnored()
331
+	{
332
+		return apply_filters(
333
+			'FHEE__Controller_Model_Read_fields_ignored',
334
+			array()
335
+		);
336
+	}
337
+
338
+
339
+	/**
340
+	 * If this field one that should be ignored by the API?
341
+	 *
342
+	 * @param EE_Model_Field_Base
343
+	 * @return boolean
344
+	 */
345
+	public function fieldIsIgnored($field_obj)
346
+	{
347
+		return $this->isSubclassOfOne($field_obj, $this->fieldsIgnored());
348
+	}
349
+
350
+
351
+	/**
352
+	 * Returns the list of model field classes that have a "raw" and non-raw formats.
353
+	 * Normally the "raw" versions are only accessible to those who can edit them.
354
+	 *
355
+	 * @return array an array of EE_Model_Field_Base child classnames
356
+	 */
357
+	public function fieldsThatHaveRenderedFormat()
358
+	{
359
+		return apply_filters(
360
+			'FHEE__Controller_Model_Read__fields_raw',
361
+			array('EE_Post_Content_Field', 'EE_Full_HTML_Field')
362
+		);
363
+	}
364
+
365
+
366
+	/**
367
+	 * If this field one that has a raw format
368
+	 *
369
+	 * @param EE_Model_Field_Base
370
+	 * @return boolean
371
+	 */
372
+	public function fieldHasRenderedFormat($field_obj)
373
+	{
374
+		return $this->isSubclassOfOne($field_obj, $this->fieldsThatHaveRenderedFormat());
375
+	}
376
+
377
+
378
+	/**
379
+	 * Returns the list of model field classes that have a "_pretty" and non-pretty versions.
380
+	 * The pretty version of the field is NOT query-able or editable, but requires no extra permissions
381
+	 * to view
382
+	 *
383
+	 * @return array an array of EE_Model_Field_Base child classnames
384
+	 */
385
+	public function fieldsThatHavePrettyFormat()
386
+	{
387
+		return apply_filters(
388
+			'FHEE__Controller_Model_Read__fields_pretty',
389
+			array('EE_Enum_Integer_Field', 'EE_Enum_Text_Field', 'EE_Money_Field')
390
+		);
391
+	}
392
+
393
+
394
+	/**
395
+	 * If this field one that has a pretty equivalent
396
+	 *
397
+	 * @param EE_Model_Field_Base
398
+	 * @return boolean
399
+	 */
400
+	public function fieldHasPrettyFormat($field_obj)
401
+	{
402
+		return $this->isSubclassOfOne($field_obj, $this->fieldsThatHavePrettyFormat());
403
+	}
404
+
405
+
406
+	/**
407
+	 * Returns an array describing what extra API resource properties have been added through the versions
408
+	 *
409
+	 * @return array @see $this->_extra_resource_properties_for_models
410
+	 */
411
+	public function resourceChanges()
412
+	{
413
+		return $this->resource_changes;
414
+	}
415
+
416
+
417
+	/**
418
+	 * Returns an array where keys are extra resource properties in this version of the API,
419
+	 * and values are key-value pairs describing the new properties. @see Model_Version::_resource_changes
420
+	 *
421
+	 * @param \EEM_Base $model
422
+	 * @return array
423
+	 */
424
+	public function extraResourcePropertiesForModel($model)
425
+	{
426
+		$extra_properties = array();
427
+		foreach ($this->resourceChangesBetweenRequestedVersionAndCurrent() as $version => $model_classnames) {
428
+			foreach ($model_classnames as $model_classname => $properties_added_in_this_version) {
429
+				if (is_subclass_of($model, $model_classname)) {
430
+					$extra_properties = array_merge($extra_properties, $properties_added_in_this_version);
431
+				}
432
+			}
433
+		}
434
+		return $extra_properties;
435
+	}
436
+
437
+
438
+	/**
439
+	 * Gets all the related models for the specified model. It's good to use this
440
+	 * in case this model didn't exist for this version or something
441
+	 *
442
+	 * @param \EEM_Base $model
443
+	 * @return \EE_Model_Relation_Base[]
444
+	 */
445
+	public function relationSettings(\EEM_Base $model)
446
+	{
447
+		$relations = array();
448
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
449
+			if ($this->isModelNameInThisVersion($relation_name)) {
450
+				$relations[ $relation_name ] = $relation_obj;
451
+			}
452
+		}
453
+		// filter the results, but use the old filter name
454
+		return apply_filters(
455
+			'FHEE__Read__create_entity_from_wpdb_result__related_models_to_include',
456
+			$relations,
457
+			$model
458
+		);
459
+	}
460 460
 }
Please login to merge, or discard this patch.
core/db_models/fields/EE_Datetime_Field.php 2 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -560,7 +560,7 @@  discard block
 block discarded – undo
560 560
      * allowed)
561 561
      *
562 562
      * @param string $datetime_string mysql timestamp in UTC
563
-     * @return  mixed null | DateTime
563
+     * @return  null|DbSafeDateTime null | DateTime
564 564
      * @throws \EE_Error
565 565
      */
566 566
     public function prepare_for_set_from_db($datetime_string)
@@ -712,7 +712,7 @@  discard block
 block discarded – undo
712 712
      *
713 713
      * @param \DateTimeZone $DateTimeZone
714 714
      * @param int           $time
715
-     * @return mixed
715
+     * @return integer
716 716
      * @throws \DomainException
717 717
      */
718 718
     public function get_timezone_offset(DateTimeZone $DateTimeZone, $time = null)
@@ -753,7 +753,7 @@  discard block
 block discarded – undo
753 753
     /**
754 754
      * Gets the default datetime object from the field's default time
755 755
      * @since $VID:$
756
-     * @return DbSafeDateTime|null
756
+     * @return DateTime|null
757 757
      * @throws InvalidArgumentException
758 758
      * @throws InvalidDataTypeException
759 759
      * @throws InvalidInterfaceException
Please login to merge, or discard this patch.
Indentation   +764 added lines, -764 removed lines patch added patch discarded remove patch
@@ -15,769 +15,769 @@
 block discarded – undo
15 15
 class EE_Datetime_Field extends EE_Model_Field_Base
16 16
 {
17 17
 
18
-    /**
19
-     * The pattern we're looking for is if only the characters 0-9 are found and there are only
20
-     * 10 or more numbers (because 9 numbers even with all 9's would be sometime in 2001 )
21
-     *
22
-     * @type string unix_timestamp_regex
23
-     */
24
-    const unix_timestamp_regex = '/[0-9]{10,}/';
25
-
26
-    /**
27
-     * @type string mysql_timestamp_format
28
-     */
29
-    const mysql_timestamp_format = 'Y-m-d H:i:s';
30
-
31
-    /**
32
-     * @type string mysql_date_format
33
-     */
34
-    const mysql_date_format = 'Y-m-d';
35
-
36
-    /**
37
-     * @type string mysql_time_format
38
-     */
39
-    const mysql_time_format = 'H:i:s';
40
-
41
-    /**
42
-     * Const for using in the default value. If the field's default is set to this,
43
-     * then we will return the time of calling `get_default_value()`, not
44
-     * just the current time at construction
45
-     */
46
-    const now = 'now';
47
-
48
-    /**
49
-     * The following properties hold the default formats for date and time.
50
-     * Defaults are set via the constructor and can be overridden on class instantiation.
51
-     * However they can also be overridden later by the set_format() method
52
-     * (and corresponding set_date_format, set_time_format methods);
53
-     */
54
-    /**
55
-     * @type string $_date_format
56
-     */
57
-    protected $_date_format = '';
58
-
59
-    /**
60
-     * @type string $_time_format
61
-     */
62
-    protected $_time_format = '';
63
-
64
-    /**
65
-     * @type string $_pretty_date_format
66
-     */
67
-    protected $_pretty_date_format = '';
68
-
69
-    /**
70
-     * @type string $_pretty_time_format
71
-     */
72
-    protected $_pretty_time_format = '';
73
-
74
-    /**
75
-     * @type DateTimeZone $_DateTimeZone
76
-     */
77
-    protected $_DateTimeZone;
78
-
79
-    /**
80
-     * @type DateTimeZone $_UTC_DateTimeZone
81
-     */
82
-    protected $_UTC_DateTimeZone;
83
-
84
-    /**
85
-     * @type DateTimeZone $_blog_DateTimeZone
86
-     */
87
-    protected $_blog_DateTimeZone;
88
-
89
-
90
-    /**
91
-     * This property holds how we want the output returned when getting a datetime string.  It is set for the
92
-     * set_date_time_output() method.  By default this is empty.  When empty, we are assuming that we want both date
93
-     * and time returned via getters.
94
-     *
95
-     * @var mixed (null|string)
96
-     */
97
-    protected $_date_time_output;
98
-
99
-
100
-    /**
101
-     * timezone string
102
-     * This gets set by the constructor and can be changed by the "set_timezone()" method so that we know what timezone
103
-     * incoming strings|timestamps are in.  This can also be used before a get to set what timezone you want strings
104
-     * coming out of the object to be in.  Default timezone is the current WP timezone option setting
105
-     *
106
-     * @var string
107
-     */
108
-    protected $_timezone_string;
109
-
110
-
111
-    /**
112
-     * This holds whatever UTC offset for the blog (we automatically convert timezone strings into their related
113
-     * offsets for comparison purposes).
114
-     *
115
-     * @var int
116
-     */
117
-    protected $_blog_offset;
118
-
119
-
120
-
121
-    /**
122
-     * @param string $table_column
123
-     * @param string $nice_name
124
-     * @param bool   $nullable
125
-     * @param string $default_value
126
-     * @param string $timezone_string
127
-     * @param string $date_format
128
-     * @param string $time_format
129
-     * @param string $pretty_date_format
130
-     * @param string $pretty_time_format
131
-     * @throws EE_Error
132
-     * @throws InvalidArgumentException
133
-     */
134
-    public function __construct(
135
-        $table_column,
136
-        $nice_name,
137
-        $nullable,
138
-        $default_value,
139
-        $timezone_string = '',
140
-        $date_format = '',
141
-        $time_format = '',
142
-        $pretty_date_format = '',
143
-        $pretty_time_format = ''
144
-    ) {
145
-
146
-        $this->_date_format        = ! empty($date_format) ? $date_format : get_option('date_format');
147
-        $this->_time_format        = ! empty($time_format) ? $time_format : get_option('time_format');
148
-        $this->_pretty_date_format = ! empty($pretty_date_format) ? $pretty_date_format : get_option('date_format');
149
-        $this->_pretty_time_format = ! empty($pretty_time_format) ? $pretty_time_format : get_option('time_format');
150
-
151
-        parent::__construct($table_column, $nice_name, $nullable, $default_value);
152
-        $this->set_timezone($timezone_string);
153
-        $this->setSchemaFormat('date-time');
154
-    }
155
-
156
-
157
-    /**
158
-     * @return DateTimeZone
159
-     * @throws \EE_Error
160
-     */
161
-    public function get_UTC_DateTimeZone()
162
-    {
163
-        return $this->_UTC_DateTimeZone instanceof DateTimeZone
164
-            ? $this->_UTC_DateTimeZone
165
-            : $this->_create_timezone_object_from_timezone_string('UTC');
166
-    }
167
-
168
-
169
-    /**
170
-     * @return DateTimeZone
171
-     * @throws \EE_Error
172
-     */
173
-    public function get_blog_DateTimeZone()
174
-    {
175
-        return $this->_blog_DateTimeZone instanceof DateTimeZone
176
-            ? $this->_blog_DateTimeZone
177
-            : $this->_create_timezone_object_from_timezone_string('');
178
-    }
179
-
180
-
181
-    /**
182
-     * this prepares any incoming date data and make sure its converted to a utc unix timestamp
183
-     *
184
-     * @param  string|int $value_inputted_for_field_on_model_object could be a string formatted date time or int unix
185
-     *                                                              timestamp
186
-     * @return DateTime
187
-     */
188
-    public function prepare_for_set($value_inputted_for_field_on_model_object)
189
-    {
190
-        return $this->_get_date_object($value_inputted_for_field_on_model_object);
191
-    }
192
-
193
-
194
-    /**
195
-     * This returns the format string to be used by getters depending on what the $_date_time_output property is set at.
196
-     * getters need to know whether we're just returning the date or the time or both.  By default we return both.
197
-     *
198
-     * @param bool $pretty If we're returning the pretty formats or standard format string.
199
-     * @return string    The final assembled format string.
200
-     */
201
-    protected function _get_date_time_output($pretty = false)
202
-    {
203
-
204
-        switch ($this->_date_time_output) {
205
-            case 'time':
206
-                return $pretty ? $this->_pretty_time_format : $this->_time_format;
207
-                break;
208
-
209
-            case 'date':
210
-                return $pretty ? $this->_pretty_date_format : $this->_date_format;
211
-                break;
212
-
213
-            default:
214
-                return $pretty
215
-                    ? $this->_pretty_date_format . ' ' . $this->_pretty_time_format
216
-                    : $this->_date_format . ' ' . $this->_time_format;
217
-        }
218
-    }
219
-
220
-
221
-    /**
222
-     * This just sets the $_date_time_output property so we can flag how date and times are formatted before being
223
-     * returned (using the format properties)
224
-     *
225
-     * @param string $what acceptable values are 'time' or 'date'.
226
-     *                     Any other value will be set but will always result
227
-     *                     in both 'date' and 'time' being returned.
228
-     * @return void
229
-     */
230
-    public function set_date_time_output($what = null)
231
-    {
232
-        $this->_date_time_output = $what;
233
-    }
234
-
235
-
236
-    /**
237
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
238
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
239
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp).
240
-     * We also set some other properties in this method.
241
-     *
242
-     * @param string $timezone_string A valid timezone string as described by @link
243
-     *                                http://www.php.net/manual/en/timezones.php
244
-     * @return void
245
-     * @throws InvalidArgumentException
246
-     * @throws InvalidDataTypeException
247
-     * @throws InvalidInterfaceException
248
-     */
249
-    public function set_timezone($timezone_string)
250
-    {
251
-        if (empty($timezone_string) && $this->_timezone_string !== null) {
252
-            // leave the timezone AS-IS if we already have one and
253
-            // the function arg didn't provide one
254
-            return;
255
-        }
256
-        $timezone_string        = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
257
-        $this->_timezone_string = ! empty($timezone_string) ? $timezone_string : 'UTC';
258
-        $this->_DateTimeZone    = $this->_create_timezone_object_from_timezone_string($this->_timezone_string);
259
-    }
260
-
261
-
262
-    /**
263
-     * _create_timezone_object_from_timezone_name
264
-     *
265
-     * @access protected
266
-     * @param string $timezone_string
267
-     * @return \DateTimeZone
268
-     * @throws InvalidArgumentException
269
-     * @throws InvalidDataTypeException
270
-     * @throws InvalidInterfaceException
271
-     */
272
-    protected function _create_timezone_object_from_timezone_string($timezone_string = '')
273
-    {
274
-        return new DateTimeZone(EEH_DTT_Helper::get_valid_timezone_string($timezone_string));
275
-    }
276
-
277
-
278
-    /**
279
-     * This just returns whatever is set for the current timezone.
280
-     *
281
-     * @access public
282
-     * @return string timezone string
283
-     */
284
-    public function get_timezone()
285
-    {
286
-        return $this->_timezone_string;
287
-    }
288
-
289
-
290
-    /**
291
-     * set the $_date_format property
292
-     *
293
-     * @access public
294
-     * @param string $format a new date format (corresponding to formats accepted by PHP date() function)
295
-     * @param bool   $pretty Whether to set pretty format or not.
296
-     * @return void
297
-     */
298
-    public function set_date_format($format, $pretty = false)
299
-    {
300
-        if ($pretty) {
301
-            $this->_pretty_date_format = $format;
302
-        } else {
303
-            $this->_date_format = $format;
304
-        }
305
-    }
306
-
307
-
308
-    /**
309
-     * return the $_date_format property value.
310
-     *
311
-     * @param bool $pretty Whether to get pretty format or not.
312
-     * @return string
313
-     */
314
-    public function get_date_format($pretty = false)
315
-    {
316
-        return $pretty ? $this->_pretty_date_format : $this->_date_format;
317
-    }
318
-
319
-
320
-    /**
321
-     * set the $_time_format property
322
-     *
323
-     * @access public
324
-     * @param string $format a new time format (corresponding to formats accepted by PHP date() function)
325
-     * @param bool   $pretty Whether to set pretty format or not.
326
-     * @return void
327
-     */
328
-    public function set_time_format($format, $pretty = false)
329
-    {
330
-        if ($pretty) {
331
-            $this->_pretty_time_format = $format;
332
-        } else {
333
-            $this->_time_format = $format;
334
-        }
335
-    }
336
-
337
-
338
-    /**
339
-     * return the $_time_format property value.
340
-     *
341
-     * @param bool $pretty Whether to get pretty format or not.
342
-     * @return string
343
-     */
344
-    public function get_time_format($pretty = false)
345
-    {
346
-        return $pretty ? $this->_pretty_time_format : $this->_time_format;
347
-    }
348
-
349
-
350
-    /**
351
-     * set the $_pretty_date_format property
352
-     *
353
-     * @access public
354
-     * @param string $format a new pretty date format (corresponding to formats accepted by PHP date() function)
355
-     * @return void
356
-     */
357
-    public function set_pretty_date_format($format)
358
-    {
359
-        $this->_pretty_date_format = $format;
360
-    }
361
-
362
-
363
-    /**
364
-     * set the $_pretty_time_format property
365
-     *
366
-     * @access public
367
-     * @param string $format a new pretty time format (corresponding to formats accepted by PHP date() function)
368
-     * @return void
369
-     */
370
-    public function set_pretty_time_format($format)
371
-    {
372
-        $this->_pretty_time_format = $format;
373
-    }
374
-
375
-
376
-    /**
377
-     * Only sets the time portion of the datetime.
378
-     *
379
-     * @param string|DateTime $time_to_set_string like 8am OR a DateTime object.
380
-     * @param DateTime        $current            current DateTime object for the datetime field
381
-     * @return DateTime
382
-     */
383
-    public function prepare_for_set_with_new_time($time_to_set_string, DateTime $current)
384
-    {
385
-        // if $time_to_set_string is datetime object, then let's use it to set the parse array.
386
-        // Otherwise parse the string.
387
-        if ($time_to_set_string instanceof DateTime) {
388
-            $parsed = array(
389
-                'hour'   => $time_to_set_string->format('H'),
390
-                'minute' => $time_to_set_string->format('i'),
391
-                'second' => $time_to_set_string->format('s'),
392
-            );
393
-        } else {
394
-            // parse incoming string
395
-            $parsed = date_parse_from_format($this->_time_format, $time_to_set_string);
396
-        }
397
-        EEH_DTT_Helper::setTimezone($current, $this->_DateTimeZone);
398
-        return $current->setTime($parsed['hour'], $parsed['minute'], $parsed['second']);
399
-    }
400
-
401
-
402
-    /**
403
-     * Only sets the date portion of the datetime.
404
-     *
405
-     * @param string|DateTime $date_to_set_string like Friday, January 8th or a DateTime object.
406
-     * @param DateTime        $current            current DateTime object for the datetime field
407
-     * @return DateTime
408
-     */
409
-    public function prepare_for_set_with_new_date($date_to_set_string, DateTime $current)
410
-    {
411
-        // if $time_to_set_string is datetime object, then let's use it to set the parse array.
412
-        // Otherwise parse the string.
413
-        if ($date_to_set_string instanceof DateTime) {
414
-            $parsed = array(
415
-                'year'  => $date_to_set_string->format('Y'),
416
-                'month' => $date_to_set_string->format('m'),
417
-                'day'   => $date_to_set_string->format('d'),
418
-            );
419
-        } else {
420
-            // parse incoming string
421
-            $parsed = date_parse_from_format($this->_date_format, $date_to_set_string);
422
-        }
423
-        EEH_DTT_Helper::setTimezone($current, $this->_DateTimeZone);
424
-        return $current->setDate($parsed['year'], $parsed['month'], $parsed['day']);
425
-    }
426
-
427
-
428
-    /**
429
-     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0 timezone).  When the
430
-     * datetime gets to this stage it should ALREADY be in UTC time
431
-     *
432
-     * @param  DateTime $DateTime
433
-     * @return string formatted date time for given timezone
434
-     * @throws \EE_Error
435
-     */
436
-    public function prepare_for_get($DateTime)
437
-    {
438
-        return $this->_prepare_for_display($DateTime);
439
-    }
440
-
441
-
442
-    /**
443
-     * This differs from prepare_for_get in that it considers whether the internal $_timezone differs
444
-     * from the set wp timezone.  If so, then it returns the datetime string formatted via
445
-     * _pretty_date_format, and _pretty_time_format.  However, it also appends a timezone
446
-     * abbreviation to the date_string.
447
-     *
448
-     * @param mixed $DateTime
449
-     * @param null  $schema
450
-     * @return string
451
-     * @throws \EE_Error
452
-     */
453
-    public function prepare_for_pretty_echoing($DateTime, $schema = null)
454
-    {
455
-        return $this->_prepare_for_display($DateTime, $schema ? $schema : true);
456
-    }
457
-
458
-
459
-    /**
460
-     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
461
-     * timezone).
462
-     *
463
-     * @param DateTime    $DateTime
464
-     * @param bool|string $schema
465
-     * @return string
466
-     * @throws \EE_Error
467
-     */
468
-    protected function _prepare_for_display($DateTime, $schema = false)
469
-    {
470
-        if (! $DateTime instanceof DateTime) {
471
-            if ($this->_nullable) {
472
-                return '';
473
-            } else {
474
-                if (WP_DEBUG) {
475
-                    throw new EE_Error(
476
-                        sprintf(
477
-                            __(
478
-                                'EE_Datetime_Field::_prepare_for_display requires a DateTime class to be the value for the $DateTime argument because the %s field is not nullable.',
479
-                                'event_espresso'
480
-                            ),
481
-                            $this->_nicename
482
-                        )
483
-                    );
484
-                } else {
485
-                    $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now);
486
-                    EE_Error::add_error(
487
-                        sprintf(
488
-                            __(
489
-                                'EE_Datetime_Field::_prepare_for_display requires a DateTime class to be the value for the $DateTime argument because the %s field is not nullable.  When WP_DEBUG is false, the value is set to "now" instead of throwing an exception.',
490
-                                'event_espresso'
491
-                            ),
492
-                            $this->_nicename
493
-                        )
494
-                    );
495
-                }
496
-            }
497
-        }
498
-        $format_string = $this->_get_date_time_output($schema);
499
-        EEH_DTT_Helper::setTimezone($DateTime, $this->_DateTimeZone);
500
-        if ($schema) {
501
-            if ($this->_display_timezone()) {
502
-                // must be explicit because schema could equal true.
503
-                if ($schema === 'no_html') {
504
-                    $timezone_string = ' (' . $DateTime->format('T') . ')';
505
-                } else {
506
-                    $timezone_string = ' <span class="ee_dtt_timezone_string">(' . $DateTime->format('T') . ')</span>';
507
-                }
508
-            } else {
509
-                $timezone_string = '';
510
-            }
511
-
512
-            return $DateTime->format($format_string) . $timezone_string;
513
-        }
514
-        return $DateTime->format($format_string);
515
-    }
516
-
517
-
518
-    /**
519
-     * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
520
-     * timezone).
521
-     *
522
-     * @param  mixed $datetime_value u
523
-     * @return string mysql timestamp in UTC
524
-     * @throws \EE_Error
525
-     */
526
-    public function prepare_for_use_in_db($datetime_value)
527
-    {
528
-        // we allow an empty value or DateTime object, but nothing else.
529
-        if (! empty($datetime_value) && ! $datetime_value instanceof DateTime) {
530
-            throw new EE_Error(
531
-                sprintf(
532
-                    __(
533
-                        'The incoming value being prepared for setting in the database must either be empty or a php 
18
+	/**
19
+	 * The pattern we're looking for is if only the characters 0-9 are found and there are only
20
+	 * 10 or more numbers (because 9 numbers even with all 9's would be sometime in 2001 )
21
+	 *
22
+	 * @type string unix_timestamp_regex
23
+	 */
24
+	const unix_timestamp_regex = '/[0-9]{10,}/';
25
+
26
+	/**
27
+	 * @type string mysql_timestamp_format
28
+	 */
29
+	const mysql_timestamp_format = 'Y-m-d H:i:s';
30
+
31
+	/**
32
+	 * @type string mysql_date_format
33
+	 */
34
+	const mysql_date_format = 'Y-m-d';
35
+
36
+	/**
37
+	 * @type string mysql_time_format
38
+	 */
39
+	const mysql_time_format = 'H:i:s';
40
+
41
+	/**
42
+	 * Const for using in the default value. If the field's default is set to this,
43
+	 * then we will return the time of calling `get_default_value()`, not
44
+	 * just the current time at construction
45
+	 */
46
+	const now = 'now';
47
+
48
+	/**
49
+	 * The following properties hold the default formats for date and time.
50
+	 * Defaults are set via the constructor and can be overridden on class instantiation.
51
+	 * However they can also be overridden later by the set_format() method
52
+	 * (and corresponding set_date_format, set_time_format methods);
53
+	 */
54
+	/**
55
+	 * @type string $_date_format
56
+	 */
57
+	protected $_date_format = '';
58
+
59
+	/**
60
+	 * @type string $_time_format
61
+	 */
62
+	protected $_time_format = '';
63
+
64
+	/**
65
+	 * @type string $_pretty_date_format
66
+	 */
67
+	protected $_pretty_date_format = '';
68
+
69
+	/**
70
+	 * @type string $_pretty_time_format
71
+	 */
72
+	protected $_pretty_time_format = '';
73
+
74
+	/**
75
+	 * @type DateTimeZone $_DateTimeZone
76
+	 */
77
+	protected $_DateTimeZone;
78
+
79
+	/**
80
+	 * @type DateTimeZone $_UTC_DateTimeZone
81
+	 */
82
+	protected $_UTC_DateTimeZone;
83
+
84
+	/**
85
+	 * @type DateTimeZone $_blog_DateTimeZone
86
+	 */
87
+	protected $_blog_DateTimeZone;
88
+
89
+
90
+	/**
91
+	 * This property holds how we want the output returned when getting a datetime string.  It is set for the
92
+	 * set_date_time_output() method.  By default this is empty.  When empty, we are assuming that we want both date
93
+	 * and time returned via getters.
94
+	 *
95
+	 * @var mixed (null|string)
96
+	 */
97
+	protected $_date_time_output;
98
+
99
+
100
+	/**
101
+	 * timezone string
102
+	 * This gets set by the constructor and can be changed by the "set_timezone()" method so that we know what timezone
103
+	 * incoming strings|timestamps are in.  This can also be used before a get to set what timezone you want strings
104
+	 * coming out of the object to be in.  Default timezone is the current WP timezone option setting
105
+	 *
106
+	 * @var string
107
+	 */
108
+	protected $_timezone_string;
109
+
110
+
111
+	/**
112
+	 * This holds whatever UTC offset for the blog (we automatically convert timezone strings into their related
113
+	 * offsets for comparison purposes).
114
+	 *
115
+	 * @var int
116
+	 */
117
+	protected $_blog_offset;
118
+
119
+
120
+
121
+	/**
122
+	 * @param string $table_column
123
+	 * @param string $nice_name
124
+	 * @param bool   $nullable
125
+	 * @param string $default_value
126
+	 * @param string $timezone_string
127
+	 * @param string $date_format
128
+	 * @param string $time_format
129
+	 * @param string $pretty_date_format
130
+	 * @param string $pretty_time_format
131
+	 * @throws EE_Error
132
+	 * @throws InvalidArgumentException
133
+	 */
134
+	public function __construct(
135
+		$table_column,
136
+		$nice_name,
137
+		$nullable,
138
+		$default_value,
139
+		$timezone_string = '',
140
+		$date_format = '',
141
+		$time_format = '',
142
+		$pretty_date_format = '',
143
+		$pretty_time_format = ''
144
+	) {
145
+
146
+		$this->_date_format        = ! empty($date_format) ? $date_format : get_option('date_format');
147
+		$this->_time_format        = ! empty($time_format) ? $time_format : get_option('time_format');
148
+		$this->_pretty_date_format = ! empty($pretty_date_format) ? $pretty_date_format : get_option('date_format');
149
+		$this->_pretty_time_format = ! empty($pretty_time_format) ? $pretty_time_format : get_option('time_format');
150
+
151
+		parent::__construct($table_column, $nice_name, $nullable, $default_value);
152
+		$this->set_timezone($timezone_string);
153
+		$this->setSchemaFormat('date-time');
154
+	}
155
+
156
+
157
+	/**
158
+	 * @return DateTimeZone
159
+	 * @throws \EE_Error
160
+	 */
161
+	public function get_UTC_DateTimeZone()
162
+	{
163
+		return $this->_UTC_DateTimeZone instanceof DateTimeZone
164
+			? $this->_UTC_DateTimeZone
165
+			: $this->_create_timezone_object_from_timezone_string('UTC');
166
+	}
167
+
168
+
169
+	/**
170
+	 * @return DateTimeZone
171
+	 * @throws \EE_Error
172
+	 */
173
+	public function get_blog_DateTimeZone()
174
+	{
175
+		return $this->_blog_DateTimeZone instanceof DateTimeZone
176
+			? $this->_blog_DateTimeZone
177
+			: $this->_create_timezone_object_from_timezone_string('');
178
+	}
179
+
180
+
181
+	/**
182
+	 * this prepares any incoming date data and make sure its converted to a utc unix timestamp
183
+	 *
184
+	 * @param  string|int $value_inputted_for_field_on_model_object could be a string formatted date time or int unix
185
+	 *                                                              timestamp
186
+	 * @return DateTime
187
+	 */
188
+	public function prepare_for_set($value_inputted_for_field_on_model_object)
189
+	{
190
+		return $this->_get_date_object($value_inputted_for_field_on_model_object);
191
+	}
192
+
193
+
194
+	/**
195
+	 * This returns the format string to be used by getters depending on what the $_date_time_output property is set at.
196
+	 * getters need to know whether we're just returning the date or the time or both.  By default we return both.
197
+	 *
198
+	 * @param bool $pretty If we're returning the pretty formats or standard format string.
199
+	 * @return string    The final assembled format string.
200
+	 */
201
+	protected function _get_date_time_output($pretty = false)
202
+	{
203
+
204
+		switch ($this->_date_time_output) {
205
+			case 'time':
206
+				return $pretty ? $this->_pretty_time_format : $this->_time_format;
207
+				break;
208
+
209
+			case 'date':
210
+				return $pretty ? $this->_pretty_date_format : $this->_date_format;
211
+				break;
212
+
213
+			default:
214
+				return $pretty
215
+					? $this->_pretty_date_format . ' ' . $this->_pretty_time_format
216
+					: $this->_date_format . ' ' . $this->_time_format;
217
+		}
218
+	}
219
+
220
+
221
+	/**
222
+	 * This just sets the $_date_time_output property so we can flag how date and times are formatted before being
223
+	 * returned (using the format properties)
224
+	 *
225
+	 * @param string $what acceptable values are 'time' or 'date'.
226
+	 *                     Any other value will be set but will always result
227
+	 *                     in both 'date' and 'time' being returned.
228
+	 * @return void
229
+	 */
230
+	public function set_date_time_output($what = null)
231
+	{
232
+		$this->_date_time_output = $what;
233
+	}
234
+
235
+
236
+	/**
237
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
238
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
239
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp).
240
+	 * We also set some other properties in this method.
241
+	 *
242
+	 * @param string $timezone_string A valid timezone string as described by @link
243
+	 *                                http://www.php.net/manual/en/timezones.php
244
+	 * @return void
245
+	 * @throws InvalidArgumentException
246
+	 * @throws InvalidDataTypeException
247
+	 * @throws InvalidInterfaceException
248
+	 */
249
+	public function set_timezone($timezone_string)
250
+	{
251
+		if (empty($timezone_string) && $this->_timezone_string !== null) {
252
+			// leave the timezone AS-IS if we already have one and
253
+			// the function arg didn't provide one
254
+			return;
255
+		}
256
+		$timezone_string        = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
257
+		$this->_timezone_string = ! empty($timezone_string) ? $timezone_string : 'UTC';
258
+		$this->_DateTimeZone    = $this->_create_timezone_object_from_timezone_string($this->_timezone_string);
259
+	}
260
+
261
+
262
+	/**
263
+	 * _create_timezone_object_from_timezone_name
264
+	 *
265
+	 * @access protected
266
+	 * @param string $timezone_string
267
+	 * @return \DateTimeZone
268
+	 * @throws InvalidArgumentException
269
+	 * @throws InvalidDataTypeException
270
+	 * @throws InvalidInterfaceException
271
+	 */
272
+	protected function _create_timezone_object_from_timezone_string($timezone_string = '')
273
+	{
274
+		return new DateTimeZone(EEH_DTT_Helper::get_valid_timezone_string($timezone_string));
275
+	}
276
+
277
+
278
+	/**
279
+	 * This just returns whatever is set for the current timezone.
280
+	 *
281
+	 * @access public
282
+	 * @return string timezone string
283
+	 */
284
+	public function get_timezone()
285
+	{
286
+		return $this->_timezone_string;
287
+	}
288
+
289
+
290
+	/**
291
+	 * set the $_date_format property
292
+	 *
293
+	 * @access public
294
+	 * @param string $format a new date format (corresponding to formats accepted by PHP date() function)
295
+	 * @param bool   $pretty Whether to set pretty format or not.
296
+	 * @return void
297
+	 */
298
+	public function set_date_format($format, $pretty = false)
299
+	{
300
+		if ($pretty) {
301
+			$this->_pretty_date_format = $format;
302
+		} else {
303
+			$this->_date_format = $format;
304
+		}
305
+	}
306
+
307
+
308
+	/**
309
+	 * return the $_date_format property value.
310
+	 *
311
+	 * @param bool $pretty Whether to get pretty format or not.
312
+	 * @return string
313
+	 */
314
+	public function get_date_format($pretty = false)
315
+	{
316
+		return $pretty ? $this->_pretty_date_format : $this->_date_format;
317
+	}
318
+
319
+
320
+	/**
321
+	 * set the $_time_format property
322
+	 *
323
+	 * @access public
324
+	 * @param string $format a new time format (corresponding to formats accepted by PHP date() function)
325
+	 * @param bool   $pretty Whether to set pretty format or not.
326
+	 * @return void
327
+	 */
328
+	public function set_time_format($format, $pretty = false)
329
+	{
330
+		if ($pretty) {
331
+			$this->_pretty_time_format = $format;
332
+		} else {
333
+			$this->_time_format = $format;
334
+		}
335
+	}
336
+
337
+
338
+	/**
339
+	 * return the $_time_format property value.
340
+	 *
341
+	 * @param bool $pretty Whether to get pretty format or not.
342
+	 * @return string
343
+	 */
344
+	public function get_time_format($pretty = false)
345
+	{
346
+		return $pretty ? $this->_pretty_time_format : $this->_time_format;
347
+	}
348
+
349
+
350
+	/**
351
+	 * set the $_pretty_date_format property
352
+	 *
353
+	 * @access public
354
+	 * @param string $format a new pretty date format (corresponding to formats accepted by PHP date() function)
355
+	 * @return void
356
+	 */
357
+	public function set_pretty_date_format($format)
358
+	{
359
+		$this->_pretty_date_format = $format;
360
+	}
361
+
362
+
363
+	/**
364
+	 * set the $_pretty_time_format property
365
+	 *
366
+	 * @access public
367
+	 * @param string $format a new pretty time format (corresponding to formats accepted by PHP date() function)
368
+	 * @return void
369
+	 */
370
+	public function set_pretty_time_format($format)
371
+	{
372
+		$this->_pretty_time_format = $format;
373
+	}
374
+
375
+
376
+	/**
377
+	 * Only sets the time portion of the datetime.
378
+	 *
379
+	 * @param string|DateTime $time_to_set_string like 8am OR a DateTime object.
380
+	 * @param DateTime        $current            current DateTime object for the datetime field
381
+	 * @return DateTime
382
+	 */
383
+	public function prepare_for_set_with_new_time($time_to_set_string, DateTime $current)
384
+	{
385
+		// if $time_to_set_string is datetime object, then let's use it to set the parse array.
386
+		// Otherwise parse the string.
387
+		if ($time_to_set_string instanceof DateTime) {
388
+			$parsed = array(
389
+				'hour'   => $time_to_set_string->format('H'),
390
+				'minute' => $time_to_set_string->format('i'),
391
+				'second' => $time_to_set_string->format('s'),
392
+			);
393
+		} else {
394
+			// parse incoming string
395
+			$parsed = date_parse_from_format($this->_time_format, $time_to_set_string);
396
+		}
397
+		EEH_DTT_Helper::setTimezone($current, $this->_DateTimeZone);
398
+		return $current->setTime($parsed['hour'], $parsed['minute'], $parsed['second']);
399
+	}
400
+
401
+
402
+	/**
403
+	 * Only sets the date portion of the datetime.
404
+	 *
405
+	 * @param string|DateTime $date_to_set_string like Friday, January 8th or a DateTime object.
406
+	 * @param DateTime        $current            current DateTime object for the datetime field
407
+	 * @return DateTime
408
+	 */
409
+	public function prepare_for_set_with_new_date($date_to_set_string, DateTime $current)
410
+	{
411
+		// if $time_to_set_string is datetime object, then let's use it to set the parse array.
412
+		// Otherwise parse the string.
413
+		if ($date_to_set_string instanceof DateTime) {
414
+			$parsed = array(
415
+				'year'  => $date_to_set_string->format('Y'),
416
+				'month' => $date_to_set_string->format('m'),
417
+				'day'   => $date_to_set_string->format('d'),
418
+			);
419
+		} else {
420
+			// parse incoming string
421
+			$parsed = date_parse_from_format($this->_date_format, $date_to_set_string);
422
+		}
423
+		EEH_DTT_Helper::setTimezone($current, $this->_DateTimeZone);
424
+		return $current->setDate($parsed['year'], $parsed['month'], $parsed['day']);
425
+	}
426
+
427
+
428
+	/**
429
+	 * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0 timezone).  When the
430
+	 * datetime gets to this stage it should ALREADY be in UTC time
431
+	 *
432
+	 * @param  DateTime $DateTime
433
+	 * @return string formatted date time for given timezone
434
+	 * @throws \EE_Error
435
+	 */
436
+	public function prepare_for_get($DateTime)
437
+	{
438
+		return $this->_prepare_for_display($DateTime);
439
+	}
440
+
441
+
442
+	/**
443
+	 * This differs from prepare_for_get in that it considers whether the internal $_timezone differs
444
+	 * from the set wp timezone.  If so, then it returns the datetime string formatted via
445
+	 * _pretty_date_format, and _pretty_time_format.  However, it also appends a timezone
446
+	 * abbreviation to the date_string.
447
+	 *
448
+	 * @param mixed $DateTime
449
+	 * @param null  $schema
450
+	 * @return string
451
+	 * @throws \EE_Error
452
+	 */
453
+	public function prepare_for_pretty_echoing($DateTime, $schema = null)
454
+	{
455
+		return $this->_prepare_for_display($DateTime, $schema ? $schema : true);
456
+	}
457
+
458
+
459
+	/**
460
+	 * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
461
+	 * timezone).
462
+	 *
463
+	 * @param DateTime    $DateTime
464
+	 * @param bool|string $schema
465
+	 * @return string
466
+	 * @throws \EE_Error
467
+	 */
468
+	protected function _prepare_for_display($DateTime, $schema = false)
469
+	{
470
+		if (! $DateTime instanceof DateTime) {
471
+			if ($this->_nullable) {
472
+				return '';
473
+			} else {
474
+				if (WP_DEBUG) {
475
+					throw new EE_Error(
476
+						sprintf(
477
+							__(
478
+								'EE_Datetime_Field::_prepare_for_display requires a DateTime class to be the value for the $DateTime argument because the %s field is not nullable.',
479
+								'event_espresso'
480
+							),
481
+							$this->_nicename
482
+						)
483
+					);
484
+				} else {
485
+					$DateTime = new DbSafeDateTime(\EE_Datetime_Field::now);
486
+					EE_Error::add_error(
487
+						sprintf(
488
+							__(
489
+								'EE_Datetime_Field::_prepare_for_display requires a DateTime class to be the value for the $DateTime argument because the %s field is not nullable.  When WP_DEBUG is false, the value is set to "now" instead of throwing an exception.',
490
+								'event_espresso'
491
+							),
492
+							$this->_nicename
493
+						)
494
+					);
495
+				}
496
+			}
497
+		}
498
+		$format_string = $this->_get_date_time_output($schema);
499
+		EEH_DTT_Helper::setTimezone($DateTime, $this->_DateTimeZone);
500
+		if ($schema) {
501
+			if ($this->_display_timezone()) {
502
+				// must be explicit because schema could equal true.
503
+				if ($schema === 'no_html') {
504
+					$timezone_string = ' (' . $DateTime->format('T') . ')';
505
+				} else {
506
+					$timezone_string = ' <span class="ee_dtt_timezone_string">(' . $DateTime->format('T') . ')</span>';
507
+				}
508
+			} else {
509
+				$timezone_string = '';
510
+			}
511
+
512
+			return $DateTime->format($format_string) . $timezone_string;
513
+		}
514
+		return $DateTime->format($format_string);
515
+	}
516
+
517
+
518
+	/**
519
+	 * This prepares the EE_DateTime value to be saved to the db as mysql timestamp (UTC +0
520
+	 * timezone).
521
+	 *
522
+	 * @param  mixed $datetime_value u
523
+	 * @return string mysql timestamp in UTC
524
+	 * @throws \EE_Error
525
+	 */
526
+	public function prepare_for_use_in_db($datetime_value)
527
+	{
528
+		// we allow an empty value or DateTime object, but nothing else.
529
+		if (! empty($datetime_value) && ! $datetime_value instanceof DateTime) {
530
+			throw new EE_Error(
531
+				sprintf(
532
+					__(
533
+						'The incoming value being prepared for setting in the database must either be empty or a php 
534 534
             		    DateTime object, instead of: %1$s %2$s',
535
-                        'event_espresso'
536
-                    ),
537
-                    '<br />',
538
-                    print_r($datetime_value, true)
539
-                )
540
-            );
541
-        }
542
-
543
-        if ($datetime_value instanceof DateTime) {
544
-            if (! $datetime_value instanceof DbSafeDateTime) {
545
-                $datetime_value = DbSafeDateTime::createFromDateTime($datetime_value);
546
-            }
547
-            EEH_DTT_Helper::setTimezone($datetime_value, $this->get_UTC_DateTimeZone());
548
-            return $datetime_value->format(
549
-                EE_Datetime_Field::mysql_timestamp_format
550
-            );
551
-        }
552
-
553
-        // if $datetime_value is empty, and ! $this->_nullable, use current_time() but set the GMT flag to true
554
-        return ! $this->_nullable && empty($datetime_value) ? current_time('mysql', true) : null;
555
-    }
556
-
557
-
558
-    /**
559
-     * This prepares the datetime for internal usage as a PHP DateTime object OR null (if nullable is
560
-     * allowed)
561
-     *
562
-     * @param string $datetime_string mysql timestamp in UTC
563
-     * @return  mixed null | DateTime
564
-     * @throws \EE_Error
565
-     */
566
-    public function prepare_for_set_from_db($datetime_string)
567
-    {
568
-        // if $datetime_value is empty, and ! $this->_nullable, just use time()
569
-        if (empty($datetime_string) && $this->_nullable) {
570
-            return null;
571
-        }
572
-        // datetime strings from the db should ALWAYS be in UTC+0, so use UTC_DateTimeZone when creating
573
-        if (empty($datetime_string)) {
574
-            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
575
-        } else {
576
-            $DateTime = DateTime::createFromFormat(
577
-                EE_Datetime_Field::mysql_timestamp_format,
578
-                $datetime_string,
579
-                $this->get_UTC_DateTimeZone()
580
-            );
581
-            if ($DateTime instanceof \DateTime) {
582
-                $DateTime = new DbSafeDateTime(
583
-                    $DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
584
-                    $this->get_UTC_DateTimeZone()
585
-                );
586
-            }
587
-        }
588
-
589
-        if (! $DateTime instanceof DbSafeDateTime) {
590
-            // if still no datetime object, then let's just use now
591
-            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
592
-        }
593
-        // THEN apply the field's set DateTimeZone
594
-        EEH_DTT_Helper::setTimezone($DateTime, $this->_DateTimeZone);
595
-        return $DateTime;
596
-    }
597
-
598
-
599
-    /**
600
-     * All this method does is determine if we're going to display the timezone string or not on any output.
601
-     * To determine this we check if the set timezone offset is different than the blog's set timezone offset.
602
-     * If so, then true.
603
-     *
604
-     * @return bool true for yes false for no
605
-     * @throws \EE_Error
606
-     */
607
-    protected function _display_timezone()
608
-    {
609
-
610
-        // first let's do a comparison of timezone strings.
611
-        // If they match then we can get out without any further calculations
612
-        $blog_string = get_option('timezone_string');
613
-        if ($blog_string === $this->_timezone_string) {
614
-            return false;
615
-        }
616
-        // now we need to calc the offset for the timezone string so we can compare with the blog offset.
617
-        $this_offset = $this->get_timezone_offset($this->_DateTimeZone);
618
-        $blog_offset = $this->get_timezone_offset($this->get_blog_DateTimeZone());
619
-        // now compare
620
-        return $blog_offset !== $this_offset;
621
-    }
622
-
623
-
624
-    /**
625
-     * This method returns a php DateTime object for setting on the EE_Base_Class model.
626
-     * EE passes around DateTime objects because they are MUCH easier to manipulate and deal
627
-     * with.
628
-     *
629
-     * @param int|string|DateTime $date_string            This should be the incoming date string.  It's assumed to be
630
-     *                                                    in the format that is set on the date_field (or DateTime
631
-     *                                                    object)!
632
-     * @return DateTime
633
-     */
634
-    protected function _get_date_object($date_string)
635
-    {
636
-        // first if this is an empty date_string and nullable is allowed, just return null.
637
-        if ($this->_nullable && empty($date_string)) {
638
-            return null;
639
-        }
640
-
641
-        // if incoming date
642
-        if ($date_string instanceof DateTime) {
643
-            EEH_DTT_Helper::setTimezone($date_string, $this->_DateTimeZone);
644
-            return $date_string;
645
-        }
646
-        // if empty date_string and made it here.
647
-        // Return a datetime object for now in the given timezone.
648
-        if (empty($date_string)) {
649
-            return new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
650
-        }
651
-        // if $date_string is matches something that looks like a Unix timestamp let's just use it.
652
-        if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $date_string)) {
653
-            try {
654
-                // This is operating under the assumption that the incoming Unix timestamp
655
-                // is an ACTUAL Unix timestamp and not the calculated one output by current_time('timestamp');
656
-                $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
657
-                $DateTime->setTimestamp($date_string);
658
-
659
-                return $DateTime;
660
-            } catch (Exception $e) {
661
-                // should be rare, but if things got fooled then let's just continue
662
-            }
663
-        }
664
-        // not a unix timestamp.  So we will use the set format on this object and set timezone to
665
-        // create the DateTime object.
666
-        $format = $this->_date_format . ' ' . $this->_time_format;
667
-        try {
668
-            $DateTime = DateTime::createFromFormat($format, $date_string, $this->_DateTimeZone);
669
-            if ($DateTime instanceof DateTime) {
670
-                $DateTime = new DbSafeDateTime(
671
-                    $DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
672
-                    $this->_DateTimeZone
673
-                );
674
-            }
675
-            if (! $DateTime instanceof DbSafeDateTime) {
676
-                throw new EE_Error(
677
-                    sprintf(
678
-                        __('"%1$s" does not represent a valid Date Time in the format "%2$s".', 'event_espresso'),
679
-                        $date_string,
680
-                        $format
681
-                    )
682
-                );
683
-            }
684
-        } catch (Exception $e) {
685
-            // if we made it here then likely then something went really wrong.
686
-            // Instead of throwing an exception, let's just return a DateTime object for now, in the set timezone.
687
-            $DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
688
-        }
689
-
690
-        return $DateTime;
691
-    }
692
-
693
-
694
-
695
-    /**
696
-     * get_timezone_transitions
697
-     *
698
-     * @param \DateTimeZone $DateTimeZone
699
-     * @param int           $time
700
-     * @param bool          $first_only
701
-     * @return mixed
702
-     */
703
-    public function get_timezone_transitions(DateTimeZone $DateTimeZone, $time = null, $first_only = true)
704
-    {
705
-        return EEH_DTT_Helper::get_timezone_transitions($DateTimeZone, $time, $first_only);
706
-    }
707
-
708
-
709
-
710
-    /**
711
-     * get_timezone_offset
712
-     *
713
-     * @param \DateTimeZone $DateTimeZone
714
-     * @param int           $time
715
-     * @return mixed
716
-     * @throws \DomainException
717
-     */
718
-    public function get_timezone_offset(DateTimeZone $DateTimeZone, $time = null)
719
-    {
720
-        return EEH_DTT_Helper::get_timezone_offset($DateTimeZone, $time);
721
-    }
722
-
723
-
724
-    /**
725
-     * This will take an incoming timezone string and return the abbreviation for that timezone
726
-     *
727
-     * @param  string $timezone_string
728
-     * @return string           abbreviation
729
-     * @throws \EE_Error
730
-     */
731
-    public function get_timezone_abbrev($timezone_string)
732
-    {
733
-        $timezone_string = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
734
-        $dateTime        = new DateTime(\EE_Datetime_Field::now, new DateTimeZone($timezone_string));
735
-
736
-        return $dateTime->format('T');
737
-    }
738
-
739
-    /**
740
-     * Overrides the parent to allow for having a dynamic "now" value
741
-     *
742
-     * @return mixed
743
-     */
744
-    public function get_default_value()
745
-    {
746
-        if ($this->_default_value === EE_Datetime_Field::now) {
747
-            return time();
748
-        } else {
749
-            return parent::get_default_value();
750
-        }
751
-    }
752
-
753
-    /**
754
-     * Gets the default datetime object from the field's default time
755
-     * @since $VID:$
756
-     * @return DbSafeDateTime|null
757
-     * @throws InvalidArgumentException
758
-     * @throws InvalidDataTypeException
759
-     * @throws InvalidInterfaceException
760
-     */
761
-    public function getDefaultDateTimeObj()
762
-    {
763
-        $default_raw = $this->get_default_value();
764
-        if ($default_raw instanceof DateTime) {
765
-            return $default_raw;
766
-        } elseif (is_null($default_raw)) {
767
-            return $default_raw;
768
-        } else {
769
-            return new DbSafeDateTime(
770
-                $this->get_default_value(),
771
-                EEH_DTT_Helper::get_valid_timezone_string($this->get_timezone())
772
-            );
773
-        }
774
-    }
775
-
776
-    public function getSchemaDescription()
777
-    {
778
-        return sprintf(
779
-            esc_html__('%s - the value for this field is in the timezone of the site.', 'event_espresso'),
780
-            $this->get_nicename()
781
-        );
782
-    }
535
+						'event_espresso'
536
+					),
537
+					'<br />',
538
+					print_r($datetime_value, true)
539
+				)
540
+			);
541
+		}
542
+
543
+		if ($datetime_value instanceof DateTime) {
544
+			if (! $datetime_value instanceof DbSafeDateTime) {
545
+				$datetime_value = DbSafeDateTime::createFromDateTime($datetime_value);
546
+			}
547
+			EEH_DTT_Helper::setTimezone($datetime_value, $this->get_UTC_DateTimeZone());
548
+			return $datetime_value->format(
549
+				EE_Datetime_Field::mysql_timestamp_format
550
+			);
551
+		}
552
+
553
+		// if $datetime_value is empty, and ! $this->_nullable, use current_time() but set the GMT flag to true
554
+		return ! $this->_nullable && empty($datetime_value) ? current_time('mysql', true) : null;
555
+	}
556
+
557
+
558
+	/**
559
+	 * This prepares the datetime for internal usage as a PHP DateTime object OR null (if nullable is
560
+	 * allowed)
561
+	 *
562
+	 * @param string $datetime_string mysql timestamp in UTC
563
+	 * @return  mixed null | DateTime
564
+	 * @throws \EE_Error
565
+	 */
566
+	public function prepare_for_set_from_db($datetime_string)
567
+	{
568
+		// if $datetime_value is empty, and ! $this->_nullable, just use time()
569
+		if (empty($datetime_string) && $this->_nullable) {
570
+			return null;
571
+		}
572
+		// datetime strings from the db should ALWAYS be in UTC+0, so use UTC_DateTimeZone when creating
573
+		if (empty($datetime_string)) {
574
+			$DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
575
+		} else {
576
+			$DateTime = DateTime::createFromFormat(
577
+				EE_Datetime_Field::mysql_timestamp_format,
578
+				$datetime_string,
579
+				$this->get_UTC_DateTimeZone()
580
+			);
581
+			if ($DateTime instanceof \DateTime) {
582
+				$DateTime = new DbSafeDateTime(
583
+					$DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
584
+					$this->get_UTC_DateTimeZone()
585
+				);
586
+			}
587
+		}
588
+
589
+		if (! $DateTime instanceof DbSafeDateTime) {
590
+			// if still no datetime object, then let's just use now
591
+			$DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->get_UTC_DateTimeZone());
592
+		}
593
+		// THEN apply the field's set DateTimeZone
594
+		EEH_DTT_Helper::setTimezone($DateTime, $this->_DateTimeZone);
595
+		return $DateTime;
596
+	}
597
+
598
+
599
+	/**
600
+	 * All this method does is determine if we're going to display the timezone string or not on any output.
601
+	 * To determine this we check if the set timezone offset is different than the blog's set timezone offset.
602
+	 * If so, then true.
603
+	 *
604
+	 * @return bool true for yes false for no
605
+	 * @throws \EE_Error
606
+	 */
607
+	protected function _display_timezone()
608
+	{
609
+
610
+		// first let's do a comparison of timezone strings.
611
+		// If they match then we can get out without any further calculations
612
+		$blog_string = get_option('timezone_string');
613
+		if ($blog_string === $this->_timezone_string) {
614
+			return false;
615
+		}
616
+		// now we need to calc the offset for the timezone string so we can compare with the blog offset.
617
+		$this_offset = $this->get_timezone_offset($this->_DateTimeZone);
618
+		$blog_offset = $this->get_timezone_offset($this->get_blog_DateTimeZone());
619
+		// now compare
620
+		return $blog_offset !== $this_offset;
621
+	}
622
+
623
+
624
+	/**
625
+	 * This method returns a php DateTime object for setting on the EE_Base_Class model.
626
+	 * EE passes around DateTime objects because they are MUCH easier to manipulate and deal
627
+	 * with.
628
+	 *
629
+	 * @param int|string|DateTime $date_string            This should be the incoming date string.  It's assumed to be
630
+	 *                                                    in the format that is set on the date_field (or DateTime
631
+	 *                                                    object)!
632
+	 * @return DateTime
633
+	 */
634
+	protected function _get_date_object($date_string)
635
+	{
636
+		// first if this is an empty date_string and nullable is allowed, just return null.
637
+		if ($this->_nullable && empty($date_string)) {
638
+			return null;
639
+		}
640
+
641
+		// if incoming date
642
+		if ($date_string instanceof DateTime) {
643
+			EEH_DTT_Helper::setTimezone($date_string, $this->_DateTimeZone);
644
+			return $date_string;
645
+		}
646
+		// if empty date_string and made it here.
647
+		// Return a datetime object for now in the given timezone.
648
+		if (empty($date_string)) {
649
+			return new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
650
+		}
651
+		// if $date_string is matches something that looks like a Unix timestamp let's just use it.
652
+		if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $date_string)) {
653
+			try {
654
+				// This is operating under the assumption that the incoming Unix timestamp
655
+				// is an ACTUAL Unix timestamp and not the calculated one output by current_time('timestamp');
656
+				$DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
657
+				$DateTime->setTimestamp($date_string);
658
+
659
+				return $DateTime;
660
+			} catch (Exception $e) {
661
+				// should be rare, but if things got fooled then let's just continue
662
+			}
663
+		}
664
+		// not a unix timestamp.  So we will use the set format on this object and set timezone to
665
+		// create the DateTime object.
666
+		$format = $this->_date_format . ' ' . $this->_time_format;
667
+		try {
668
+			$DateTime = DateTime::createFromFormat($format, $date_string, $this->_DateTimeZone);
669
+			if ($DateTime instanceof DateTime) {
670
+				$DateTime = new DbSafeDateTime(
671
+					$DateTime->format(\EE_Datetime_Field::mysql_timestamp_format),
672
+					$this->_DateTimeZone
673
+				);
674
+			}
675
+			if (! $DateTime instanceof DbSafeDateTime) {
676
+				throw new EE_Error(
677
+					sprintf(
678
+						__('"%1$s" does not represent a valid Date Time in the format "%2$s".', 'event_espresso'),
679
+						$date_string,
680
+						$format
681
+					)
682
+				);
683
+			}
684
+		} catch (Exception $e) {
685
+			// if we made it here then likely then something went really wrong.
686
+			// Instead of throwing an exception, let's just return a DateTime object for now, in the set timezone.
687
+			$DateTime = new DbSafeDateTime(\EE_Datetime_Field::now, $this->_DateTimeZone);
688
+		}
689
+
690
+		return $DateTime;
691
+	}
692
+
693
+
694
+
695
+	/**
696
+	 * get_timezone_transitions
697
+	 *
698
+	 * @param \DateTimeZone $DateTimeZone
699
+	 * @param int           $time
700
+	 * @param bool          $first_only
701
+	 * @return mixed
702
+	 */
703
+	public function get_timezone_transitions(DateTimeZone $DateTimeZone, $time = null, $first_only = true)
704
+	{
705
+		return EEH_DTT_Helper::get_timezone_transitions($DateTimeZone, $time, $first_only);
706
+	}
707
+
708
+
709
+
710
+	/**
711
+	 * get_timezone_offset
712
+	 *
713
+	 * @param \DateTimeZone $DateTimeZone
714
+	 * @param int           $time
715
+	 * @return mixed
716
+	 * @throws \DomainException
717
+	 */
718
+	public function get_timezone_offset(DateTimeZone $DateTimeZone, $time = null)
719
+	{
720
+		return EEH_DTT_Helper::get_timezone_offset($DateTimeZone, $time);
721
+	}
722
+
723
+
724
+	/**
725
+	 * This will take an incoming timezone string and return the abbreviation for that timezone
726
+	 *
727
+	 * @param  string $timezone_string
728
+	 * @return string           abbreviation
729
+	 * @throws \EE_Error
730
+	 */
731
+	public function get_timezone_abbrev($timezone_string)
732
+	{
733
+		$timezone_string = EEH_DTT_Helper::get_valid_timezone_string($timezone_string);
734
+		$dateTime        = new DateTime(\EE_Datetime_Field::now, new DateTimeZone($timezone_string));
735
+
736
+		return $dateTime->format('T');
737
+	}
738
+
739
+	/**
740
+	 * Overrides the parent to allow for having a dynamic "now" value
741
+	 *
742
+	 * @return mixed
743
+	 */
744
+	public function get_default_value()
745
+	{
746
+		if ($this->_default_value === EE_Datetime_Field::now) {
747
+			return time();
748
+		} else {
749
+			return parent::get_default_value();
750
+		}
751
+	}
752
+
753
+	/**
754
+	 * Gets the default datetime object from the field's default time
755
+	 * @since $VID:$
756
+	 * @return DbSafeDateTime|null
757
+	 * @throws InvalidArgumentException
758
+	 * @throws InvalidDataTypeException
759
+	 * @throws InvalidInterfaceException
760
+	 */
761
+	public function getDefaultDateTimeObj()
762
+	{
763
+		$default_raw = $this->get_default_value();
764
+		if ($default_raw instanceof DateTime) {
765
+			return $default_raw;
766
+		} elseif (is_null($default_raw)) {
767
+			return $default_raw;
768
+		} else {
769
+			return new DbSafeDateTime(
770
+				$this->get_default_value(),
771
+				EEH_DTT_Helper::get_valid_timezone_string($this->get_timezone())
772
+			);
773
+		}
774
+	}
775
+
776
+	public function getSchemaDescription()
777
+	{
778
+		return sprintf(
779
+			esc_html__('%s - the value for this field is in the timezone of the site.', 'event_espresso'),
780
+			$this->get_nicename()
781
+		);
782
+	}
783 783
 }
Please login to merge, or discard this patch.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1278 added lines, -1278 removed lines patch added patch discarded remove patch
@@ -16,1282 +16,1282 @@
 block discarded – undo
16 16
 {
17 17
 
18 18
 
19
-    /**
20
-     * Extend_Events_Admin_Page constructor.
21
-     *
22
-     * @param bool $routing
23
-     */
24
-    public function __construct($routing = true)
25
-    {
26
-        parent::__construct($routing);
27
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
29
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
30
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
31
-        }
32
-    }
33
-
34
-
35
-    /**
36
-     * Sets routes.
37
-     */
38
-    protected function _extend_page_config()
39
-    {
40
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
41
-        // is there a evt_id in the request?
42
-        $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
43
-            ? $this->_req_data['EVT_ID']
44
-            : 0;
45
-        $evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
46
-        // tkt_id?
47
-        $tkt_id = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
48
-            ? $this->_req_data['TKT_ID']
49
-            : 0;
50
-        $new_page_routes = array(
51
-            'duplicate_event'          => array(
52
-                'func'       => '_duplicate_event',
53
-                'capability' => 'ee_edit_event',
54
-                'obj_id'     => $evt_id,
55
-                'noheader'   => true,
56
-            ),
57
-            'ticket_list_table'        => array(
58
-                'func'       => '_tickets_overview_list_table',
59
-                'capability' => 'ee_read_default_tickets',
60
-            ),
61
-            'trash_ticket'             => array(
62
-                'func'       => '_trash_or_restore_ticket',
63
-                'capability' => 'ee_delete_default_ticket',
64
-                'obj_id'     => $tkt_id,
65
-                'noheader'   => true,
66
-                'args'       => array('trash' => true),
67
-            ),
68
-            'trash_tickets'            => array(
69
-                'func'       => '_trash_or_restore_ticket',
70
-                'capability' => 'ee_delete_default_tickets',
71
-                'noheader'   => true,
72
-                'args'       => array('trash' => true),
73
-            ),
74
-            'restore_ticket'           => array(
75
-                'func'       => '_trash_or_restore_ticket',
76
-                'capability' => 'ee_delete_default_ticket',
77
-                'obj_id'     => $tkt_id,
78
-                'noheader'   => true,
79
-            ),
80
-            'restore_tickets'          => array(
81
-                'func'       => '_trash_or_restore_ticket',
82
-                'capability' => 'ee_delete_default_tickets',
83
-                'noheader'   => true,
84
-            ),
85
-            'delete_ticket'            => array(
86
-                'func'       => '_delete_ticket',
87
-                'capability' => 'ee_delete_default_ticket',
88
-                'obj_id'     => $tkt_id,
89
-                'noheader'   => true,
90
-            ),
91
-            'delete_tickets'           => array(
92
-                'func'       => '_delete_ticket',
93
-                'capability' => 'ee_delete_default_tickets',
94
-                'noheader'   => true,
95
-            ),
96
-            'import_page'              => array(
97
-                'func'       => '_import_page',
98
-                'capability' => 'import',
99
-            ),
100
-            'import'                   => array(
101
-                'func'       => '_import_events',
102
-                'capability' => 'import',
103
-                'noheader'   => true,
104
-            ),
105
-            'import_events'            => array(
106
-                'func'       => '_import_events',
107
-                'capability' => 'import',
108
-                'noheader'   => true,
109
-            ),
110
-            'export_events'            => array(
111
-                'func'       => '_events_export',
112
-                'capability' => 'export',
113
-                'noheader'   => true,
114
-            ),
115
-            'export_categories'        => array(
116
-                'func'       => '_categories_export',
117
-                'capability' => 'export',
118
-                'noheader'   => true,
119
-            ),
120
-            'sample_export_file'       => array(
121
-                'func'       => '_sample_export_file',
122
-                'capability' => 'export',
123
-                'noheader'   => true,
124
-            ),
125
-            'update_template_settings' => array(
126
-                'func'       => '_update_template_settings',
127
-                'capability' => 'manage_options',
128
-                'noheader'   => true,
129
-            ),
130
-        );
131
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
132
-        // partial route/config override
133
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
134
-        $this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
135
-        $this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
136
-        $this->_page_config['edit']['qtips'][] = 'EE_Event_Editor_Tips';
137
-        $this->_page_config['edit']['metaboxes'][] = '_premium_event_editor_meta_boxes';
138
-        $this->_page_config['default']['list_table'] = 'Extend_Events_Admin_List_Table';
139
-        // add tickets tab but only if there are more than one default ticket!
140
-        $tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
141
-            array(array('TKT_is_default' => 1)),
142
-            'TKT_ID',
143
-            true
144
-        );
145
-        if ($tkt_count > 1) {
146
-            $new_page_config = array(
147
-                'ticket_list_table' => array(
148
-                    'nav'           => array(
149
-                        'label' => esc_html__('Default Tickets', 'event_espresso'),
150
-                        'order' => 60,
151
-                    ),
152
-                    'list_table'    => 'Tickets_List_Table',
153
-                    'require_nonce' => false,
154
-                ),
155
-            );
156
-        }
157
-        // template settings
158
-        $new_page_config['template_settings'] = array(
159
-            'nav'           => array(
160
-                'label' => esc_html__('Templates', 'event_espresso'),
161
-                'order' => 30,
162
-            ),
163
-            'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
164
-            'help_tabs'     => array(
165
-                'general_settings_templates_help_tab' => array(
166
-                    'title'    => esc_html__('Templates', 'event_espresso'),
167
-                    'filename' => 'general_settings_templates',
168
-                ),
169
-            ),
170
-            'help_tour'     => array('Templates_Help_Tour'),
171
-            'require_nonce' => false,
172
-        );
173
-        $this->_page_config = array_merge($this->_page_config, $new_page_config);
174
-        // add filters and actions
175
-        // modifying _views
176
-        add_filter(
177
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
178
-            array($this, 'add_additional_datetime_button'),
179
-            10,
180
-            2
181
-        );
182
-        add_filter(
183
-            'FHEE_event_datetime_metabox_clone_button_template',
184
-            array($this, 'add_datetime_clone_button'),
185
-            10,
186
-            2
187
-        );
188
-        add_filter(
189
-            'FHEE_event_datetime_metabox_timezones_template',
190
-            array($this, 'datetime_timezones_template'),
191
-            10,
192
-            2
193
-        );
194
-        // filters for event list table
195
-        add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
196
-        add_filter(
197
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
198
-            array($this, 'extra_list_table_actions'),
199
-            10,
200
-            2
201
-        );
202
-        // legend item
203
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
204
-        add_action('admin_init', array($this, 'admin_init'));
205
-        // heartbeat stuff
206
-        add_filter('heartbeat_received', array($this, 'heartbeat_response'), 10, 2);
207
-    }
208
-
209
-
210
-    /**
211
-     * admin_init
212
-     */
213
-    public function admin_init()
214
-    {
215
-        EE_Registry::$i18n_js_strings = array_merge(
216
-            EE_Registry::$i18n_js_strings,
217
-            array(
218
-                'image_confirm'          => esc_html__(
219
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
220
-                    'event_espresso'
221
-                ),
222
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
223
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
224
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
225
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
226
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
227
-            )
228
-        );
229
-    }
230
-
231
-
232
-    /**
233
-     * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
234
-     * accordingly.
235
-     *
236
-     * @param array $response The existing heartbeat response array.
237
-     * @param array $data     The incoming data package.
238
-     * @return array  possibly appended response.
239
-     */
240
-    public function heartbeat_response($response, $data)
241
-    {
242
-        /**
243
-         * check whether count of tickets is approaching the potential
244
-         * limits for the server.
245
-         */
246
-        if (! empty($data['input_count'])) {
247
-            $response['max_input_vars_check'] = EE_Registry::instance()->CFG->environment->max_input_vars_limit_check(
248
-                $data['input_count']
249
-            );
250
-        }
251
-        return $response;
252
-    }
253
-
254
-
255
-    /**
256
-     * Add per page screen options to the default ticket list table view.
257
-     */
258
-    protected function _add_screen_options_ticket_list_table()
259
-    {
260
-        $this->_per_page_screen_option();
261
-    }
262
-
263
-
264
-    /**
265
-     * @param string $return
266
-     * @param int    $id
267
-     * @param string $new_title
268
-     * @param string $new_slug
269
-     * @return string
270
-     */
271
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
272
-    {
273
-        $return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
274
-        // make sure this is only when editing
275
-        if (! empty($id)) {
276
-            $href = EE_Admin_Page::add_query_args_and_nonce(
277
-                array('action' => 'duplicate_event', 'EVT_ID' => $id),
278
-                $this->_admin_base_url
279
-            );
280
-            $title = esc_attr__('Duplicate Event', 'event_espresso');
281
-            $return .= '<a href="'
282
-                       . $href
283
-                       . '" title="'
284
-                       . $title
285
-                       . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
286
-                       . $title
287
-                       . '</a>';
288
-        }
289
-        return $return;
290
-    }
291
-
292
-
293
-    /**
294
-     * Set the list table views for the default ticket list table view.
295
-     */
296
-    public function _set_list_table_views_ticket_list_table()
297
-    {
298
-        $this->_views = array(
299
-            'all'     => array(
300
-                'slug'        => 'all',
301
-                'label'       => esc_html__('All', 'event_espresso'),
302
-                'count'       => 0,
303
-                'bulk_action' => array(
304
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
305
-                ),
306
-            ),
307
-            'trashed' => array(
308
-                'slug'        => 'trashed',
309
-                'label'       => esc_html__('Trash', 'event_espresso'),
310
-                'count'       => 0,
311
-                'bulk_action' => array(
312
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
313
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
314
-                ),
315
-            ),
316
-        );
317
-    }
318
-
319
-
320
-    /**
321
-     * Enqueue scripts and styles for the event editor.
322
-     */
323
-    public function load_scripts_styles_edit()
324
-    {
325
-        wp_register_script(
326
-            'ee-event-editor-heartbeat',
327
-            EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
328
-            array('ee_admin_js', 'heartbeat'),
329
-            EVENT_ESPRESSO_VERSION,
330
-            true
331
-        );
332
-        wp_enqueue_script('ee-accounting');
333
-        // styles
334
-        wp_enqueue_style('espresso-ui-theme');
335
-        wp_enqueue_script('event_editor_js');
336
-        wp_enqueue_script('ee-event-editor-heartbeat');
337
-    }
338
-
339
-
340
-    /**
341
-     * Returns template for the additional datetime.
342
-     *
343
-     * @param $template
344
-     * @param $template_args
345
-     * @return mixed
346
-     * @throws DomainException
347
-     */
348
-    public function add_additional_datetime_button($template, $template_args)
349
-    {
350
-        return EEH_Template::display_template(
351
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
352
-            $template_args,
353
-            true
354
-        );
355
-    }
356
-
357
-
358
-    /**
359
-     * Returns the template for cloning a datetime.
360
-     *
361
-     * @param $template
362
-     * @param $template_args
363
-     * @return mixed
364
-     * @throws DomainException
365
-     */
366
-    public function add_datetime_clone_button($template, $template_args)
367
-    {
368
-        return EEH_Template::display_template(
369
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
370
-            $template_args,
371
-            true
372
-        );
373
-    }
374
-
375
-
376
-    /**
377
-     * Returns the template for datetime timezones.
378
-     *
379
-     * @param $template
380
-     * @param $template_args
381
-     * @return mixed
382
-     * @throws DomainException
383
-     */
384
-    public function datetime_timezones_template($template, $template_args)
385
-    {
386
-        return EEH_Template::display_template(
387
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
388
-            $template_args,
389
-            true
390
-        );
391
-    }
392
-
393
-
394
-    /**
395
-     * Sets the views for the default list table view.
396
-     */
397
-    protected function _set_list_table_views_default()
398
-    {
399
-        parent::_set_list_table_views_default();
400
-        $new_views = array(
401
-            'today' => array(
402
-                'slug'        => 'today',
403
-                'label'       => esc_html__('Today', 'event_espresso'),
404
-                'count'       => $this->total_events_today(),
405
-                'bulk_action' => array(
406
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
407
-                ),
408
-            ),
409
-            'month' => array(
410
-                'slug'        => 'month',
411
-                'label'       => esc_html__('This Month', 'event_espresso'),
412
-                'count'       => $this->total_events_this_month(),
413
-                'bulk_action' => array(
414
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
415
-                ),
416
-            ),
417
-        );
418
-        $this->_views = array_merge($this->_views, $new_views);
419
-    }
420
-
421
-
422
-    /**
423
-     * Returns the extra action links for the default list table view.
424
-     *
425
-     * @param array     $action_links
426
-     * @param \EE_Event $event
427
-     * @return array
428
-     * @throws EE_Error
429
-     */
430
-    public function extra_list_table_actions(array $action_links, \EE_Event $event)
431
-    {
432
-        if (EE_Registry::instance()->CAP->current_user_can(
433
-            'ee_read_registrations',
434
-            'espresso_registrations_reports',
435
-            $event->ID()
436
-        )
437
-        ) {
438
-            $reports_query_args = array(
439
-                'action' => 'reports',
440
-                'EVT_ID' => $event->ID(),
441
-            );
442
-            $reports_link = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
443
-            $action_links[] = '<a href="'
444
-                              . $reports_link
445
-                              . '" title="'
446
-                              . esc_attr__('View Report', 'event_espresso')
447
-                              . '"><div class="dashicons dashicons-chart-bar"></div></a>'
448
-                              . "\n\t";
449
-        }
450
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
451
-            EE_Registry::instance()->load_helper('MSG_Template');
452
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
453
-                'see_notifications_for',
454
-                null,
455
-                array('EVT_ID' => $event->ID())
456
-            );
457
-        }
458
-        return $action_links;
459
-    }
460
-
461
-
462
-    /**
463
-     * @param $items
464
-     * @return mixed
465
-     */
466
-    public function additional_legend_items($items)
467
-    {
468
-        if (EE_Registry::instance()->CAP->current_user_can(
469
-            'ee_read_registrations',
470
-            'espresso_registrations_reports'
471
-        )
472
-        ) {
473
-            $items['reports'] = array(
474
-                'class' => 'dashicons dashicons-chart-bar',
475
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
476
-            );
477
-        }
478
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
479
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
480
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
481
-                $items['view_related_messages'] = array(
482
-                    'class' => $related_for_icon['css_class'],
483
-                    'desc'  => $related_for_icon['label'],
484
-                );
485
-            }
486
-        }
487
-        return $items;
488
-    }
489
-
490
-
491
-    /**
492
-     * This is the callback method for the duplicate event route
493
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
494
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
495
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
496
-     * After duplication the redirect is to the new event edit page.
497
-     *
498
-     * @return void
499
-     * @access protected
500
-     * @throws EE_Error If EE_Event is not available with given ID
501
-     */
502
-    protected function _duplicate_event()
503
-    {
504
-        // first make sure the ID for the event is in the request.
505
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
506
-        if (! isset($this->_req_data['EVT_ID'])) {
507
-            EE_Error::add_error(
508
-                esc_html__(
509
-                    'In order to duplicate an event an Event ID is required.  None was given.',
510
-                    'event_espresso'
511
-                ),
512
-                __FILE__,
513
-                __FUNCTION__,
514
-                __LINE__
515
-            );
516
-            $this->_redirect_after_action(false, '', '', array(), true);
517
-            return;
518
-        }
519
-        // k we've got EVT_ID so let's use that to get the event we'll duplicate
520
-        $orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
521
-        if (! $orig_event instanceof EE_Event) {
522
-            throw new EE_Error(
523
-                sprintf(
524
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
525
-                    $this->_req_data['EVT_ID']
526
-                )
527
-            );
528
-        }
529
-        // k now let's clone the $orig_event before getting relations
530
-        $new_event = clone $orig_event;
531
-        // original datetimes
532
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
533
-        // other original relations
534
-        $orig_ven = $orig_event->get_many_related('Venue');
535
-        // reset the ID and modify other details to make it clear this is a dupe
536
-        $new_event->set('EVT_ID', 0);
537
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
538
-        $new_event->set('EVT_name', $new_name);
539
-        $new_event->set(
540
-            'EVT_slug',
541
-            wp_unique_post_slug(
542
-                sanitize_title($orig_event->name()),
543
-                0,
544
-                'publish',
545
-                'espresso_events',
546
-                0
547
-            )
548
-        );
549
-        $new_event->set('status', 'draft');
550
-        // duplicate discussion settings
551
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
552
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
553
-        // save the new event
554
-        $new_event->save();
555
-        // venues
556
-        foreach ($orig_ven as $ven) {
557
-            $new_event->_add_relation_to($ven, 'Venue');
558
-        }
559
-        $new_event->save();
560
-        // now we need to get the question group relations and handle that
561
-        // first primary question groups
562
-        $orig_primary_qgs = $orig_event->get_many_related(
563
-            'Question_Group',
564
-            array(array('Event_Question_Group.EQG_primary' => 1))
565
-        );
566
-        if (! empty($orig_primary_qgs)) {
567
-            foreach ($orig_primary_qgs as $id => $obj) {
568
-                if ($obj instanceof EE_Question_Group) {
569
-                    $new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 1));
570
-                }
571
-            }
572
-        }
573
-        // next additional attendee question groups
574
-        $orig_additional_qgs = $orig_event->get_many_related(
575
-            'Question_Group',
576
-            array(array('Event_Question_Group.EQG_primary' => 0))
577
-        );
578
-        if (! empty($orig_additional_qgs)) {
579
-            foreach ($orig_additional_qgs as $id => $obj) {
580
-                if ($obj instanceof EE_Question_Group) {
581
-                    $new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 0));
582
-                }
583
-            }
584
-        }
585
-
586
-        $new_event->save();
587
-
588
-        // k now that we have the new event saved we can loop through the datetimes and start adding relations.
589
-        $cloned_tickets = array();
590
-        foreach ($orig_datetimes as $orig_dtt) {
591
-            if (! $orig_dtt instanceof EE_Datetime) {
592
-                continue;
593
-            }
594
-            $new_dtt = clone $orig_dtt;
595
-            $orig_tkts = $orig_dtt->tickets();
596
-            // save new dtt then add to event
597
-            $new_dtt->set('DTT_ID', 0);
598
-            $new_dtt->set('DTT_sold', 0);
599
-            $new_dtt->set_reserved(0);
600
-            $new_dtt->save();
601
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
602
-            $new_event->save();
603
-            // now let's get the ticket relations setup.
604
-            foreach ((array) $orig_tkts as $orig_tkt) {
605
-                // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
606
-                if (! $orig_tkt instanceof EE_Ticket) {
607
-                    continue;
608
-                }
609
-                // is this ticket archived?  If it is then let's skip
610
-                if ($orig_tkt->get('TKT_deleted')) {
611
-                    continue;
612
-                }
613
-                // does this original ticket already exist in the clone_tickets cache?
614
-                //  If so we'll just use the new ticket from it.
615
-                if (isset($cloned_tickets[ $orig_tkt->ID() ])) {
616
-                    $new_tkt = $cloned_tickets[ $orig_tkt->ID() ];
617
-                } else {
618
-                    $new_tkt = clone $orig_tkt;
619
-                    // get relations on the $orig_tkt that we need to setup.
620
-                    $orig_prices = $orig_tkt->prices();
621
-                    $new_tkt->set('TKT_ID', 0);
622
-                    $new_tkt->set('TKT_sold', 0);
623
-                    $new_tkt->set('TKT_reserved', 0);
624
-                    $new_tkt->save(); // make sure new ticket has ID.
625
-                    // price relations on new ticket need to be setup.
626
-                    foreach ($orig_prices as $orig_price) {
627
-                        $new_price = clone $orig_price;
628
-                        $new_price->set('PRC_ID', 0);
629
-                        $new_price->save();
630
-                        $new_tkt->_add_relation_to($new_price, 'Price');
631
-                        $new_tkt->save();
632
-                    }
633
-
634
-                    do_action(
635
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
636
-                        $orig_tkt,
637
-                        $new_tkt,
638
-                        $orig_prices,
639
-                        $orig_event,
640
-                        $orig_dtt,
641
-                        $new_dtt
642
-                    );
643
-                }
644
-                // k now we can add the new ticket as a relation to the new datetime
645
-                // and make sure its added to our cached $cloned_tickets array
646
-                // for use with later datetimes that have the same ticket.
647
-                $new_dtt->_add_relation_to($new_tkt, 'Ticket');
648
-                $new_dtt->save();
649
-                $cloned_tickets[ $orig_tkt->ID() ] = $new_tkt;
650
-            }
651
-        }
652
-        // clone taxonomy information
653
-        $taxonomies_to_clone_with = apply_filters(
654
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
655
-            array('espresso_event_categories', 'espresso_event_type', 'post_tag')
656
-        );
657
-        // get terms for original event (notice)
658
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
659
-        // loop through terms and add them to new event.
660
-        foreach ($orig_terms as $term) {
661
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
662
-        }
663
-
664
-        // duplicate other core WP_Post items for this event.
665
-        // post thumbnail (feature image).
666
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
667
-        if ($feature_image_id) {
668
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
669
-        }
670
-
671
-        // duplicate page_template setting
672
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
673
-        if ($page_template) {
674
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
675
-        }
676
-
677
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
678
-        // now let's redirect to the edit page for this duplicated event if we have a new event id.
679
-        if ($new_event->ID()) {
680
-            $redirect_args = array(
681
-                'post'   => $new_event->ID(),
682
-                'action' => 'edit',
683
-            );
684
-            EE_Error::add_success(
685
-                esc_html__(
686
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
687
-                    'event_espresso'
688
-                )
689
-            );
690
-        } else {
691
-            $redirect_args = array(
692
-                'action' => 'default',
693
-            );
694
-            EE_Error::add_error(
695
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
696
-                __FILE__,
697
-                __FUNCTION__,
698
-                __LINE__
699
-            );
700
-        }
701
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
702
-    }
703
-
704
-
705
-    /**
706
-     * Generates output for the import page.
707
-     *
708
-     * @throws DomainException
709
-     */
710
-    protected function _import_page()
711
-    {
712
-        $title = esc_html__('Import', 'event_espresso');
713
-        $intro = esc_html__(
714
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
715
-            'event_espresso'
716
-        );
717
-        $form_url = EVENTS_ADMIN_URL;
718
-        $action = 'import_events';
719
-        $type = 'csv';
720
-        $this->_template_args['form'] = EE_Import::instance()->upload_form(
721
-            $title,
722
-            $intro,
723
-            $form_url,
724
-            $action,
725
-            $type
726
-        );
727
-        $this->_template_args['sample_file_link'] = EE_Admin_Page::add_query_args_and_nonce(
728
-            array('action' => 'sample_export_file'),
729
-            $this->_admin_base_url
730
-        );
731
-        $content = EEH_Template::display_template(
732
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
733
-            $this->_template_args,
734
-            true
735
-        );
736
-        $this->_template_args['admin_page_content'] = $content;
737
-        $this->display_admin_page_with_sidebar();
738
-    }
739
-
740
-
741
-    /**
742
-     * _import_events
743
-     * This handles displaying the screen and running imports for importing events.
744
-     *
745
-     * @return void
746
-     */
747
-    protected function _import_events()
748
-    {
749
-        require_once(EE_CLASSES . 'EE_Import.class.php');
750
-        $success = EE_Import::instance()->import();
751
-        $this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
752
-    }
753
-
754
-
755
-    /**
756
-     * _events_export
757
-     * Will export all (or just the given event) to a Excel compatible file.
758
-     *
759
-     * @access protected
760
-     * @return void
761
-     */
762
-    protected function _events_export()
763
-    {
764
-        if (isset($this->_req_data['EVT_ID'])) {
765
-            $event_ids = $this->_req_data['EVT_ID'];
766
-        } elseif (isset($this->_req_data['EVT_IDs'])) {
767
-            $event_ids = $this->_req_data['EVT_IDs'];
768
-        } else {
769
-            $event_ids = null;
770
-        }
771
-        // todo: I don't like doing this but it'll do until we modify EE_Export Class.
772
-        $new_request_args = array(
773
-            'export' => 'report',
774
-            'action' => 'all_event_data',
775
-            'EVT_ID' => $event_ids,
776
-        );
777
-        $this->_req_data = array_merge($this->_req_data, $new_request_args);
778
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
779
-            require_once(EE_CLASSES . 'EE_Export.class.php');
780
-            $EE_Export = EE_Export::instance($this->_req_data);
781
-            $EE_Export->export();
782
-        }
783
-    }
784
-
785
-
786
-    /**
787
-     * handle category exports()
788
-     *
789
-     * @return void
790
-     */
791
-    protected function _categories_export()
792
-    {
793
-        // todo: I don't like doing this but it'll do until we modify EE_Export Class.
794
-        $new_request_args = array(
795
-            'export'       => 'report',
796
-            'action'       => 'categories',
797
-            'category_ids' => $this->_req_data['EVT_CAT_ID'],
798
-        );
799
-        $this->_req_data = array_merge($this->_req_data, $new_request_args);
800
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
801
-            require_once(EE_CLASSES . 'EE_Export.class.php');
802
-            $EE_Export = EE_Export::instance($this->_req_data);
803
-            $EE_Export->export();
804
-        }
805
-    }
806
-
807
-
808
-    /**
809
-     * Creates a sample CSV file for importing
810
-     */
811
-    protected function _sample_export_file()
812
-    {
813
-        // require_once(EE_CLASSES . 'EE_Export.class.php');
814
-        EE_Export::instance()->export_sample();
815
-    }
816
-
817
-
818
-    /*************        Template Settings        *************/
819
-    /**
820
-     * Generates template settings page output
821
-     *
822
-     * @throws DomainException
823
-     * @throws EE_Error
824
-     */
825
-    protected function _template_settings()
826
-    {
827
-        $this->_template_args['values'] = $this->_yes_no_values;
828
-        /**
829
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
830
-         * from General_Settings_Admin_Page to here.
831
-         */
832
-        $this->_template_args = apply_filters(
833
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
834
-            $this->_template_args
835
-        );
836
-        $this->_set_add_edit_form_tags('update_template_settings');
837
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
838
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
839
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
840
-            $this->_template_args,
841
-            true
842
-        );
843
-        $this->display_admin_page_with_sidebar();
844
-    }
845
-
846
-
847
-    /**
848
-     * Handler for updating template settings.
849
-     *
850
-     * @throws InvalidInterfaceException
851
-     * @throws InvalidDataTypeException
852
-     * @throws InvalidArgumentException
853
-     */
854
-    protected function _update_template_settings()
855
-    {
856
-        /**
857
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
858
-         * from General_Settings_Admin_Page to here.
859
-         */
860
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
861
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
862
-            EE_Registry::instance()->CFG->template_settings,
863
-            $this->_req_data
864
-        );
865
-        // update custom post type slugs and detect if we need to flush rewrite rules
866
-        $old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
867
-        EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
868
-            ? EE_Registry::instance()->CFG->core->event_cpt_slug
869
-            : EEH_URL::slugify($this->_req_data['event_cpt_slug'], 'events');
870
-        $what = 'Template Settings';
871
-        $success = $this->_update_espresso_configuration(
872
-            $what,
873
-            EE_Registry::instance()->CFG->template_settings,
874
-            __FILE__,
875
-            __FUNCTION__,
876
-            __LINE__
877
-        );
878
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
879
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
880
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
881
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
882
-            );
883
-            $rewrite_rules->flush();
884
-        }
885
-        $this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
886
-    }
887
-
888
-
889
-    /**
890
-     * _premium_event_editor_meta_boxes
891
-     * add all metaboxes related to the event_editor
892
-     *
893
-     * @access protected
894
-     * @return void
895
-     * @throws EE_Error
896
-     */
897
-    protected function _premium_event_editor_meta_boxes()
898
-    {
899
-        $this->verify_cpt_object();
900
-        add_meta_box(
901
-            'espresso_event_editor_event_options',
902
-            esc_html__('Event Registration Options', 'event_espresso'),
903
-            array($this, 'registration_options_meta_box'),
904
-            $this->page_slug,
905
-            'side',
906
-            'core'
907
-        );
908
-    }
909
-
910
-
911
-    /**
912
-     * override caf metabox
913
-     *
914
-     * @return void
915
-     * @throws DomainException
916
-     */
917
-    public function registration_options_meta_box()
918
-    {
919
-        $yes_no_values = array(
920
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
921
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
922
-        );
923
-        $default_reg_status_values = EEM_Registration::reg_status_array(
924
-            array(
925
-                EEM_Registration::status_id_cancelled,
926
-                EEM_Registration::status_id_declined,
927
-                EEM_Registration::status_id_incomplete,
928
-                EEM_Registration::status_id_wait_list,
929
-            ),
930
-            true
931
-        );
932
-        $template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
933
-        $template_args['_event'] = $this->_cpt_model_obj;
934
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
935
-        $template_args['default_registration_status'] = EEH_Form_Fields::select_input(
936
-            'default_reg_status',
937
-            $default_reg_status_values,
938
-            $this->_cpt_model_obj->default_registration_status()
939
-        );
940
-        $template_args['display_description'] = EEH_Form_Fields::select_input(
941
-            'display_desc',
942
-            $yes_no_values,
943
-            $this->_cpt_model_obj->display_description()
944
-        );
945
-        $template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
946
-            'display_ticket_selector',
947
-            $yes_no_values,
948
-            $this->_cpt_model_obj->display_ticket_selector(),
949
-            '',
950
-            '',
951
-            false
952
-        );
953
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
954
-            'EVT_default_registration_status',
955
-            $default_reg_status_values,
956
-            $this->_cpt_model_obj->default_registration_status()
957
-        );
958
-        $template_args['additional_registration_options'] = apply_filters(
959
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
960
-            '',
961
-            $template_args,
962
-            $yes_no_values,
963
-            $default_reg_status_values
964
-        );
965
-        EEH_Template::display_template(
966
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
967
-            $template_args
968
-        );
969
-    }
970
-
971
-
972
-
973
-    /**
974
-     * wp_list_table_mods for caf
975
-     * ============================
976
-     */
977
-    /**
978
-     * hook into list table filters and provide filters for caffeinated list table
979
-     *
980
-     * @param  array $old_filters    any existing filters present
981
-     * @param  array $list_table_obj the list table object
982
-     * @return array                  new filters
983
-     */
984
-    public function list_table_filters($old_filters, $list_table_obj)
985
-    {
986
-        $filters = array();
987
-        // first month/year filters
988
-        $filters[] = $this->espresso_event_months_dropdown();
989
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
990
-        // active status dropdown
991
-        if ($status !== 'draft') {
992
-            $filters[] = $this->active_status_dropdown(
993
-                isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
994
-            );
995
-        }
996
-        // category filter
997
-        $filters[] = $this->category_dropdown();
998
-        return array_merge($old_filters, $filters);
999
-    }
1000
-
1001
-
1002
-    /**
1003
-     * espresso_event_months_dropdown
1004
-     *
1005
-     * @access public
1006
-     * @return string                dropdown listing month/year selections for events.
1007
-     */
1008
-    public function espresso_event_months_dropdown()
1009
-    {
1010
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
1011
-        // Note we need to include any other filters that are set!
1012
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
1013
-        // categories?
1014
-        $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1015
-            ? $this->_req_data['EVT_CAT']
1016
-            : null;
1017
-        // active status?
1018
-        $active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
1019
-        $cur_date = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
1020
-        return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * returns a list of "active" statuses on the event
1026
-     *
1027
-     * @param  string $current_value whatever the current active status is
1028
-     * @return string
1029
-     */
1030
-    public function active_status_dropdown($current_value = '')
1031
-    {
1032
-        $select_name = 'active_status';
1033
-        $values = array(
1034
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1035
-            'active'   => esc_html__('Active', 'event_espresso'),
1036
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1037
-            'expired'  => esc_html__('Expired', 'event_espresso'),
1038
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
1039
-        );
1040
-        $id = 'id="espresso-active-status-dropdown-filter"';
1041
-        $class = 'wide';
1042
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1043
-    }
1044
-
1045
-
1046
-    /**
1047
-     * output a dropdown of the categories for the category filter on the event admin list table
1048
-     *
1049
-     * @access  public
1050
-     * @return string html
1051
-     */
1052
-    public function category_dropdown()
1053
-    {
1054
-        $cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1055
-        return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1056
-    }
1057
-
1058
-
1059
-    /**
1060
-     * get total number of events today
1061
-     *
1062
-     * @access public
1063
-     * @return int
1064
-     * @throws EE_Error
1065
-     */
1066
-    public function total_events_today()
1067
-    {
1068
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1069
-            'DTT_EVT_start',
1070
-            date('Y-m-d') . ' 00:00:00',
1071
-            'Y-m-d H:i:s',
1072
-            'UTC'
1073
-        );
1074
-        $end = EEM_Datetime::instance()->convert_datetime_for_query(
1075
-            'DTT_EVT_start',
1076
-            date('Y-m-d') . ' 23:59:59',
1077
-            'Y-m-d H:i:s',
1078
-            'UTC'
1079
-        );
1080
-        $where = array(
1081
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1082
-        );
1083
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1084
-        return $count;
1085
-    }
1086
-
1087
-
1088
-    /**
1089
-     * get total number of events this month
1090
-     *
1091
-     * @access public
1092
-     * @return int
1093
-     * @throws EE_Error
1094
-     */
1095
-    public function total_events_this_month()
1096
-    {
1097
-        // Dates
1098
-        $this_year_r = date('Y');
1099
-        $this_month_r = date('m');
1100
-        $days_this_month = date('t');
1101
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1102
-            'DTT_EVT_start',
1103
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1104
-            'Y-m-d H:i:s',
1105
-            'UTC'
1106
-        );
1107
-        $end = EEM_Datetime::instance()->convert_datetime_for_query(
1108
-            'DTT_EVT_start',
1109
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1110
-            'Y-m-d H:i:s',
1111
-            'UTC'
1112
-        );
1113
-        $where = array(
1114
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1115
-        );
1116
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1117
-        return $count;
1118
-    }
1119
-
1120
-
1121
-    /** DEFAULT TICKETS STUFF **/
1122
-
1123
-    /**
1124
-     * Output default tickets list table view.
1125
-     */
1126
-    public function _tickets_overview_list_table()
1127
-    {
1128
-        $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1129
-        $this->display_admin_list_table_page_with_no_sidebar();
1130
-    }
1131
-
1132
-
1133
-    /**
1134
-     * @param int  $per_page
1135
-     * @param bool $count
1136
-     * @param bool $trashed
1137
-     * @return \EE_Soft_Delete_Base_Class[]|int
1138
-     */
1139
-    public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1140
-    {
1141
-        $orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1142
-        $order = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1143
-        switch ($orderby) {
1144
-            case 'TKT_name':
1145
-                $orderby = array('TKT_name' => $order);
1146
-                break;
1147
-            case 'TKT_price':
1148
-                $orderby = array('TKT_price' => $order);
1149
-                break;
1150
-            case 'TKT_uses':
1151
-                $orderby = array('TKT_uses' => $order);
1152
-                break;
1153
-            case 'TKT_min':
1154
-                $orderby = array('TKT_min' => $order);
1155
-                break;
1156
-            case 'TKT_max':
1157
-                $orderby = array('TKT_max' => $order);
1158
-                break;
1159
-            case 'TKT_qty':
1160
-                $orderby = array('TKT_qty' => $order);
1161
-                break;
1162
-        }
1163
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1164
-            ? $this->_req_data['paged']
1165
-            : 1;
1166
-        $per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1167
-            ? $this->_req_data['perpage']
1168
-            : $per_page;
1169
-        $_where = array(
1170
-            'TKT_is_default' => 1,
1171
-            'TKT_deleted'    => $trashed,
1172
-        );
1173
-        $offset = ($current_page - 1) * $per_page;
1174
-        $limit = array($offset, $per_page);
1175
-        if (isset($this->_req_data['s'])) {
1176
-            $sstr = '%' . $this->_req_data['s'] . '%';
1177
-            $_where['OR'] = array(
1178
-                'TKT_name'        => array('LIKE', $sstr),
1179
-                'TKT_description' => array('LIKE', $sstr),
1180
-            );
1181
-        }
1182
-        $query_params = array(
1183
-            $_where,
1184
-            'order_by' => $orderby,
1185
-            'limit'    => $limit,
1186
-            'group_by' => 'TKT_ID',
1187
-        );
1188
-        if ($count) {
1189
-            return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1190
-        } else {
1191
-            return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1192
-        }
1193
-    }
1194
-
1195
-
1196
-    /**
1197
-     * @param bool $trash
1198
-     * @throws EE_Error
1199
-     */
1200
-    protected function _trash_or_restore_ticket($trash = false)
1201
-    {
1202
-        $success = 1;
1203
-        $TKT = EEM_Ticket::instance();
1204
-        // checkboxes?
1205
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1206
-            // if array has more than one element then success message should be plural
1207
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1208
-            // cycle thru the boxes
1209
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1210
-                if ($trash) {
1211
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1212
-                        $success = 0;
1213
-                    }
1214
-                } else {
1215
-                    if (! $TKT->restore_by_ID($TKT_ID)) {
1216
-                        $success = 0;
1217
-                    }
1218
-                }
1219
-            }
1220
-        } else {
1221
-            // grab single id and trash
1222
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1223
-            if ($trash) {
1224
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1225
-                    $success = 0;
1226
-                }
1227
-            } else {
1228
-                if (! $TKT->restore_by_ID($TKT_ID)) {
1229
-                    $success = 0;
1230
-                }
1231
-            }
1232
-        }
1233
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1234
-        $query_args = array(
1235
-            'action' => 'ticket_list_table',
1236
-            'status' => $trash ? '' : 'trashed',
1237
-        );
1238
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1239
-    }
1240
-
1241
-
1242
-    /**
1243
-     * Handles trashing default ticket.
1244
-     */
1245
-    protected function _delete_ticket()
1246
-    {
1247
-        $success = 1;
1248
-        // checkboxes?
1249
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1250
-            // if array has more than one element then success message should be plural
1251
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1252
-            // cycle thru the boxes
1253
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1254
-                // delete
1255
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1256
-                    $success = 0;
1257
-                }
1258
-            }
1259
-        } else {
1260
-            // grab single id and trash
1261
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1262
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1263
-                $success = 0;
1264
-            }
1265
-        }
1266
-        $action_desc = 'deleted';
1267
-        $query_args = array(
1268
-            'action' => 'ticket_list_table',
1269
-            'status' => 'trashed',
1270
-        );
1271
-        // fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1272
-        if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1273
-            array(array('TKT_is_default' => 1)),
1274
-            'TKT_ID',
1275
-            true
1276
-        )
1277
-        ) {
1278
-            $query_args = array();
1279
-        }
1280
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1281
-    }
1282
-
1283
-
1284
-    /**
1285
-     * @param int $TKT_ID
1286
-     * @return bool|int
1287
-     * @throws EE_Error
1288
-     */
1289
-    protected function _delete_the_ticket($TKT_ID)
1290
-    {
1291
-        $tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1292
-        $tkt->_remove_relations('Datetime');
1293
-        // delete all related prices first
1294
-        $tkt->delete_related_permanently('Price');
1295
-        return $tkt->delete_permanently();
1296
-    }
19
+	/**
20
+	 * Extend_Events_Admin_Page constructor.
21
+	 *
22
+	 * @param bool $routing
23
+	 */
24
+	public function __construct($routing = true)
25
+	{
26
+		parent::__construct($routing);
27
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
29
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
30
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
31
+		}
32
+	}
33
+
34
+
35
+	/**
36
+	 * Sets routes.
37
+	 */
38
+	protected function _extend_page_config()
39
+	{
40
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
41
+		// is there a evt_id in the request?
42
+		$evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
43
+			? $this->_req_data['EVT_ID']
44
+			: 0;
45
+		$evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
46
+		// tkt_id?
47
+		$tkt_id = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
48
+			? $this->_req_data['TKT_ID']
49
+			: 0;
50
+		$new_page_routes = array(
51
+			'duplicate_event'          => array(
52
+				'func'       => '_duplicate_event',
53
+				'capability' => 'ee_edit_event',
54
+				'obj_id'     => $evt_id,
55
+				'noheader'   => true,
56
+			),
57
+			'ticket_list_table'        => array(
58
+				'func'       => '_tickets_overview_list_table',
59
+				'capability' => 'ee_read_default_tickets',
60
+			),
61
+			'trash_ticket'             => array(
62
+				'func'       => '_trash_or_restore_ticket',
63
+				'capability' => 'ee_delete_default_ticket',
64
+				'obj_id'     => $tkt_id,
65
+				'noheader'   => true,
66
+				'args'       => array('trash' => true),
67
+			),
68
+			'trash_tickets'            => array(
69
+				'func'       => '_trash_or_restore_ticket',
70
+				'capability' => 'ee_delete_default_tickets',
71
+				'noheader'   => true,
72
+				'args'       => array('trash' => true),
73
+			),
74
+			'restore_ticket'           => array(
75
+				'func'       => '_trash_or_restore_ticket',
76
+				'capability' => 'ee_delete_default_ticket',
77
+				'obj_id'     => $tkt_id,
78
+				'noheader'   => true,
79
+			),
80
+			'restore_tickets'          => array(
81
+				'func'       => '_trash_or_restore_ticket',
82
+				'capability' => 'ee_delete_default_tickets',
83
+				'noheader'   => true,
84
+			),
85
+			'delete_ticket'            => array(
86
+				'func'       => '_delete_ticket',
87
+				'capability' => 'ee_delete_default_ticket',
88
+				'obj_id'     => $tkt_id,
89
+				'noheader'   => true,
90
+			),
91
+			'delete_tickets'           => array(
92
+				'func'       => '_delete_ticket',
93
+				'capability' => 'ee_delete_default_tickets',
94
+				'noheader'   => true,
95
+			),
96
+			'import_page'              => array(
97
+				'func'       => '_import_page',
98
+				'capability' => 'import',
99
+			),
100
+			'import'                   => array(
101
+				'func'       => '_import_events',
102
+				'capability' => 'import',
103
+				'noheader'   => true,
104
+			),
105
+			'import_events'            => array(
106
+				'func'       => '_import_events',
107
+				'capability' => 'import',
108
+				'noheader'   => true,
109
+			),
110
+			'export_events'            => array(
111
+				'func'       => '_events_export',
112
+				'capability' => 'export',
113
+				'noheader'   => true,
114
+			),
115
+			'export_categories'        => array(
116
+				'func'       => '_categories_export',
117
+				'capability' => 'export',
118
+				'noheader'   => true,
119
+			),
120
+			'sample_export_file'       => array(
121
+				'func'       => '_sample_export_file',
122
+				'capability' => 'export',
123
+				'noheader'   => true,
124
+			),
125
+			'update_template_settings' => array(
126
+				'func'       => '_update_template_settings',
127
+				'capability' => 'manage_options',
128
+				'noheader'   => true,
129
+			),
130
+		);
131
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
132
+		// partial route/config override
133
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
134
+		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
135
+		$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
136
+		$this->_page_config['edit']['qtips'][] = 'EE_Event_Editor_Tips';
137
+		$this->_page_config['edit']['metaboxes'][] = '_premium_event_editor_meta_boxes';
138
+		$this->_page_config['default']['list_table'] = 'Extend_Events_Admin_List_Table';
139
+		// add tickets tab but only if there are more than one default ticket!
140
+		$tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
141
+			array(array('TKT_is_default' => 1)),
142
+			'TKT_ID',
143
+			true
144
+		);
145
+		if ($tkt_count > 1) {
146
+			$new_page_config = array(
147
+				'ticket_list_table' => array(
148
+					'nav'           => array(
149
+						'label' => esc_html__('Default Tickets', 'event_espresso'),
150
+						'order' => 60,
151
+					),
152
+					'list_table'    => 'Tickets_List_Table',
153
+					'require_nonce' => false,
154
+				),
155
+			);
156
+		}
157
+		// template settings
158
+		$new_page_config['template_settings'] = array(
159
+			'nav'           => array(
160
+				'label' => esc_html__('Templates', 'event_espresso'),
161
+				'order' => 30,
162
+			),
163
+			'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
164
+			'help_tabs'     => array(
165
+				'general_settings_templates_help_tab' => array(
166
+					'title'    => esc_html__('Templates', 'event_espresso'),
167
+					'filename' => 'general_settings_templates',
168
+				),
169
+			),
170
+			'help_tour'     => array('Templates_Help_Tour'),
171
+			'require_nonce' => false,
172
+		);
173
+		$this->_page_config = array_merge($this->_page_config, $new_page_config);
174
+		// add filters and actions
175
+		// modifying _views
176
+		add_filter(
177
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
178
+			array($this, 'add_additional_datetime_button'),
179
+			10,
180
+			2
181
+		);
182
+		add_filter(
183
+			'FHEE_event_datetime_metabox_clone_button_template',
184
+			array($this, 'add_datetime_clone_button'),
185
+			10,
186
+			2
187
+		);
188
+		add_filter(
189
+			'FHEE_event_datetime_metabox_timezones_template',
190
+			array($this, 'datetime_timezones_template'),
191
+			10,
192
+			2
193
+		);
194
+		// filters for event list table
195
+		add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
196
+		add_filter(
197
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
198
+			array($this, 'extra_list_table_actions'),
199
+			10,
200
+			2
201
+		);
202
+		// legend item
203
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
204
+		add_action('admin_init', array($this, 'admin_init'));
205
+		// heartbeat stuff
206
+		add_filter('heartbeat_received', array($this, 'heartbeat_response'), 10, 2);
207
+	}
208
+
209
+
210
+	/**
211
+	 * admin_init
212
+	 */
213
+	public function admin_init()
214
+	{
215
+		EE_Registry::$i18n_js_strings = array_merge(
216
+			EE_Registry::$i18n_js_strings,
217
+			array(
218
+				'image_confirm'          => esc_html__(
219
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
220
+					'event_espresso'
221
+				),
222
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
223
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
224
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
225
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
226
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
227
+			)
228
+		);
229
+	}
230
+
231
+
232
+	/**
233
+	 * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
234
+	 * accordingly.
235
+	 *
236
+	 * @param array $response The existing heartbeat response array.
237
+	 * @param array $data     The incoming data package.
238
+	 * @return array  possibly appended response.
239
+	 */
240
+	public function heartbeat_response($response, $data)
241
+	{
242
+		/**
243
+		 * check whether count of tickets is approaching the potential
244
+		 * limits for the server.
245
+		 */
246
+		if (! empty($data['input_count'])) {
247
+			$response['max_input_vars_check'] = EE_Registry::instance()->CFG->environment->max_input_vars_limit_check(
248
+				$data['input_count']
249
+			);
250
+		}
251
+		return $response;
252
+	}
253
+
254
+
255
+	/**
256
+	 * Add per page screen options to the default ticket list table view.
257
+	 */
258
+	protected function _add_screen_options_ticket_list_table()
259
+	{
260
+		$this->_per_page_screen_option();
261
+	}
262
+
263
+
264
+	/**
265
+	 * @param string $return
266
+	 * @param int    $id
267
+	 * @param string $new_title
268
+	 * @param string $new_slug
269
+	 * @return string
270
+	 */
271
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
272
+	{
273
+		$return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
274
+		// make sure this is only when editing
275
+		if (! empty($id)) {
276
+			$href = EE_Admin_Page::add_query_args_and_nonce(
277
+				array('action' => 'duplicate_event', 'EVT_ID' => $id),
278
+				$this->_admin_base_url
279
+			);
280
+			$title = esc_attr__('Duplicate Event', 'event_espresso');
281
+			$return .= '<a href="'
282
+					   . $href
283
+					   . '" title="'
284
+					   . $title
285
+					   . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
286
+					   . $title
287
+					   . '</a>';
288
+		}
289
+		return $return;
290
+	}
291
+
292
+
293
+	/**
294
+	 * Set the list table views for the default ticket list table view.
295
+	 */
296
+	public function _set_list_table_views_ticket_list_table()
297
+	{
298
+		$this->_views = array(
299
+			'all'     => array(
300
+				'slug'        => 'all',
301
+				'label'       => esc_html__('All', 'event_espresso'),
302
+				'count'       => 0,
303
+				'bulk_action' => array(
304
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
305
+				),
306
+			),
307
+			'trashed' => array(
308
+				'slug'        => 'trashed',
309
+				'label'       => esc_html__('Trash', 'event_espresso'),
310
+				'count'       => 0,
311
+				'bulk_action' => array(
312
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
313
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
314
+				),
315
+			),
316
+		);
317
+	}
318
+
319
+
320
+	/**
321
+	 * Enqueue scripts and styles for the event editor.
322
+	 */
323
+	public function load_scripts_styles_edit()
324
+	{
325
+		wp_register_script(
326
+			'ee-event-editor-heartbeat',
327
+			EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
328
+			array('ee_admin_js', 'heartbeat'),
329
+			EVENT_ESPRESSO_VERSION,
330
+			true
331
+		);
332
+		wp_enqueue_script('ee-accounting');
333
+		// styles
334
+		wp_enqueue_style('espresso-ui-theme');
335
+		wp_enqueue_script('event_editor_js');
336
+		wp_enqueue_script('ee-event-editor-heartbeat');
337
+	}
338
+
339
+
340
+	/**
341
+	 * Returns template for the additional datetime.
342
+	 *
343
+	 * @param $template
344
+	 * @param $template_args
345
+	 * @return mixed
346
+	 * @throws DomainException
347
+	 */
348
+	public function add_additional_datetime_button($template, $template_args)
349
+	{
350
+		return EEH_Template::display_template(
351
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
352
+			$template_args,
353
+			true
354
+		);
355
+	}
356
+
357
+
358
+	/**
359
+	 * Returns the template for cloning a datetime.
360
+	 *
361
+	 * @param $template
362
+	 * @param $template_args
363
+	 * @return mixed
364
+	 * @throws DomainException
365
+	 */
366
+	public function add_datetime_clone_button($template, $template_args)
367
+	{
368
+		return EEH_Template::display_template(
369
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
370
+			$template_args,
371
+			true
372
+		);
373
+	}
374
+
375
+
376
+	/**
377
+	 * Returns the template for datetime timezones.
378
+	 *
379
+	 * @param $template
380
+	 * @param $template_args
381
+	 * @return mixed
382
+	 * @throws DomainException
383
+	 */
384
+	public function datetime_timezones_template($template, $template_args)
385
+	{
386
+		return EEH_Template::display_template(
387
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
388
+			$template_args,
389
+			true
390
+		);
391
+	}
392
+
393
+
394
+	/**
395
+	 * Sets the views for the default list table view.
396
+	 */
397
+	protected function _set_list_table_views_default()
398
+	{
399
+		parent::_set_list_table_views_default();
400
+		$new_views = array(
401
+			'today' => array(
402
+				'slug'        => 'today',
403
+				'label'       => esc_html__('Today', 'event_espresso'),
404
+				'count'       => $this->total_events_today(),
405
+				'bulk_action' => array(
406
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
407
+				),
408
+			),
409
+			'month' => array(
410
+				'slug'        => 'month',
411
+				'label'       => esc_html__('This Month', 'event_espresso'),
412
+				'count'       => $this->total_events_this_month(),
413
+				'bulk_action' => array(
414
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
415
+				),
416
+			),
417
+		);
418
+		$this->_views = array_merge($this->_views, $new_views);
419
+	}
420
+
421
+
422
+	/**
423
+	 * Returns the extra action links for the default list table view.
424
+	 *
425
+	 * @param array     $action_links
426
+	 * @param \EE_Event $event
427
+	 * @return array
428
+	 * @throws EE_Error
429
+	 */
430
+	public function extra_list_table_actions(array $action_links, \EE_Event $event)
431
+	{
432
+		if (EE_Registry::instance()->CAP->current_user_can(
433
+			'ee_read_registrations',
434
+			'espresso_registrations_reports',
435
+			$event->ID()
436
+		)
437
+		) {
438
+			$reports_query_args = array(
439
+				'action' => 'reports',
440
+				'EVT_ID' => $event->ID(),
441
+			);
442
+			$reports_link = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
443
+			$action_links[] = '<a href="'
444
+							  . $reports_link
445
+							  . '" title="'
446
+							  . esc_attr__('View Report', 'event_espresso')
447
+							  . '"><div class="dashicons dashicons-chart-bar"></div></a>'
448
+							  . "\n\t";
449
+		}
450
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
451
+			EE_Registry::instance()->load_helper('MSG_Template');
452
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
453
+				'see_notifications_for',
454
+				null,
455
+				array('EVT_ID' => $event->ID())
456
+			);
457
+		}
458
+		return $action_links;
459
+	}
460
+
461
+
462
+	/**
463
+	 * @param $items
464
+	 * @return mixed
465
+	 */
466
+	public function additional_legend_items($items)
467
+	{
468
+		if (EE_Registry::instance()->CAP->current_user_can(
469
+			'ee_read_registrations',
470
+			'espresso_registrations_reports'
471
+		)
472
+		) {
473
+			$items['reports'] = array(
474
+				'class' => 'dashicons dashicons-chart-bar',
475
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
476
+			);
477
+		}
478
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
479
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
480
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
481
+				$items['view_related_messages'] = array(
482
+					'class' => $related_for_icon['css_class'],
483
+					'desc'  => $related_for_icon['label'],
484
+				);
485
+			}
486
+		}
487
+		return $items;
488
+	}
489
+
490
+
491
+	/**
492
+	 * This is the callback method for the duplicate event route
493
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
494
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
495
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
496
+	 * After duplication the redirect is to the new event edit page.
497
+	 *
498
+	 * @return void
499
+	 * @access protected
500
+	 * @throws EE_Error If EE_Event is not available with given ID
501
+	 */
502
+	protected function _duplicate_event()
503
+	{
504
+		// first make sure the ID for the event is in the request.
505
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
506
+		if (! isset($this->_req_data['EVT_ID'])) {
507
+			EE_Error::add_error(
508
+				esc_html__(
509
+					'In order to duplicate an event an Event ID is required.  None was given.',
510
+					'event_espresso'
511
+				),
512
+				__FILE__,
513
+				__FUNCTION__,
514
+				__LINE__
515
+			);
516
+			$this->_redirect_after_action(false, '', '', array(), true);
517
+			return;
518
+		}
519
+		// k we've got EVT_ID so let's use that to get the event we'll duplicate
520
+		$orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
521
+		if (! $orig_event instanceof EE_Event) {
522
+			throw new EE_Error(
523
+				sprintf(
524
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
525
+					$this->_req_data['EVT_ID']
526
+				)
527
+			);
528
+		}
529
+		// k now let's clone the $orig_event before getting relations
530
+		$new_event = clone $orig_event;
531
+		// original datetimes
532
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
533
+		// other original relations
534
+		$orig_ven = $orig_event->get_many_related('Venue');
535
+		// reset the ID and modify other details to make it clear this is a dupe
536
+		$new_event->set('EVT_ID', 0);
537
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
538
+		$new_event->set('EVT_name', $new_name);
539
+		$new_event->set(
540
+			'EVT_slug',
541
+			wp_unique_post_slug(
542
+				sanitize_title($orig_event->name()),
543
+				0,
544
+				'publish',
545
+				'espresso_events',
546
+				0
547
+			)
548
+		);
549
+		$new_event->set('status', 'draft');
550
+		// duplicate discussion settings
551
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
552
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
553
+		// save the new event
554
+		$new_event->save();
555
+		// venues
556
+		foreach ($orig_ven as $ven) {
557
+			$new_event->_add_relation_to($ven, 'Venue');
558
+		}
559
+		$new_event->save();
560
+		// now we need to get the question group relations and handle that
561
+		// first primary question groups
562
+		$orig_primary_qgs = $orig_event->get_many_related(
563
+			'Question_Group',
564
+			array(array('Event_Question_Group.EQG_primary' => 1))
565
+		);
566
+		if (! empty($orig_primary_qgs)) {
567
+			foreach ($orig_primary_qgs as $id => $obj) {
568
+				if ($obj instanceof EE_Question_Group) {
569
+					$new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 1));
570
+				}
571
+			}
572
+		}
573
+		// next additional attendee question groups
574
+		$orig_additional_qgs = $orig_event->get_many_related(
575
+			'Question_Group',
576
+			array(array('Event_Question_Group.EQG_primary' => 0))
577
+		);
578
+		if (! empty($orig_additional_qgs)) {
579
+			foreach ($orig_additional_qgs as $id => $obj) {
580
+				if ($obj instanceof EE_Question_Group) {
581
+					$new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 0));
582
+				}
583
+			}
584
+		}
585
+
586
+		$new_event->save();
587
+
588
+		// k now that we have the new event saved we can loop through the datetimes and start adding relations.
589
+		$cloned_tickets = array();
590
+		foreach ($orig_datetimes as $orig_dtt) {
591
+			if (! $orig_dtt instanceof EE_Datetime) {
592
+				continue;
593
+			}
594
+			$new_dtt = clone $orig_dtt;
595
+			$orig_tkts = $orig_dtt->tickets();
596
+			// save new dtt then add to event
597
+			$new_dtt->set('DTT_ID', 0);
598
+			$new_dtt->set('DTT_sold', 0);
599
+			$new_dtt->set_reserved(0);
600
+			$new_dtt->save();
601
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
602
+			$new_event->save();
603
+			// now let's get the ticket relations setup.
604
+			foreach ((array) $orig_tkts as $orig_tkt) {
605
+				// it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
606
+				if (! $orig_tkt instanceof EE_Ticket) {
607
+					continue;
608
+				}
609
+				// is this ticket archived?  If it is then let's skip
610
+				if ($orig_tkt->get('TKT_deleted')) {
611
+					continue;
612
+				}
613
+				// does this original ticket already exist in the clone_tickets cache?
614
+				//  If so we'll just use the new ticket from it.
615
+				if (isset($cloned_tickets[ $orig_tkt->ID() ])) {
616
+					$new_tkt = $cloned_tickets[ $orig_tkt->ID() ];
617
+				} else {
618
+					$new_tkt = clone $orig_tkt;
619
+					// get relations on the $orig_tkt that we need to setup.
620
+					$orig_prices = $orig_tkt->prices();
621
+					$new_tkt->set('TKT_ID', 0);
622
+					$new_tkt->set('TKT_sold', 0);
623
+					$new_tkt->set('TKT_reserved', 0);
624
+					$new_tkt->save(); // make sure new ticket has ID.
625
+					// price relations on new ticket need to be setup.
626
+					foreach ($orig_prices as $orig_price) {
627
+						$new_price = clone $orig_price;
628
+						$new_price->set('PRC_ID', 0);
629
+						$new_price->save();
630
+						$new_tkt->_add_relation_to($new_price, 'Price');
631
+						$new_tkt->save();
632
+					}
633
+
634
+					do_action(
635
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
636
+						$orig_tkt,
637
+						$new_tkt,
638
+						$orig_prices,
639
+						$orig_event,
640
+						$orig_dtt,
641
+						$new_dtt
642
+					);
643
+				}
644
+				// k now we can add the new ticket as a relation to the new datetime
645
+				// and make sure its added to our cached $cloned_tickets array
646
+				// for use with later datetimes that have the same ticket.
647
+				$new_dtt->_add_relation_to($new_tkt, 'Ticket');
648
+				$new_dtt->save();
649
+				$cloned_tickets[ $orig_tkt->ID() ] = $new_tkt;
650
+			}
651
+		}
652
+		// clone taxonomy information
653
+		$taxonomies_to_clone_with = apply_filters(
654
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
655
+			array('espresso_event_categories', 'espresso_event_type', 'post_tag')
656
+		);
657
+		// get terms for original event (notice)
658
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
659
+		// loop through terms and add them to new event.
660
+		foreach ($orig_terms as $term) {
661
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
662
+		}
663
+
664
+		// duplicate other core WP_Post items for this event.
665
+		// post thumbnail (feature image).
666
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
667
+		if ($feature_image_id) {
668
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
669
+		}
670
+
671
+		// duplicate page_template setting
672
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
673
+		if ($page_template) {
674
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
675
+		}
676
+
677
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
678
+		// now let's redirect to the edit page for this duplicated event if we have a new event id.
679
+		if ($new_event->ID()) {
680
+			$redirect_args = array(
681
+				'post'   => $new_event->ID(),
682
+				'action' => 'edit',
683
+			);
684
+			EE_Error::add_success(
685
+				esc_html__(
686
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
687
+					'event_espresso'
688
+				)
689
+			);
690
+		} else {
691
+			$redirect_args = array(
692
+				'action' => 'default',
693
+			);
694
+			EE_Error::add_error(
695
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
696
+				__FILE__,
697
+				__FUNCTION__,
698
+				__LINE__
699
+			);
700
+		}
701
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
702
+	}
703
+
704
+
705
+	/**
706
+	 * Generates output for the import page.
707
+	 *
708
+	 * @throws DomainException
709
+	 */
710
+	protected function _import_page()
711
+	{
712
+		$title = esc_html__('Import', 'event_espresso');
713
+		$intro = esc_html__(
714
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
715
+			'event_espresso'
716
+		);
717
+		$form_url = EVENTS_ADMIN_URL;
718
+		$action = 'import_events';
719
+		$type = 'csv';
720
+		$this->_template_args['form'] = EE_Import::instance()->upload_form(
721
+			$title,
722
+			$intro,
723
+			$form_url,
724
+			$action,
725
+			$type
726
+		);
727
+		$this->_template_args['sample_file_link'] = EE_Admin_Page::add_query_args_and_nonce(
728
+			array('action' => 'sample_export_file'),
729
+			$this->_admin_base_url
730
+		);
731
+		$content = EEH_Template::display_template(
732
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
733
+			$this->_template_args,
734
+			true
735
+		);
736
+		$this->_template_args['admin_page_content'] = $content;
737
+		$this->display_admin_page_with_sidebar();
738
+	}
739
+
740
+
741
+	/**
742
+	 * _import_events
743
+	 * This handles displaying the screen and running imports for importing events.
744
+	 *
745
+	 * @return void
746
+	 */
747
+	protected function _import_events()
748
+	{
749
+		require_once(EE_CLASSES . 'EE_Import.class.php');
750
+		$success = EE_Import::instance()->import();
751
+		$this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
752
+	}
753
+
754
+
755
+	/**
756
+	 * _events_export
757
+	 * Will export all (or just the given event) to a Excel compatible file.
758
+	 *
759
+	 * @access protected
760
+	 * @return void
761
+	 */
762
+	protected function _events_export()
763
+	{
764
+		if (isset($this->_req_data['EVT_ID'])) {
765
+			$event_ids = $this->_req_data['EVT_ID'];
766
+		} elseif (isset($this->_req_data['EVT_IDs'])) {
767
+			$event_ids = $this->_req_data['EVT_IDs'];
768
+		} else {
769
+			$event_ids = null;
770
+		}
771
+		// todo: I don't like doing this but it'll do until we modify EE_Export Class.
772
+		$new_request_args = array(
773
+			'export' => 'report',
774
+			'action' => 'all_event_data',
775
+			'EVT_ID' => $event_ids,
776
+		);
777
+		$this->_req_data = array_merge($this->_req_data, $new_request_args);
778
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
779
+			require_once(EE_CLASSES . 'EE_Export.class.php');
780
+			$EE_Export = EE_Export::instance($this->_req_data);
781
+			$EE_Export->export();
782
+		}
783
+	}
784
+
785
+
786
+	/**
787
+	 * handle category exports()
788
+	 *
789
+	 * @return void
790
+	 */
791
+	protected function _categories_export()
792
+	{
793
+		// todo: I don't like doing this but it'll do until we modify EE_Export Class.
794
+		$new_request_args = array(
795
+			'export'       => 'report',
796
+			'action'       => 'categories',
797
+			'category_ids' => $this->_req_data['EVT_CAT_ID'],
798
+		);
799
+		$this->_req_data = array_merge($this->_req_data, $new_request_args);
800
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
801
+			require_once(EE_CLASSES . 'EE_Export.class.php');
802
+			$EE_Export = EE_Export::instance($this->_req_data);
803
+			$EE_Export->export();
804
+		}
805
+	}
806
+
807
+
808
+	/**
809
+	 * Creates a sample CSV file for importing
810
+	 */
811
+	protected function _sample_export_file()
812
+	{
813
+		// require_once(EE_CLASSES . 'EE_Export.class.php');
814
+		EE_Export::instance()->export_sample();
815
+	}
816
+
817
+
818
+	/*************        Template Settings        *************/
819
+	/**
820
+	 * Generates template settings page output
821
+	 *
822
+	 * @throws DomainException
823
+	 * @throws EE_Error
824
+	 */
825
+	protected function _template_settings()
826
+	{
827
+		$this->_template_args['values'] = $this->_yes_no_values;
828
+		/**
829
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
830
+		 * from General_Settings_Admin_Page to here.
831
+		 */
832
+		$this->_template_args = apply_filters(
833
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
834
+			$this->_template_args
835
+		);
836
+		$this->_set_add_edit_form_tags('update_template_settings');
837
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
838
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
839
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
840
+			$this->_template_args,
841
+			true
842
+		);
843
+		$this->display_admin_page_with_sidebar();
844
+	}
845
+
846
+
847
+	/**
848
+	 * Handler for updating template settings.
849
+	 *
850
+	 * @throws InvalidInterfaceException
851
+	 * @throws InvalidDataTypeException
852
+	 * @throws InvalidArgumentException
853
+	 */
854
+	protected function _update_template_settings()
855
+	{
856
+		/**
857
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
858
+		 * from General_Settings_Admin_Page to here.
859
+		 */
860
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
861
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
862
+			EE_Registry::instance()->CFG->template_settings,
863
+			$this->_req_data
864
+		);
865
+		// update custom post type slugs and detect if we need to flush rewrite rules
866
+		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
867
+		EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
868
+			? EE_Registry::instance()->CFG->core->event_cpt_slug
869
+			: EEH_URL::slugify($this->_req_data['event_cpt_slug'], 'events');
870
+		$what = 'Template Settings';
871
+		$success = $this->_update_espresso_configuration(
872
+			$what,
873
+			EE_Registry::instance()->CFG->template_settings,
874
+			__FILE__,
875
+			__FUNCTION__,
876
+			__LINE__
877
+		);
878
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
879
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
880
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
881
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
882
+			);
883
+			$rewrite_rules->flush();
884
+		}
885
+		$this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
886
+	}
887
+
888
+
889
+	/**
890
+	 * _premium_event_editor_meta_boxes
891
+	 * add all metaboxes related to the event_editor
892
+	 *
893
+	 * @access protected
894
+	 * @return void
895
+	 * @throws EE_Error
896
+	 */
897
+	protected function _premium_event_editor_meta_boxes()
898
+	{
899
+		$this->verify_cpt_object();
900
+		add_meta_box(
901
+			'espresso_event_editor_event_options',
902
+			esc_html__('Event Registration Options', 'event_espresso'),
903
+			array($this, 'registration_options_meta_box'),
904
+			$this->page_slug,
905
+			'side',
906
+			'core'
907
+		);
908
+	}
909
+
910
+
911
+	/**
912
+	 * override caf metabox
913
+	 *
914
+	 * @return void
915
+	 * @throws DomainException
916
+	 */
917
+	public function registration_options_meta_box()
918
+	{
919
+		$yes_no_values = array(
920
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
921
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
922
+		);
923
+		$default_reg_status_values = EEM_Registration::reg_status_array(
924
+			array(
925
+				EEM_Registration::status_id_cancelled,
926
+				EEM_Registration::status_id_declined,
927
+				EEM_Registration::status_id_incomplete,
928
+				EEM_Registration::status_id_wait_list,
929
+			),
930
+			true
931
+		);
932
+		$template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
933
+		$template_args['_event'] = $this->_cpt_model_obj;
934
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
935
+		$template_args['default_registration_status'] = EEH_Form_Fields::select_input(
936
+			'default_reg_status',
937
+			$default_reg_status_values,
938
+			$this->_cpt_model_obj->default_registration_status()
939
+		);
940
+		$template_args['display_description'] = EEH_Form_Fields::select_input(
941
+			'display_desc',
942
+			$yes_no_values,
943
+			$this->_cpt_model_obj->display_description()
944
+		);
945
+		$template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
946
+			'display_ticket_selector',
947
+			$yes_no_values,
948
+			$this->_cpt_model_obj->display_ticket_selector(),
949
+			'',
950
+			'',
951
+			false
952
+		);
953
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
954
+			'EVT_default_registration_status',
955
+			$default_reg_status_values,
956
+			$this->_cpt_model_obj->default_registration_status()
957
+		);
958
+		$template_args['additional_registration_options'] = apply_filters(
959
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
960
+			'',
961
+			$template_args,
962
+			$yes_no_values,
963
+			$default_reg_status_values
964
+		);
965
+		EEH_Template::display_template(
966
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
967
+			$template_args
968
+		);
969
+	}
970
+
971
+
972
+
973
+	/**
974
+	 * wp_list_table_mods for caf
975
+	 * ============================
976
+	 */
977
+	/**
978
+	 * hook into list table filters and provide filters for caffeinated list table
979
+	 *
980
+	 * @param  array $old_filters    any existing filters present
981
+	 * @param  array $list_table_obj the list table object
982
+	 * @return array                  new filters
983
+	 */
984
+	public function list_table_filters($old_filters, $list_table_obj)
985
+	{
986
+		$filters = array();
987
+		// first month/year filters
988
+		$filters[] = $this->espresso_event_months_dropdown();
989
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
990
+		// active status dropdown
991
+		if ($status !== 'draft') {
992
+			$filters[] = $this->active_status_dropdown(
993
+				isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
994
+			);
995
+		}
996
+		// category filter
997
+		$filters[] = $this->category_dropdown();
998
+		return array_merge($old_filters, $filters);
999
+	}
1000
+
1001
+
1002
+	/**
1003
+	 * espresso_event_months_dropdown
1004
+	 *
1005
+	 * @access public
1006
+	 * @return string                dropdown listing month/year selections for events.
1007
+	 */
1008
+	public function espresso_event_months_dropdown()
1009
+	{
1010
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
1011
+		// Note we need to include any other filters that are set!
1012
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
1013
+		// categories?
1014
+		$category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1015
+			? $this->_req_data['EVT_CAT']
1016
+			: null;
1017
+		// active status?
1018
+		$active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
1019
+		$cur_date = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
1020
+		return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * returns a list of "active" statuses on the event
1026
+	 *
1027
+	 * @param  string $current_value whatever the current active status is
1028
+	 * @return string
1029
+	 */
1030
+	public function active_status_dropdown($current_value = '')
1031
+	{
1032
+		$select_name = 'active_status';
1033
+		$values = array(
1034
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1035
+			'active'   => esc_html__('Active', 'event_espresso'),
1036
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1037
+			'expired'  => esc_html__('Expired', 'event_espresso'),
1038
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
1039
+		);
1040
+		$id = 'id="espresso-active-status-dropdown-filter"';
1041
+		$class = 'wide';
1042
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1043
+	}
1044
+
1045
+
1046
+	/**
1047
+	 * output a dropdown of the categories for the category filter on the event admin list table
1048
+	 *
1049
+	 * @access  public
1050
+	 * @return string html
1051
+	 */
1052
+	public function category_dropdown()
1053
+	{
1054
+		$cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1055
+		return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1056
+	}
1057
+
1058
+
1059
+	/**
1060
+	 * get total number of events today
1061
+	 *
1062
+	 * @access public
1063
+	 * @return int
1064
+	 * @throws EE_Error
1065
+	 */
1066
+	public function total_events_today()
1067
+	{
1068
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1069
+			'DTT_EVT_start',
1070
+			date('Y-m-d') . ' 00:00:00',
1071
+			'Y-m-d H:i:s',
1072
+			'UTC'
1073
+		);
1074
+		$end = EEM_Datetime::instance()->convert_datetime_for_query(
1075
+			'DTT_EVT_start',
1076
+			date('Y-m-d') . ' 23:59:59',
1077
+			'Y-m-d H:i:s',
1078
+			'UTC'
1079
+		);
1080
+		$where = array(
1081
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1082
+		);
1083
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1084
+		return $count;
1085
+	}
1086
+
1087
+
1088
+	/**
1089
+	 * get total number of events this month
1090
+	 *
1091
+	 * @access public
1092
+	 * @return int
1093
+	 * @throws EE_Error
1094
+	 */
1095
+	public function total_events_this_month()
1096
+	{
1097
+		// Dates
1098
+		$this_year_r = date('Y');
1099
+		$this_month_r = date('m');
1100
+		$days_this_month = date('t');
1101
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1102
+			'DTT_EVT_start',
1103
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1104
+			'Y-m-d H:i:s',
1105
+			'UTC'
1106
+		);
1107
+		$end = EEM_Datetime::instance()->convert_datetime_for_query(
1108
+			'DTT_EVT_start',
1109
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1110
+			'Y-m-d H:i:s',
1111
+			'UTC'
1112
+		);
1113
+		$where = array(
1114
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1115
+		);
1116
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1117
+		return $count;
1118
+	}
1119
+
1120
+
1121
+	/** DEFAULT TICKETS STUFF **/
1122
+
1123
+	/**
1124
+	 * Output default tickets list table view.
1125
+	 */
1126
+	public function _tickets_overview_list_table()
1127
+	{
1128
+		$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1129
+		$this->display_admin_list_table_page_with_no_sidebar();
1130
+	}
1131
+
1132
+
1133
+	/**
1134
+	 * @param int  $per_page
1135
+	 * @param bool $count
1136
+	 * @param bool $trashed
1137
+	 * @return \EE_Soft_Delete_Base_Class[]|int
1138
+	 */
1139
+	public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1140
+	{
1141
+		$orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1142
+		$order = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1143
+		switch ($orderby) {
1144
+			case 'TKT_name':
1145
+				$orderby = array('TKT_name' => $order);
1146
+				break;
1147
+			case 'TKT_price':
1148
+				$orderby = array('TKT_price' => $order);
1149
+				break;
1150
+			case 'TKT_uses':
1151
+				$orderby = array('TKT_uses' => $order);
1152
+				break;
1153
+			case 'TKT_min':
1154
+				$orderby = array('TKT_min' => $order);
1155
+				break;
1156
+			case 'TKT_max':
1157
+				$orderby = array('TKT_max' => $order);
1158
+				break;
1159
+			case 'TKT_qty':
1160
+				$orderby = array('TKT_qty' => $order);
1161
+				break;
1162
+		}
1163
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1164
+			? $this->_req_data['paged']
1165
+			: 1;
1166
+		$per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1167
+			? $this->_req_data['perpage']
1168
+			: $per_page;
1169
+		$_where = array(
1170
+			'TKT_is_default' => 1,
1171
+			'TKT_deleted'    => $trashed,
1172
+		);
1173
+		$offset = ($current_page - 1) * $per_page;
1174
+		$limit = array($offset, $per_page);
1175
+		if (isset($this->_req_data['s'])) {
1176
+			$sstr = '%' . $this->_req_data['s'] . '%';
1177
+			$_where['OR'] = array(
1178
+				'TKT_name'        => array('LIKE', $sstr),
1179
+				'TKT_description' => array('LIKE', $sstr),
1180
+			);
1181
+		}
1182
+		$query_params = array(
1183
+			$_where,
1184
+			'order_by' => $orderby,
1185
+			'limit'    => $limit,
1186
+			'group_by' => 'TKT_ID',
1187
+		);
1188
+		if ($count) {
1189
+			return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1190
+		} else {
1191
+			return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1192
+		}
1193
+	}
1194
+
1195
+
1196
+	/**
1197
+	 * @param bool $trash
1198
+	 * @throws EE_Error
1199
+	 */
1200
+	protected function _trash_or_restore_ticket($trash = false)
1201
+	{
1202
+		$success = 1;
1203
+		$TKT = EEM_Ticket::instance();
1204
+		// checkboxes?
1205
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1206
+			// if array has more than one element then success message should be plural
1207
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1208
+			// cycle thru the boxes
1209
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1210
+				if ($trash) {
1211
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1212
+						$success = 0;
1213
+					}
1214
+				} else {
1215
+					if (! $TKT->restore_by_ID($TKT_ID)) {
1216
+						$success = 0;
1217
+					}
1218
+				}
1219
+			}
1220
+		} else {
1221
+			// grab single id and trash
1222
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1223
+			if ($trash) {
1224
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1225
+					$success = 0;
1226
+				}
1227
+			} else {
1228
+				if (! $TKT->restore_by_ID($TKT_ID)) {
1229
+					$success = 0;
1230
+				}
1231
+			}
1232
+		}
1233
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1234
+		$query_args = array(
1235
+			'action' => 'ticket_list_table',
1236
+			'status' => $trash ? '' : 'trashed',
1237
+		);
1238
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1239
+	}
1240
+
1241
+
1242
+	/**
1243
+	 * Handles trashing default ticket.
1244
+	 */
1245
+	protected function _delete_ticket()
1246
+	{
1247
+		$success = 1;
1248
+		// checkboxes?
1249
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1250
+			// if array has more than one element then success message should be plural
1251
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1252
+			// cycle thru the boxes
1253
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1254
+				// delete
1255
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1256
+					$success = 0;
1257
+				}
1258
+			}
1259
+		} else {
1260
+			// grab single id and trash
1261
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1262
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1263
+				$success = 0;
1264
+			}
1265
+		}
1266
+		$action_desc = 'deleted';
1267
+		$query_args = array(
1268
+			'action' => 'ticket_list_table',
1269
+			'status' => 'trashed',
1270
+		);
1271
+		// fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1272
+		if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1273
+			array(array('TKT_is_default' => 1)),
1274
+			'TKT_ID',
1275
+			true
1276
+		)
1277
+		) {
1278
+			$query_args = array();
1279
+		}
1280
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1281
+	}
1282
+
1283
+
1284
+	/**
1285
+	 * @param int $TKT_ID
1286
+	 * @return bool|int
1287
+	 * @throws EE_Error
1288
+	 */
1289
+	protected function _delete_the_ticket($TKT_ID)
1290
+	{
1291
+		$tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1292
+		$tkt->_remove_relations('Datetime');
1293
+		// delete all related prices first
1294
+		$tkt->delete_related_permanently('Price');
1295
+		return $tkt->delete_permanently();
1296
+	}
1297 1297
 }
Please login to merge, or discard this patch.
core/helpers/EEH_URL.helper.php 1 patch
Indentation   +260 added lines, -260 removed lines patch added patch discarded remove patch
@@ -12,285 +12,285 @@
 block discarded – undo
12 12
 class EEH_URL
13 13
 {
14 14
 
15
-    /**
16
-     * _add_query_arg
17
-     * adds nonce to array of arguments then calls WP add_query_arg function
18
-     *
19
-     * @access public
20
-     * @param array  $args
21
-     * @param string $url
22
-     * @param bool   $exclude_nonce If true then the nonce will be excluded from the generated url.
23
-     * @return string
24
-     */
25
-    public static function add_query_args_and_nonce($args = array(), $url = '', $exclude_nonce = false)
26
-    {
27
-        if (empty($url)) {
28
-            $user_msg = esc_html__(
29
-                'An error occurred. A URL is a required parameter for the add_query_args_and_nonce method.',
30
-                'event_espresso'
31
-            );
32
-            $dev_msg  = $user_msg . "\n"
33
-                . sprintf(
34
-                    esc_html__(
35
-                        'In order to dynamically generate nonces for your actions, you need to supply a valid URL as a second parameter for the %s method.',
36
-                        'event_espresso'
37
-                    ),
38
-                    __CLASS__ . '::add_query_args_and_nonce'
39
-                );
40
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
41
-        }
42
-        // check that an action exists and add nonce
43
-        if (! $exclude_nonce) {
44
-            if (isset($args['action']) && ! empty($args['action'])) {
45
-                $args = array_merge(
46
-                    $args,
47
-                    array(
48
-                        $args['action'] . '_nonce' => wp_create_nonce($args['action'] . '_nonce')
49
-                    )
50
-                );
51
-            } else {
52
-                $args = array_merge(
53
-                    $args,
54
-                    array(
55
-                        'action' => 'default', 'default_nonce' => wp_create_nonce('default_nonce')
56
-                    )
57
-                );
58
-            }
59
-        }
15
+	/**
16
+	 * _add_query_arg
17
+	 * adds nonce to array of arguments then calls WP add_query_arg function
18
+	 *
19
+	 * @access public
20
+	 * @param array  $args
21
+	 * @param string $url
22
+	 * @param bool   $exclude_nonce If true then the nonce will be excluded from the generated url.
23
+	 * @return string
24
+	 */
25
+	public static function add_query_args_and_nonce($args = array(), $url = '', $exclude_nonce = false)
26
+	{
27
+		if (empty($url)) {
28
+			$user_msg = esc_html__(
29
+				'An error occurred. A URL is a required parameter for the add_query_args_and_nonce method.',
30
+				'event_espresso'
31
+			);
32
+			$dev_msg  = $user_msg . "\n"
33
+				. sprintf(
34
+					esc_html__(
35
+						'In order to dynamically generate nonces for your actions, you need to supply a valid URL as a second parameter for the %s method.',
36
+						'event_espresso'
37
+					),
38
+					__CLASS__ . '::add_query_args_and_nonce'
39
+				);
40
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
41
+		}
42
+		// check that an action exists and add nonce
43
+		if (! $exclude_nonce) {
44
+			if (isset($args['action']) && ! empty($args['action'])) {
45
+				$args = array_merge(
46
+					$args,
47
+					array(
48
+						$args['action'] . '_nonce' => wp_create_nonce($args['action'] . '_nonce')
49
+					)
50
+				);
51
+			} else {
52
+				$args = array_merge(
53
+					$args,
54
+					array(
55
+						'action' => 'default', 'default_nonce' => wp_create_nonce('default_nonce')
56
+					)
57
+				);
58
+			}
59
+		}
60 60
 
61
-        // finally, let's always add a return address (if present) :)
62
-        $args = ! empty($_REQUEST['action']) && ! isset($_REQUEST['return'])
63
-            ? array_merge($args, array('return' => $_REQUEST['action']))
64
-            : $args;
61
+		// finally, let's always add a return address (if present) :)
62
+		$args = ! empty($_REQUEST['action']) && ! isset($_REQUEST['return'])
63
+			? array_merge($args, array('return' => $_REQUEST['action']))
64
+			: $args;
65 65
 
66
-        return add_query_arg($args, $url);
67
-    }
66
+		return add_query_arg($args, $url);
67
+	}
68 68
 
69 69
 
70
-    /**
71
-     * Returns whether not the remote file exists.
72
-     * Checking via GET because HEAD requests are blocked on some server configurations.
73
-     *
74
-     * @param string  $url
75
-     * @param array $args  the arguments that should be passed through to the wp_remote_request call.
76
-     * @return boolean
77
-     */
78
-    public static function remote_file_exists($url, $args = array())
79
-    {
80
-        $results = wp_remote_request(
81
-            $url,
82
-            array_merge(
83
-                array(
84
-                    'method'      => 'GET',
85
-                    'redirection' => 1,
86
-                ),
87
-                $args
88
-            )
89
-        );
90
-        if (! $results instanceof WP_Error &&
91
-            isset($results['response']) &&
92
-            isset($results['response']['code']) &&
93
-            $results['response']['code'] == '200') {
94
-            return true;
95
-        } else {
96
-            return false;
97
-        }
98
-    }
70
+	/**
71
+	 * Returns whether not the remote file exists.
72
+	 * Checking via GET because HEAD requests are blocked on some server configurations.
73
+	 *
74
+	 * @param string  $url
75
+	 * @param array $args  the arguments that should be passed through to the wp_remote_request call.
76
+	 * @return boolean
77
+	 */
78
+	public static function remote_file_exists($url, $args = array())
79
+	{
80
+		$results = wp_remote_request(
81
+			$url,
82
+			array_merge(
83
+				array(
84
+					'method'      => 'GET',
85
+					'redirection' => 1,
86
+				),
87
+				$args
88
+			)
89
+		);
90
+		if (! $results instanceof WP_Error &&
91
+			isset($results['response']) &&
92
+			isset($results['response']['code']) &&
93
+			$results['response']['code'] == '200') {
94
+			return true;
95
+		} else {
96
+			return false;
97
+		}
98
+	}
99 99
 
100 100
 
101
-    /**
102
-     * refactor_url
103
-     * primarily used for removing the query string from a URL
104
-     *
105
-     * @param string $url
106
-     * @param bool   $remove_query  - TRUE (default) will strip off any URL params, ie: ?this=1&that=2
107
-     * @param bool   $base_url_only - TRUE will only return the scheme and host with no other parameters
108
-     * @return string
109
-     */
110
-    public static function refactor_url($url = '', $remove_query = true, $base_url_only = false)
111
-    {
112
-        // break apart incoming URL
113
-        $url_bits = parse_url($url);
114
-        // HTTP or HTTPS ?
115
-        $scheme = isset($url_bits['scheme']) ? $url_bits['scheme'] . '://' : 'http://';
116
-        // domain
117
-        $host = isset($url_bits['host']) ? $url_bits['host'] : '';
118
-        // if only the base URL is requested, then return that now
119
-        if ($base_url_only) {
120
-            return $scheme . $host;
121
-        }
122
-        $port = isset($url_bits['port']) ? ':' . $url_bits['port'] : '';
123
-        $user = isset($url_bits['user']) ? $url_bits['user'] : '';
124
-        $pass = isset($url_bits['pass']) ? ':' . $url_bits['pass'] : '';
125
-        $pass = ($user || $pass) ? $pass . '@' : '';
126
-        $path = isset($url_bits['path']) ? $url_bits['path'] : '';
127
-        // if the query string is not required, then return what we have so far
128
-        if ($remove_query) {
129
-            return $scheme . $user . $pass . $host . $port . $path;
130
-        }
131
-        $query    = isset($url_bits['query']) ? '?' . $url_bits['query'] : '';
132
-        $fragment = isset($url_bits['fragment']) ? '#' . $url_bits['fragment'] : '';
133
-        return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
134
-    }
101
+	/**
102
+	 * refactor_url
103
+	 * primarily used for removing the query string from a URL
104
+	 *
105
+	 * @param string $url
106
+	 * @param bool   $remove_query  - TRUE (default) will strip off any URL params, ie: ?this=1&that=2
107
+	 * @param bool   $base_url_only - TRUE will only return the scheme and host with no other parameters
108
+	 * @return string
109
+	 */
110
+	public static function refactor_url($url = '', $remove_query = true, $base_url_only = false)
111
+	{
112
+		// break apart incoming URL
113
+		$url_bits = parse_url($url);
114
+		// HTTP or HTTPS ?
115
+		$scheme = isset($url_bits['scheme']) ? $url_bits['scheme'] . '://' : 'http://';
116
+		// domain
117
+		$host = isset($url_bits['host']) ? $url_bits['host'] : '';
118
+		// if only the base URL is requested, then return that now
119
+		if ($base_url_only) {
120
+			return $scheme . $host;
121
+		}
122
+		$port = isset($url_bits['port']) ? ':' . $url_bits['port'] : '';
123
+		$user = isset($url_bits['user']) ? $url_bits['user'] : '';
124
+		$pass = isset($url_bits['pass']) ? ':' . $url_bits['pass'] : '';
125
+		$pass = ($user || $pass) ? $pass . '@' : '';
126
+		$path = isset($url_bits['path']) ? $url_bits['path'] : '';
127
+		// if the query string is not required, then return what we have so far
128
+		if ($remove_query) {
129
+			return $scheme . $user . $pass . $host . $port . $path;
130
+		}
131
+		$query    = isset($url_bits['query']) ? '?' . $url_bits['query'] : '';
132
+		$fragment = isset($url_bits['fragment']) ? '#' . $url_bits['fragment'] : '';
133
+		return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
134
+	}
135 135
 
136 136
 
137
-    /**
138
-     * get_query_string
139
-     * returns just the query string from a URL, formatted by default into an array of key value pairs
140
-     *
141
-     * @param string $url
142
-     * @param bool   $as_array TRUE (default) will return query params as an array of key value pairs, FALSE will
143
-     *                         simply return the query string
144
-     * @return string|array
145
-     */
146
-    public static function get_query_string($url = '', $as_array = true)
147
-    {
148
-        // decode, then break apart incoming URL
149
-        $url_bits = parse_url(html_entity_decode($url));
150
-        // grab query string from URL
151
-        $query = isset($url_bits['query']) ? $url_bits['query'] : '';
152
-        // if we don't want the query string formatted into an array of key => value pairs, then just return it as is
153
-        if (! $as_array) {
154
-            return $query;
155
-        }
156
-        // if no query string exists then just return an empty array now
157
-        if (empty($query)) {
158
-            return array();
159
-        }
160
-        // empty array to hold results
161
-        $query_params = array();
162
-        // now break apart the query string into separate params
163
-        $query = explode('&', $query);
164
-        // loop thru our query params
165
-        foreach ($query as $query_args) {
166
-            // break apart the key value pairs
167
-            $query_args = explode('=', $query_args);
168
-            // and add to our results array
169
-            $query_params[ $query_args[0] ] = $query_args[1];
170
-        }
171
-        return $query_params;
172
-    }
137
+	/**
138
+	 * get_query_string
139
+	 * returns just the query string from a URL, formatted by default into an array of key value pairs
140
+	 *
141
+	 * @param string $url
142
+	 * @param bool   $as_array TRUE (default) will return query params as an array of key value pairs, FALSE will
143
+	 *                         simply return the query string
144
+	 * @return string|array
145
+	 */
146
+	public static function get_query_string($url = '', $as_array = true)
147
+	{
148
+		// decode, then break apart incoming URL
149
+		$url_bits = parse_url(html_entity_decode($url));
150
+		// grab query string from URL
151
+		$query = isset($url_bits['query']) ? $url_bits['query'] : '';
152
+		// if we don't want the query string formatted into an array of key => value pairs, then just return it as is
153
+		if (! $as_array) {
154
+			return $query;
155
+		}
156
+		// if no query string exists then just return an empty array now
157
+		if (empty($query)) {
158
+			return array();
159
+		}
160
+		// empty array to hold results
161
+		$query_params = array();
162
+		// now break apart the query string into separate params
163
+		$query = explode('&', $query);
164
+		// loop thru our query params
165
+		foreach ($query as $query_args) {
166
+			// break apart the key value pairs
167
+			$query_args = explode('=', $query_args);
168
+			// and add to our results array
169
+			$query_params[ $query_args[0] ] = $query_args[1];
170
+		}
171
+		return $query_params;
172
+	}
173 173
 
174 174
 
175
-    /**
176
-     * prevent_prefetching
177
-     *
178
-     * @return void
179
-     */
180
-    public static function prevent_prefetching()
181
-    {
182
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes
183
-        // with the registration process
184
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
185
-    }
175
+	/**
176
+	 * prevent_prefetching
177
+	 *
178
+	 * @return void
179
+	 */
180
+	public static function prevent_prefetching()
181
+	{
182
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes
183
+		// with the registration process
184
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
185
+	}
186 186
 
187 187
 
188
-    /**
189
-     * This generates a unique site-specific string.
190
-     * An example usage for this string would be to save as a unique identifier for a record in the db for usage in
191
-     * urls.
192
-     *
193
-     * @param   string $prefix Use this to prefix the string with something.
194
-     * @return string
195
-     */
196
-    public static function generate_unique_token($prefix = '')
197
-    {
198
-        $token = md5(uniqid() . mt_rand());
199
-        return $prefix ? $prefix . '_' . $token : $token;
200
-    }
188
+	/**
189
+	 * This generates a unique site-specific string.
190
+	 * An example usage for this string would be to save as a unique identifier for a record in the db for usage in
191
+	 * urls.
192
+	 *
193
+	 * @param   string $prefix Use this to prefix the string with something.
194
+	 * @return string
195
+	 */
196
+	public static function generate_unique_token($prefix = '')
197
+	{
198
+		$token = md5(uniqid() . mt_rand());
199
+		return $prefix ? $prefix . '_' . $token : $token;
200
+	}
201 201
 
202 202
 
203
-    /**
204
-     * filter_input_server_url
205
-     * uses filter_input() to sanitize one of the INPUT_SERVER URL values
206
-     * but adds a backup in case filter_input() returns nothing, which can erringly happen on some servers
207
-     *
208
-     * @param string $server_variable
209
-     * @return string
210
-     */
211
-    public static function filter_input_server_url($server_variable = 'REQUEST_URI')
212
-    {
213
-        $URL              = '';
214
-        $server_variables = array(
215
-            'REQUEST_URI' => 1,
216
-            'HTTP_HOST'   => 1,
217
-            'PHP_SELF'    => 1,
218
-        );
219
-        $server_variable  = strtoupper($server_variable);
220
-        // whitelist INPUT_SERVER var
221
-        if (isset($server_variables[ $server_variable ])) {
222
-            $URL = filter_input(INPUT_SERVER, $server_variable, FILTER_SANITIZE_URL, FILTER_NULL_ON_FAILURE);
223
-            if (empty($URL)) {
224
-                // fallback sanitization if the above fails
225
-                $URL = wp_sanitize_redirect($_SERVER[ $server_variable ]);
226
-            }
227
-        }
228
-        return $URL;
229
-    }
203
+	/**
204
+	 * filter_input_server_url
205
+	 * uses filter_input() to sanitize one of the INPUT_SERVER URL values
206
+	 * but adds a backup in case filter_input() returns nothing, which can erringly happen on some servers
207
+	 *
208
+	 * @param string $server_variable
209
+	 * @return string
210
+	 */
211
+	public static function filter_input_server_url($server_variable = 'REQUEST_URI')
212
+	{
213
+		$URL              = '';
214
+		$server_variables = array(
215
+			'REQUEST_URI' => 1,
216
+			'HTTP_HOST'   => 1,
217
+			'PHP_SELF'    => 1,
218
+		);
219
+		$server_variable  = strtoupper($server_variable);
220
+		// whitelist INPUT_SERVER var
221
+		if (isset($server_variables[ $server_variable ])) {
222
+			$URL = filter_input(INPUT_SERVER, $server_variable, FILTER_SANITIZE_URL, FILTER_NULL_ON_FAILURE);
223
+			if (empty($URL)) {
224
+				// fallback sanitization if the above fails
225
+				$URL = wp_sanitize_redirect($_SERVER[ $server_variable ]);
226
+			}
227
+		}
228
+		return $URL;
229
+	}
230 230
 
231 231
 
232
-    /**
233
-     * Gets the current page's full URL.
234
-     *
235
-     * @return string
236
-     */
237
-    public static function current_url()
238
-    {
239
-        $url = '';
240
-        if (isset($_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'])) {
241
-            $url = is_ssl() ? 'https://' : 'http://';
242
-            $url .= \EEH_URL::filter_input_server_url('HTTP_HOST');
243
-            $url .= \EEH_URL::filter_input_server_url('REQUEST_URI');
244
-        }
245
-        return $url;
246
-    }
232
+	/**
233
+	 * Gets the current page's full URL.
234
+	 *
235
+	 * @return string
236
+	 */
237
+	public static function current_url()
238
+	{
239
+		$url = '';
240
+		if (isset($_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'])) {
241
+			$url = is_ssl() ? 'https://' : 'http://';
242
+			$url .= \EEH_URL::filter_input_server_url('HTTP_HOST');
243
+			$url .= \EEH_URL::filter_input_server_url('REQUEST_URI');
244
+		}
245
+		return $url;
246
+	}
247 247
 
248 248
 
249
-    /**
250
-     * Identical in functionality to EEH_current_url except it removes any provided query_parameters from it.
251
-     *
252
-     * @param array $query_parameters An array of query_parameters to remove from the current url.
253
-     * @since 4.9.46.rc.029
254
-     * @return string
255
-     */
256
-    public static function current_url_without_query_paramaters(array $query_parameters)
257
-    {
258
-        return remove_query_arg($query_parameters, EEH_URL::current_url());
259
-    }
249
+	/**
250
+	 * Identical in functionality to EEH_current_url except it removes any provided query_parameters from it.
251
+	 *
252
+	 * @param array $query_parameters An array of query_parameters to remove from the current url.
253
+	 * @since 4.9.46.rc.029
254
+	 * @return string
255
+	 */
256
+	public static function current_url_without_query_paramaters(array $query_parameters)
257
+	{
258
+		return remove_query_arg($query_parameters, EEH_URL::current_url());
259
+	}
260 260
 
261 261
 
262
-    /**
263
-     * @param string $location
264
-     * @param int    $status
265
-     * @param string $exit_notice
266
-     */
267
-    public static function safeRedirectAndExit($location, $status = 302, $exit_notice = '')
268
-    {
269
-        EE_Error::get_notices(false, true);
270
-        wp_safe_redirect($location, $status);
271
-        exit($exit_notice);
272
-    }
262
+	/**
263
+	 * @param string $location
264
+	 * @param int    $status
265
+	 * @param string $exit_notice
266
+	 */
267
+	public static function safeRedirectAndExit($location, $status = 302, $exit_notice = '')
268
+	{
269
+		EE_Error::get_notices(false, true);
270
+		wp_safe_redirect($location, $status);
271
+		exit($exit_notice);
272
+	}
273 273
 
274
-    /**
275
-     * Slugifies text for usage in a URL.
276
-     *
277
-     * Currently, this isn't just calling `sanitize_title()` on it, because that percent-encodes unicode characters,
278
-     * and WordPress chokes on them when used as CPT and custom taxonomy slugs.
279
-     *
280
-     * @since $VID:$
281
-     * @param string $text
282
-     * @param string $fallback
283
-     * @return string which can be used in a URL
284
-     */
285
-    public static function slugify($text, $fallback)
286
-    {
287
-        // url decode after sanitizing title to restore unicode characters,
288
-        // see https://github.com/eventespresso/event-espresso-core/issues/575
289
-        return urldecode(
290
-            sanitize_title(
291
-                $text,
292
-                $fallback
293
-            )
294
-        );
295
-    }
274
+	/**
275
+	 * Slugifies text for usage in a URL.
276
+	 *
277
+	 * Currently, this isn't just calling `sanitize_title()` on it, because that percent-encodes unicode characters,
278
+	 * and WordPress chokes on them when used as CPT and custom taxonomy slugs.
279
+	 *
280
+	 * @since $VID:$
281
+	 * @param string $text
282
+	 * @param string $fallback
283
+	 * @return string which can be used in a URL
284
+	 */
285
+	public static function slugify($text, $fallback)
286
+	{
287
+		// url decode after sanitizing title to restore unicode characters,
288
+		// see https://github.com/eventespresso/event-espresso-core/issues/575
289
+		return urldecode(
290
+			sanitize_title(
291
+				$text,
292
+				$fallback
293
+			)
294
+		);
295
+	}
296 296
 }
Please login to merge, or discard this patch.
core/domain/entities/custom_post_types/CustomTaxonomyDefinitions.php 1 patch
Indentation   +131 added lines, -131 removed lines patch added patch discarded remove patch
@@ -15,145 +15,145 @@
 block discarded – undo
15 15
 class CustomTaxonomyDefinitions
16 16
 {
17 17
 
18
-    /**
19
-     * @var array $taxonomies
20
-     */
21
-    private $taxonomies;
18
+	/**
19
+	 * @var array $taxonomies
20
+	 */
21
+	private $taxonomies;
22 22
 
23 23
 
24
-    /**
25
-     * EspressoCustomPostTypeDefinitions constructor.
26
-     */
27
-    public function __construct()
28
-    {
29
-        $this->setTaxonomies();
30
-        add_filter('pre_term_description', array($this, 'filterCustomTermDescription'), 1, 2);
31
-    }
24
+	/**
25
+	 * EspressoCustomPostTypeDefinitions constructor.
26
+	 */
27
+	public function __construct()
28
+	{
29
+		$this->setTaxonomies();
30
+		add_filter('pre_term_description', array($this, 'filterCustomTermDescription'), 1, 2);
31
+	}
32 32
 
33 33
 
34
-    private function setTaxonomies()
35
-    {
36
-        $this->taxonomies = array(
37
-            'espresso_event_categories' => array(
38
-                'singular_name' => esc_html__('Event Category', 'event_espresso'),
39
-                'plural_name'   => esc_html__('Event Categories', 'event_espresso'),
40
-                'args'          => array(
41
-                    'public'            => true,
42
-                    'show_in_nav_menus' => true,
43
-                    'show_in_rest'      => true,
44
-                    'capabilities'      => array(
45
-                        'manage_terms' => 'ee_manage_event_categories',
46
-                        'edit_terms'   => 'ee_edit_event_category',
47
-                        'delete_terms' => 'ee_delete_event_category',
48
-                        'assign_terms' => 'ee_assign_event_category',
49
-                    ),
50
-                    'rewrite'           => array(
51
-                        'slug' => EEH_URL::slugify(
52
-                            __('event-category', 'event_espresso'),
53
-                            'event-category'
54
-                        )
55
-                    ),
56
-                ),
57
-            ),
58
-            'espresso_venue_categories' => array(
59
-                'singular_name' => esc_html__('Venue Category', 'event_espresso'),
60
-                'plural_name'   => esc_html__('Venue Categories', 'event_espresso'),
61
-                'args'          => array(
62
-                    'public'            => true,
63
-                    'show_in_nav_menus' => false, // by default this doesn't show for decaf
64
-                    'show_in_rest'      => true,
65
-                    'capabilities'      => array(
66
-                        'manage_terms' => 'ee_manage_venue_categories',
67
-                        'edit_terms'   => 'ee_edit_venue_category',
68
-                        'delete_terms' => 'ee_delete_venue_category',
69
-                        'assign_terms' => 'ee_assign_venue_category',
70
-                    ),
71
-                    'rewrite'           => array(
72
-                        'slug' => EEH_URL::slugify(
73
-                            __('venue-category', 'event_espresso'),
74
-                            'venue-category'
75
-                        )
76
-                    ),
77
-                ),
78
-            ),
79
-            'espresso_event_type'       => array(
80
-                'singular_name' => esc_html__('Event Type', 'event_espresso'),
81
-                'plural_name'   => esc_html__('Event Types', 'event_espresso'),
82
-                'args'          => array(
83
-                    'public'       => true,
84
-                    'show_ui'      => false,
85
-                    'show_in_rest' => true,
86
-                    'capabilities' => array(
87
-                        'manage_terms' => 'ee_read_event_type',
88
-                        'edit_terms'   => 'ee_edit_event_type',
89
-                        'delete_terms' => 'ee_delete_event_type',
90
-                        'assign_terms' => 'ee_assign_event_type',
91
-                    ),
92
-                    'rewrite'      => array(
93
-                        'slug' => EEH_URL::slugify(
94
-                            __('event-type', 'event_espresso'),
95
-                            'event-type'
96
-                        )
97
-                    ),
98
-                    'hierarchical' => true,
99
-                ),
100
-            ),
101
-        );
102
-    }
34
+	private function setTaxonomies()
35
+	{
36
+		$this->taxonomies = array(
37
+			'espresso_event_categories' => array(
38
+				'singular_name' => esc_html__('Event Category', 'event_espresso'),
39
+				'plural_name'   => esc_html__('Event Categories', 'event_espresso'),
40
+				'args'          => array(
41
+					'public'            => true,
42
+					'show_in_nav_menus' => true,
43
+					'show_in_rest'      => true,
44
+					'capabilities'      => array(
45
+						'manage_terms' => 'ee_manage_event_categories',
46
+						'edit_terms'   => 'ee_edit_event_category',
47
+						'delete_terms' => 'ee_delete_event_category',
48
+						'assign_terms' => 'ee_assign_event_category',
49
+					),
50
+					'rewrite'           => array(
51
+						'slug' => EEH_URL::slugify(
52
+							__('event-category', 'event_espresso'),
53
+							'event-category'
54
+						)
55
+					),
56
+				),
57
+			),
58
+			'espresso_venue_categories' => array(
59
+				'singular_name' => esc_html__('Venue Category', 'event_espresso'),
60
+				'plural_name'   => esc_html__('Venue Categories', 'event_espresso'),
61
+				'args'          => array(
62
+					'public'            => true,
63
+					'show_in_nav_menus' => false, // by default this doesn't show for decaf
64
+					'show_in_rest'      => true,
65
+					'capabilities'      => array(
66
+						'manage_terms' => 'ee_manage_venue_categories',
67
+						'edit_terms'   => 'ee_edit_venue_category',
68
+						'delete_terms' => 'ee_delete_venue_category',
69
+						'assign_terms' => 'ee_assign_venue_category',
70
+					),
71
+					'rewrite'           => array(
72
+						'slug' => EEH_URL::slugify(
73
+							__('venue-category', 'event_espresso'),
74
+							'venue-category'
75
+						)
76
+					),
77
+				),
78
+			),
79
+			'espresso_event_type'       => array(
80
+				'singular_name' => esc_html__('Event Type', 'event_espresso'),
81
+				'plural_name'   => esc_html__('Event Types', 'event_espresso'),
82
+				'args'          => array(
83
+					'public'       => true,
84
+					'show_ui'      => false,
85
+					'show_in_rest' => true,
86
+					'capabilities' => array(
87
+						'manage_terms' => 'ee_read_event_type',
88
+						'edit_terms'   => 'ee_edit_event_type',
89
+						'delete_terms' => 'ee_delete_event_type',
90
+						'assign_terms' => 'ee_assign_event_type',
91
+					),
92
+					'rewrite'      => array(
93
+						'slug' => EEH_URL::slugify(
94
+							__('event-type', 'event_espresso'),
95
+							'event-type'
96
+						)
97
+					),
98
+					'hierarchical' => true,
99
+				),
100
+			),
101
+		);
102
+	}
103 103
 
104 104
 
105
-    /**
106
-     * @return array
107
-     */
108
-    public function getCustomTaxonomyDefinitions()
109
-    {
110
-        return (array) apply_filters(
111
-            'FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies',
112
-            // legacy filter applied for now,
113
-            // later on we'll run a has_filter($tag) check and throw a doing_it_wrong() notice
114
-            apply_filters(
115
-                'FHEE__EE_Register_CPTs__get_taxonomies__taxonomies',
116
-                $this->taxonomies
117
-            )
118
-        );
119
-    }
105
+	/**
106
+	 * @return array
107
+	 */
108
+	public function getCustomTaxonomyDefinitions()
109
+	{
110
+		return (array) apply_filters(
111
+			'FHEE__EventEspresso_core_domain_entities_custom_post_types_TaxonomyDefinitions__getTaxonomies',
112
+			// legacy filter applied for now,
113
+			// later on we'll run a has_filter($tag) check and throw a doing_it_wrong() notice
114
+			apply_filters(
115
+				'FHEE__EE_Register_CPTs__get_taxonomies__taxonomies',
116
+				$this->taxonomies
117
+			)
118
+		);
119
+	}
120 120
 
121 121
 
122
-    /**
123
-     * @return array
124
-     */
125
-    public function getCustomTaxonomySlugs()
126
-    {
127
-        return array_keys($this->getCustomTaxonomyDefinitions());
128
-    }
122
+	/**
123
+	 * @return array
124
+	 */
125
+	public function getCustomTaxonomySlugs()
126
+	{
127
+		return array_keys($this->getCustomTaxonomyDefinitions());
128
+	}
129 129
 
130 130
 
131
-    /**
132
-     * By default, WordPress strips all html from term taxonomy description content.
133
-     * The purpose of this method is to remove that restriction
134
-     * and ensure that we still run ee term taxonomy descriptions
135
-     * through some full html sanitization equivalent to the post content field.
136
-     * So first we remove default filter for term description
137
-     * but we have to do this earlier before wp sets their own filter
138
-     * because they just set a global filter on all term descriptions
139
-     * before the custom term description filter.
140
-     * Really sux.
141
-     *
142
-     * @param string $description The description content.
143
-     * @param string $taxonomy    The taxonomy name for the taxonomy being filtered.
144
-     * @return string
145
-     */
146
-    public function filterCustomTermDescription($description, $taxonomy)
147
-    {
148
-        // get a list of EE taxonomies
149
-        $custom_taxonomies = $this->getCustomTaxonomySlugs();
150
-        // only do our own thing if the taxonomy listed is an ee taxonomy.
151
-        if (in_array($taxonomy, $custom_taxonomies, true)) {
152
-            // remove default wp filter
153
-            remove_filter('pre_term_description', 'wp_filter_kses');
154
-            // sanitize THIS content.
155
-            $description = wp_kses($description, wp_kses_allowed_html('post'));
156
-        }
157
-        return $description;
158
-    }
131
+	/**
132
+	 * By default, WordPress strips all html from term taxonomy description content.
133
+	 * The purpose of this method is to remove that restriction
134
+	 * and ensure that we still run ee term taxonomy descriptions
135
+	 * through some full html sanitization equivalent to the post content field.
136
+	 * So first we remove default filter for term description
137
+	 * but we have to do this earlier before wp sets their own filter
138
+	 * because they just set a global filter on all term descriptions
139
+	 * before the custom term description filter.
140
+	 * Really sux.
141
+	 *
142
+	 * @param string $description The description content.
143
+	 * @param string $taxonomy    The taxonomy name for the taxonomy being filtered.
144
+	 * @return string
145
+	 */
146
+	public function filterCustomTermDescription($description, $taxonomy)
147
+	{
148
+		// get a list of EE taxonomies
149
+		$custom_taxonomies = $this->getCustomTaxonomySlugs();
150
+		// only do our own thing if the taxonomy listed is an ee taxonomy.
151
+		if (in_array($taxonomy, $custom_taxonomies, true)) {
152
+			// remove default wp filter
153
+			remove_filter('pre_term_description', 'wp_filter_kses');
154
+			// sanitize THIS content.
155
+			$description = wp_kses($description, wp_kses_allowed_html('post'));
156
+		}
157
+		return $description;
158
+	}
159 159
 }
Please login to merge, or discard this patch.