Completed
Branch BUG/11268/session-ticket-relea... (f9aa59)
by
unknown
13:30 queued 24s
created
caffeinated/admin/new/pricing/espresso_events_Pricing_Hooks.class.php 3 patches
Doc Comments   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -1163,8 +1163,8 @@  discard block
 block discarded – undo
1163 1163
      * @param array       $datetime_tickets
1164 1164
      * @param array       $all_tickets
1165 1165
      * @param bool        $default
1166
-     * @param array       $all_datetimes
1167
-     * @return mixed
1166
+     * @param EE_Datetime[]       $all_datetimes
1167
+     * @return string
1168 1168
      * @throws DomainException
1169 1169
      * @throws EE_Error
1170 1170
      */
@@ -1275,7 +1275,7 @@  discard block
 block discarded – undo
1275 1275
      * @param array       $datetime_tickets
1276 1276
      * @param array       $all_tickets
1277 1277
      * @param bool        $default
1278
-     * @return mixed
1278
+     * @return string
1279 1279
      * @throws DomainException
1280 1280
      * @throws EE_Error
1281 1281
      */
@@ -1343,7 +1343,7 @@  discard block
 block discarded – undo
1343 1343
      * @param EE_Ticket   $ticket
1344 1344
      * @param array       $datetime_tickets
1345 1345
      * @param bool        $default
1346
-     * @return mixed
1346
+     * @return string
1347 1347
      * @throws DomainException
1348 1348
      * @throws EE_Error
1349 1349
      */
@@ -1413,7 +1413,7 @@  discard block
 block discarded – undo
1413 1413
      * @param bool          $default          Whether default row being generated or not.
1414 1414
      * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1415 1415
      *                                        (or empty in the case of defaults)
1416
-     * @return mixed
1416
+     * @return string
1417 1417
      * @throws InvalidArgumentException
1418 1418
      * @throws InvalidInterfaceException
1419 1419
      * @throws InvalidDataTypeException
@@ -1737,7 +1737,7 @@  discard block
 block discarded – undo
1737 1737
      * @param EE_Ticket|null $ticket
1738 1738
      * @param bool           $show_trash
1739 1739
      * @param bool           $show_create
1740
-     * @return mixed
1740
+     * @return string
1741 1741
      * @throws InvalidArgumentException
1742 1742
      * @throws InvalidInterfaceException
1743 1743
      * @throws InvalidDataTypeException
@@ -1840,7 +1840,7 @@  discard block
 block discarded – undo
1840 1840
      * @param EE_Price $price
1841 1841
      * @param bool     $default
1842 1842
      * @param bool     $disabled
1843
-     * @return mixed
1843
+     * @return string
1844 1844
      * @throws ReflectionException
1845 1845
      * @throws InvalidArgumentException
1846 1846
      * @throws InvalidInterfaceException
@@ -1873,7 +1873,7 @@  discard block
 block discarded – undo
1873 1873
      * @param int      $price_row
1874 1874
      * @param EE_Price $price
1875 1875
      * @param bool     $default
1876
-     * @return mixed
1876
+     * @return string
1877 1877
      * @throws DomainException
1878 1878
      * @throws EE_Error
1879 1879
      */
@@ -1910,7 +1910,7 @@  discard block
 block discarded – undo
1910 1910
      * @param EE_Price $price
1911 1911
      * @param bool     $default
1912 1912
      * @param bool     $disabled
1913
-     * @return mixed
1913
+     * @return string
1914 1914
      * @throws ReflectionException
1915 1915
      * @throws InvalidArgumentException
1916 1916
      * @throws InvalidInterfaceException
@@ -2012,7 +2012,7 @@  discard block
 block discarded – undo
2012 2012
      * @param EE_Ticket|null   $ticket
2013 2013
      * @param array            $ticket_datetimes
2014 2014
      * @param bool             $default
2015
-     * @return mixed
2015
+     * @return string
2016 2016
      * @throws DomainException
2017 2017
      * @throws EE_Error
2018 2018
      */
@@ -2065,9 +2065,9 @@  discard block
 block discarded – undo
2065 2065
 
2066 2066
 
2067 2067
     /**
2068
-     * @param array $all_datetimes
2068
+     * @param EE_Datetime[] $all_datetimes
2069 2069
      * @param array $all_tickets
2070
-     * @return mixed
2070
+     * @return string
2071 2071
      * @throws ReflectionException
2072 2072
      * @throws InvalidArgumentException
2073 2073
      * @throws InvalidInterfaceException
Please login to merge, or discard this patch.
Indentation   +2130 added lines, -2130 removed lines patch added patch discarded remove patch
@@ -19,2190 +19,2190 @@
 block discarded – undo
19 19
 class espresso_events_Pricing_Hooks extends EE_Admin_Hooks
20 20
 {
21 21
 
22
-    /**
23
-     * This property is just used to hold the status of whether an event is currently being
24
-     * created (true) or edited (false)
25
-     *
26
-     * @access protected
27
-     * @var bool
28
-     */
29
-    protected $_is_creating_event;
22
+	/**
23
+	 * This property is just used to hold the status of whether an event is currently being
24
+	 * created (true) or edited (false)
25
+	 *
26
+	 * @access protected
27
+	 * @var bool
28
+	 */
29
+	protected $_is_creating_event;
30 30
 
31
-    /**
32
-     * Used to contain the format strings for date and time that will be used for php date and
33
-     * time.
34
-     * Is set in the _set_hooks_properties() method.
35
-     *
36
-     * @var array
37
-     */
38
-    protected $_date_format_strings;
31
+	/**
32
+	 * Used to contain the format strings for date and time that will be used for php date and
33
+	 * time.
34
+	 * Is set in the _set_hooks_properties() method.
35
+	 *
36
+	 * @var array
37
+	 */
38
+	protected $_date_format_strings;
39 39
 
40
-    /**
41
-     * @var string $_date_time_format
42
-     */
43
-    protected $_date_time_format;
40
+	/**
41
+	 * @var string $_date_time_format
42
+	 */
43
+	protected $_date_time_format;
44 44
 
45 45
 
46
-    /**
47
-     * @throws InvalidArgumentException
48
-     * @throws InvalidInterfaceException
49
-     * @throws InvalidDataTypeException
50
-     */
51
-    protected function _set_hooks_properties()
52
-    {
53
-        $this->_name = 'pricing';
54
-        //capability check
55
-        if (! EE_Registry::instance()->CAP->current_user_can(
56
-            'ee_read_default_prices',
57
-            'advanced_ticket_datetime_metabox'
58
-        )) {
59
-            return;
60
-        }
61
-        $this->_setup_metaboxes();
62
-        $this->_set_date_time_formats();
63
-        $this->_validate_format_strings();
64
-        $this->_set_scripts_styles();
65
-        // commented out temporarily until logic is implemented in callback
66
-        // add_action(
67
-        //     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
68
-        //     array($this, 'autosave_handling')
69
-        // );
70
-        add_filter(
71
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
72
-            array($this, 'caf_updates')
73
-        );
74
-    }
46
+	/**
47
+	 * @throws InvalidArgumentException
48
+	 * @throws InvalidInterfaceException
49
+	 * @throws InvalidDataTypeException
50
+	 */
51
+	protected function _set_hooks_properties()
52
+	{
53
+		$this->_name = 'pricing';
54
+		//capability check
55
+		if (! EE_Registry::instance()->CAP->current_user_can(
56
+			'ee_read_default_prices',
57
+			'advanced_ticket_datetime_metabox'
58
+		)) {
59
+			return;
60
+		}
61
+		$this->_setup_metaboxes();
62
+		$this->_set_date_time_formats();
63
+		$this->_validate_format_strings();
64
+		$this->_set_scripts_styles();
65
+		// commented out temporarily until logic is implemented in callback
66
+		// add_action(
67
+		//     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
68
+		//     array($this, 'autosave_handling')
69
+		// );
70
+		add_filter(
71
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
72
+			array($this, 'caf_updates')
73
+		);
74
+	}
75 75
 
76 76
 
77
-    /**
78
-     * @return void
79
-     */
80
-    protected function _setup_metaboxes()
81
-    {
82
-        //if we were going to add our own metaboxes we'd use the below.
83
-        $this->_metaboxes        = array(
84
-            0 => array(
85
-                'page_route' => array('edit', 'create_new'),
86
-                'func'       => 'pricing_metabox',
87
-                'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
88
-                'priority'   => 'high',
89
-                'context'    => 'normal',
90
-            ),
91
-        );
92
-        $this->_remove_metaboxes = array(
93
-            0 => array(
94
-                'page_route' => array('edit', 'create_new'),
95
-                'id'         => 'espresso_event_editor_tickets',
96
-                'context'    => 'normal',
97
-            ),
98
-        );
99
-    }
77
+	/**
78
+	 * @return void
79
+	 */
80
+	protected function _setup_metaboxes()
81
+	{
82
+		//if we were going to add our own metaboxes we'd use the below.
83
+		$this->_metaboxes        = array(
84
+			0 => array(
85
+				'page_route' => array('edit', 'create_new'),
86
+				'func'       => 'pricing_metabox',
87
+				'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
88
+				'priority'   => 'high',
89
+				'context'    => 'normal',
90
+			),
91
+		);
92
+		$this->_remove_metaboxes = array(
93
+			0 => array(
94
+				'page_route' => array('edit', 'create_new'),
95
+				'id'         => 'espresso_event_editor_tickets',
96
+				'context'    => 'normal',
97
+			),
98
+		);
99
+	}
100 100
 
101 101
 
102
-    /**
103
-     * @return void
104
-     */
105
-    protected function _set_date_time_formats()
106
-    {
107
-        /**
108
-         * Format strings for date and time.  Defaults are existing behaviour from 4.1.
109
-         * Note, that if you return null as the value for 'date', and 'time' in the array, then
110
-         * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
111
-         *
112
-         * @since 4.6.7
113
-         * @var array  Expected an array returned with 'date' and 'time' keys.
114
-         */
115
-        $this->_date_format_strings = apply_filters(
116
-            'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
117
-            array(
118
-                'date' => 'Y-m-d',
119
-                'time' => 'h:i a',
120
-            )
121
-        );
122
-        //validate
123
-        $this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
124
-            ? $this->_date_format_strings['date']
125
-            : null;
126
-        $this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
127
-            ? $this->_date_format_strings['time']
128
-            : null;
129
-        $this->_date_time_format            = $this->_date_format_strings['date']
130
-                                              . ' '
131
-                                              . $this->_date_format_strings['time'];
132
-    }
102
+	/**
103
+	 * @return void
104
+	 */
105
+	protected function _set_date_time_formats()
106
+	{
107
+		/**
108
+		 * Format strings for date and time.  Defaults are existing behaviour from 4.1.
109
+		 * Note, that if you return null as the value for 'date', and 'time' in the array, then
110
+		 * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
111
+		 *
112
+		 * @since 4.6.7
113
+		 * @var array  Expected an array returned with 'date' and 'time' keys.
114
+		 */
115
+		$this->_date_format_strings = apply_filters(
116
+			'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
117
+			array(
118
+				'date' => 'Y-m-d',
119
+				'time' => 'h:i a',
120
+			)
121
+		);
122
+		//validate
123
+		$this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
124
+			? $this->_date_format_strings['date']
125
+			: null;
126
+		$this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
127
+			? $this->_date_format_strings['time']
128
+			: null;
129
+		$this->_date_time_format            = $this->_date_format_strings['date']
130
+											  . ' '
131
+											  . $this->_date_format_strings['time'];
132
+	}
133 133
 
134 134
 
135
-    /**
136
-     * @return void
137
-     */
138
-    protected function _validate_format_strings()
139
-    {
140
-        //validate format strings
141
-        $format_validation = EEH_DTT_Helper::validate_format_string(
142
-            $this->_date_time_format
143
-        );
144
-        if (is_array($format_validation)) {
145
-            $msg = '<p>';
146
-            $msg .= sprintf(
147
-                esc_html__(
148
-                    'The format "%s" was likely added via a filter and is invalid for the following reasons:',
149
-                    'event_espresso'
150
-                ),
151
-                $this->_date_time_format
152
-            );
153
-            $msg .= '</p><ul>';
154
-            foreach ($format_validation as $error) {
155
-                $msg .= '<li>' . $error . '</li>';
156
-            }
157
-            $msg .= '</ul><p>';
158
-            $msg .= sprintf(
159
-                esc_html__(
160
-                    '%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
161
-                    'event_espresso'
162
-                ),
163
-                '<span style="color:#D54E21;">',
164
-                '</span>'
165
-            );
166
-            $msg .= '</p>';
167
-            EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
168
-            $this->_date_format_strings = array(
169
-                'date' => 'Y-m-d',
170
-                'time' => 'h:i a',
171
-            );
172
-        }
173
-    }
135
+	/**
136
+	 * @return void
137
+	 */
138
+	protected function _validate_format_strings()
139
+	{
140
+		//validate format strings
141
+		$format_validation = EEH_DTT_Helper::validate_format_string(
142
+			$this->_date_time_format
143
+		);
144
+		if (is_array($format_validation)) {
145
+			$msg = '<p>';
146
+			$msg .= sprintf(
147
+				esc_html__(
148
+					'The format "%s" was likely added via a filter and is invalid for the following reasons:',
149
+					'event_espresso'
150
+				),
151
+				$this->_date_time_format
152
+			);
153
+			$msg .= '</p><ul>';
154
+			foreach ($format_validation as $error) {
155
+				$msg .= '<li>' . $error . '</li>';
156
+			}
157
+			$msg .= '</ul><p>';
158
+			$msg .= sprintf(
159
+				esc_html__(
160
+					'%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
161
+					'event_espresso'
162
+				),
163
+				'<span style="color:#D54E21;">',
164
+				'</span>'
165
+			);
166
+			$msg .= '</p>';
167
+			EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
168
+			$this->_date_format_strings = array(
169
+				'date' => 'Y-m-d',
170
+				'time' => 'h:i a',
171
+			);
172
+		}
173
+	}
174 174
 
175 175
 
176
-    /**
177
-     * @return void
178
-     */
179
-    protected function _set_scripts_styles()
180
-    {
181
-        $this->_scripts_styles = array(
182
-            'registers'   => array(
183
-                'ee-tickets-datetimes-css' => array(
184
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
185
-                    'type' => 'css',
186
-                ),
187
-                'ee-dtt-ticket-metabox'    => array(
188
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
189
-                    'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
190
-                ),
191
-            ),
192
-            'deregisters' => array(
193
-                'event-editor-css'       => array('type' => 'css'),
194
-                'event-datetime-metabox' => array('type' => 'js'),
195
-            ),
196
-            'enqueues'    => array(
197
-                'ee-tickets-datetimes-css' => array('edit', 'create_new'),
198
-                'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
199
-            ),
200
-            'localize'    => array(
201
-                'ee-dtt-ticket-metabox' => array(
202
-                    'DTT_TRASH_BLOCK'       => array(
203
-                        'main_warning'            => esc_html__(
204
-                            'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
205
-                            'event_espresso'
206
-                        ),
207
-                        'after_warning'           => esc_html__(
208
-                            'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
209
-                            'event_espresso'
210
-                        ),
211
-                        'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
212
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
213
-                        'close_button'            => '<button class="button-secondary ee-modal-cancel">'
214
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
215
-                        'single_warning_from_tkt' => esc_html__(
216
-                            'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
217
-                            'event_espresso'
218
-                        ),
219
-                        'single_warning_from_dtt' => esc_html__(
220
-                            'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
221
-                            'event_espresso'
222
-                        ),
223
-                        'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
224
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
225
-                    ),
226
-                    'DTT_ERROR_MSG'         => array(
227
-                        'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
228
-                        'dismiss_button' => '<div class="save-cancel-button-container">'
229
-                                            . '<button class="button-secondary ee-modal-cancel">'
230
-                                            . esc_html__('Dismiss', 'event_espresso')
231
-                                            . '</button></div>',
232
-                    ),
233
-                    'DTT_OVERSELL_WARNING'  => array(
234
-                        'datetime_ticket' => esc_html__(
235
-                            'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
236
-                            'event_espresso'
237
-                        ),
238
-                        'ticket_datetime' => esc_html__(
239
-                            'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
240
-                            'event_espresso'
241
-                        ),
242
-                    ),
243
-                    'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
244
-                        $this->_date_format_strings['date'],
245
-                        $this->_date_format_strings['time']
246
-                    ),
247
-                    'DTT_START_OF_WEEK'     => array('dayValue' => (int) get_option('start_of_week')),
248
-                ),
249
-            ),
250
-        );
251
-    }
176
+	/**
177
+	 * @return void
178
+	 */
179
+	protected function _set_scripts_styles()
180
+	{
181
+		$this->_scripts_styles = array(
182
+			'registers'   => array(
183
+				'ee-tickets-datetimes-css' => array(
184
+					'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
185
+					'type' => 'css',
186
+				),
187
+				'ee-dtt-ticket-metabox'    => array(
188
+					'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
189
+					'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
190
+				),
191
+			),
192
+			'deregisters' => array(
193
+				'event-editor-css'       => array('type' => 'css'),
194
+				'event-datetime-metabox' => array('type' => 'js'),
195
+			),
196
+			'enqueues'    => array(
197
+				'ee-tickets-datetimes-css' => array('edit', 'create_new'),
198
+				'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
199
+			),
200
+			'localize'    => array(
201
+				'ee-dtt-ticket-metabox' => array(
202
+					'DTT_TRASH_BLOCK'       => array(
203
+						'main_warning'            => esc_html__(
204
+							'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
205
+							'event_espresso'
206
+						),
207
+						'after_warning'           => esc_html__(
208
+							'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
209
+							'event_espresso'
210
+						),
211
+						'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
212
+													 . esc_html__('Cancel', 'event_espresso') . '</button>',
213
+						'close_button'            => '<button class="button-secondary ee-modal-cancel">'
214
+													 . esc_html__('Close', 'event_espresso') . '</button>',
215
+						'single_warning_from_tkt' => esc_html__(
216
+							'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
217
+							'event_espresso'
218
+						),
219
+						'single_warning_from_dtt' => esc_html__(
220
+							'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
221
+							'event_espresso'
222
+						),
223
+						'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
224
+													 . esc_html__('Dismiss', 'event_espresso') . '</button>',
225
+					),
226
+					'DTT_ERROR_MSG'         => array(
227
+						'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
228
+						'dismiss_button' => '<div class="save-cancel-button-container">'
229
+											. '<button class="button-secondary ee-modal-cancel">'
230
+											. esc_html__('Dismiss', 'event_espresso')
231
+											. '</button></div>',
232
+					),
233
+					'DTT_OVERSELL_WARNING'  => array(
234
+						'datetime_ticket' => esc_html__(
235
+							'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
236
+							'event_espresso'
237
+						),
238
+						'ticket_datetime' => esc_html__(
239
+							'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
240
+							'event_espresso'
241
+						),
242
+					),
243
+					'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
244
+						$this->_date_format_strings['date'],
245
+						$this->_date_format_strings['time']
246
+					),
247
+					'DTT_START_OF_WEEK'     => array('dayValue' => (int) get_option('start_of_week')),
248
+				),
249
+			),
250
+		);
251
+	}
252 252
 
253 253
 
254
-    /**
255
-     * @param array $update_callbacks
256
-     * @return array
257
-     */
258
-    public function caf_updates(array $update_callbacks)
259
-    {
260
-        foreach ($update_callbacks as $key => $callback) {
261
-            if ($callback[1] === '_default_tickets_update') {
262
-                unset($update_callbacks[ $key ]);
263
-            }
264
-        }
265
-        $update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
266
-        return $update_callbacks;
267
-    }
254
+	/**
255
+	 * @param array $update_callbacks
256
+	 * @return array
257
+	 */
258
+	public function caf_updates(array $update_callbacks)
259
+	{
260
+		foreach ($update_callbacks as $key => $callback) {
261
+			if ($callback[1] === '_default_tickets_update') {
262
+				unset($update_callbacks[ $key ]);
263
+			}
264
+		}
265
+		$update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
266
+		return $update_callbacks;
267
+	}
268 268
 
269 269
 
270
-    /**
271
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
272
-     *
273
-     * @param  EE_Event $event The Event object we're attaching data to
274
-     * @param  array    $data  The request data from the form
275
-     * @throws ReflectionException
276
-     * @throws Exception
277
-     * @throws InvalidInterfaceException
278
-     * @throws InvalidDataTypeException
279
-     * @throws EE_Error
280
-     * @throws InvalidArgumentException
281
-     */
282
-    public function datetime_and_tickets_caf_update($event, $data)
283
-    {
284
-        //first we need to start with datetimes cause they are the "root" items attached to events.
285
-        $saved_datetimes = $this->_update_datetimes($event, $data);
286
-        //next tackle the tickets (and prices?)
287
-        $this->_update_tickets($event, $saved_datetimes, $data);
288
-    }
270
+	/**
271
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
272
+	 *
273
+	 * @param  EE_Event $event The Event object we're attaching data to
274
+	 * @param  array    $data  The request data from the form
275
+	 * @throws ReflectionException
276
+	 * @throws Exception
277
+	 * @throws InvalidInterfaceException
278
+	 * @throws InvalidDataTypeException
279
+	 * @throws EE_Error
280
+	 * @throws InvalidArgumentException
281
+	 */
282
+	public function datetime_and_tickets_caf_update($event, $data)
283
+	{
284
+		//first we need to start with datetimes cause they are the "root" items attached to events.
285
+		$saved_datetimes = $this->_update_datetimes($event, $data);
286
+		//next tackle the tickets (and prices?)
287
+		$this->_update_tickets($event, $saved_datetimes, $data);
288
+	}
289 289
 
290 290
 
291
-    /**
292
-     * update event_datetimes
293
-     *
294
-     * @param  EE_Event $event Event being updated
295
-     * @param  array    $data  the request data from the form
296
-     * @return EE_Datetime[]
297
-     * @throws Exception
298
-     * @throws ReflectionException
299
-     * @throws InvalidInterfaceException
300
-     * @throws InvalidDataTypeException
301
-     * @throws InvalidArgumentException
302
-     * @throws EE_Error
303
-     */
304
-    protected function _update_datetimes($event, $data)
305
-    {
306
-        $timezone       = isset($data['timezone_string']) ? $data['timezone_string'] : null;
307
-        $saved_dtt_ids  = array();
308
-        $saved_dtt_objs = array();
309
-        if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
310
-            throw new InvalidArgumentException(
311
-                esc_html__(
312
-                    'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
313
-                    'event_espresso'
314
-                )
315
-            );
316
-        }
317
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
318
-            //trim all values to ensure any excess whitespace is removed.
319
-            $datetime_data                = array_map(
320
-                function ($datetime_data)
321
-                {
322
-                    return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
323
-                },
324
-                $datetime_data
325
-            );
326
-            $datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
327
-                                            && ! empty($datetime_data['DTT_EVT_end'])
328
-                ? $datetime_data['DTT_EVT_end']
329
-                : $datetime_data['DTT_EVT_start'];
330
-            $datetime_values              = array(
331
-                'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332
-                    ? $datetime_data['DTT_ID']
333
-                    : null,
334
-                'DTT_name'        => ! empty($datetime_data['DTT_name'])
335
-                    ? $datetime_data['DTT_name']
336
-                    : '',
337
-                'DTT_description' => ! empty($datetime_data['DTT_description'])
338
-                    ? $datetime_data['DTT_description']
339
-                    : '',
340
-                'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
341
-                'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
342
-                'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
343
-                    ? EE_INF
344
-                    : $datetime_data['DTT_reg_limit'],
345
-                'DTT_order'       => ! isset($datetime_data['DTT_order'])
346
-                    ? $row
347
-                    : $datetime_data['DTT_order'],
348
-            );
349
-            // if we have an id then let's get existing object first and then set the new values.
350
-            // Otherwise we instantiate a new object for save.
351
-            if (! empty($datetime_data['DTT_ID'])) {
352
-                $datetime = EE_Registry::instance()
353
-                                       ->load_model('Datetime', array($timezone))
354
-                                       ->get_one_by_ID($datetime_data['DTT_ID']);
355
-                //set date and time format according to what is set in this class.
356
-                $datetime->set_date_format($this->_date_format_strings['date']);
357
-                $datetime->set_time_format($this->_date_format_strings['time']);
358
-                foreach ($datetime_values as $field => $value) {
359
-                    $datetime->set($field, $value);
360
-                }
361
-                // make sure the $dtt_id here is saved just in case
362
-                // after the add_relation_to() the autosave replaces it.
363
-                // We need to do this so we dont' TRASH the parent DTT.
364
-                // (save the ID for both key and value to avoid duplications)
365
-                $saved_dtt_ids[ $datetime->ID() ] = $datetime->ID();
366
-            } else {
367
-                $datetime = EE_Registry::instance()->load_class(
368
-                    'Datetime',
369
-                    array(
370
-                        $datetime_values,
371
-                        $timezone,
372
-                        array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
373
-                    ),
374
-                    false,
375
-                    false
376
-                );
377
-                foreach ($datetime_values as $field => $value) {
378
-                    $datetime->set($field, $value);
379
-                }
380
-            }
381
-            $datetime->save();
382
-            $datetime = $event->_add_relation_to($datetime, 'Datetime');
383
-            // before going any further make sure our dates are setup correctly
384
-            // so that the end date is always equal or greater than the start date.
385
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
386
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
387
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
388
-                $datetime->save();
389
-            }
390
-            //	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
391
-            // because it is possible there was a new one created for the autosave.
392
-            // (save the ID for both key and value to avoid duplications)
393
-            $DTT_ID                   = $datetime->ID();
394
-            $saved_dtt_ids[ $DTT_ID ] = $DTT_ID;
395
-            $saved_dtt_objs[ $row ]   = $datetime;
396
-            //todo if ANY of these updates fail then we want the appropriate global error message.
397
-        }
398
-        $event->save();
399
-        // now we need to REMOVE any datetimes that got deleted.
400
-        // Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
401
-        // So its safe to permanently delete at this point.
402
-        $old_datetimes = explode(',', $data['datetime_IDs']);
403
-        $old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
404
-        if (is_array($old_datetimes)) {
405
-            $datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
406
-            foreach ($datetimes_to_delete as $id) {
407
-                $id = absint($id);
408
-                if (empty($id)) {
409
-                    continue;
410
-                }
411
-                $dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
412
-                //remove tkt relationships.
413
-                $related_tickets = $dtt_to_remove->get_many_related('Ticket');
414
-                foreach ($related_tickets as $tkt) {
415
-                    $dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
416
-                }
417
-                $event->_remove_relation_to($id, 'Datetime');
418
-                $dtt_to_remove->refresh_cache_of_related_objects();
419
-            }
420
-        }
421
-        return $saved_dtt_objs;
422
-    }
291
+	/**
292
+	 * update event_datetimes
293
+	 *
294
+	 * @param  EE_Event $event Event being updated
295
+	 * @param  array    $data  the request data from the form
296
+	 * @return EE_Datetime[]
297
+	 * @throws Exception
298
+	 * @throws ReflectionException
299
+	 * @throws InvalidInterfaceException
300
+	 * @throws InvalidDataTypeException
301
+	 * @throws InvalidArgumentException
302
+	 * @throws EE_Error
303
+	 */
304
+	protected function _update_datetimes($event, $data)
305
+	{
306
+		$timezone       = isset($data['timezone_string']) ? $data['timezone_string'] : null;
307
+		$saved_dtt_ids  = array();
308
+		$saved_dtt_objs = array();
309
+		if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
310
+			throw new InvalidArgumentException(
311
+				esc_html__(
312
+					'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
313
+					'event_espresso'
314
+				)
315
+			);
316
+		}
317
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
318
+			//trim all values to ensure any excess whitespace is removed.
319
+			$datetime_data                = array_map(
320
+				function ($datetime_data)
321
+				{
322
+					return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
323
+				},
324
+				$datetime_data
325
+			);
326
+			$datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
327
+											&& ! empty($datetime_data['DTT_EVT_end'])
328
+				? $datetime_data['DTT_EVT_end']
329
+				: $datetime_data['DTT_EVT_start'];
330
+			$datetime_values              = array(
331
+				'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332
+					? $datetime_data['DTT_ID']
333
+					: null,
334
+				'DTT_name'        => ! empty($datetime_data['DTT_name'])
335
+					? $datetime_data['DTT_name']
336
+					: '',
337
+				'DTT_description' => ! empty($datetime_data['DTT_description'])
338
+					? $datetime_data['DTT_description']
339
+					: '',
340
+				'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
341
+				'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
342
+				'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
343
+					? EE_INF
344
+					: $datetime_data['DTT_reg_limit'],
345
+				'DTT_order'       => ! isset($datetime_data['DTT_order'])
346
+					? $row
347
+					: $datetime_data['DTT_order'],
348
+			);
349
+			// if we have an id then let's get existing object first and then set the new values.
350
+			// Otherwise we instantiate a new object for save.
351
+			if (! empty($datetime_data['DTT_ID'])) {
352
+				$datetime = EE_Registry::instance()
353
+									   ->load_model('Datetime', array($timezone))
354
+									   ->get_one_by_ID($datetime_data['DTT_ID']);
355
+				//set date and time format according to what is set in this class.
356
+				$datetime->set_date_format($this->_date_format_strings['date']);
357
+				$datetime->set_time_format($this->_date_format_strings['time']);
358
+				foreach ($datetime_values as $field => $value) {
359
+					$datetime->set($field, $value);
360
+				}
361
+				// make sure the $dtt_id here is saved just in case
362
+				// after the add_relation_to() the autosave replaces it.
363
+				// We need to do this so we dont' TRASH the parent DTT.
364
+				// (save the ID for both key and value to avoid duplications)
365
+				$saved_dtt_ids[ $datetime->ID() ] = $datetime->ID();
366
+			} else {
367
+				$datetime = EE_Registry::instance()->load_class(
368
+					'Datetime',
369
+					array(
370
+						$datetime_values,
371
+						$timezone,
372
+						array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
373
+					),
374
+					false,
375
+					false
376
+				);
377
+				foreach ($datetime_values as $field => $value) {
378
+					$datetime->set($field, $value);
379
+				}
380
+			}
381
+			$datetime->save();
382
+			$datetime = $event->_add_relation_to($datetime, 'Datetime');
383
+			// before going any further make sure our dates are setup correctly
384
+			// so that the end date is always equal or greater than the start date.
385
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
386
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
387
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
388
+				$datetime->save();
389
+			}
390
+			//	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
391
+			// because it is possible there was a new one created for the autosave.
392
+			// (save the ID for both key and value to avoid duplications)
393
+			$DTT_ID                   = $datetime->ID();
394
+			$saved_dtt_ids[ $DTT_ID ] = $DTT_ID;
395
+			$saved_dtt_objs[ $row ]   = $datetime;
396
+			//todo if ANY of these updates fail then we want the appropriate global error message.
397
+		}
398
+		$event->save();
399
+		// now we need to REMOVE any datetimes that got deleted.
400
+		// Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
401
+		// So its safe to permanently delete at this point.
402
+		$old_datetimes = explode(',', $data['datetime_IDs']);
403
+		$old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
404
+		if (is_array($old_datetimes)) {
405
+			$datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
406
+			foreach ($datetimes_to_delete as $id) {
407
+				$id = absint($id);
408
+				if (empty($id)) {
409
+					continue;
410
+				}
411
+				$dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
412
+				//remove tkt relationships.
413
+				$related_tickets = $dtt_to_remove->get_many_related('Ticket');
414
+				foreach ($related_tickets as $tkt) {
415
+					$dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
416
+				}
417
+				$event->_remove_relation_to($id, 'Datetime');
418
+				$dtt_to_remove->refresh_cache_of_related_objects();
419
+			}
420
+		}
421
+		return $saved_dtt_objs;
422
+	}
423 423
 
424 424
 
425
-    /**
426
-     * update tickets
427
-     *
428
-     * @param  EE_Event      $event           Event object being updated
429
-     * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
430
-     * @param  array         $data            incoming request data
431
-     * @return EE_Ticket[]
432
-     * @throws Exception
433
-     * @throws ReflectionException
434
-     * @throws InvalidInterfaceException
435
-     * @throws InvalidDataTypeException
436
-     * @throws InvalidArgumentException
437
-     * @throws EE_Error
438
-     */
439
-    protected function _update_tickets($event, $saved_datetimes, $data)
440
-    {
441
-        $new_tkt     = null;
442
-        $new_default = null;
443
-        //stripslashes because WP filtered the $_POST ($data) array to add slashes
444
-        $data          = stripslashes_deep($data);
445
-        $timezone      = isset($data['timezone_string']) ? $data['timezone_string'] : null;
446
-        $saved_tickets = $datetimes_on_existing = array();
447
-        $old_tickets   = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
448
-        if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
449
-            throw new InvalidArgumentException(
450
-                esc_html__(
451
-                    'The "edit_tickets" array is invalid therefore the event can not be updated.',
452
-                    'event_espresso'
453
-                )
454
-            );
455
-        }
456
-        foreach ($data['edit_tickets'] as $row => $tkt) {
457
-            $update_prices = $create_new_TKT = false;
458
-            // figure out what datetimes were added to the ticket
459
-            // and what datetimes were removed from the ticket in the session.
460
-            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
461
-            $tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
462
-            $datetimes_added       = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
463
-            $datetimes_removed     = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
464
-            // trim inputs to ensure any excess whitespace is removed.
465
-            $tkt = array_map(
466
-                function ($ticket_data)
467
-                {
468
-                    return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
469
-                },
470
-                $tkt
471
-            );
472
-            // note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
473
-            // because we're doing calculations prior to using the models.
474
-            // note incoming ['TKT_price'] value is already in standard notation (via js).
475
-            $ticket_price = isset($tkt['TKT_price'])
476
-                ? round((float) $tkt['TKT_price'], 3)
477
-                : 0;
478
-            //note incoming base price needs converted from localized value.
479
-            $base_price = isset($tkt['TKT_base_price'])
480
-                ? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
481
-                : 0;
482
-            //if ticket price == 0 and $base_price != 0 then ticket price == base_price
483
-            $ticket_price  = $ticket_price === 0 && $base_price !== 0
484
-                ? $base_price
485
-                : $ticket_price;
486
-            $base_price_id = isset($tkt['TKT_base_price_ID'])
487
-                ? $tkt['TKT_base_price_ID']
488
-                : 0;
489
-            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
490
-                ? $data['edit_prices'][ $row ]
491
-                : array();
492
-            $now           = null;
493
-            if (empty($tkt['TKT_start_date'])) {
494
-                //lets' use now in the set timezone.
495
-                $now                   = new DateTime('now', new DateTimeZone($event->get_timezone()));
496
-                $tkt['TKT_start_date'] = $now->format($this->_date_time_format);
497
-            }
498
-            if (empty($tkt['TKT_end_date'])) {
499
-                /**
500
-                 * set the TKT_end_date to the first datetime attached to the ticket.
501
-                 */
502
-                $first_dtt           = $saved_datetimes[ reset($tkt_dtt_rows) ];
503
-                $tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
504
-            }
505
-            $TKT_values = array(
506
-                'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
507
-                'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
508
-                'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
509
-                'TKT_description' => ! empty($tkt['TKT_description'])
510
-                                     && $tkt['TKT_description'] !== esc_html__(
511
-                    'You can modify this description',
512
-                    'event_espresso'
513
-                )
514
-                    ? $tkt['TKT_description']
515
-                    : '',
516
-                'TKT_start_date'  => $tkt['TKT_start_date'],
517
-                'TKT_end_date'    => $tkt['TKT_end_date'],
518
-                'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
519
-                    ? EE_INF
520
-                    : $tkt['TKT_qty'],
521
-                'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
522
-                    ? EE_INF
523
-                    : $tkt['TKT_uses'],
524
-                'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
525
-                'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
526
-                'TKT_row'         => $row,
527
-                'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
528
-                'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
529
-                'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
530
-                'TKT_price'       => $ticket_price,
531
-            );
532
-            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
533
-            // which means in turn that the prices will become new prices as well.
534
-            if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
535
-                $TKT_values['TKT_ID']         = 0;
536
-                $TKT_values['TKT_is_default'] = 0;
537
-                $update_prices                = true;
538
-            }
539
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
540
-            // we actually do our saves ahead of doing any add_relations to
541
-            // because its entirely possible that this ticket wasn't removed or added to any datetime in the session
542
-            // but DID have it's items modified.
543
-            // keep in mind that if the TKT has been sold (and we have changed pricing information),
544
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
545
-            if (absint($TKT_values['TKT_ID'])) {
546
-                $ticket = EE_Registry::instance()
547
-                                     ->load_model('Ticket', array($timezone))
548
-                                     ->get_one_by_ID($tkt['TKT_ID']);
549
-                if ($ticket instanceof EE_Ticket) {
550
-                    $ticket = $this->_update_ticket_datetimes(
551
-                        $ticket,
552
-                        $saved_datetimes,
553
-                        $datetimes_added,
554
-                        $datetimes_removed
555
-                    );
556
-                    // are there any registrations using this ticket ?
557
-                    $tickets_sold = $ticket->count_related(
558
-                        'Registration',
559
-                        array(
560
-                            array(
561
-                                'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
562
-                            ),
563
-                        )
564
-                    );
565
-                    //set ticket formats
566
-                    $ticket->set_date_format($this->_date_format_strings['date']);
567
-                    $ticket->set_time_format($this->_date_format_strings['time']);
568
-                    // let's just check the total price for the existing ticket
569
-                    // and determine if it matches the new total price.
570
-                    // if they are different then we create a new ticket (if tickets sold)
571
-                    // if they aren't different then we go ahead and modify existing ticket.
572
-                    $create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
573
-                    //set new values
574
-                    foreach ($TKT_values as $field => $value) {
575
-                        if ($field === 'TKT_qty') {
576
-                            $ticket->set_qty($value);
577
-                        } else {
578
-                            $ticket->set($field, $value);
579
-                        }
580
-                    }
581
-                    // if $create_new_TKT is false then we can safely update the existing ticket.
582
-                    // Otherwise we have to create a new ticket.
583
-                    if ($create_new_TKT) {
584
-                        $new_tkt = $this->_duplicate_ticket(
585
-                            $ticket,
586
-                            $price_rows,
587
-                            $ticket_price,
588
-                            $base_price,
589
-                            $base_price_id
590
-                        );
591
-                    }
592
-                }
593
-            } else {
594
-                // no TKT_id so a new TKT
595
-                $ticket = EE_Ticket::new_instance(
596
-                    $TKT_values,
597
-                    $timezone,
598
-                    array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
599
-                );
600
-                if ($ticket instanceof EE_Ticket) {
601
-                    // make sure ticket has an ID of setting relations won't work
602
-                    $ticket->save();
603
-                    $ticket        = $this->_update_ticket_datetimes(
604
-                        $ticket,
605
-                        $saved_datetimes,
606
-                        $datetimes_added,
607
-                        $datetimes_removed
608
-                    );
609
-                    $update_prices = true;
610
-                }
611
-            }
612
-            //make sure any current values have been saved.
613
-            //$ticket->save();
614
-            // before going any further make sure our dates are setup correctly
615
-            // so that the end date is always equal or greater than the start date.
616
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
617
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
618
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
619
-            }
620
-            //let's make sure the base price is handled
621
-            $ticket = ! $create_new_TKT
622
-                ? $this->_add_prices_to_ticket(
623
-                    array(),
624
-                    $ticket,
625
-                    $update_prices,
626
-                    $base_price,
627
-                    $base_price_id
628
-                )
629
-                : $ticket;
630
-            //add/update price_modifiers
631
-            $ticket = ! $create_new_TKT
632
-                ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
633
-                : $ticket;
634
-            //need to make sue that the TKT_price is accurate after saving the prices.
635
-            $ticket->ensure_TKT_Price_correct();
636
-            //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
637
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
638
-                $update_prices = true;
639
-                $new_default   = clone $ticket;
640
-                $new_default->set('TKT_ID', 0);
641
-                $new_default->set('TKT_is_default', 1);
642
-                $new_default->set('TKT_row', 1);
643
-                $new_default->set('TKT_price', $ticket_price);
644
-                // remove any dtt relations cause we DON'T want dtt relations attached
645
-                // (note this is just removing the cached relations in the object)
646
-                $new_default->_remove_relations('Datetime');
647
-                //todo we need to add the current attached prices as new prices to the new default ticket.
648
-                $new_default = $this->_add_prices_to_ticket(
649
-                    $price_rows,
650
-                    $new_default,
651
-                    $update_prices
652
-                );
653
-                //don't forget the base price!
654
-                $new_default = $this->_add_prices_to_ticket(
655
-                    array(),
656
-                    $new_default,
657
-                    $update_prices,
658
-                    $base_price,
659
-                    $base_price_id
660
-                );
661
-                $new_default->save();
662
-                do_action(
663
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
664
-                    $new_default,
665
-                    $row,
666
-                    $ticket,
667
-                    $data
668
-                );
669
-            }
670
-            // DO ALL dtt relationships for both current tickets and any archived tickets
671
-            // for the given dtt that are related to the current ticket.
672
-            // TODO... not sure exactly how we're going to do this considering we don't know
673
-            // what current ticket the archived tickets are related to
674
-            // (and TKT_parent is used for autosaves so that's not a field we can reliably use).
675
-            //let's assign any tickets that have been setup to the saved_tickets tracker
676
-            //save existing TKT
677
-            $ticket->save();
678
-            if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
679
-                //save new TKT
680
-                $new_tkt->save();
681
-                //add new ticket to array
682
-                $saved_tickets[ $new_tkt->ID() ] = $new_tkt;
683
-                do_action(
684
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
685
-                    $new_tkt,
686
-                    $row,
687
-                    $tkt,
688
-                    $data
689
-                );
690
-            } else {
691
-                //add tkt to saved tkts
692
-                $saved_tickets[ $ticket->ID() ] = $ticket;
693
-                do_action(
694
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
695
-                    $ticket,
696
-                    $row,
697
-                    $tkt,
698
-                    $data
699
-                );
700
-            }
701
-        }
702
-        // now we need to handle tickets actually "deleted permanently".
703
-        // There are cases where we'd want this to happen
704
-        // (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
705
-        // Or a draft event was saved and in the process of editing a ticket is trashed.
706
-        // No sense in keeping all the related data in the db!
707
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
708
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
709
-        foreach ($tickets_removed as $id) {
710
-            $id = absint($id);
711
-            //get the ticket for this id
712
-            $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
713
-            //if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
714
-            if ($tkt_to_remove->get('TKT_is_default')) {
715
-                continue;
716
-            }
717
-            // if this tkt has any registrations attached so then we just ARCHIVE
718
-            // because we don't actually permanently delete these tickets.
719
-            if ($tkt_to_remove->count_related('Registration') > 0) {
720
-                $tkt_to_remove->delete();
721
-                continue;
722
-            }
723
-            // need to get all the related datetimes on this ticket and remove from every single one of them
724
-            // (remember this process can ONLY kick off if there are NO tkts_sold)
725
-            $datetimes = $tkt_to_remove->get_many_related('Datetime');
726
-            foreach ($datetimes as $datetime) {
727
-                $tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
728
-            }
729
-            // need to do the same for prices (except these prices can also be deleted because again,
730
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
731
-            $tkt_to_remove->delete_related_permanently('Price');
732
-            do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
733
-            // finally let's delete this ticket
734
-            // (which should not be blocked at this point b/c we've removed all our relationships)
735
-            $tkt_to_remove->delete_permanently();
736
-        }
737
-        return $saved_tickets;
738
-    }
425
+	/**
426
+	 * update tickets
427
+	 *
428
+	 * @param  EE_Event      $event           Event object being updated
429
+	 * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
430
+	 * @param  array         $data            incoming request data
431
+	 * @return EE_Ticket[]
432
+	 * @throws Exception
433
+	 * @throws ReflectionException
434
+	 * @throws InvalidInterfaceException
435
+	 * @throws InvalidDataTypeException
436
+	 * @throws InvalidArgumentException
437
+	 * @throws EE_Error
438
+	 */
439
+	protected function _update_tickets($event, $saved_datetimes, $data)
440
+	{
441
+		$new_tkt     = null;
442
+		$new_default = null;
443
+		//stripslashes because WP filtered the $_POST ($data) array to add slashes
444
+		$data          = stripslashes_deep($data);
445
+		$timezone      = isset($data['timezone_string']) ? $data['timezone_string'] : null;
446
+		$saved_tickets = $datetimes_on_existing = array();
447
+		$old_tickets   = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
448
+		if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
449
+			throw new InvalidArgumentException(
450
+				esc_html__(
451
+					'The "edit_tickets" array is invalid therefore the event can not be updated.',
452
+					'event_espresso'
453
+				)
454
+			);
455
+		}
456
+		foreach ($data['edit_tickets'] as $row => $tkt) {
457
+			$update_prices = $create_new_TKT = false;
458
+			// figure out what datetimes were added to the ticket
459
+			// and what datetimes were removed from the ticket in the session.
460
+			$starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
461
+			$tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
462
+			$datetimes_added       = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
463
+			$datetimes_removed     = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
464
+			// trim inputs to ensure any excess whitespace is removed.
465
+			$tkt = array_map(
466
+				function ($ticket_data)
467
+				{
468
+					return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
469
+				},
470
+				$tkt
471
+			);
472
+			// note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
473
+			// because we're doing calculations prior to using the models.
474
+			// note incoming ['TKT_price'] value is already in standard notation (via js).
475
+			$ticket_price = isset($tkt['TKT_price'])
476
+				? round((float) $tkt['TKT_price'], 3)
477
+				: 0;
478
+			//note incoming base price needs converted from localized value.
479
+			$base_price = isset($tkt['TKT_base_price'])
480
+				? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
481
+				: 0;
482
+			//if ticket price == 0 and $base_price != 0 then ticket price == base_price
483
+			$ticket_price  = $ticket_price === 0 && $base_price !== 0
484
+				? $base_price
485
+				: $ticket_price;
486
+			$base_price_id = isset($tkt['TKT_base_price_ID'])
487
+				? $tkt['TKT_base_price_ID']
488
+				: 0;
489
+			$price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
490
+				? $data['edit_prices'][ $row ]
491
+				: array();
492
+			$now           = null;
493
+			if (empty($tkt['TKT_start_date'])) {
494
+				//lets' use now in the set timezone.
495
+				$now                   = new DateTime('now', new DateTimeZone($event->get_timezone()));
496
+				$tkt['TKT_start_date'] = $now->format($this->_date_time_format);
497
+			}
498
+			if (empty($tkt['TKT_end_date'])) {
499
+				/**
500
+				 * set the TKT_end_date to the first datetime attached to the ticket.
501
+				 */
502
+				$first_dtt           = $saved_datetimes[ reset($tkt_dtt_rows) ];
503
+				$tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
504
+			}
505
+			$TKT_values = array(
506
+				'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
507
+				'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
508
+				'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
509
+				'TKT_description' => ! empty($tkt['TKT_description'])
510
+									 && $tkt['TKT_description'] !== esc_html__(
511
+					'You can modify this description',
512
+					'event_espresso'
513
+				)
514
+					? $tkt['TKT_description']
515
+					: '',
516
+				'TKT_start_date'  => $tkt['TKT_start_date'],
517
+				'TKT_end_date'    => $tkt['TKT_end_date'],
518
+				'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
519
+					? EE_INF
520
+					: $tkt['TKT_qty'],
521
+				'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
522
+					? EE_INF
523
+					: $tkt['TKT_uses'],
524
+				'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
525
+				'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
526
+				'TKT_row'         => $row,
527
+				'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
528
+				'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
529
+				'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
530
+				'TKT_price'       => $ticket_price,
531
+			);
532
+			// if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
533
+			// which means in turn that the prices will become new prices as well.
534
+			if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
535
+				$TKT_values['TKT_ID']         = 0;
536
+				$TKT_values['TKT_is_default'] = 0;
537
+				$update_prices                = true;
538
+			}
539
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
540
+			// we actually do our saves ahead of doing any add_relations to
541
+			// because its entirely possible that this ticket wasn't removed or added to any datetime in the session
542
+			// but DID have it's items modified.
543
+			// keep in mind that if the TKT has been sold (and we have changed pricing information),
544
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
545
+			if (absint($TKT_values['TKT_ID'])) {
546
+				$ticket = EE_Registry::instance()
547
+									 ->load_model('Ticket', array($timezone))
548
+									 ->get_one_by_ID($tkt['TKT_ID']);
549
+				if ($ticket instanceof EE_Ticket) {
550
+					$ticket = $this->_update_ticket_datetimes(
551
+						$ticket,
552
+						$saved_datetimes,
553
+						$datetimes_added,
554
+						$datetimes_removed
555
+					);
556
+					// are there any registrations using this ticket ?
557
+					$tickets_sold = $ticket->count_related(
558
+						'Registration',
559
+						array(
560
+							array(
561
+								'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
562
+							),
563
+						)
564
+					);
565
+					//set ticket formats
566
+					$ticket->set_date_format($this->_date_format_strings['date']);
567
+					$ticket->set_time_format($this->_date_format_strings['time']);
568
+					// let's just check the total price for the existing ticket
569
+					// and determine if it matches the new total price.
570
+					// if they are different then we create a new ticket (if tickets sold)
571
+					// if they aren't different then we go ahead and modify existing ticket.
572
+					$create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
573
+					//set new values
574
+					foreach ($TKT_values as $field => $value) {
575
+						if ($field === 'TKT_qty') {
576
+							$ticket->set_qty($value);
577
+						} else {
578
+							$ticket->set($field, $value);
579
+						}
580
+					}
581
+					// if $create_new_TKT is false then we can safely update the existing ticket.
582
+					// Otherwise we have to create a new ticket.
583
+					if ($create_new_TKT) {
584
+						$new_tkt = $this->_duplicate_ticket(
585
+							$ticket,
586
+							$price_rows,
587
+							$ticket_price,
588
+							$base_price,
589
+							$base_price_id
590
+						);
591
+					}
592
+				}
593
+			} else {
594
+				// no TKT_id so a new TKT
595
+				$ticket = EE_Ticket::new_instance(
596
+					$TKT_values,
597
+					$timezone,
598
+					array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
599
+				);
600
+				if ($ticket instanceof EE_Ticket) {
601
+					// make sure ticket has an ID of setting relations won't work
602
+					$ticket->save();
603
+					$ticket        = $this->_update_ticket_datetimes(
604
+						$ticket,
605
+						$saved_datetimes,
606
+						$datetimes_added,
607
+						$datetimes_removed
608
+					);
609
+					$update_prices = true;
610
+				}
611
+			}
612
+			//make sure any current values have been saved.
613
+			//$ticket->save();
614
+			// before going any further make sure our dates are setup correctly
615
+			// so that the end date is always equal or greater than the start date.
616
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
617
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
618
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
619
+			}
620
+			//let's make sure the base price is handled
621
+			$ticket = ! $create_new_TKT
622
+				? $this->_add_prices_to_ticket(
623
+					array(),
624
+					$ticket,
625
+					$update_prices,
626
+					$base_price,
627
+					$base_price_id
628
+				)
629
+				: $ticket;
630
+			//add/update price_modifiers
631
+			$ticket = ! $create_new_TKT
632
+				? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
633
+				: $ticket;
634
+			//need to make sue that the TKT_price is accurate after saving the prices.
635
+			$ticket->ensure_TKT_Price_correct();
636
+			//handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
637
+			if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
638
+				$update_prices = true;
639
+				$new_default   = clone $ticket;
640
+				$new_default->set('TKT_ID', 0);
641
+				$new_default->set('TKT_is_default', 1);
642
+				$new_default->set('TKT_row', 1);
643
+				$new_default->set('TKT_price', $ticket_price);
644
+				// remove any dtt relations cause we DON'T want dtt relations attached
645
+				// (note this is just removing the cached relations in the object)
646
+				$new_default->_remove_relations('Datetime');
647
+				//todo we need to add the current attached prices as new prices to the new default ticket.
648
+				$new_default = $this->_add_prices_to_ticket(
649
+					$price_rows,
650
+					$new_default,
651
+					$update_prices
652
+				);
653
+				//don't forget the base price!
654
+				$new_default = $this->_add_prices_to_ticket(
655
+					array(),
656
+					$new_default,
657
+					$update_prices,
658
+					$base_price,
659
+					$base_price_id
660
+				);
661
+				$new_default->save();
662
+				do_action(
663
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
664
+					$new_default,
665
+					$row,
666
+					$ticket,
667
+					$data
668
+				);
669
+			}
670
+			// DO ALL dtt relationships for both current tickets and any archived tickets
671
+			// for the given dtt that are related to the current ticket.
672
+			// TODO... not sure exactly how we're going to do this considering we don't know
673
+			// what current ticket the archived tickets are related to
674
+			// (and TKT_parent is used for autosaves so that's not a field we can reliably use).
675
+			//let's assign any tickets that have been setup to the saved_tickets tracker
676
+			//save existing TKT
677
+			$ticket->save();
678
+			if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
679
+				//save new TKT
680
+				$new_tkt->save();
681
+				//add new ticket to array
682
+				$saved_tickets[ $new_tkt->ID() ] = $new_tkt;
683
+				do_action(
684
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
685
+					$new_tkt,
686
+					$row,
687
+					$tkt,
688
+					$data
689
+				);
690
+			} else {
691
+				//add tkt to saved tkts
692
+				$saved_tickets[ $ticket->ID() ] = $ticket;
693
+				do_action(
694
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
695
+					$ticket,
696
+					$row,
697
+					$tkt,
698
+					$data
699
+				);
700
+			}
701
+		}
702
+		// now we need to handle tickets actually "deleted permanently".
703
+		// There are cases where we'd want this to happen
704
+		// (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
705
+		// Or a draft event was saved and in the process of editing a ticket is trashed.
706
+		// No sense in keeping all the related data in the db!
707
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
708
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
709
+		foreach ($tickets_removed as $id) {
710
+			$id = absint($id);
711
+			//get the ticket for this id
712
+			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
713
+			//if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
714
+			if ($tkt_to_remove->get('TKT_is_default')) {
715
+				continue;
716
+			}
717
+			// if this tkt has any registrations attached so then we just ARCHIVE
718
+			// because we don't actually permanently delete these tickets.
719
+			if ($tkt_to_remove->count_related('Registration') > 0) {
720
+				$tkt_to_remove->delete();
721
+				continue;
722
+			}
723
+			// need to get all the related datetimes on this ticket and remove from every single one of them
724
+			// (remember this process can ONLY kick off if there are NO tkts_sold)
725
+			$datetimes = $tkt_to_remove->get_many_related('Datetime');
726
+			foreach ($datetimes as $datetime) {
727
+				$tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
728
+			}
729
+			// need to do the same for prices (except these prices can also be deleted because again,
730
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
731
+			$tkt_to_remove->delete_related_permanently('Price');
732
+			do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
733
+			// finally let's delete this ticket
734
+			// (which should not be blocked at this point b/c we've removed all our relationships)
735
+			$tkt_to_remove->delete_permanently();
736
+		}
737
+		return $saved_tickets;
738
+	}
739 739
 
740 740
 
741
-    /**
742
-     * @access  protected
743
-     * @param EE_Ticket      $ticket
744
-     * @param \EE_Datetime[] $saved_datetimes
745
-     * @param \EE_Datetime[] $added_datetimes
746
-     * @param \EE_Datetime[] $removed_datetimes
747
-     * @return EE_Ticket
748
-     * @throws EE_Error
749
-     */
750
-    protected function _update_ticket_datetimes(
751
-        EE_Ticket $ticket,
752
-        $saved_datetimes = array(),
753
-        $added_datetimes = array(),
754
-        $removed_datetimes = array()
755
-    ) {
756
-        // to start we have to add the ticket to all the datetimes its supposed to be with,
757
-        // and removing the ticket from datetimes it got removed from.
758
-        // first let's add datetimes
759
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
760
-            foreach ($added_datetimes as $row_id) {
761
-                $row_id = (int) $row_id;
762
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
763
-                    $ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
764
-                    // Is this an existing ticket (has an ID) and does it have any sold?
765
-                    // If so, then we need to add that to the DTT sold because this DTT is getting added.
766
-                    if ($ticket->ID() && $ticket->sold() > 0) {
767
-                        $saved_datetimes[ $row_id ]->increase_sold($ticket->sold());
768
-                        $saved_datetimes[ $row_id ]->save();
769
-                    }
770
-                }
771
-            }
772
-        }
773
-        // then remove datetimes
774
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
775
-            foreach ($removed_datetimes as $row_id) {
776
-                $row_id = (int) $row_id;
777
-                // its entirely possible that a datetime got deleted (instead of just removed from relationship.
778
-                // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
779
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
780
-                    $ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
781
-                    // Is this an existing ticket (has an ID) and does it have any sold?
782
-                    // If so, then we need to remove it's sold from the DTT_sold.
783
-                    if ($ticket->ID() && $ticket->sold() > 0) {
784
-                        $saved_datetimes[ $row_id ]->decrease_sold($ticket->sold());
785
-                        $saved_datetimes[ $row_id ]->save();
786
-                    }
787
-                }
788
-            }
789
-        }
790
-        // cap ticket qty by datetime reg limits
791
-        $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
792
-        return $ticket;
793
-    }
741
+	/**
742
+	 * @access  protected
743
+	 * @param EE_Ticket      $ticket
744
+	 * @param \EE_Datetime[] $saved_datetimes
745
+	 * @param \EE_Datetime[] $added_datetimes
746
+	 * @param \EE_Datetime[] $removed_datetimes
747
+	 * @return EE_Ticket
748
+	 * @throws EE_Error
749
+	 */
750
+	protected function _update_ticket_datetimes(
751
+		EE_Ticket $ticket,
752
+		$saved_datetimes = array(),
753
+		$added_datetimes = array(),
754
+		$removed_datetimes = array()
755
+	) {
756
+		// to start we have to add the ticket to all the datetimes its supposed to be with,
757
+		// and removing the ticket from datetimes it got removed from.
758
+		// first let's add datetimes
759
+		if (! empty($added_datetimes) && is_array($added_datetimes)) {
760
+			foreach ($added_datetimes as $row_id) {
761
+				$row_id = (int) $row_id;
762
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
763
+					$ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
764
+					// Is this an existing ticket (has an ID) and does it have any sold?
765
+					// If so, then we need to add that to the DTT sold because this DTT is getting added.
766
+					if ($ticket->ID() && $ticket->sold() > 0) {
767
+						$saved_datetimes[ $row_id ]->increase_sold($ticket->sold());
768
+						$saved_datetimes[ $row_id ]->save();
769
+					}
770
+				}
771
+			}
772
+		}
773
+		// then remove datetimes
774
+		if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
775
+			foreach ($removed_datetimes as $row_id) {
776
+				$row_id = (int) $row_id;
777
+				// its entirely possible that a datetime got deleted (instead of just removed from relationship.
778
+				// So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
779
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
780
+					$ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
781
+					// Is this an existing ticket (has an ID) and does it have any sold?
782
+					// If so, then we need to remove it's sold from the DTT_sold.
783
+					if ($ticket->ID() && $ticket->sold() > 0) {
784
+						$saved_datetimes[ $row_id ]->decrease_sold($ticket->sold());
785
+						$saved_datetimes[ $row_id ]->save();
786
+					}
787
+				}
788
+			}
789
+		}
790
+		// cap ticket qty by datetime reg limits
791
+		$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
792
+		return $ticket;
793
+	}
794 794
 
795 795
 
796
-    /**
797
-     * @access  protected
798
-     * @param EE_Ticket $ticket
799
-     * @param array     $price_rows
800
-     * @param int       $ticket_price
801
-     * @param int       $base_price
802
-     * @param int       $base_price_id
803
-     * @return EE_Ticket
804
-     * @throws ReflectionException
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidInterfaceException
807
-     * @throws InvalidDataTypeException
808
-     * @throws EE_Error
809
-     */
810
-    protected function _duplicate_ticket(
811
-        EE_Ticket $ticket,
812
-        $price_rows = array(),
813
-        $ticket_price = 0,
814
-        $base_price = 0,
815
-        $base_price_id = 0
816
-    ) {
817
-        // create new ticket that's a copy of the existing
818
-        // except a new id of course (and not archived)
819
-        // AND has the new TKT_price associated with it.
820
-        $new_ticket = clone $ticket;
821
-        $new_ticket->set('TKT_ID', 0);
822
-        $new_ticket->set_deleted(0);
823
-        $new_ticket->set_price($ticket_price);
824
-        $new_ticket->set_sold(0);
825
-        // let's get a new ID for this ticket
826
-        $new_ticket->save();
827
-        // we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
828
-        $datetimes_on_existing = $ticket->datetimes();
829
-        $new_ticket            = $this->_update_ticket_datetimes(
830
-            $new_ticket,
831
-            $datetimes_on_existing,
832
-            array_keys($datetimes_on_existing)
833
-        );
834
-        // $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
835
-        // if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
836
-        // available.
837
-        if ($ticket->sold() > 0) {
838
-            $new_qty = $ticket->qty() - $ticket->sold();
839
-            $new_ticket->set_qty($new_qty);
840
-        }
841
-        //now we update the prices just for this ticket
842
-        $new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
843
-        //and we update the base price
844
-        $new_ticket = $this->_add_prices_to_ticket(
845
-            array(),
846
-            $new_ticket,
847
-            true,
848
-            $base_price,
849
-            $base_price_id
850
-        );
851
-        return $new_ticket;
852
-    }
796
+	/**
797
+	 * @access  protected
798
+	 * @param EE_Ticket $ticket
799
+	 * @param array     $price_rows
800
+	 * @param int       $ticket_price
801
+	 * @param int       $base_price
802
+	 * @param int       $base_price_id
803
+	 * @return EE_Ticket
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws EE_Error
809
+	 */
810
+	protected function _duplicate_ticket(
811
+		EE_Ticket $ticket,
812
+		$price_rows = array(),
813
+		$ticket_price = 0,
814
+		$base_price = 0,
815
+		$base_price_id = 0
816
+	) {
817
+		// create new ticket that's a copy of the existing
818
+		// except a new id of course (and not archived)
819
+		// AND has the new TKT_price associated with it.
820
+		$new_ticket = clone $ticket;
821
+		$new_ticket->set('TKT_ID', 0);
822
+		$new_ticket->set_deleted(0);
823
+		$new_ticket->set_price($ticket_price);
824
+		$new_ticket->set_sold(0);
825
+		// let's get a new ID for this ticket
826
+		$new_ticket->save();
827
+		// we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
828
+		$datetimes_on_existing = $ticket->datetimes();
829
+		$new_ticket            = $this->_update_ticket_datetimes(
830
+			$new_ticket,
831
+			$datetimes_on_existing,
832
+			array_keys($datetimes_on_existing)
833
+		);
834
+		// $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
835
+		// if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
836
+		// available.
837
+		if ($ticket->sold() > 0) {
838
+			$new_qty = $ticket->qty() - $ticket->sold();
839
+			$new_ticket->set_qty($new_qty);
840
+		}
841
+		//now we update the prices just for this ticket
842
+		$new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
843
+		//and we update the base price
844
+		$new_ticket = $this->_add_prices_to_ticket(
845
+			array(),
846
+			$new_ticket,
847
+			true,
848
+			$base_price,
849
+			$base_price_id
850
+		);
851
+		return $new_ticket;
852
+	}
853 853
 
854 854
 
855
-    /**
856
-     * This attaches a list of given prices to a ticket.
857
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
858
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
859
-     * price info and prices are automatically "archived" via the ticket.
860
-     *
861
-     * @access  private
862
-     * @param array     $prices        Array of prices from the form.
863
-     * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
864
-     * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
865
-     * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
866
-     * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
867
-     * @return EE_Ticket
868
-     * @throws ReflectionException
869
-     * @throws InvalidArgumentException
870
-     * @throws InvalidInterfaceException
871
-     * @throws InvalidDataTypeException
872
-     * @throws EE_Error
873
-     */
874
-    protected function _add_prices_to_ticket(
875
-        $prices = array(),
876
-        EE_Ticket $ticket,
877
-        $new_prices = false,
878
-        $base_price = false,
879
-        $base_price_id = false
880
-    ) {
881
-        // let's just get any current prices that may exist on the given ticket
882
-        // so we can remove any prices that got trashed in this session.
883
-        $current_prices_on_ticket = $base_price !== false
884
-            ? $ticket->base_price(true)
885
-            : $ticket->price_modifiers();
886
-        $updated_prices           = array();
887
-        // if $base_price ! FALSE then updating a base price.
888
-        if ($base_price !== false) {
889
-            $prices[1] = array(
890
-                'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
891
-                'PRT_ID'     => 1,
892
-                'PRC_amount' => $base_price,
893
-                'PRC_name'   => $ticket->get('TKT_name'),
894
-                'PRC_desc'   => $ticket->get('TKT_description'),
895
-            );
896
-        }
897
-        //possibly need to save tkt
898
-        if (! $ticket->ID()) {
899
-            $ticket->save();
900
-        }
901
-        foreach ($prices as $row => $prc) {
902
-            $prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
903
-            if (empty($prt_id)) {
904
-                continue;
905
-            } //prices MUST have a price type id.
906
-            $PRC_values = array(
907
-                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
908
-                'PRT_ID'         => $prt_id,
909
-                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
910
-                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
911
-                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
912
-                'PRC_is_default' => false,
913
-                //make sure we set PRC_is_default to false for all ticket saves from event_editor
914
-                'PRC_order'      => $row,
915
-            );
916
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
917
-                $PRC_values['PRC_ID'] = 0;
918
-                $price                = EE_Registry::instance()->load_class(
919
-                    'Price',
920
-                    array($PRC_values),
921
-                    false,
922
-                    false
923
-                );
924
-            } else {
925
-                $price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
926
-                //update this price with new values
927
-                foreach ($PRC_values as $field => $value) {
928
-                    $price->set($field, $value);
929
-                }
930
-            }
931
-            $price->save();
932
-            $updated_prices[ $price->ID() ] = $price;
933
-            $ticket->_add_relation_to($price, 'Price');
934
-        }
935
-        //now let's remove any prices that got removed from the ticket
936
-        if (! empty ($current_prices_on_ticket)) {
937
-            $current          = array_keys($current_prices_on_ticket);
938
-            $updated          = array_keys($updated_prices);
939
-            $prices_to_remove = array_diff($current, $updated);
940
-            if (! empty($prices_to_remove)) {
941
-                foreach ($prices_to_remove as $prc_id) {
942
-                    $p = $current_prices_on_ticket[ $prc_id ];
943
-                    $ticket->_remove_relation_to($p, 'Price');
944
-                    //delete permanently the price
945
-                    $p->delete_permanently();
946
-                }
947
-            }
948
-        }
949
-        return $ticket;
950
-    }
855
+	/**
856
+	 * This attaches a list of given prices to a ticket.
857
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
858
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
859
+	 * price info and prices are automatically "archived" via the ticket.
860
+	 *
861
+	 * @access  private
862
+	 * @param array     $prices        Array of prices from the form.
863
+	 * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
864
+	 * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
865
+	 * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
866
+	 * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
867
+	 * @return EE_Ticket
868
+	 * @throws ReflectionException
869
+	 * @throws InvalidArgumentException
870
+	 * @throws InvalidInterfaceException
871
+	 * @throws InvalidDataTypeException
872
+	 * @throws EE_Error
873
+	 */
874
+	protected function _add_prices_to_ticket(
875
+		$prices = array(),
876
+		EE_Ticket $ticket,
877
+		$new_prices = false,
878
+		$base_price = false,
879
+		$base_price_id = false
880
+	) {
881
+		// let's just get any current prices that may exist on the given ticket
882
+		// so we can remove any prices that got trashed in this session.
883
+		$current_prices_on_ticket = $base_price !== false
884
+			? $ticket->base_price(true)
885
+			: $ticket->price_modifiers();
886
+		$updated_prices           = array();
887
+		// if $base_price ! FALSE then updating a base price.
888
+		if ($base_price !== false) {
889
+			$prices[1] = array(
890
+				'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
891
+				'PRT_ID'     => 1,
892
+				'PRC_amount' => $base_price,
893
+				'PRC_name'   => $ticket->get('TKT_name'),
894
+				'PRC_desc'   => $ticket->get('TKT_description'),
895
+			);
896
+		}
897
+		//possibly need to save tkt
898
+		if (! $ticket->ID()) {
899
+			$ticket->save();
900
+		}
901
+		foreach ($prices as $row => $prc) {
902
+			$prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
903
+			if (empty($prt_id)) {
904
+				continue;
905
+			} //prices MUST have a price type id.
906
+			$PRC_values = array(
907
+				'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
908
+				'PRT_ID'         => $prt_id,
909
+				'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
910
+				'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
911
+				'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
912
+				'PRC_is_default' => false,
913
+				//make sure we set PRC_is_default to false for all ticket saves from event_editor
914
+				'PRC_order'      => $row,
915
+			);
916
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
917
+				$PRC_values['PRC_ID'] = 0;
918
+				$price                = EE_Registry::instance()->load_class(
919
+					'Price',
920
+					array($PRC_values),
921
+					false,
922
+					false
923
+				);
924
+			} else {
925
+				$price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
926
+				//update this price with new values
927
+				foreach ($PRC_values as $field => $value) {
928
+					$price->set($field, $value);
929
+				}
930
+			}
931
+			$price->save();
932
+			$updated_prices[ $price->ID() ] = $price;
933
+			$ticket->_add_relation_to($price, 'Price');
934
+		}
935
+		//now let's remove any prices that got removed from the ticket
936
+		if (! empty ($current_prices_on_ticket)) {
937
+			$current          = array_keys($current_prices_on_ticket);
938
+			$updated          = array_keys($updated_prices);
939
+			$prices_to_remove = array_diff($current, $updated);
940
+			if (! empty($prices_to_remove)) {
941
+				foreach ($prices_to_remove as $prc_id) {
942
+					$p = $current_prices_on_ticket[ $prc_id ];
943
+					$ticket->_remove_relation_to($p, 'Price');
944
+					//delete permanently the price
945
+					$p->delete_permanently();
946
+				}
947
+			}
948
+		}
949
+		return $ticket;
950
+	}
951 951
 
952 952
 
953
-    /**
954
-     * @param Events_Admin_Page $event_admin_obj
955
-     * @return Events_Admin_Page
956
-     */
957
-    public function autosave_handling(Events_Admin_Page $event_admin_obj)
958
-    {
959
-        return $event_admin_obj;
960
-        //doing nothing for the moment.
961
-        // todo when I get to this remember that I need to set the template args on the $event_admin_obj
962
-        // (use the set_template_args() method)
963
-        /**
964
-         * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
965
-         * 1. TKT_is_default_selector (visible)
966
-         * 2. TKT_is_default (hidden)
967
-         * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
968
-         * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
969
-         * this ticket to be saved as a default.
970
-         * The tricky part is, on an initial display on create or edit (or after manually updating),
971
-         * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
972
-         * if this is a create.  However, after an autosave, users will want some sort of indicator that
973
-         * the TKT HAS been saved as a default..
974
-         * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
975
-         * On Autosave:
976
-         * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
977
-         * then set the TKT_is_default to false.
978
-         * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
979
-         *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
980
-         * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
981
-         */
982
-    }
953
+	/**
954
+	 * @param Events_Admin_Page $event_admin_obj
955
+	 * @return Events_Admin_Page
956
+	 */
957
+	public function autosave_handling(Events_Admin_Page $event_admin_obj)
958
+	{
959
+		return $event_admin_obj;
960
+		//doing nothing for the moment.
961
+		// todo when I get to this remember that I need to set the template args on the $event_admin_obj
962
+		// (use the set_template_args() method)
963
+		/**
964
+		 * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
965
+		 * 1. TKT_is_default_selector (visible)
966
+		 * 2. TKT_is_default (hidden)
967
+		 * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
968
+		 * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
969
+		 * this ticket to be saved as a default.
970
+		 * The tricky part is, on an initial display on create or edit (or after manually updating),
971
+		 * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
972
+		 * if this is a create.  However, after an autosave, users will want some sort of indicator that
973
+		 * the TKT HAS been saved as a default..
974
+		 * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
975
+		 * On Autosave:
976
+		 * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
977
+		 * then set the TKT_is_default to false.
978
+		 * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
979
+		 *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
980
+		 * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
981
+		 */
982
+	}
983 983
 
984 984
 
985
-    /**
986
-     * @throws ReflectionException
987
-     * @throws InvalidArgumentException
988
-     * @throws InvalidInterfaceException
989
-     * @throws InvalidDataTypeException
990
-     * @throws DomainException
991
-     * @throws EE_Error
992
-     */
993
-    public function pricing_metabox()
994
-    {
995
-        $existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
996
-        $event                 = $this->_adminpage_obj->get_cpt_model_obj();
997
-        //set is_creating_event property.
998
-        $EVT_ID                   = $event->ID();
999
-        $this->_is_creating_event = absint($EVT_ID) === 0;
1000
-        //default main template args
1001
-        $main_template_args = array(
1002
-            'event_datetime_help_link' => EEH_Template::get_help_tab_link(
1003
-                'event_editor_event_datetimes_help_tab',
1004
-                $this->_adminpage_obj->page_slug,
1005
-                $this->_adminpage_obj->get_req_action(),
1006
-                false,
1007
-                false
1008
-            ),
1009
-            // todo need to add a filter to the template for the help text
1010
-            // in the Events_Admin_Page core file so we can add further help
1011
-            'existing_datetime_ids'    => '',
1012
-            'total_dtt_rows'           => 1,
1013
-            'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
1014
-                'add_new_dtt_info',
1015
-                $this->_adminpage_obj->page_slug,
1016
-                $this->_adminpage_obj->get_req_action(),
1017
-                false,
1018
-                false
1019
-            ),
1020
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1021
-            'datetime_rows'            => '',
1022
-            'show_tickets_container'   => '',
1023
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
1024
-            'ticket_rows'              => '',
1025
-            'existing_ticket_ids'      => '',
1026
-            'total_ticket_rows'        => 1,
1027
-            'ticket_js_structure'      => '',
1028
-            'ee_collapsible_status'    => ' ee-collapsible-open'
1029
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1030
-        );
1031
-        $timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
1032
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1033
-        /**
1034
-         * 1. Start with retrieving Datetimes
1035
-         * 2. For each datetime get related tickets
1036
-         * 3. For each ticket get related prices
1037
-         */
1038
-        /** @var EEM_Datetime $datetime_model */
1039
-        $datetime_model                       = EE_Registry::instance()->load_model('Datetime', array($timezone));
1040
-        $datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
1041
-        $main_template_args['total_dtt_rows'] = count($datetimes);
1042
-        /**
1043
-         * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
1044
-         * for why we are counting $datetime_row and then setting that on the Datetime object
1045
-         */
1046
-        $datetime_row = 1;
1047
-        foreach ($datetimes as $datetime) {
1048
-            $DTT_ID = $datetime->get('DTT_ID');
1049
-            $datetime->set('DTT_order', $datetime_row);
1050
-            $existing_datetime_ids[] = $DTT_ID;
1051
-            //tickets attached
1052
-            $related_tickets = $datetime->ID() > 0
1053
-                ? $datetime->get_many_related(
1054
-                    'Ticket',
1055
-                    array(
1056
-                        array(
1057
-                            'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1058
-                        ),
1059
-                        'default_where_conditions' => 'none',
1060
-                        'order_by'                 => array('TKT_order' => 'ASC'),
1061
-                    )
1062
-                )
1063
-                : array();
1064
-            //if there are no related tickets this is likely a new event OR autodraft
1065
-            // event so we need to generate the default tickets because datetimes
1066
-            // ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1067
-            // datetime on the event.
1068
-            if (empty ($related_tickets) && count($datetimes) < 2) {
1069
-                /** @var EEM_Ticket $ticket_model */
1070
-                $ticket_model    = EE_Registry::instance()->load_model('Ticket');
1071
-                $related_tickets = $ticket_model->get_all_default_tickets();
1072
-                // this should be ordered by TKT_ID, so let's grab the first default ticket
1073
-                // (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1074
-                $default_prices      = EEM_Price::instance()->get_all_default_prices();
1075
-                $main_default_ticket = reset($related_tickets);
1076
-                if ($main_default_ticket instanceof EE_Ticket) {
1077
-                    foreach ($default_prices as $default_price) {
1078
-                        if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1079
-                            continue;
1080
-                        }
1081
-                        $main_default_ticket->cache('Price', $default_price);
1082
-                    }
1083
-                }
1084
-            }
1085
-            // we can't actually setup rows in this loop yet cause we don't know all
1086
-            // the unique tickets for this event yet (tickets are linked through all datetimes).
1087
-            // So we're going to temporarily cache some of that information.
1088
-            //loop through and setup the ticket rows and make sure the order is set.
1089
-            foreach ($related_tickets as $ticket) {
1090
-                $TKT_ID     = $ticket->get('TKT_ID');
1091
-                $ticket_row = $ticket->get('TKT_row');
1092
-                //we only want unique tickets in our final display!!
1093
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1094
-                    $existing_ticket_ids[] = $TKT_ID;
1095
-                    $all_tickets[]         = $ticket;
1096
-                }
1097
-                //temporary cache of this ticket info for this datetime for later processing of datetime rows.
1098
-                $datetime_tickets[ $DTT_ID ][] = $ticket_row;
1099
-                //temporary cache of this datetime info for this ticket for later processing of ticket rows.
1100
-                if (
1101
-                    ! isset($ticket_datetimes[ $TKT_ID ])
1102
-                    || ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1103
-                ) {
1104
-                    $ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1105
-                }
1106
-            }
1107
-            $datetime_row++;
1108
-        }
1109
-        $main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1110
-        $main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1111
-        $main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1112
-        //sort $all_tickets by order
1113
-        usort(
1114
-            $all_tickets,
1115
-            function (EE_Ticket $a, EE_Ticket $b)
1116
-            {
1117
-                $a_order = (int) $a->get('TKT_order');
1118
-                $b_order = (int) $b->get('TKT_order');
1119
-                if ($a_order === $b_order) {
1120
-                    return 0;
1121
-                }
1122
-                return ($a_order < $b_order) ? -1 : 1;
1123
-            }
1124
-        );
1125
-        // k NOW we have all the data we need for setting up the dtt rows
1126
-        // and ticket rows so we start our dtt loop again.
1127
-        $datetime_row = 1;
1128
-        foreach ($datetimes as $datetime) {
1129
-            $main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1130
-                $datetime_row,
1131
-                $datetime,
1132
-                $datetime_tickets,
1133
-                $all_tickets,
1134
-                false,
1135
-                $datetimes
1136
-            );
1137
-            $datetime_row++;
1138
-        }
1139
-        //then loop through all tickets for the ticket rows.
1140
-        $ticket_row = 1;
1141
-        foreach ($all_tickets as $ticket) {
1142
-            $main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1143
-                $ticket_row,
1144
-                $ticket,
1145
-                $ticket_datetimes,
1146
-                $datetimes,
1147
-                false,
1148
-                $all_tickets
1149
-            );
1150
-            $ticket_row++;
1151
-        }
1152
-        $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1153
-        EEH_Template::display_template(
1154
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1155
-            $main_template_args
1156
-        );
1157
-    }
985
+	/**
986
+	 * @throws ReflectionException
987
+	 * @throws InvalidArgumentException
988
+	 * @throws InvalidInterfaceException
989
+	 * @throws InvalidDataTypeException
990
+	 * @throws DomainException
991
+	 * @throws EE_Error
992
+	 */
993
+	public function pricing_metabox()
994
+	{
995
+		$existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
996
+		$event                 = $this->_adminpage_obj->get_cpt_model_obj();
997
+		//set is_creating_event property.
998
+		$EVT_ID                   = $event->ID();
999
+		$this->_is_creating_event = absint($EVT_ID) === 0;
1000
+		//default main template args
1001
+		$main_template_args = array(
1002
+			'event_datetime_help_link' => EEH_Template::get_help_tab_link(
1003
+				'event_editor_event_datetimes_help_tab',
1004
+				$this->_adminpage_obj->page_slug,
1005
+				$this->_adminpage_obj->get_req_action(),
1006
+				false,
1007
+				false
1008
+			),
1009
+			// todo need to add a filter to the template for the help text
1010
+			// in the Events_Admin_Page core file so we can add further help
1011
+			'existing_datetime_ids'    => '',
1012
+			'total_dtt_rows'           => 1,
1013
+			'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
1014
+				'add_new_dtt_info',
1015
+				$this->_adminpage_obj->page_slug,
1016
+				$this->_adminpage_obj->get_req_action(),
1017
+				false,
1018
+				false
1019
+			),
1020
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1021
+			'datetime_rows'            => '',
1022
+			'show_tickets_container'   => '',
1023
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
1024
+			'ticket_rows'              => '',
1025
+			'existing_ticket_ids'      => '',
1026
+			'total_ticket_rows'        => 1,
1027
+			'ticket_js_structure'      => '',
1028
+			'ee_collapsible_status'    => ' ee-collapsible-open'
1029
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1030
+		);
1031
+		$timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
1032
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1033
+		/**
1034
+		 * 1. Start with retrieving Datetimes
1035
+		 * 2. For each datetime get related tickets
1036
+		 * 3. For each ticket get related prices
1037
+		 */
1038
+		/** @var EEM_Datetime $datetime_model */
1039
+		$datetime_model                       = EE_Registry::instance()->load_model('Datetime', array($timezone));
1040
+		$datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
1041
+		$main_template_args['total_dtt_rows'] = count($datetimes);
1042
+		/**
1043
+		 * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
1044
+		 * for why we are counting $datetime_row and then setting that on the Datetime object
1045
+		 */
1046
+		$datetime_row = 1;
1047
+		foreach ($datetimes as $datetime) {
1048
+			$DTT_ID = $datetime->get('DTT_ID');
1049
+			$datetime->set('DTT_order', $datetime_row);
1050
+			$existing_datetime_ids[] = $DTT_ID;
1051
+			//tickets attached
1052
+			$related_tickets = $datetime->ID() > 0
1053
+				? $datetime->get_many_related(
1054
+					'Ticket',
1055
+					array(
1056
+						array(
1057
+							'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1058
+						),
1059
+						'default_where_conditions' => 'none',
1060
+						'order_by'                 => array('TKT_order' => 'ASC'),
1061
+					)
1062
+				)
1063
+				: array();
1064
+			//if there are no related tickets this is likely a new event OR autodraft
1065
+			// event so we need to generate the default tickets because datetimes
1066
+			// ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1067
+			// datetime on the event.
1068
+			if (empty ($related_tickets) && count($datetimes) < 2) {
1069
+				/** @var EEM_Ticket $ticket_model */
1070
+				$ticket_model    = EE_Registry::instance()->load_model('Ticket');
1071
+				$related_tickets = $ticket_model->get_all_default_tickets();
1072
+				// this should be ordered by TKT_ID, so let's grab the first default ticket
1073
+				// (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1074
+				$default_prices      = EEM_Price::instance()->get_all_default_prices();
1075
+				$main_default_ticket = reset($related_tickets);
1076
+				if ($main_default_ticket instanceof EE_Ticket) {
1077
+					foreach ($default_prices as $default_price) {
1078
+						if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1079
+							continue;
1080
+						}
1081
+						$main_default_ticket->cache('Price', $default_price);
1082
+					}
1083
+				}
1084
+			}
1085
+			// we can't actually setup rows in this loop yet cause we don't know all
1086
+			// the unique tickets for this event yet (tickets are linked through all datetimes).
1087
+			// So we're going to temporarily cache some of that information.
1088
+			//loop through and setup the ticket rows and make sure the order is set.
1089
+			foreach ($related_tickets as $ticket) {
1090
+				$TKT_ID     = $ticket->get('TKT_ID');
1091
+				$ticket_row = $ticket->get('TKT_row');
1092
+				//we only want unique tickets in our final display!!
1093
+				if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1094
+					$existing_ticket_ids[] = $TKT_ID;
1095
+					$all_tickets[]         = $ticket;
1096
+				}
1097
+				//temporary cache of this ticket info for this datetime for later processing of datetime rows.
1098
+				$datetime_tickets[ $DTT_ID ][] = $ticket_row;
1099
+				//temporary cache of this datetime info for this ticket for later processing of ticket rows.
1100
+				if (
1101
+					! isset($ticket_datetimes[ $TKT_ID ])
1102
+					|| ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1103
+				) {
1104
+					$ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1105
+				}
1106
+			}
1107
+			$datetime_row++;
1108
+		}
1109
+		$main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1110
+		$main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1111
+		$main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1112
+		//sort $all_tickets by order
1113
+		usort(
1114
+			$all_tickets,
1115
+			function (EE_Ticket $a, EE_Ticket $b)
1116
+			{
1117
+				$a_order = (int) $a->get('TKT_order');
1118
+				$b_order = (int) $b->get('TKT_order');
1119
+				if ($a_order === $b_order) {
1120
+					return 0;
1121
+				}
1122
+				return ($a_order < $b_order) ? -1 : 1;
1123
+			}
1124
+		);
1125
+		// k NOW we have all the data we need for setting up the dtt rows
1126
+		// and ticket rows so we start our dtt loop again.
1127
+		$datetime_row = 1;
1128
+		foreach ($datetimes as $datetime) {
1129
+			$main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1130
+				$datetime_row,
1131
+				$datetime,
1132
+				$datetime_tickets,
1133
+				$all_tickets,
1134
+				false,
1135
+				$datetimes
1136
+			);
1137
+			$datetime_row++;
1138
+		}
1139
+		//then loop through all tickets for the ticket rows.
1140
+		$ticket_row = 1;
1141
+		foreach ($all_tickets as $ticket) {
1142
+			$main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1143
+				$ticket_row,
1144
+				$ticket,
1145
+				$ticket_datetimes,
1146
+				$datetimes,
1147
+				false,
1148
+				$all_tickets
1149
+			);
1150
+			$ticket_row++;
1151
+		}
1152
+		$main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1153
+		EEH_Template::display_template(
1154
+			PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1155
+			$main_template_args
1156
+		);
1157
+	}
1158 1158
 
1159 1159
 
1160
-    /**
1161
-     * @param int         $datetime_row
1162
-     * @param EE_Datetime $datetime
1163
-     * @param array       $datetime_tickets
1164
-     * @param array       $all_tickets
1165
-     * @param bool        $default
1166
-     * @param array       $all_datetimes
1167
-     * @return mixed
1168
-     * @throws DomainException
1169
-     * @throws EE_Error
1170
-     */
1171
-    protected function _get_datetime_row(
1172
-        $datetime_row,
1173
-        EE_Datetime $datetime,
1174
-        $datetime_tickets = array(),
1175
-        $all_tickets = array(),
1176
-        $default = false,
1177
-        $all_datetimes = array()
1178
-    ) {
1179
-        $dtt_display_template_args = array(
1180
-            'dtt_edit_row'             => $this->_get_dtt_edit_row(
1181
-                $datetime_row,
1182
-                $datetime,
1183
-                $default,
1184
-                $all_datetimes
1185
-            ),
1186
-            'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1187
-                $datetime_row,
1188
-                $datetime,
1189
-                $datetime_tickets,
1190
-                $all_tickets,
1191
-                $default
1192
-            ),
1193
-            'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1194
-        );
1195
-        return EEH_Template::display_template(
1196
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1197
-            $dtt_display_template_args,
1198
-            true
1199
-        );
1200
-    }
1160
+	/**
1161
+	 * @param int         $datetime_row
1162
+	 * @param EE_Datetime $datetime
1163
+	 * @param array       $datetime_tickets
1164
+	 * @param array       $all_tickets
1165
+	 * @param bool        $default
1166
+	 * @param array       $all_datetimes
1167
+	 * @return mixed
1168
+	 * @throws DomainException
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	protected function _get_datetime_row(
1172
+		$datetime_row,
1173
+		EE_Datetime $datetime,
1174
+		$datetime_tickets = array(),
1175
+		$all_tickets = array(),
1176
+		$default = false,
1177
+		$all_datetimes = array()
1178
+	) {
1179
+		$dtt_display_template_args = array(
1180
+			'dtt_edit_row'             => $this->_get_dtt_edit_row(
1181
+				$datetime_row,
1182
+				$datetime,
1183
+				$default,
1184
+				$all_datetimes
1185
+			),
1186
+			'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1187
+				$datetime_row,
1188
+				$datetime,
1189
+				$datetime_tickets,
1190
+				$all_tickets,
1191
+				$default
1192
+			),
1193
+			'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1194
+		);
1195
+		return EEH_Template::display_template(
1196
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1197
+			$dtt_display_template_args,
1198
+			true
1199
+		);
1200
+	}
1201 1201
 
1202 1202
 
1203
-    /**
1204
-     * This method is used to generate a dtt fields  edit row.
1205
-     * The same row is used to generate a row with valid DTT objects
1206
-     * and the default row that is used as the skeleton by the js.
1207
-     *
1208
-     * @param int           $datetime_row  The row number for the row being generated.
1209
-     * @param EE_Datetime   $datetime
1210
-     * @param bool          $default       Whether a default row is being generated or not.
1211
-     * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1212
-     * @return string
1213
-     * @throws DomainException
1214
-     * @throws EE_Error
1215
-     */
1216
-    protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1217
-    {
1218
-        // if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1219
-        $default                     = ! $datetime instanceof EE_Datetime ? true : $default;
1220
-        $template_args               = array(
1221
-            'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1222
-            'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1223
-            'edit_dtt_expanded'    => '',
1224
-            'DTT_ID'               => $default ? '' : $datetime->ID(),
1225
-            'DTT_name'             => $default ? '' : $datetime->get_f('DTT_name'),
1226
-            'DTT_description'      => $default ? '' : $datetime->get_f('DTT_description'),
1227
-            'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1228
-            'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1229
-            'DTT_reg_limit'        => $default
1230
-                ? ''
1231
-                : $datetime->get_pretty(
1232
-                    'DTT_reg_limit',
1233
-                    'input'
1234
-                ),
1235
-            'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1236
-            'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1237
-            'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1238
-            'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1239
-                ? ''
1240
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1241
-            'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1242
-                ? 'ee-lock-icon'
1243
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1244
-            'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1245
-                ? ''
1246
-                : EE_Admin_Page::add_query_args_and_nonce(
1247
-                    array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1248
-                    REG_ADMIN_URL
1249
-                ),
1250
-        );
1251
-        $template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1252
-            ? ' style="display:none"'
1253
-            : '';
1254
-        //allow filtering of template args at this point.
1255
-        $template_args = apply_filters(
1256
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1257
-            $template_args,
1258
-            $datetime_row,
1259
-            $datetime,
1260
-            $default,
1261
-            $all_datetimes,
1262
-            $this->_is_creating_event
1263
-        );
1264
-        return EEH_Template::display_template(
1265
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1266
-            $template_args,
1267
-            true
1268
-        );
1269
-    }
1203
+	/**
1204
+	 * This method is used to generate a dtt fields  edit row.
1205
+	 * The same row is used to generate a row with valid DTT objects
1206
+	 * and the default row that is used as the skeleton by the js.
1207
+	 *
1208
+	 * @param int           $datetime_row  The row number for the row being generated.
1209
+	 * @param EE_Datetime   $datetime
1210
+	 * @param bool          $default       Whether a default row is being generated or not.
1211
+	 * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1212
+	 * @return string
1213
+	 * @throws DomainException
1214
+	 * @throws EE_Error
1215
+	 */
1216
+	protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1217
+	{
1218
+		// if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1219
+		$default                     = ! $datetime instanceof EE_Datetime ? true : $default;
1220
+		$template_args               = array(
1221
+			'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1222
+			'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1223
+			'edit_dtt_expanded'    => '',
1224
+			'DTT_ID'               => $default ? '' : $datetime->ID(),
1225
+			'DTT_name'             => $default ? '' : $datetime->get_f('DTT_name'),
1226
+			'DTT_description'      => $default ? '' : $datetime->get_f('DTT_description'),
1227
+			'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1228
+			'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1229
+			'DTT_reg_limit'        => $default
1230
+				? ''
1231
+				: $datetime->get_pretty(
1232
+					'DTT_reg_limit',
1233
+					'input'
1234
+				),
1235
+			'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1236
+			'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1237
+			'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1238
+			'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1239
+				? ''
1240
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1241
+			'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1242
+				? 'ee-lock-icon'
1243
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1244
+			'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1245
+				? ''
1246
+				: EE_Admin_Page::add_query_args_and_nonce(
1247
+					array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1248
+					REG_ADMIN_URL
1249
+				),
1250
+		);
1251
+		$template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1252
+			? ' style="display:none"'
1253
+			: '';
1254
+		//allow filtering of template args at this point.
1255
+		$template_args = apply_filters(
1256
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1257
+			$template_args,
1258
+			$datetime_row,
1259
+			$datetime,
1260
+			$default,
1261
+			$all_datetimes,
1262
+			$this->_is_creating_event
1263
+		);
1264
+		return EEH_Template::display_template(
1265
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1266
+			$template_args,
1267
+			true
1268
+		);
1269
+	}
1270 1270
 
1271 1271
 
1272
-    /**
1273
-     * @param int         $datetime_row
1274
-     * @param EE_Datetime $datetime
1275
-     * @param array       $datetime_tickets
1276
-     * @param array       $all_tickets
1277
-     * @param bool        $default
1278
-     * @return mixed
1279
-     * @throws DomainException
1280
-     * @throws EE_Error
1281
-     */
1282
-    protected function _get_dtt_attached_tickets_row(
1283
-        $datetime_row,
1284
-        $datetime,
1285
-        $datetime_tickets = array(),
1286
-        $all_tickets = array(),
1287
-        $default
1288
-    ) {
1289
-        $template_args = array(
1290
-            'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1291
-            'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1292
-            'DTT_description'                   => $default ? '' : $datetime->get_f('DTT_description'),
1293
-            'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1294
-            'show_tickets_row'                  => ' style="display:none;"',
1295
-            'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1296
-                'add_new_ticket_via_datetime',
1297
-                $this->_adminpage_obj->page_slug,
1298
-                $this->_adminpage_obj->get_req_action(),
1299
-                false,
1300
-                false
1301
-            ),
1302
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1303
-            'DTT_ID'                            => $default ? '' : $datetime->ID(),
1304
-        );
1305
-        //need to setup the list items (but only if this isn't a default skeleton setup)
1306
-        if (! $default) {
1307
-            $ticket_row = 1;
1308
-            foreach ($all_tickets as $ticket) {
1309
-                $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1310
-                    $datetime_row,
1311
-                    $ticket_row,
1312
-                    $datetime,
1313
-                    $ticket,
1314
-                    $datetime_tickets,
1315
-                    $default
1316
-                );
1317
-                $ticket_row++;
1318
-            }
1319
-        }
1320
-        //filter template args at this point
1321
-        $template_args = apply_filters(
1322
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1323
-            $template_args,
1324
-            $datetime_row,
1325
-            $datetime,
1326
-            $datetime_tickets,
1327
-            $all_tickets,
1328
-            $default,
1329
-            $this->_is_creating_event
1330
-        );
1331
-        return EEH_Template::display_template(
1332
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1333
-            $template_args,
1334
-            true
1335
-        );
1336
-    }
1272
+	/**
1273
+	 * @param int         $datetime_row
1274
+	 * @param EE_Datetime $datetime
1275
+	 * @param array       $datetime_tickets
1276
+	 * @param array       $all_tickets
1277
+	 * @param bool        $default
1278
+	 * @return mixed
1279
+	 * @throws DomainException
1280
+	 * @throws EE_Error
1281
+	 */
1282
+	protected function _get_dtt_attached_tickets_row(
1283
+		$datetime_row,
1284
+		$datetime,
1285
+		$datetime_tickets = array(),
1286
+		$all_tickets = array(),
1287
+		$default
1288
+	) {
1289
+		$template_args = array(
1290
+			'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1291
+			'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1292
+			'DTT_description'                   => $default ? '' : $datetime->get_f('DTT_description'),
1293
+			'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1294
+			'show_tickets_row'                  => ' style="display:none;"',
1295
+			'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1296
+				'add_new_ticket_via_datetime',
1297
+				$this->_adminpage_obj->page_slug,
1298
+				$this->_adminpage_obj->get_req_action(),
1299
+				false,
1300
+				false
1301
+			),
1302
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1303
+			'DTT_ID'                            => $default ? '' : $datetime->ID(),
1304
+		);
1305
+		//need to setup the list items (but only if this isn't a default skeleton setup)
1306
+		if (! $default) {
1307
+			$ticket_row = 1;
1308
+			foreach ($all_tickets as $ticket) {
1309
+				$template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1310
+					$datetime_row,
1311
+					$ticket_row,
1312
+					$datetime,
1313
+					$ticket,
1314
+					$datetime_tickets,
1315
+					$default
1316
+				);
1317
+				$ticket_row++;
1318
+			}
1319
+		}
1320
+		//filter template args at this point
1321
+		$template_args = apply_filters(
1322
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1323
+			$template_args,
1324
+			$datetime_row,
1325
+			$datetime,
1326
+			$datetime_tickets,
1327
+			$all_tickets,
1328
+			$default,
1329
+			$this->_is_creating_event
1330
+		);
1331
+		return EEH_Template::display_template(
1332
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1333
+			$template_args,
1334
+			true
1335
+		);
1336
+	}
1337 1337
 
1338 1338
 
1339
-    /**
1340
-     * @param int         $datetime_row
1341
-     * @param int         $ticket_row
1342
-     * @param EE_Datetime $datetime
1343
-     * @param EE_Ticket   $ticket
1344
-     * @param array       $datetime_tickets
1345
-     * @param bool        $default
1346
-     * @return mixed
1347
-     * @throws DomainException
1348
-     * @throws EE_Error
1349
-     */
1350
-    protected function _get_datetime_tickets_list_item(
1351
-        $datetime_row,
1352
-        $ticket_row,
1353
-        $datetime,
1354
-        $ticket,
1355
-        $datetime_tickets = array(),
1356
-        $default
1357
-    ) {
1358
-        $dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1359
-            ? $datetime_tickets[ $datetime->ID() ]
1360
-            : array();
1361
-        $display_row   = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1362
-        $no_ticket     = $default && empty($ticket);
1363
-        $template_args = array(
1364
-            'dtt_row'                 => $default
1365
-                ? 'DTTNUM'
1366
-                : $datetime_row,
1367
-            'tkt_row'                 => $no_ticket
1368
-                ? 'TICKETNUM'
1369
-                : $ticket_row,
1370
-            'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1371
-                ? ' checked="checked"'
1372
-                : '',
1373
-            'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1374
-                ? ' ticket-selected'
1375
-                : '',
1376
-            'TKT_name'                => $no_ticket
1377
-                ? 'TKTNAME'
1378
-                : $ticket->get('TKT_name'),
1379
-            'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1380
-                ? ' tkt-status-' . EE_Ticket::onsale
1381
-                : ' tkt-status-' . $ticket->ticket_status(),
1382
-        );
1383
-        //filter template args
1384
-        $template_args = apply_filters(
1385
-            'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1386
-            $template_args,
1387
-            $datetime_row,
1388
-            $ticket_row,
1389
-            $datetime,
1390
-            $ticket,
1391
-            $datetime_tickets,
1392
-            $default,
1393
-            $this->_is_creating_event
1394
-        );
1395
-        return EEH_Template::display_template(
1396
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1397
-            $template_args,
1398
-            true
1399
-        );
1400
-    }
1339
+	/**
1340
+	 * @param int         $datetime_row
1341
+	 * @param int         $ticket_row
1342
+	 * @param EE_Datetime $datetime
1343
+	 * @param EE_Ticket   $ticket
1344
+	 * @param array       $datetime_tickets
1345
+	 * @param bool        $default
1346
+	 * @return mixed
1347
+	 * @throws DomainException
1348
+	 * @throws EE_Error
1349
+	 */
1350
+	protected function _get_datetime_tickets_list_item(
1351
+		$datetime_row,
1352
+		$ticket_row,
1353
+		$datetime,
1354
+		$ticket,
1355
+		$datetime_tickets = array(),
1356
+		$default
1357
+	) {
1358
+		$dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1359
+			? $datetime_tickets[ $datetime->ID() ]
1360
+			: array();
1361
+		$display_row   = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1362
+		$no_ticket     = $default && empty($ticket);
1363
+		$template_args = array(
1364
+			'dtt_row'                 => $default
1365
+				? 'DTTNUM'
1366
+				: $datetime_row,
1367
+			'tkt_row'                 => $no_ticket
1368
+				? 'TICKETNUM'
1369
+				: $ticket_row,
1370
+			'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1371
+				? ' checked="checked"'
1372
+				: '',
1373
+			'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1374
+				? ' ticket-selected'
1375
+				: '',
1376
+			'TKT_name'                => $no_ticket
1377
+				? 'TKTNAME'
1378
+				: $ticket->get('TKT_name'),
1379
+			'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1380
+				? ' tkt-status-' . EE_Ticket::onsale
1381
+				: ' tkt-status-' . $ticket->ticket_status(),
1382
+		);
1383
+		//filter template args
1384
+		$template_args = apply_filters(
1385
+			'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1386
+			$template_args,
1387
+			$datetime_row,
1388
+			$ticket_row,
1389
+			$datetime,
1390
+			$ticket,
1391
+			$datetime_tickets,
1392
+			$default,
1393
+			$this->_is_creating_event
1394
+		);
1395
+		return EEH_Template::display_template(
1396
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1397
+			$template_args,
1398
+			true
1399
+		);
1400
+	}
1401 1401
 
1402 1402
 
1403
-    /**
1404
-     * This generates the ticket row for tickets.
1405
-     * This same method is used to generate both the actual rows and the js skeleton row
1406
-     * (when default === true)
1407
-     *
1408
-     * @param int           $ticket_row       Represents the row number being generated.
1409
-     * @param               $ticket
1410
-     * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1411
-     *                                        or empty for default
1412
-     * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1413
-     * @param bool          $default          Whether default row being generated or not.
1414
-     * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1415
-     *                                        (or empty in the case of defaults)
1416
-     * @return mixed
1417
-     * @throws InvalidArgumentException
1418
-     * @throws InvalidInterfaceException
1419
-     * @throws InvalidDataTypeException
1420
-     * @throws DomainException
1421
-     * @throws EE_Error
1422
-     * @throws ReflectionException
1423
-     */
1424
-    protected function _get_ticket_row(
1425
-        $ticket_row,
1426
-        $ticket,
1427
-        $ticket_datetimes,
1428
-        $all_datetimes,
1429
-        $default = false,
1430
-        $all_tickets = array()
1431
-    ) {
1432
-        // if $ticket is not an instance of EE_Ticket then force default to true.
1433
-        $default = ! $ticket instanceof EE_Ticket ? true : $default;
1434
-        $prices  = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1435
-            array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1436
-        // if there is only one price (which would be the base price)
1437
-        // or NO prices and this ticket is a default ticket,
1438
-        // let's just make sure there are no cached default prices on the object.
1439
-        // This is done by not including any query_params.
1440
-        if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1441
-            $prices = $ticket->prices();
1442
-        }
1443
-        // check if we're dealing with a default ticket in which case
1444
-        // we don't want any starting_ticket_datetime_row values set
1445
-        // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1446
-        // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1447
-        $default_dtt      = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1448
-        $tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1449
-            ? $ticket_datetimes[ $ticket->ID() ]
1450
-            : array();
1451
-        $ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1452
-        $base_price       = $default ? null : $ticket->base_price();
1453
-        $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1454
-        //breaking out complicated condition for ticket_status
1455
-        if ($default) {
1456
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1457
-        } else {
1458
-            $ticket_status_class = $ticket->is_default()
1459
-                ? ' tkt-status-' . EE_Ticket::onsale
1460
-                : ' tkt-status-' . $ticket->ticket_status();
1461
-        }
1462
-        //breaking out complicated condition for TKT_taxable
1463
-        if ($default) {
1464
-            $TKT_taxable = '';
1465
-        } else {
1466
-            $TKT_taxable = $ticket->taxable()
1467
-                ? ' checked="checked"'
1468
-                : '';
1469
-        }
1470
-        if ($default) {
1471
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1472
-        } elseif ($ticket->is_default()) {
1473
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1474
-        } else {
1475
-            $TKT_status = $ticket->ticket_status(true);
1476
-        }
1477
-        if ($default) {
1478
-            $TKT_min = '';
1479
-        } else {
1480
-            $TKT_min = $ticket->min();
1481
-            if ($TKT_min === -1 || $TKT_min === 0) {
1482
-                $TKT_min = '';
1483
-            }
1484
-        }
1485
-        $template_args                 = array(
1486
-            'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1487
-            'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1488
-            //on initial page load this will always be the correct order.
1489
-            'tkt_status_class'              => $ticket_status_class,
1490
-            'display_edit_tkt_row'          => ' style="display:none;"',
1491
-            'edit_tkt_expanded'             => '',
1492
-            'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1493
-            'TKT_name'                      => $default ? '' : $ticket->get_f('TKT_name'),
1494
-            'TKT_start_date'                => $default
1495
-                ? ''
1496
-                : $ticket->get_date('TKT_start_date', $this->_date_time_format),
1497
-            'TKT_end_date'                  => $default
1498
-                ? ''
1499
-                : $ticket->get_date('TKT_end_date', $this->_date_time_format),
1500
-            'TKT_status'                    => $TKT_status,
1501
-            'TKT_price'                     => $default
1502
-                ? ''
1503
-                : EEH_Template::format_currency(
1504
-                    $ticket->get_ticket_total_with_taxes(),
1505
-                    false,
1506
-                    false
1507
-                ),
1508
-            'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1509
-            'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1510
-            'TKT_qty'                       => $default
1511
-                ? ''
1512
-                : $ticket->get_pretty('TKT_qty', 'symbol'),
1513
-            'TKT_qty_for_input'             => $default
1514
-                ? ''
1515
-                : $ticket->get_pretty('TKT_qty', 'input'),
1516
-            'TKT_uses'                      => $default
1517
-                ? ''
1518
-                : $ticket->get_pretty('TKT_uses', 'input'),
1519
-            'TKT_min'                       => $TKT_min,
1520
-            'TKT_max'                       => $default
1521
-                ? ''
1522
-                : $ticket->get_pretty('TKT_max', 'input'),
1523
-            'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1524
-            'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1525
-            'TKT_registrations'             => $default
1526
-                ? 0
1527
-                : $ticket->count_registrations(
1528
-                    array(
1529
-                        array(
1530
-                            'STS_ID' => array(
1531
-                                '!=',
1532
-                                EEM_Registration::status_id_incomplete,
1533
-                            ),
1534
-                        ),
1535
-                    )
1536
-                ),
1537
-            'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1538
-            'TKT_description'               => $default ? '' : $ticket->get_f('TKT_description'),
1539
-            'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1540
-            'TKT_required'                  => $default ? 0 : $ticket->required(),
1541
-            'TKT_is_default_selector'       => '',
1542
-            'ticket_price_rows'             => '',
1543
-            'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1544
-                ? ''
1545
-                : $base_price->get_pretty('PRC_amount', 'localized_float'),
1546
-            'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1547
-            'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1548
-                ? ''
1549
-                : ' style="display:none;"',
1550
-            'show_price_mod_button'         => count($prices) > 1
1551
-                                               || ($default && $count_price_mods > 0)
1552
-                                               || (! $default && $ticket->deleted())
1553
-                ? ' style="display:none;"'
1554
-                : '',
1555
-            'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1556
-            'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1557
-            'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1558
-            'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1559
-            'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1560
-            'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1561
-            'TKT_taxable'                   => $TKT_taxable,
1562
-            'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1563
-                ? ''
1564
-                : ' style="display:none"',
1565
-            'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1566
-            'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1567
-                $ticket_subtotal,
1568
-                false,
1569
-                false
1570
-            ),
1571
-            'TKT_subtotal_amount'           => $ticket_subtotal,
1572
-            'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1573
-            'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1574
-            'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1575
-                ? ' ticket-archived'
1576
-                : '',
1577
-            'trash_icon'                    => $ticket instanceof EE_Ticket
1578
-                                               && $ticket->deleted()
1579
-                                               && ! $ticket->is_permanently_deleteable()
1580
-                ? 'ee-lock-icon '
1581
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1582
-            'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1583
-                ? ''
1584
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1585
-        );
1586
-        $template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1587
-            ? ' style="display:none"'
1588
-            : '';
1589
-        //handle rows that should NOT be empty
1590
-        if (empty($template_args['TKT_start_date'])) {
1591
-            //if empty then the start date will be now.
1592
-            $template_args['TKT_start_date']   = date($this->_date_time_format,
1593
-                current_time('timestamp'));
1594
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1595
-        }
1596
-        if (empty($template_args['TKT_end_date'])) {
1597
-            //get the earliest datetime (if present);
1598
-            $earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1599
-                ? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1600
-                    'Datetime',
1601
-                    array('order_by' => array('DTT_EVT_start' => 'ASC'))
1602
-                )
1603
-                : null;
1604
-            if (! empty($earliest_dtt)) {
1605
-                $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1606
-                    'DTT_EVT_start',
1607
-                    $this->_date_time_format
1608
-                );
1609
-            } else {
1610
-                //default so let's just use what's been set for the default date-time which is 30 days from now.
1611
-                $template_args['TKT_end_date'] = date(
1612
-                    $this->_date_time_format,
1613
-                    mktime(
1614
-                        24, 0, 0, date('m'), date('d') + 29, date('Y')
1615
-                    )
1616
-                );
1617
-            }
1618
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1619
-        }
1620
-        //generate ticket_datetime items
1621
-        if (! $default) {
1622
-            $datetime_row = 1;
1623
-            foreach ($all_datetimes as $datetime) {
1624
-                $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1625
-                    $datetime_row,
1626
-                    $ticket_row,
1627
-                    $datetime,
1628
-                    $ticket,
1629
-                    $ticket_datetimes,
1630
-                    $default
1631
-                );
1632
-                $datetime_row++;
1633
-            }
1634
-        }
1635
-        $price_row = 1;
1636
-        foreach ($prices as $price) {
1637
-            if (! $price instanceof EE_Price) {
1638
-                continue;
1639
-            }
1640
-            if ($price->is_base_price()) {
1641
-                $price_row++;
1642
-                continue;
1643
-            }
1644
-            $show_trash                         = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1645
-            $show_create                        = ! (count($prices) > 1 && count($prices) !== $price_row);
1646
-            $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1647
-                $ticket_row,
1648
-                $price_row,
1649
-                $price,
1650
-                $default,
1651
-                $ticket,
1652
-                $show_trash,
1653
-                $show_create
1654
-            );
1655
-            $price_row++;
1656
-        }
1657
-        //filter $template_args
1658
-        $template_args = apply_filters(
1659
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1660
-            $template_args,
1661
-            $ticket_row,
1662
-            $ticket,
1663
-            $ticket_datetimes,
1664
-            $all_datetimes,
1665
-            $default,
1666
-            $all_tickets,
1667
-            $this->_is_creating_event
1668
-        );
1669
-        return EEH_Template::display_template(
1670
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1671
-            $template_args,
1672
-            true
1673
-        );
1674
-    }
1403
+	/**
1404
+	 * This generates the ticket row for tickets.
1405
+	 * This same method is used to generate both the actual rows and the js skeleton row
1406
+	 * (when default === true)
1407
+	 *
1408
+	 * @param int           $ticket_row       Represents the row number being generated.
1409
+	 * @param               $ticket
1410
+	 * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1411
+	 *                                        or empty for default
1412
+	 * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1413
+	 * @param bool          $default          Whether default row being generated or not.
1414
+	 * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1415
+	 *                                        (or empty in the case of defaults)
1416
+	 * @return mixed
1417
+	 * @throws InvalidArgumentException
1418
+	 * @throws InvalidInterfaceException
1419
+	 * @throws InvalidDataTypeException
1420
+	 * @throws DomainException
1421
+	 * @throws EE_Error
1422
+	 * @throws ReflectionException
1423
+	 */
1424
+	protected function _get_ticket_row(
1425
+		$ticket_row,
1426
+		$ticket,
1427
+		$ticket_datetimes,
1428
+		$all_datetimes,
1429
+		$default = false,
1430
+		$all_tickets = array()
1431
+	) {
1432
+		// if $ticket is not an instance of EE_Ticket then force default to true.
1433
+		$default = ! $ticket instanceof EE_Ticket ? true : $default;
1434
+		$prices  = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1435
+			array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1436
+		// if there is only one price (which would be the base price)
1437
+		// or NO prices and this ticket is a default ticket,
1438
+		// let's just make sure there are no cached default prices on the object.
1439
+		// This is done by not including any query_params.
1440
+		if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1441
+			$prices = $ticket->prices();
1442
+		}
1443
+		// check if we're dealing with a default ticket in which case
1444
+		// we don't want any starting_ticket_datetime_row values set
1445
+		// (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1446
+		// This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1447
+		$default_dtt      = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1448
+		$tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1449
+			? $ticket_datetimes[ $ticket->ID() ]
1450
+			: array();
1451
+		$ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1452
+		$base_price       = $default ? null : $ticket->base_price();
1453
+		$count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1454
+		//breaking out complicated condition for ticket_status
1455
+		if ($default) {
1456
+			$ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1457
+		} else {
1458
+			$ticket_status_class = $ticket->is_default()
1459
+				? ' tkt-status-' . EE_Ticket::onsale
1460
+				: ' tkt-status-' . $ticket->ticket_status();
1461
+		}
1462
+		//breaking out complicated condition for TKT_taxable
1463
+		if ($default) {
1464
+			$TKT_taxable = '';
1465
+		} else {
1466
+			$TKT_taxable = $ticket->taxable()
1467
+				? ' checked="checked"'
1468
+				: '';
1469
+		}
1470
+		if ($default) {
1471
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1472
+		} elseif ($ticket->is_default()) {
1473
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1474
+		} else {
1475
+			$TKT_status = $ticket->ticket_status(true);
1476
+		}
1477
+		if ($default) {
1478
+			$TKT_min = '';
1479
+		} else {
1480
+			$TKT_min = $ticket->min();
1481
+			if ($TKT_min === -1 || $TKT_min === 0) {
1482
+				$TKT_min = '';
1483
+			}
1484
+		}
1485
+		$template_args                 = array(
1486
+			'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1487
+			'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1488
+			//on initial page load this will always be the correct order.
1489
+			'tkt_status_class'              => $ticket_status_class,
1490
+			'display_edit_tkt_row'          => ' style="display:none;"',
1491
+			'edit_tkt_expanded'             => '',
1492
+			'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1493
+			'TKT_name'                      => $default ? '' : $ticket->get_f('TKT_name'),
1494
+			'TKT_start_date'                => $default
1495
+				? ''
1496
+				: $ticket->get_date('TKT_start_date', $this->_date_time_format),
1497
+			'TKT_end_date'                  => $default
1498
+				? ''
1499
+				: $ticket->get_date('TKT_end_date', $this->_date_time_format),
1500
+			'TKT_status'                    => $TKT_status,
1501
+			'TKT_price'                     => $default
1502
+				? ''
1503
+				: EEH_Template::format_currency(
1504
+					$ticket->get_ticket_total_with_taxes(),
1505
+					false,
1506
+					false
1507
+				),
1508
+			'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1509
+			'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1510
+			'TKT_qty'                       => $default
1511
+				? ''
1512
+				: $ticket->get_pretty('TKT_qty', 'symbol'),
1513
+			'TKT_qty_for_input'             => $default
1514
+				? ''
1515
+				: $ticket->get_pretty('TKT_qty', 'input'),
1516
+			'TKT_uses'                      => $default
1517
+				? ''
1518
+				: $ticket->get_pretty('TKT_uses', 'input'),
1519
+			'TKT_min'                       => $TKT_min,
1520
+			'TKT_max'                       => $default
1521
+				? ''
1522
+				: $ticket->get_pretty('TKT_max', 'input'),
1523
+			'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1524
+			'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1525
+			'TKT_registrations'             => $default
1526
+				? 0
1527
+				: $ticket->count_registrations(
1528
+					array(
1529
+						array(
1530
+							'STS_ID' => array(
1531
+								'!=',
1532
+								EEM_Registration::status_id_incomplete,
1533
+							),
1534
+						),
1535
+					)
1536
+				),
1537
+			'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1538
+			'TKT_description'               => $default ? '' : $ticket->get_f('TKT_description'),
1539
+			'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1540
+			'TKT_required'                  => $default ? 0 : $ticket->required(),
1541
+			'TKT_is_default_selector'       => '',
1542
+			'ticket_price_rows'             => '',
1543
+			'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1544
+				? ''
1545
+				: $base_price->get_pretty('PRC_amount', 'localized_float'),
1546
+			'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1547
+			'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1548
+				? ''
1549
+				: ' style="display:none;"',
1550
+			'show_price_mod_button'         => count($prices) > 1
1551
+											   || ($default && $count_price_mods > 0)
1552
+											   || (! $default && $ticket->deleted())
1553
+				? ' style="display:none;"'
1554
+				: '',
1555
+			'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1556
+			'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1557
+			'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1558
+			'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1559
+			'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1560
+			'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1561
+			'TKT_taxable'                   => $TKT_taxable,
1562
+			'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1563
+				? ''
1564
+				: ' style="display:none"',
1565
+			'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1566
+			'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1567
+				$ticket_subtotal,
1568
+				false,
1569
+				false
1570
+			),
1571
+			'TKT_subtotal_amount'           => $ticket_subtotal,
1572
+			'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1573
+			'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1574
+			'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1575
+				? ' ticket-archived'
1576
+				: '',
1577
+			'trash_icon'                    => $ticket instanceof EE_Ticket
1578
+											   && $ticket->deleted()
1579
+											   && ! $ticket->is_permanently_deleteable()
1580
+				? 'ee-lock-icon '
1581
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1582
+			'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1583
+				? ''
1584
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1585
+		);
1586
+		$template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1587
+			? ' style="display:none"'
1588
+			: '';
1589
+		//handle rows that should NOT be empty
1590
+		if (empty($template_args['TKT_start_date'])) {
1591
+			//if empty then the start date will be now.
1592
+			$template_args['TKT_start_date']   = date($this->_date_time_format,
1593
+				current_time('timestamp'));
1594
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1595
+		}
1596
+		if (empty($template_args['TKT_end_date'])) {
1597
+			//get the earliest datetime (if present);
1598
+			$earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1599
+				? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1600
+					'Datetime',
1601
+					array('order_by' => array('DTT_EVT_start' => 'ASC'))
1602
+				)
1603
+				: null;
1604
+			if (! empty($earliest_dtt)) {
1605
+				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1606
+					'DTT_EVT_start',
1607
+					$this->_date_time_format
1608
+				);
1609
+			} else {
1610
+				//default so let's just use what's been set for the default date-time which is 30 days from now.
1611
+				$template_args['TKT_end_date'] = date(
1612
+					$this->_date_time_format,
1613
+					mktime(
1614
+						24, 0, 0, date('m'), date('d') + 29, date('Y')
1615
+					)
1616
+				);
1617
+			}
1618
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1619
+		}
1620
+		//generate ticket_datetime items
1621
+		if (! $default) {
1622
+			$datetime_row = 1;
1623
+			foreach ($all_datetimes as $datetime) {
1624
+				$template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1625
+					$datetime_row,
1626
+					$ticket_row,
1627
+					$datetime,
1628
+					$ticket,
1629
+					$ticket_datetimes,
1630
+					$default
1631
+				);
1632
+				$datetime_row++;
1633
+			}
1634
+		}
1635
+		$price_row = 1;
1636
+		foreach ($prices as $price) {
1637
+			if (! $price instanceof EE_Price) {
1638
+				continue;
1639
+			}
1640
+			if ($price->is_base_price()) {
1641
+				$price_row++;
1642
+				continue;
1643
+			}
1644
+			$show_trash                         = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1645
+			$show_create                        = ! (count($prices) > 1 && count($prices) !== $price_row);
1646
+			$template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1647
+				$ticket_row,
1648
+				$price_row,
1649
+				$price,
1650
+				$default,
1651
+				$ticket,
1652
+				$show_trash,
1653
+				$show_create
1654
+			);
1655
+			$price_row++;
1656
+		}
1657
+		//filter $template_args
1658
+		$template_args = apply_filters(
1659
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1660
+			$template_args,
1661
+			$ticket_row,
1662
+			$ticket,
1663
+			$ticket_datetimes,
1664
+			$all_datetimes,
1665
+			$default,
1666
+			$all_tickets,
1667
+			$this->_is_creating_event
1668
+		);
1669
+		return EEH_Template::display_template(
1670
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1671
+			$template_args,
1672
+			true
1673
+		);
1674
+	}
1675 1675
 
1676 1676
 
1677
-    /**
1678
-     * @param int            $ticket_row
1679
-     * @param EE_Ticket|null $ticket
1680
-     * @return string
1681
-     * @throws DomainException
1682
-     * @throws EE_Error
1683
-     */
1684
-    protected function _get_tax_rows($ticket_row, $ticket)
1685
-    {
1686
-        $tax_rows = '';
1687
-        /** @var EE_Price[] $taxes */
1688
-        $taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1689
-        foreach ($taxes as $tax) {
1690
-            $tax_added     = $this->_get_tax_added($tax, $ticket);
1691
-            $template_args = array(
1692
-                'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1693
-                    ? ''
1694
-                    : ' style="display:none;"',
1695
-                'tax_id'            => $tax->ID(),
1696
-                'tkt_row'           => $ticket_row,
1697
-                'tax_label'         => $tax->get('PRC_name'),
1698
-                'tax_added'         => $tax_added,
1699
-                'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1700
-                'tax_amount'        => $tax->get('PRC_amount'),
1701
-            );
1702
-            $template_args = apply_filters(
1703
-                'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1704
-                $template_args,
1705
-                $ticket_row,
1706
-                $ticket,
1707
-                $this->_is_creating_event
1708
-            );
1709
-            $tax_rows      .= EEH_Template::display_template(
1710
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1711
-                $template_args,
1712
-                true
1713
-            );
1714
-        }
1715
-        return $tax_rows;
1716
-    }
1677
+	/**
1678
+	 * @param int            $ticket_row
1679
+	 * @param EE_Ticket|null $ticket
1680
+	 * @return string
1681
+	 * @throws DomainException
1682
+	 * @throws EE_Error
1683
+	 */
1684
+	protected function _get_tax_rows($ticket_row, $ticket)
1685
+	{
1686
+		$tax_rows = '';
1687
+		/** @var EE_Price[] $taxes */
1688
+		$taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1689
+		foreach ($taxes as $tax) {
1690
+			$tax_added     = $this->_get_tax_added($tax, $ticket);
1691
+			$template_args = array(
1692
+				'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1693
+					? ''
1694
+					: ' style="display:none;"',
1695
+				'tax_id'            => $tax->ID(),
1696
+				'tkt_row'           => $ticket_row,
1697
+				'tax_label'         => $tax->get('PRC_name'),
1698
+				'tax_added'         => $tax_added,
1699
+				'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1700
+				'tax_amount'        => $tax->get('PRC_amount'),
1701
+			);
1702
+			$template_args = apply_filters(
1703
+				'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1704
+				$template_args,
1705
+				$ticket_row,
1706
+				$ticket,
1707
+				$this->_is_creating_event
1708
+			);
1709
+			$tax_rows      .= EEH_Template::display_template(
1710
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1711
+				$template_args,
1712
+				true
1713
+			);
1714
+		}
1715
+		return $tax_rows;
1716
+	}
1717 1717
 
1718 1718
 
1719
-    /**
1720
-     * @param EE_Price       $tax
1721
-     * @param EE_Ticket|null $ticket
1722
-     * @return float|int
1723
-     * @throws EE_Error
1724
-     */
1725
-    protected function _get_tax_added(EE_Price $tax, $ticket)
1726
-    {
1727
-        $subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1728
-        return $subtotal * $tax->get('PRC_amount') / 100;
1729
-    }
1719
+	/**
1720
+	 * @param EE_Price       $tax
1721
+	 * @param EE_Ticket|null $ticket
1722
+	 * @return float|int
1723
+	 * @throws EE_Error
1724
+	 */
1725
+	protected function _get_tax_added(EE_Price $tax, $ticket)
1726
+	{
1727
+		$subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1728
+		return $subtotal * $tax->get('PRC_amount') / 100;
1729
+	}
1730 1730
 
1731 1731
 
1732
-    /**
1733
-     * @param int            $ticket_row
1734
-     * @param int            $price_row
1735
-     * @param EE_Price|null  $price
1736
-     * @param bool           $default
1737
-     * @param EE_Ticket|null $ticket
1738
-     * @param bool           $show_trash
1739
-     * @param bool           $show_create
1740
-     * @return mixed
1741
-     * @throws InvalidArgumentException
1742
-     * @throws InvalidInterfaceException
1743
-     * @throws InvalidDataTypeException
1744
-     * @throws DomainException
1745
-     * @throws EE_Error
1746
-     * @throws ReflectionException
1747
-     */
1748
-    protected function _get_ticket_price_row(
1749
-        $ticket_row,
1750
-        $price_row,
1751
-        $price,
1752
-        $default,
1753
-        $ticket,
1754
-        $show_trash = true,
1755
-        $show_create = true
1756
-    ) {
1757
-        $send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1758
-        $template_args = array(
1759
-            'tkt_row'               => $default && empty($ticket)
1760
-                ? 'TICKETNUM'
1761
-                : $ticket_row,
1762
-            'PRC_order'             => $default && empty($price)
1763
-                ? 'PRICENUM'
1764
-                : $price_row,
1765
-            'edit_prices_name'      => $default && empty($price)
1766
-                ? 'PRICENAMEATTR'
1767
-                : 'edit_prices',
1768
-            'price_type_selector'   => $default && empty($price)
1769
-                ? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1770
-                : $this->_get_price_type_selector(
1771
-                    $ticket_row,
1772
-                    $price_row,
1773
-                    $price,
1774
-                    $default,
1775
-                    $send_disabled
1776
-                ),
1777
-            'PRC_ID'                => $default && empty($price)
1778
-                ? 0
1779
-                : $price->ID(),
1780
-            'PRC_is_default'        => $default && empty($price)
1781
-                ? 0
1782
-                : $price->get('PRC_is_default'),
1783
-            'PRC_name'              => $default && empty($price)
1784
-                ? ''
1785
-                : $price->get('PRC_name'),
1786
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1787
-            'show_plus_or_minus'    => $default && empty($price)
1788
-                ? ''
1789
-                : ' style="display:none;"',
1790
-            'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1791
-                ? ' style="display:none;"'
1792
-                : '',
1793
-            'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1794
-                ? ' style="display:none;"'
1795
-                : '',
1796
-            'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1797
-                ? ' style="display:none"'
1798
-                : '',
1799
-            'PRC_amount'            => $default && empty($price)
1800
-                ? 0
1801
-                : $price->get_pretty('PRC_amount',
1802
-                    'localized_float'),
1803
-            'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1804
-                ? ' style="display:none;"'
1805
-                : '',
1806
-            'show_trash_icon'       => $show_trash
1807
-                ? ''
1808
-                : ' style="display:none;"',
1809
-            'show_create_button'    => $show_create
1810
-                ? ''
1811
-                : ' style="display:none;"',
1812
-            'PRC_desc'              => $default && empty($price)
1813
-                ? ''
1814
-                : $price->get('PRC_desc'),
1815
-            'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1816
-        );
1817
-        $template_args = apply_filters(
1818
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1819
-            $template_args,
1820
-            $ticket_row,
1821
-            $price_row,
1822
-            $price,
1823
-            $default,
1824
-            $ticket,
1825
-            $show_trash,
1826
-            $show_create,
1827
-            $this->_is_creating_event
1828
-        );
1829
-        return EEH_Template::display_template(
1830
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1831
-            $template_args,
1832
-            true
1833
-        );
1834
-    }
1732
+	/**
1733
+	 * @param int            $ticket_row
1734
+	 * @param int            $price_row
1735
+	 * @param EE_Price|null  $price
1736
+	 * @param bool           $default
1737
+	 * @param EE_Ticket|null $ticket
1738
+	 * @param bool           $show_trash
1739
+	 * @param bool           $show_create
1740
+	 * @return mixed
1741
+	 * @throws InvalidArgumentException
1742
+	 * @throws InvalidInterfaceException
1743
+	 * @throws InvalidDataTypeException
1744
+	 * @throws DomainException
1745
+	 * @throws EE_Error
1746
+	 * @throws ReflectionException
1747
+	 */
1748
+	protected function _get_ticket_price_row(
1749
+		$ticket_row,
1750
+		$price_row,
1751
+		$price,
1752
+		$default,
1753
+		$ticket,
1754
+		$show_trash = true,
1755
+		$show_create = true
1756
+	) {
1757
+		$send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1758
+		$template_args = array(
1759
+			'tkt_row'               => $default && empty($ticket)
1760
+				? 'TICKETNUM'
1761
+				: $ticket_row,
1762
+			'PRC_order'             => $default && empty($price)
1763
+				? 'PRICENUM'
1764
+				: $price_row,
1765
+			'edit_prices_name'      => $default && empty($price)
1766
+				? 'PRICENAMEATTR'
1767
+				: 'edit_prices',
1768
+			'price_type_selector'   => $default && empty($price)
1769
+				? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1770
+				: $this->_get_price_type_selector(
1771
+					$ticket_row,
1772
+					$price_row,
1773
+					$price,
1774
+					$default,
1775
+					$send_disabled
1776
+				),
1777
+			'PRC_ID'                => $default && empty($price)
1778
+				? 0
1779
+				: $price->ID(),
1780
+			'PRC_is_default'        => $default && empty($price)
1781
+				? 0
1782
+				: $price->get('PRC_is_default'),
1783
+			'PRC_name'              => $default && empty($price)
1784
+				? ''
1785
+				: $price->get('PRC_name'),
1786
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1787
+			'show_plus_or_minus'    => $default && empty($price)
1788
+				? ''
1789
+				: ' style="display:none;"',
1790
+			'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1791
+				? ' style="display:none;"'
1792
+				: '',
1793
+			'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1794
+				? ' style="display:none;"'
1795
+				: '',
1796
+			'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1797
+				? ' style="display:none"'
1798
+				: '',
1799
+			'PRC_amount'            => $default && empty($price)
1800
+				? 0
1801
+				: $price->get_pretty('PRC_amount',
1802
+					'localized_float'),
1803
+			'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1804
+				? ' style="display:none;"'
1805
+				: '',
1806
+			'show_trash_icon'       => $show_trash
1807
+				? ''
1808
+				: ' style="display:none;"',
1809
+			'show_create_button'    => $show_create
1810
+				? ''
1811
+				: ' style="display:none;"',
1812
+			'PRC_desc'              => $default && empty($price)
1813
+				? ''
1814
+				: $price->get('PRC_desc'),
1815
+			'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1816
+		);
1817
+		$template_args = apply_filters(
1818
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1819
+			$template_args,
1820
+			$ticket_row,
1821
+			$price_row,
1822
+			$price,
1823
+			$default,
1824
+			$ticket,
1825
+			$show_trash,
1826
+			$show_create,
1827
+			$this->_is_creating_event
1828
+		);
1829
+		return EEH_Template::display_template(
1830
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1831
+			$template_args,
1832
+			true
1833
+		);
1834
+	}
1835 1835
 
1836 1836
 
1837
-    /**
1838
-     * @param int      $ticket_row
1839
-     * @param int      $price_row
1840
-     * @param EE_Price $price
1841
-     * @param bool     $default
1842
-     * @param bool     $disabled
1843
-     * @return mixed
1844
-     * @throws ReflectionException
1845
-     * @throws InvalidArgumentException
1846
-     * @throws InvalidInterfaceException
1847
-     * @throws InvalidDataTypeException
1848
-     * @throws DomainException
1849
-     * @throws EE_Error
1850
-     */
1851
-    protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1852
-    {
1853
-        if ($price->is_base_price()) {
1854
-            return $this->_get_base_price_template(
1855
-                $ticket_row,
1856
-                $price_row,
1857
-                $price,
1858
-                $default
1859
-            );
1860
-        }
1861
-        return $this->_get_price_modifier_template(
1862
-            $ticket_row,
1863
-            $price_row,
1864
-            $price,
1865
-            $default,
1866
-            $disabled
1867
-        );
1868
-    }
1837
+	/**
1838
+	 * @param int      $ticket_row
1839
+	 * @param int      $price_row
1840
+	 * @param EE_Price $price
1841
+	 * @param bool     $default
1842
+	 * @param bool     $disabled
1843
+	 * @return mixed
1844
+	 * @throws ReflectionException
1845
+	 * @throws InvalidArgumentException
1846
+	 * @throws InvalidInterfaceException
1847
+	 * @throws InvalidDataTypeException
1848
+	 * @throws DomainException
1849
+	 * @throws EE_Error
1850
+	 */
1851
+	protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1852
+	{
1853
+		if ($price->is_base_price()) {
1854
+			return $this->_get_base_price_template(
1855
+				$ticket_row,
1856
+				$price_row,
1857
+				$price,
1858
+				$default
1859
+			);
1860
+		}
1861
+		return $this->_get_price_modifier_template(
1862
+			$ticket_row,
1863
+			$price_row,
1864
+			$price,
1865
+			$default,
1866
+			$disabled
1867
+		);
1868
+	}
1869 1869
 
1870 1870
 
1871
-    /**
1872
-     * @param int      $ticket_row
1873
-     * @param int      $price_row
1874
-     * @param EE_Price $price
1875
-     * @param bool     $default
1876
-     * @return mixed
1877
-     * @throws DomainException
1878
-     * @throws EE_Error
1879
-     */
1880
-    protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1881
-    {
1882
-        $template_args = array(
1883
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1884
-            'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1885
-            'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1886
-            'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1887
-            'price_selected_operator'   => '+',
1888
-            'price_selected_is_percent' => 0,
1889
-        );
1890
-        $template_args = apply_filters(
1891
-            'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1892
-            $template_args,
1893
-            $ticket_row,
1894
-            $price_row,
1895
-            $price,
1896
-            $default,
1897
-            $this->_is_creating_event
1898
-        );
1899
-        return EEH_Template::display_template(
1900
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1901
-            $template_args,
1902
-            true
1903
-        );
1904
-    }
1871
+	/**
1872
+	 * @param int      $ticket_row
1873
+	 * @param int      $price_row
1874
+	 * @param EE_Price $price
1875
+	 * @param bool     $default
1876
+	 * @return mixed
1877
+	 * @throws DomainException
1878
+	 * @throws EE_Error
1879
+	 */
1880
+	protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1881
+	{
1882
+		$template_args = array(
1883
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1884
+			'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1885
+			'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1886
+			'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1887
+			'price_selected_operator'   => '+',
1888
+			'price_selected_is_percent' => 0,
1889
+		);
1890
+		$template_args = apply_filters(
1891
+			'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1892
+			$template_args,
1893
+			$ticket_row,
1894
+			$price_row,
1895
+			$price,
1896
+			$default,
1897
+			$this->_is_creating_event
1898
+		);
1899
+		return EEH_Template::display_template(
1900
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1901
+			$template_args,
1902
+			true
1903
+		);
1904
+	}
1905 1905
 
1906 1906
 
1907
-    /**
1908
-     * @param int      $ticket_row
1909
-     * @param int      $price_row
1910
-     * @param EE_Price $price
1911
-     * @param bool     $default
1912
-     * @param bool     $disabled
1913
-     * @return mixed
1914
-     * @throws ReflectionException
1915
-     * @throws InvalidArgumentException
1916
-     * @throws InvalidInterfaceException
1917
-     * @throws InvalidDataTypeException
1918
-     * @throws DomainException
1919
-     * @throws EE_Error
1920
-     */
1921
-    protected function _get_price_modifier_template(
1922
-        $ticket_row,
1923
-        $price_row,
1924
-        $price,
1925
-        $default,
1926
-        $disabled = false
1927
-    ) {
1928
-        $select_name = $default && ! $price instanceof EE_Price
1929
-            ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1930
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1931
-        /** @var EEM_Price_Type $price_type_model */
1932
-        $price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1933
-        $price_types            = $price_type_model->get_all(array(
1934
-            array(
1935
-                'OR' => array(
1936
-                    'PBT_ID'  => '2',
1937
-                    'PBT_ID*' => '3',
1938
-                ),
1939
-            ),
1940
-        ));
1941
-        $all_price_types        = $default && ! $price instanceof EE_Price
1942
-            ? array(esc_html__('Select Modifier', 'event_espresso'))
1943
-            : array();
1944
-        $selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1945
-        $price_option_spans     = '';
1946
-        //setup price types for selector
1947
-        foreach ($price_types as $price_type) {
1948
-            if (! $price_type instanceof EE_Price_Type) {
1949
-                continue;
1950
-            }
1951
-            $all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1952
-            //while we're in the loop let's setup the option spans used by js
1953
-            $span_args          = array(
1954
-                'PRT_ID'         => $price_type->ID(),
1955
-                'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1956
-                'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1957
-            );
1958
-            $price_option_spans .= EEH_Template::display_template(
1959
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1960
-                $span_args,
1961
-                true
1962
-            );
1963
-        }
1964
-        $select_name               = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1965
-            : $select_name;
1966
-        $select_input              = new EE_Select_Input(
1967
-            $all_price_types,
1968
-            array(
1969
-                'default'               => $selected_price_type_id,
1970
-                'html_name'             => $select_name,
1971
-                'html_class'            => 'edit-price-PRT_ID',
1972
-                'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1973
-            )
1974
-        );
1975
-        $price_selected_operator   = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1976
-        $price_selected_operator   = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1977
-        $price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1978
-        $price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1979
-        $template_args             = array(
1980
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1981
-            'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1982
-            'price_modifier_selector'   => $select_input->get_html_for_input(),
1983
-            'main_name'                 => $select_name,
1984
-            'selected_price_type_id'    => $selected_price_type_id,
1985
-            'price_option_spans'        => $price_option_spans,
1986
-            'price_selected_operator'   => $price_selected_operator,
1987
-            'price_selected_is_percent' => $price_selected_is_percent,
1988
-            'disabled'                  => $disabled,
1989
-        );
1990
-        $template_args             = apply_filters(
1991
-            'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1992
-            $template_args,
1993
-            $ticket_row,
1994
-            $price_row,
1995
-            $price,
1996
-            $default,
1997
-            $disabled,
1998
-            $this->_is_creating_event
1999
-        );
2000
-        return EEH_Template::display_template(
2001
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2002
-            $template_args,
2003
-            true
2004
-        );
2005
-    }
1907
+	/**
1908
+	 * @param int      $ticket_row
1909
+	 * @param int      $price_row
1910
+	 * @param EE_Price $price
1911
+	 * @param bool     $default
1912
+	 * @param bool     $disabled
1913
+	 * @return mixed
1914
+	 * @throws ReflectionException
1915
+	 * @throws InvalidArgumentException
1916
+	 * @throws InvalidInterfaceException
1917
+	 * @throws InvalidDataTypeException
1918
+	 * @throws DomainException
1919
+	 * @throws EE_Error
1920
+	 */
1921
+	protected function _get_price_modifier_template(
1922
+		$ticket_row,
1923
+		$price_row,
1924
+		$price,
1925
+		$default,
1926
+		$disabled = false
1927
+	) {
1928
+		$select_name = $default && ! $price instanceof EE_Price
1929
+			? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1930
+			: 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1931
+		/** @var EEM_Price_Type $price_type_model */
1932
+		$price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1933
+		$price_types            = $price_type_model->get_all(array(
1934
+			array(
1935
+				'OR' => array(
1936
+					'PBT_ID'  => '2',
1937
+					'PBT_ID*' => '3',
1938
+				),
1939
+			),
1940
+		));
1941
+		$all_price_types        = $default && ! $price instanceof EE_Price
1942
+			? array(esc_html__('Select Modifier', 'event_espresso'))
1943
+			: array();
1944
+		$selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1945
+		$price_option_spans     = '';
1946
+		//setup price types for selector
1947
+		foreach ($price_types as $price_type) {
1948
+			if (! $price_type instanceof EE_Price_Type) {
1949
+				continue;
1950
+			}
1951
+			$all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1952
+			//while we're in the loop let's setup the option spans used by js
1953
+			$span_args          = array(
1954
+				'PRT_ID'         => $price_type->ID(),
1955
+				'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1956
+				'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1957
+			);
1958
+			$price_option_spans .= EEH_Template::display_template(
1959
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1960
+				$span_args,
1961
+				true
1962
+			);
1963
+		}
1964
+		$select_name               = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1965
+			: $select_name;
1966
+		$select_input              = new EE_Select_Input(
1967
+			$all_price_types,
1968
+			array(
1969
+				'default'               => $selected_price_type_id,
1970
+				'html_name'             => $select_name,
1971
+				'html_class'            => 'edit-price-PRT_ID',
1972
+				'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1973
+			)
1974
+		);
1975
+		$price_selected_operator   = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1976
+		$price_selected_operator   = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1977
+		$price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1978
+		$price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1979
+		$template_args             = array(
1980
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1981
+			'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1982
+			'price_modifier_selector'   => $select_input->get_html_for_input(),
1983
+			'main_name'                 => $select_name,
1984
+			'selected_price_type_id'    => $selected_price_type_id,
1985
+			'price_option_spans'        => $price_option_spans,
1986
+			'price_selected_operator'   => $price_selected_operator,
1987
+			'price_selected_is_percent' => $price_selected_is_percent,
1988
+			'disabled'                  => $disabled,
1989
+		);
1990
+		$template_args             = apply_filters(
1991
+			'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1992
+			$template_args,
1993
+			$ticket_row,
1994
+			$price_row,
1995
+			$price,
1996
+			$default,
1997
+			$disabled,
1998
+			$this->_is_creating_event
1999
+		);
2000
+		return EEH_Template::display_template(
2001
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2002
+			$template_args,
2003
+			true
2004
+		);
2005
+	}
2006 2006
 
2007 2007
 
2008
-    /**
2009
-     * @param int              $datetime_row
2010
-     * @param int              $ticket_row
2011
-     * @param EE_Datetime|null $datetime
2012
-     * @param EE_Ticket|null   $ticket
2013
-     * @param array            $ticket_datetimes
2014
-     * @param bool             $default
2015
-     * @return mixed
2016
-     * @throws DomainException
2017
-     * @throws EE_Error
2018
-     */
2019
-    protected function _get_ticket_datetime_list_item(
2020
-        $datetime_row,
2021
-        $ticket_row,
2022
-        $datetime,
2023
-        $ticket,
2024
-        $ticket_datetimes = array(),
2025
-        $default
2026
-    ) {
2027
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2028
-            ? $ticket_datetimes[ $ticket->ID() ]
2029
-            : array();
2030
-        $template_args = array(
2031
-            'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2032
-                ? 'DTTNUM'
2033
-                : $datetime_row,
2034
-            'tkt_row'                  => $default
2035
-                ? 'TICKETNUM'
2036
-                : $ticket_row,
2037
-            'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
2038
-                ? ' ticket-selected'
2039
-                : '',
2040
-            'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
2041
-                ? ' checked="checked"'
2042
-                : '',
2043
-            'DTT_name'                 => $default && empty($datetime)
2044
-                ? 'DTTNAME'
2045
-                : $datetime->get_dtt_display_name(true),
2046
-            'tkt_status_class'         => '',
2047
-        );
2048
-        $template_args = apply_filters(
2049
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2050
-            $template_args,
2051
-            $datetime_row,
2052
-            $ticket_row,
2053
-            $datetime,
2054
-            $ticket,
2055
-            $ticket_datetimes,
2056
-            $default,
2057
-            $this->_is_creating_event
2058
-        );
2059
-        return EEH_Template::display_template(
2060
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2061
-            $template_args,
2062
-            true
2063
-        );
2064
-    }
2008
+	/**
2009
+	 * @param int              $datetime_row
2010
+	 * @param int              $ticket_row
2011
+	 * @param EE_Datetime|null $datetime
2012
+	 * @param EE_Ticket|null   $ticket
2013
+	 * @param array            $ticket_datetimes
2014
+	 * @param bool             $default
2015
+	 * @return mixed
2016
+	 * @throws DomainException
2017
+	 * @throws EE_Error
2018
+	 */
2019
+	protected function _get_ticket_datetime_list_item(
2020
+		$datetime_row,
2021
+		$ticket_row,
2022
+		$datetime,
2023
+		$ticket,
2024
+		$ticket_datetimes = array(),
2025
+		$default
2026
+	) {
2027
+		$tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2028
+			? $ticket_datetimes[ $ticket->ID() ]
2029
+			: array();
2030
+		$template_args = array(
2031
+			'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2032
+				? 'DTTNUM'
2033
+				: $datetime_row,
2034
+			'tkt_row'                  => $default
2035
+				? 'TICKETNUM'
2036
+				: $ticket_row,
2037
+			'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
2038
+				? ' ticket-selected'
2039
+				: '',
2040
+			'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
2041
+				? ' checked="checked"'
2042
+				: '',
2043
+			'DTT_name'                 => $default && empty($datetime)
2044
+				? 'DTTNAME'
2045
+				: $datetime->get_dtt_display_name(true),
2046
+			'tkt_status_class'         => '',
2047
+		);
2048
+		$template_args = apply_filters(
2049
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2050
+			$template_args,
2051
+			$datetime_row,
2052
+			$ticket_row,
2053
+			$datetime,
2054
+			$ticket,
2055
+			$ticket_datetimes,
2056
+			$default,
2057
+			$this->_is_creating_event
2058
+		);
2059
+		return EEH_Template::display_template(
2060
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2061
+			$template_args,
2062
+			true
2063
+		);
2064
+	}
2065 2065
 
2066 2066
 
2067
-    /**
2068
-     * @param array $all_datetimes
2069
-     * @param array $all_tickets
2070
-     * @return mixed
2071
-     * @throws ReflectionException
2072
-     * @throws InvalidArgumentException
2073
-     * @throws InvalidInterfaceException
2074
-     * @throws InvalidDataTypeException
2075
-     * @throws DomainException
2076
-     * @throws EE_Error
2077
-     */
2078
-    protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2079
-    {
2080
-        $template_args = array(
2081
-            'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2082
-                'DTTNUM',
2083
-                null,
2084
-                true,
2085
-                $all_datetimes
2086
-            ),
2087
-            'default_ticket_row'                       => $this->_get_ticket_row(
2088
-                'TICKETNUM',
2089
-                null,
2090
-                array(),
2091
-                array(),
2092
-                true
2093
-            ),
2094
-            'default_price_row'                        => $this->_get_ticket_price_row(
2095
-                'TICKETNUM',
2096
-                'PRICENUM',
2097
-                null,
2098
-                true,
2099
-                null
2100
-            ),
2101
-            'default_price_rows'                       => '',
2102
-            'default_base_price_amount'                => 0,
2103
-            'default_base_price_name'                  => '',
2104
-            'default_base_price_description'           => '',
2105
-            'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2106
-                'TICKETNUM',
2107
-                'PRICENUM',
2108
-                null,
2109
-                true
2110
-            ),
2111
-            'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2112
-                'DTTNUM',
2113
-                null,
2114
-                array(),
2115
-                array(),
2116
-                true
2117
-            ),
2118
-            'existing_available_datetime_tickets_list' => '',
2119
-            'existing_available_ticket_datetimes_list' => '',
2120
-            'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2121
-                'DTTNUM',
2122
-                'TICKETNUM',
2123
-                null,
2124
-                null,
2125
-                array(),
2126
-                true
2127
-            ),
2128
-            'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2129
-                'DTTNUM',
2130
-                'TICKETNUM',
2131
-                null,
2132
-                null,
2133
-                array(),
2134
-                true
2135
-            ),
2136
-        );
2137
-        $ticket_row    = 1;
2138
-        foreach ($all_tickets as $ticket) {
2139
-            $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2140
-                'DTTNUM',
2141
-                $ticket_row,
2142
-                null,
2143
-                $ticket,
2144
-                array(),
2145
-                true
2146
-            );
2147
-            $ticket_row++;
2148
-        }
2149
-        $datetime_row = 1;
2150
-        foreach ($all_datetimes as $datetime) {
2151
-            $template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2152
-                $datetime_row,
2153
-                'TICKETNUM',
2154
-                $datetime,
2155
-                null,
2156
-                array(),
2157
-                true
2158
-            );
2159
-            $datetime_row++;
2160
-        }
2161
-        /** @var EEM_Price $price_model */
2162
-        $price_model    = EE_Registry::instance()->load_model('Price');
2163
-        $default_prices = $price_model->get_all_default_prices();
2164
-        $price_row      = 1;
2165
-        foreach ($default_prices as $price) {
2166
-            if (! $price instanceof EE_Price) {
2167
-                continue;
2168
-            }
2169
-            if ($price->is_base_price()) {
2170
-                $template_args['default_base_price_amount']      = $price->get_pretty(
2171
-                    'PRC_amount',
2172
-                    'localized_float'
2173
-                );
2174
-                $template_args['default_base_price_name']        = $price->get('PRC_name');
2175
-                $template_args['default_base_price_description'] = $price->get('PRC_desc');
2176
-                $price_row++;
2177
-                continue;
2178
-            }
2179
-            $show_trash                          = ! ((count($default_prices) > 1 && $price_row === 1)
2180
-                                                      || count($default_prices) === 1);
2181
-            $show_create                         = ! (count($default_prices) > 1
2182
-                                                      && count($default_prices)
2183
-                                                         !== $price_row);
2184
-            $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2185
-                'TICKETNUM',
2186
-                $price_row,
2187
-                $price,
2188
-                true,
2189
-                null,
2190
-                $show_trash,
2191
-                $show_create
2192
-            );
2193
-            $price_row++;
2194
-        }
2195
-        $template_args = apply_filters(
2196
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2197
-            $template_args,
2198
-            $all_datetimes,
2199
-            $all_tickets,
2200
-            $this->_is_creating_event
2201
-        );
2202
-        return EEH_Template::display_template(
2203
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2204
-            $template_args,
2205
-            true
2206
-        );
2207
-    }
2067
+	/**
2068
+	 * @param array $all_datetimes
2069
+	 * @param array $all_tickets
2070
+	 * @return mixed
2071
+	 * @throws ReflectionException
2072
+	 * @throws InvalidArgumentException
2073
+	 * @throws InvalidInterfaceException
2074
+	 * @throws InvalidDataTypeException
2075
+	 * @throws DomainException
2076
+	 * @throws EE_Error
2077
+	 */
2078
+	protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2079
+	{
2080
+		$template_args = array(
2081
+			'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2082
+				'DTTNUM',
2083
+				null,
2084
+				true,
2085
+				$all_datetimes
2086
+			),
2087
+			'default_ticket_row'                       => $this->_get_ticket_row(
2088
+				'TICKETNUM',
2089
+				null,
2090
+				array(),
2091
+				array(),
2092
+				true
2093
+			),
2094
+			'default_price_row'                        => $this->_get_ticket_price_row(
2095
+				'TICKETNUM',
2096
+				'PRICENUM',
2097
+				null,
2098
+				true,
2099
+				null
2100
+			),
2101
+			'default_price_rows'                       => '',
2102
+			'default_base_price_amount'                => 0,
2103
+			'default_base_price_name'                  => '',
2104
+			'default_base_price_description'           => '',
2105
+			'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2106
+				'TICKETNUM',
2107
+				'PRICENUM',
2108
+				null,
2109
+				true
2110
+			),
2111
+			'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2112
+				'DTTNUM',
2113
+				null,
2114
+				array(),
2115
+				array(),
2116
+				true
2117
+			),
2118
+			'existing_available_datetime_tickets_list' => '',
2119
+			'existing_available_ticket_datetimes_list' => '',
2120
+			'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2121
+				'DTTNUM',
2122
+				'TICKETNUM',
2123
+				null,
2124
+				null,
2125
+				array(),
2126
+				true
2127
+			),
2128
+			'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2129
+				'DTTNUM',
2130
+				'TICKETNUM',
2131
+				null,
2132
+				null,
2133
+				array(),
2134
+				true
2135
+			),
2136
+		);
2137
+		$ticket_row    = 1;
2138
+		foreach ($all_tickets as $ticket) {
2139
+			$template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2140
+				'DTTNUM',
2141
+				$ticket_row,
2142
+				null,
2143
+				$ticket,
2144
+				array(),
2145
+				true
2146
+			);
2147
+			$ticket_row++;
2148
+		}
2149
+		$datetime_row = 1;
2150
+		foreach ($all_datetimes as $datetime) {
2151
+			$template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2152
+				$datetime_row,
2153
+				'TICKETNUM',
2154
+				$datetime,
2155
+				null,
2156
+				array(),
2157
+				true
2158
+			);
2159
+			$datetime_row++;
2160
+		}
2161
+		/** @var EEM_Price $price_model */
2162
+		$price_model    = EE_Registry::instance()->load_model('Price');
2163
+		$default_prices = $price_model->get_all_default_prices();
2164
+		$price_row      = 1;
2165
+		foreach ($default_prices as $price) {
2166
+			if (! $price instanceof EE_Price) {
2167
+				continue;
2168
+			}
2169
+			if ($price->is_base_price()) {
2170
+				$template_args['default_base_price_amount']      = $price->get_pretty(
2171
+					'PRC_amount',
2172
+					'localized_float'
2173
+				);
2174
+				$template_args['default_base_price_name']        = $price->get('PRC_name');
2175
+				$template_args['default_base_price_description'] = $price->get('PRC_desc');
2176
+				$price_row++;
2177
+				continue;
2178
+			}
2179
+			$show_trash                          = ! ((count($default_prices) > 1 && $price_row === 1)
2180
+													  || count($default_prices) === 1);
2181
+			$show_create                         = ! (count($default_prices) > 1
2182
+													  && count($default_prices)
2183
+														 !== $price_row);
2184
+			$template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2185
+				'TICKETNUM',
2186
+				$price_row,
2187
+				$price,
2188
+				true,
2189
+				null,
2190
+				$show_trash,
2191
+				$show_create
2192
+			);
2193
+			$price_row++;
2194
+		}
2195
+		$template_args = apply_filters(
2196
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2197
+			$template_args,
2198
+			$all_datetimes,
2199
+			$all_tickets,
2200
+			$this->_is_creating_event
2201
+		);
2202
+		return EEH_Template::display_template(
2203
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2204
+			$template_args,
2205
+			true
2206
+		);
2207
+	}
2208 2208
 } //end class espresso_events_Pricing_Hooks
Please login to merge, or discard this patch.
Spacing   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -52,7 +52,7 @@  discard block
 block discarded – undo
52 52
     {
53 53
         $this->_name = 'pricing';
54 54
         //capability check
55
-        if (! EE_Registry::instance()->CAP->current_user_can(
55
+        if ( ! EE_Registry::instance()->CAP->current_user_can(
56 56
             'ee_read_default_prices',
57 57
             'advanced_ticket_datetime_metabox'
58 58
         )) {
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
     protected function _setup_metaboxes()
81 81
     {
82 82
         //if we were going to add our own metaboxes we'd use the below.
83
-        $this->_metaboxes        = array(
83
+        $this->_metaboxes = array(
84 84
             0 => array(
85 85
                 'page_route' => array('edit', 'create_new'),
86 86
                 'func'       => 'pricing_metabox',
@@ -152,7 +152,7 @@  discard block
 block discarded – undo
152 152
             );
153 153
             $msg .= '</p><ul>';
154 154
             foreach ($format_validation as $error) {
155
-                $msg .= '<li>' . $error . '</li>';
155
+                $msg .= '<li>'.$error.'</li>';
156 156
             }
157 157
             $msg .= '</ul><p>';
158 158
             $msg .= sprintf(
@@ -181,11 +181,11 @@  discard block
 block discarded – undo
181 181
         $this->_scripts_styles = array(
182 182
             'registers'   => array(
183 183
                 'ee-tickets-datetimes-css' => array(
184
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
184
+                    'url'  => PRICING_ASSETS_URL.'event-tickets-datetimes.css',
185 185
                     'type' => 'css',
186 186
                 ),
187 187
                 'ee-dtt-ticket-metabox'    => array(
188
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
188
+                    'url'     => PRICING_ASSETS_URL.'ee-datetime-ticket-metabox.js',
189 189
                     'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
190 190
                 ),
191 191
             ),
@@ -209,9 +209,9 @@  discard block
 block discarded – undo
209 209
                             'event_espresso'
210 210
                         ),
211 211
                         'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
212
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
212
+                                                     . esc_html__('Cancel', 'event_espresso').'</button>',
213 213
                         'close_button'            => '<button class="button-secondary ee-modal-cancel">'
214
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
214
+                                                     . esc_html__('Close', 'event_espresso').'</button>',
215 215
                         'single_warning_from_tkt' => esc_html__(
216 216
                             'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
217 217
                             'event_espresso'
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
                             'event_espresso'
222 222
                         ),
223 223
                         'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
224
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
224
+                                                     . esc_html__('Dismiss', 'event_espresso').'</button>',
225 225
                     ),
226 226
                     'DTT_ERROR_MSG'         => array(
227 227
                         'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
     {
260 260
         foreach ($update_callbacks as $key => $callback) {
261 261
             if ($callback[1] === '_default_tickets_update') {
262
-                unset($update_callbacks[ $key ]);
262
+                unset($update_callbacks[$key]);
263 263
             }
264 264
         }
265 265
         $update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
@@ -316,8 +316,8 @@  discard block
 block discarded – undo
316 316
         }
317 317
         foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
318 318
             //trim all values to ensure any excess whitespace is removed.
319
-            $datetime_data                = array_map(
320
-                function ($datetime_data)
319
+            $datetime_data = array_map(
320
+                function($datetime_data)
321 321
                 {
322 322
                     return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
323 323
                 },
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
                                             && ! empty($datetime_data['DTT_EVT_end'])
328 328
                 ? $datetime_data['DTT_EVT_end']
329 329
                 : $datetime_data['DTT_EVT_start'];
330
-            $datetime_values              = array(
330
+            $datetime_values = array(
331 331
                 'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332 332
                     ? $datetime_data['DTT_ID']
333 333
                     : null,
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
             );
349 349
             // if we have an id then let's get existing object first and then set the new values.
350 350
             // Otherwise we instantiate a new object for save.
351
-            if (! empty($datetime_data['DTT_ID'])) {
351
+            if ( ! empty($datetime_data['DTT_ID'])) {
352 352
                 $datetime = EE_Registry::instance()
353 353
                                        ->load_model('Datetime', array($timezone))
354 354
                                        ->get_one_by_ID($datetime_data['DTT_ID']);
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
                 // after the add_relation_to() the autosave replaces it.
363 363
                 // We need to do this so we dont' TRASH the parent DTT.
364 364
                 // (save the ID for both key and value to avoid duplications)
365
-                $saved_dtt_ids[ $datetime->ID() ] = $datetime->ID();
365
+                $saved_dtt_ids[$datetime->ID()] = $datetime->ID();
366 366
             } else {
367 367
                 $datetime = EE_Registry::instance()->load_class(
368 368
                     'Datetime',
@@ -391,8 +391,8 @@  discard block
 block discarded – undo
391 391
             // because it is possible there was a new one created for the autosave.
392 392
             // (save the ID for both key and value to avoid duplications)
393 393
             $DTT_ID                   = $datetime->ID();
394
-            $saved_dtt_ids[ $DTT_ID ] = $DTT_ID;
395
-            $saved_dtt_objs[ $row ]   = $datetime;
394
+            $saved_dtt_ids[$DTT_ID] = $DTT_ID;
395
+            $saved_dtt_objs[$row]   = $datetime;
396 396
             //todo if ANY of these updates fail then we want the appropriate global error message.
397 397
         }
398 398
         $event->save();
@@ -457,13 +457,13 @@  discard block
 block discarded – undo
457 457
             $update_prices = $create_new_TKT = false;
458 458
             // figure out what datetimes were added to the ticket
459 459
             // and what datetimes were removed from the ticket in the session.
460
-            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
461
-            $tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
460
+            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][$row]);
461
+            $tkt_dtt_rows          = explode(',', $data['ticket_datetime_rows'][$row]);
462 462
             $datetimes_added       = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
463 463
             $datetimes_removed     = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
464 464
             // trim inputs to ensure any excess whitespace is removed.
465 465
             $tkt = array_map(
466
-                function ($ticket_data)
466
+                function($ticket_data)
467 467
                 {
468 468
                     return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
469 469
                 },
@@ -486,8 +486,8 @@  discard block
 block discarded – undo
486 486
             $base_price_id = isset($tkt['TKT_base_price_ID'])
487 487
                 ? $tkt['TKT_base_price_ID']
488 488
                 : 0;
489
-            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
490
-                ? $data['edit_prices'][ $row ]
489
+            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][$row])
490
+                ? $data['edit_prices'][$row]
491 491
                 : array();
492 492
             $now           = null;
493 493
             if (empty($tkt['TKT_start_date'])) {
@@ -499,7 +499,7 @@  discard block
 block discarded – undo
499 499
                 /**
500 500
                  * set the TKT_end_date to the first datetime attached to the ticket.
501 501
                  */
502
-                $first_dtt           = $saved_datetimes[ reset($tkt_dtt_rows) ];
502
+                $first_dtt           = $saved_datetimes[reset($tkt_dtt_rows)];
503 503
                 $tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
504 504
             }
505 505
             $TKT_values = array(
@@ -600,7 +600,7 @@  discard block
 block discarded – undo
600 600
                 if ($ticket instanceof EE_Ticket) {
601 601
                     // make sure ticket has an ID of setting relations won't work
602 602
                     $ticket->save();
603
-                    $ticket        = $this->_update_ticket_datetimes(
603
+                    $ticket = $this->_update_ticket_datetimes(
604 604
                         $ticket,
605 605
                         $saved_datetimes,
606 606
                         $datetimes_added,
@@ -634,7 +634,7 @@  discard block
 block discarded – undo
634 634
             //need to make sue that the TKT_price is accurate after saving the prices.
635 635
             $ticket->ensure_TKT_Price_correct();
636 636
             //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
637
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
637
+            if ( ! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
638 638
                 $update_prices = true;
639 639
                 $new_default   = clone $ticket;
640 640
                 $new_default->set('TKT_ID', 0);
@@ -679,7 +679,7 @@  discard block
 block discarded – undo
679 679
                 //save new TKT
680 680
                 $new_tkt->save();
681 681
                 //add new ticket to array
682
-                $saved_tickets[ $new_tkt->ID() ] = $new_tkt;
682
+                $saved_tickets[$new_tkt->ID()] = $new_tkt;
683 683
                 do_action(
684 684
                     'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
685 685
                     $new_tkt,
@@ -689,7 +689,7 @@  discard block
 block discarded – undo
689 689
                 );
690 690
             } else {
691 691
                 //add tkt to saved tkts
692
-                $saved_tickets[ $ticket->ID() ] = $ticket;
692
+                $saved_tickets[$ticket->ID()] = $ticket;
693 693
                 do_action(
694 694
                     'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
695 695
                     $ticket,
@@ -756,33 +756,33 @@  discard block
 block discarded – undo
756 756
         // to start we have to add the ticket to all the datetimes its supposed to be with,
757 757
         // and removing the ticket from datetimes it got removed from.
758 758
         // first let's add datetimes
759
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
759
+        if ( ! empty($added_datetimes) && is_array($added_datetimes)) {
760 760
             foreach ($added_datetimes as $row_id) {
761 761
                 $row_id = (int) $row_id;
762
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
763
-                    $ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
762
+                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
763
+                    $ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
764 764
                     // Is this an existing ticket (has an ID) and does it have any sold?
765 765
                     // If so, then we need to add that to the DTT sold because this DTT is getting added.
766 766
                     if ($ticket->ID() && $ticket->sold() > 0) {
767
-                        $saved_datetimes[ $row_id ]->increase_sold($ticket->sold());
768
-                        $saved_datetimes[ $row_id ]->save();
767
+                        $saved_datetimes[$row_id]->increase_sold($ticket->sold());
768
+                        $saved_datetimes[$row_id]->save();
769 769
                     }
770 770
                 }
771 771
             }
772 772
         }
773 773
         // then remove datetimes
774
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
774
+        if ( ! empty($removed_datetimes) && is_array($removed_datetimes)) {
775 775
             foreach ($removed_datetimes as $row_id) {
776 776
                 $row_id = (int) $row_id;
777 777
                 // its entirely possible that a datetime got deleted (instead of just removed from relationship.
778 778
                 // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
779
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
780
-                    $ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
779
+                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
780
+                    $ticket->_remove_relation_to($saved_datetimes[$row_id], 'Datetime');
781 781
                     // Is this an existing ticket (has an ID) and does it have any sold?
782 782
                     // If so, then we need to remove it's sold from the DTT_sold.
783 783
                     if ($ticket->ID() && $ticket->sold() > 0) {
784
-                        $saved_datetimes[ $row_id ]->decrease_sold($ticket->sold());
785
-                        $saved_datetimes[ $row_id ]->save();
784
+                        $saved_datetimes[$row_id]->decrease_sold($ticket->sold());
785
+                        $saved_datetimes[$row_id]->save();
786 786
                     }
787 787
                 }
788 788
             }
@@ -895,7 +895,7 @@  discard block
 block discarded – undo
895 895
             );
896 896
         }
897 897
         //possibly need to save tkt
898
-        if (! $ticket->ID()) {
898
+        if ( ! $ticket->ID()) {
899 899
             $ticket->save();
900 900
         }
901 901
         foreach ($prices as $row => $prc) {
@@ -929,17 +929,17 @@  discard block
 block discarded – undo
929 929
                 }
930 930
             }
931 931
             $price->save();
932
-            $updated_prices[ $price->ID() ] = $price;
932
+            $updated_prices[$price->ID()] = $price;
933 933
             $ticket->_add_relation_to($price, 'Price');
934 934
         }
935 935
         //now let's remove any prices that got removed from the ticket
936
-        if (! empty ($current_prices_on_ticket)) {
936
+        if ( ! empty ($current_prices_on_ticket)) {
937 937
             $current          = array_keys($current_prices_on_ticket);
938 938
             $updated          = array_keys($updated_prices);
939 939
             $prices_to_remove = array_diff($current, $updated);
940
-            if (! empty($prices_to_remove)) {
940
+            if ( ! empty($prices_to_remove)) {
941 941
                 foreach ($prices_to_remove as $prc_id) {
942
-                    $p = $current_prices_on_ticket[ $prc_id ];
942
+                    $p = $current_prices_on_ticket[$prc_id];
943 943
                     $ticket->_remove_relation_to($p, 'Price');
944 944
                     //delete permanently the price
945 945
                     $p->delete_permanently();
@@ -1028,7 +1028,7 @@  discard block
 block discarded – undo
1028 1028
             'ee_collapsible_status'    => ' ee-collapsible-open'
1029 1029
             //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1030 1030
         );
1031
-        $timezone           = $event instanceof EE_Event ? $event->timezone_string() : null;
1031
+        $timezone = $event instanceof EE_Event ? $event->timezone_string() : null;
1032 1032
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1033 1033
         /**
1034 1034
          * 1. Start with retrieving Datetimes
@@ -1090,18 +1090,18 @@  discard block
 block discarded – undo
1090 1090
                 $TKT_ID     = $ticket->get('TKT_ID');
1091 1091
                 $ticket_row = $ticket->get('TKT_row');
1092 1092
                 //we only want unique tickets in our final display!!
1093
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1093
+                if ( ! in_array($TKT_ID, $existing_ticket_ids, true)) {
1094 1094
                     $existing_ticket_ids[] = $TKT_ID;
1095 1095
                     $all_tickets[]         = $ticket;
1096 1096
                 }
1097 1097
                 //temporary cache of this ticket info for this datetime for later processing of datetime rows.
1098
-                $datetime_tickets[ $DTT_ID ][] = $ticket_row;
1098
+                $datetime_tickets[$DTT_ID][] = $ticket_row;
1099 1099
                 //temporary cache of this datetime info for this ticket for later processing of ticket rows.
1100 1100
                 if (
1101
-                    ! isset($ticket_datetimes[ $TKT_ID ])
1102
-                    || ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1101
+                    ! isset($ticket_datetimes[$TKT_ID])
1102
+                    || ! in_array($datetime_row, $ticket_datetimes[$TKT_ID], true)
1103 1103
                 ) {
1104
-                    $ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1104
+                    $ticket_datetimes[$TKT_ID][] = $datetime_row;
1105 1105
                 }
1106 1106
             }
1107 1107
             $datetime_row++;
@@ -1112,7 +1112,7 @@  discard block
 block discarded – undo
1112 1112
         //sort $all_tickets by order
1113 1113
         usort(
1114 1114
             $all_tickets,
1115
-            function (EE_Ticket $a, EE_Ticket $b)
1115
+            function(EE_Ticket $a, EE_Ticket $b)
1116 1116
             {
1117 1117
                 $a_order = (int) $a->get('TKT_order');
1118 1118
                 $b_order = (int) $b->get('TKT_order');
@@ -1151,7 +1151,7 @@  discard block
 block discarded – undo
1151 1151
         }
1152 1152
         $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1153 1153
         EEH_Template::display_template(
1154
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1154
+            PRICING_TEMPLATE_PATH.'event_tickets_metabox_main.template.php',
1155 1155
             $main_template_args
1156 1156
         );
1157 1157
     }
@@ -1193,7 +1193,7 @@  discard block
 block discarded – undo
1193 1193
             'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1194 1194
         );
1195 1195
         return EEH_Template::display_template(
1196
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1196
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_row_wrapper.template.php',
1197 1197
             $dtt_display_template_args,
1198 1198
             true
1199 1199
         );
@@ -1262,7 +1262,7 @@  discard block
 block discarded – undo
1262 1262
             $this->_is_creating_event
1263 1263
         );
1264 1264
         return EEH_Template::display_template(
1265
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1265
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_edit_row.template.php',
1266 1266
             $template_args,
1267 1267
             true
1268 1268
         );
@@ -1303,7 +1303,7 @@  discard block
 block discarded – undo
1303 1303
             'DTT_ID'                            => $default ? '' : $datetime->ID(),
1304 1304
         );
1305 1305
         //need to setup the list items (but only if this isn't a default skeleton setup)
1306
-        if (! $default) {
1306
+        if ( ! $default) {
1307 1307
             $ticket_row = 1;
1308 1308
             foreach ($all_tickets as $ticket) {
1309 1309
                 $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
@@ -1329,7 +1329,7 @@  discard block
 block discarded – undo
1329 1329
             $this->_is_creating_event
1330 1330
         );
1331 1331
         return EEH_Template::display_template(
1332
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1332
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_attached_tickets_row.template.php',
1333 1333
             $template_args,
1334 1334
             true
1335 1335
         );
@@ -1355,8 +1355,8 @@  discard block
 block discarded – undo
1355 1355
         $datetime_tickets = array(),
1356 1356
         $default
1357 1357
     ) {
1358
-        $dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1359
-            ? $datetime_tickets[ $datetime->ID() ]
1358
+        $dtt_tkts      = $datetime instanceof EE_Datetime && isset($datetime_tickets[$datetime->ID()])
1359
+            ? $datetime_tickets[$datetime->ID()]
1360 1360
             : array();
1361 1361
         $display_row   = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1362 1362
         $no_ticket     = $default && empty($ticket);
@@ -1377,8 +1377,8 @@  discard block
 block discarded – undo
1377 1377
                 ? 'TKTNAME'
1378 1378
                 : $ticket->get('TKT_name'),
1379 1379
             'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1380
-                ? ' tkt-status-' . EE_Ticket::onsale
1381
-                : ' tkt-status-' . $ticket->ticket_status(),
1380
+                ? ' tkt-status-'.EE_Ticket::onsale
1381
+                : ' tkt-status-'.$ticket->ticket_status(),
1382 1382
         );
1383 1383
         //filter template args
1384 1384
         $template_args = apply_filters(
@@ -1393,7 +1393,7 @@  discard block
 block discarded – undo
1393 1393
             $this->_is_creating_event
1394 1394
         );
1395 1395
         return EEH_Template::display_template(
1396
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1396
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_dtt_tickets_list.template.php',
1397 1397
             $template_args,
1398 1398
             true
1399 1399
         );
@@ -1445,19 +1445,19 @@  discard block
 block discarded – undo
1445 1445
         // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1446 1446
         // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1447 1447
         $default_dtt      = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1448
-        $tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1449
-            ? $ticket_datetimes[ $ticket->ID() ]
1448
+        $tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1449
+            ? $ticket_datetimes[$ticket->ID()]
1450 1450
             : array();
1451 1451
         $ticket_subtotal  = $default ? 0 : $ticket->get_ticket_subtotal();
1452 1452
         $base_price       = $default ? null : $ticket->base_price();
1453 1453
         $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1454 1454
         //breaking out complicated condition for ticket_status
1455 1455
         if ($default) {
1456
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1456
+            $ticket_status_class = ' tkt-status-'.EE_Ticket::onsale;
1457 1457
         } else {
1458 1458
             $ticket_status_class = $ticket->is_default()
1459
-                ? ' tkt-status-' . EE_Ticket::onsale
1460
-                : ' tkt-status-' . $ticket->ticket_status();
1459
+                ? ' tkt-status-'.EE_Ticket::onsale
1460
+                : ' tkt-status-'.$ticket->ticket_status();
1461 1461
         }
1462 1462
         //breaking out complicated condition for TKT_taxable
1463 1463
         if ($default) {
@@ -1482,7 +1482,7 @@  discard block
 block discarded – undo
1482 1482
                 $TKT_min = '';
1483 1483
             }
1484 1484
         }
1485
-        $template_args                 = array(
1485
+        $template_args = array(
1486 1486
             'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1487 1487
             'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1488 1488
             //on initial page load this will always be the correct order.
@@ -1549,7 +1549,7 @@  discard block
 block discarded – undo
1549 1549
                 : ' style="display:none;"',
1550 1550
             'show_price_mod_button'         => count($prices) > 1
1551 1551
                                                || ($default && $count_price_mods > 0)
1552
-                                               || (! $default && $ticket->deleted())
1552
+                                               || ( ! $default && $ticket->deleted())
1553 1553
                 ? ' style="display:none;"'
1554 1554
                 : '',
1555 1555
             'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
@@ -1591,7 +1591,7 @@  discard block
 block discarded – undo
1591 1591
             //if empty then the start date will be now.
1592 1592
             $template_args['TKT_start_date']   = date($this->_date_time_format,
1593 1593
                 current_time('timestamp'));
1594
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1594
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1595 1595
         }
1596 1596
         if (empty($template_args['TKT_end_date'])) {
1597 1597
             //get the earliest datetime (if present);
@@ -1601,7 +1601,7 @@  discard block
 block discarded – undo
1601 1601
                     array('order_by' => array('DTT_EVT_start' => 'ASC'))
1602 1602
                 )
1603 1603
                 : null;
1604
-            if (! empty($earliest_dtt)) {
1604
+            if ( ! empty($earliest_dtt)) {
1605 1605
                 $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1606 1606
                     'DTT_EVT_start',
1607 1607
                     $this->_date_time_format
@@ -1615,10 +1615,10 @@  discard block
 block discarded – undo
1615 1615
                     )
1616 1616
                 );
1617 1617
             }
1618
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1618
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1619 1619
         }
1620 1620
         //generate ticket_datetime items
1621
-        if (! $default) {
1621
+        if ( ! $default) {
1622 1622
             $datetime_row = 1;
1623 1623
             foreach ($all_datetimes as $datetime) {
1624 1624
                 $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
@@ -1634,7 +1634,7 @@  discard block
 block discarded – undo
1634 1634
         }
1635 1635
         $price_row = 1;
1636 1636
         foreach ($prices as $price) {
1637
-            if (! $price instanceof EE_Price) {
1637
+            if ( ! $price instanceof EE_Price) {
1638 1638
                 continue;
1639 1639
             }
1640 1640
             if ($price->is_base_price()) {
@@ -1667,7 +1667,7 @@  discard block
 block discarded – undo
1667 1667
             $this->_is_creating_event
1668 1668
         );
1669 1669
         return EEH_Template::display_template(
1670
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1670
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_row.template.php',
1671 1671
             $template_args,
1672 1672
             true
1673 1673
         );
@@ -1706,8 +1706,8 @@  discard block
 block discarded – undo
1706 1706
                 $ticket,
1707 1707
                 $this->_is_creating_event
1708 1708
             );
1709
-            $tax_rows      .= EEH_Template::display_template(
1710
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1709
+            $tax_rows .= EEH_Template::display_template(
1710
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_tax_row.template.php',
1711 1711
                 $template_args,
1712 1712
                 true
1713 1713
             );
@@ -1827,7 +1827,7 @@  discard block
 block discarded – undo
1827 1827
             $this->_is_creating_event
1828 1828
         );
1829 1829
         return EEH_Template::display_template(
1830
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1830
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_price_row.template.php',
1831 1831
             $template_args,
1832 1832
             true
1833 1833
         );
@@ -1897,7 +1897,7 @@  discard block
 block discarded – undo
1897 1897
             $this->_is_creating_event
1898 1898
         );
1899 1899
         return EEH_Template::display_template(
1900
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1900
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_type_base.template.php',
1901 1901
             $template_args,
1902 1902
             true
1903 1903
         );
@@ -1927,7 +1927,7 @@  discard block
 block discarded – undo
1927 1927
     ) {
1928 1928
         $select_name = $default && ! $price instanceof EE_Price
1929 1929
             ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1930
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1930
+            : 'edit_prices['.$ticket_row.']['.$price_row.'][PRT_ID]';
1931 1931
         /** @var EEM_Price_Type $price_type_model */
1932 1932
         $price_type_model       = EE_Registry::instance()->load_model('Price_Type');
1933 1933
         $price_types            = $price_type_model->get_all(array(
@@ -1945,23 +1945,23 @@  discard block
 block discarded – undo
1945 1945
         $price_option_spans     = '';
1946 1946
         //setup price types for selector
1947 1947
         foreach ($price_types as $price_type) {
1948
-            if (! $price_type instanceof EE_Price_Type) {
1948
+            if ( ! $price_type instanceof EE_Price_Type) {
1949 1949
                 continue;
1950 1950
             }
1951
-            $all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
1951
+            $all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
1952 1952
             //while we're in the loop let's setup the option spans used by js
1953
-            $span_args          = array(
1953
+            $span_args = array(
1954 1954
                 'PRT_ID'         => $price_type->ID(),
1955 1955
                 'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1956 1956
                 'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1957 1957
             );
1958 1958
             $price_option_spans .= EEH_Template::display_template(
1959
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1959
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_option_span.template.php',
1960 1960
                 $span_args,
1961 1961
                 true
1962 1962
             );
1963 1963
         }
1964
-        $select_name               = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
1964
+        $select_name               = $disabled ? 'archive_price['.$ticket_row.']['.$price_row.'][PRT_ID]'
1965 1965
             : $select_name;
1966 1966
         $select_input              = new EE_Select_Input(
1967 1967
             $all_price_types,
@@ -1987,7 +1987,7 @@  discard block
 block discarded – undo
1987 1987
             'price_selected_is_percent' => $price_selected_is_percent,
1988 1988
             'disabled'                  => $disabled,
1989 1989
         );
1990
-        $template_args             = apply_filters(
1990
+        $template_args = apply_filters(
1991 1991
             'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1992 1992
             $template_args,
1993 1993
             $ticket_row,
@@ -1998,7 +1998,7 @@  discard block
 block discarded – undo
1998 1998
             $this->_is_creating_event
1999 1999
         );
2000 2000
         return EEH_Template::display_template(
2001
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2001
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_modifier_selector.template.php',
2002 2002
             $template_args,
2003 2003
             true
2004 2004
         );
@@ -2024,8 +2024,8 @@  discard block
 block discarded – undo
2024 2024
         $ticket_datetimes = array(),
2025 2025
         $default
2026 2026
     ) {
2027
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2028
-            ? $ticket_datetimes[ $ticket->ID() ]
2027
+        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
2028
+            ? $ticket_datetimes[$ticket->ID()]
2029 2029
             : array();
2030 2030
         $template_args = array(
2031 2031
             'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
@@ -2057,7 +2057,7 @@  discard block
 block discarded – undo
2057 2057
             $this->_is_creating_event
2058 2058
         );
2059 2059
         return EEH_Template::display_template(
2060
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2060
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2061 2061
             $template_args,
2062 2062
             true
2063 2063
         );
@@ -2134,7 +2134,7 @@  discard block
 block discarded – undo
2134 2134
                 true
2135 2135
             ),
2136 2136
         );
2137
-        $ticket_row    = 1;
2137
+        $ticket_row = 1;
2138 2138
         foreach ($all_tickets as $ticket) {
2139 2139
             $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2140 2140
                 'DTTNUM',
@@ -2163,11 +2163,11 @@  discard block
 block discarded – undo
2163 2163
         $default_prices = $price_model->get_all_default_prices();
2164 2164
         $price_row      = 1;
2165 2165
         foreach ($default_prices as $price) {
2166
-            if (! $price instanceof EE_Price) {
2166
+            if ( ! $price instanceof EE_Price) {
2167 2167
                 continue;
2168 2168
             }
2169 2169
             if ($price->is_base_price()) {
2170
-                $template_args['default_base_price_amount']      = $price->get_pretty(
2170
+                $template_args['default_base_price_amount'] = $price->get_pretty(
2171 2171
                     'PRC_amount',
2172 2172
                     'localized_float'
2173 2173
                 );
@@ -2200,7 +2200,7 @@  discard block
 block discarded – undo
2200 2200
             $this->_is_creating_event
2201 2201
         );
2202 2202
         return EEH_Template::display_template(
2203
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2203
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_js_structure.template.php',
2204 2204
             $template_args,
2205 2205
             true
2206 2206
         );
Please login to merge, or discard this patch.
core/db_classes/EE_Datetime.class.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -578,7 +578,7 @@  discard block
 block discarded – undo
578 578
      * @param string $dt_frmt     string representation of date format defaults to WP settings
579 579
      * @param string $conjunction conjunction junction what's your function ?
580 580
      *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
581
-     * @return mixed              string on success, FALSE on fail
581
+     * @return string              string on success, FALSE on fail
582 582
      * @throws ReflectionException
583 583
      * @throws InvalidArgumentException
584 584
      * @throws InvalidInterfaceException
@@ -686,7 +686,7 @@  discard block
 block discarded – undo
686 686
      * @param string $tm_format   string representation of time format defaults to 'g:i a'
687 687
      * @param string $conjunction conjunction junction what's your function ?
688 688
      *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
689
-     * @return mixed              string on success, FALSE on fail
689
+     * @return string              string on success, FALSE on fail
690 690
      * @throws ReflectionException
691 691
      * @throws InvalidArgumentException
692 692
      * @throws InvalidInterfaceException
Please login to merge, or discard this patch.
Indentation   +1270 added lines, -1270 removed lines patch added patch discarded remove patch
@@ -14,1276 +14,1276 @@
 block discarded – undo
14 14
 class EE_Datetime extends EE_Soft_Delete_Base_Class
15 15
 {
16 16
 
17
-    /**
18
-     * constant used by get_active_status, indicates datetime has no more available spaces
19
-     */
20
-    const sold_out = 'DTS';
21
-
22
-    /**
23
-     * constant used by get_active_status, indicating datetime is still active (even is not over, can be registered-for)
24
-     */
25
-    const active = 'DTA';
26
-
27
-    /**
28
-     * constant used by get_active_status, indicating the datetime cannot be used for registrations yet, but has not
29
-     * expired
30
-     */
31
-    const upcoming = 'DTU';
32
-
33
-    /**
34
-     * Datetime is postponed
35
-     */
36
-    const postponed = 'DTP';
37
-
38
-    /**
39
-     * Datetime is cancelled
40
-     */
41
-    const cancelled = 'DTC';
42
-
43
-    /**
44
-     * constant used by get_active_status, indicates datetime has expired (event is over)
45
-     */
46
-    const expired = 'DTE';
47
-
48
-    /**
49
-     * constant used in various places indicating that an event is INACTIVE (not yet ready to be published)
50
-     */
51
-    const inactive = 'DTI';
52
-
53
-
54
-    /**
55
-     * @param array  $props_n_values    incoming values
56
-     * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
57
-     * @param array $date_formats       incoming date_formats in an array where the first value is the date_format
58
-     *                                  and the second value is the time format
59
-     * @return EE_Datetime
60
-     * @throws ReflectionException
61
-     * @throws InvalidArgumentException
62
-     * @throws InvalidInterfaceException
63
-     * @throws InvalidDataTypeException
64
-     * @throws EE_Error
65
-     */
66
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
67
-    {
68
-        $has_object = parent::_check_for_object(
69
-            $props_n_values,
70
-            __CLASS__,
71
-            $timezone,
72
-            $date_formats
73
-        );
74
-        return $has_object
75
-            ? $has_object
76
-            : new self($props_n_values, false, $timezone, $date_formats);
77
-    }
78
-
79
-
80
-    /**
81
-     * @param array  $props_n_values  incoming values from the database
82
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
83
-     *                                the website will be used.
84
-     * @return EE_Datetime
85
-     * @throws ReflectionException
86
-     * @throws InvalidArgumentException
87
-     * @throws InvalidInterfaceException
88
-     * @throws InvalidDataTypeException
89
-     * @throws EE_Error
90
-     */
91
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
92
-    {
93
-        return new self($props_n_values, true, $timezone);
94
-    }
95
-
96
-
97
-    /**
98
-     * @param $name
99
-     * @throws ReflectionException
100
-     * @throws InvalidArgumentException
101
-     * @throws InvalidInterfaceException
102
-     * @throws InvalidDataTypeException
103
-     * @throws EE_Error
104
-     */
105
-    public function set_name($name)
106
-    {
107
-        $this->set('DTT_name', $name);
108
-    }
109
-
110
-
111
-    /**
112
-     * @param $description
113
-     * @throws ReflectionException
114
-     * @throws InvalidArgumentException
115
-     * @throws InvalidInterfaceException
116
-     * @throws InvalidDataTypeException
117
-     * @throws EE_Error
118
-     */
119
-    public function set_description($description)
120
-    {
121
-        $this->set('DTT_description', $description);
122
-    }
123
-
124
-
125
-    /**
126
-     * Set event start date
127
-     * set the start date for an event
128
-     *
129
-     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
130
-     * @throws ReflectionException
131
-     * @throws InvalidArgumentException
132
-     * @throws InvalidInterfaceException
133
-     * @throws InvalidDataTypeException
134
-     * @throws EE_Error
135
-     */
136
-    public function set_start_date($date)
137
-    {
138
-        $this->_set_date_for($date, 'DTT_EVT_start');
139
-    }
140
-
141
-
142
-    /**
143
-     * Set event start time
144
-     * set the start time for an event
145
-     *
146
-     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
147
-     * @throws ReflectionException
148
-     * @throws InvalidArgumentException
149
-     * @throws InvalidInterfaceException
150
-     * @throws InvalidDataTypeException
151
-     * @throws EE_Error
152
-     */
153
-    public function set_start_time($time)
154
-    {
155
-        $this->_set_time_for($time, 'DTT_EVT_start');
156
-    }
157
-
158
-
159
-    /**
160
-     * Set event end date
161
-     * set the end date for an event
162
-     *
163
-     * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
164
-     * @throws ReflectionException
165
-     * @throws InvalidArgumentException
166
-     * @throws InvalidInterfaceException
167
-     * @throws InvalidDataTypeException
168
-     * @throws EE_Error
169
-     */
170
-    public function set_end_date($date)
171
-    {
172
-        $this->_set_date_for($date, 'DTT_EVT_end');
173
-    }
174
-
175
-
176
-    /**
177
-     * Set event end time
178
-     * set the end time for an event
179
-     *
180
-     * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
181
-     * @throws ReflectionException
182
-     * @throws InvalidArgumentException
183
-     * @throws InvalidInterfaceException
184
-     * @throws InvalidDataTypeException
185
-     * @throws EE_Error
186
-     */
187
-    public function set_end_time($time)
188
-    {
189
-        $this->_set_time_for($time, 'DTT_EVT_end');
190
-    }
191
-
192
-
193
-    /**
194
-     * Set registration limit
195
-     * set the maximum number of attendees that can be registered for this datetime slot
196
-     *
197
-     * @param int $reg_limit
198
-     * @throws ReflectionException
199
-     * @throws InvalidArgumentException
200
-     * @throws InvalidInterfaceException
201
-     * @throws InvalidDataTypeException
202
-     * @throws EE_Error
203
-     */
204
-    public function set_reg_limit($reg_limit)
205
-    {
206
-        $this->set('DTT_reg_limit', $reg_limit);
207
-    }
208
-
209
-
210
-    /**
211
-     * get the number of tickets sold for this datetime slot
212
-     *
213
-     * @return mixed int on success, FALSE on fail
214
-     * @throws ReflectionException
215
-     * @throws InvalidArgumentException
216
-     * @throws InvalidInterfaceException
217
-     * @throws InvalidDataTypeException
218
-     * @throws EE_Error
219
-     */
220
-    public function sold()
221
-    {
222
-        return $this->get_raw('DTT_sold');
223
-    }
224
-
225
-
226
-    /**
227
-     * @param int $sold
228
-     * @throws ReflectionException
229
-     * @throws InvalidArgumentException
230
-     * @throws InvalidInterfaceException
231
-     * @throws InvalidDataTypeException
232
-     * @throws EE_Error
233
-     */
234
-    public function set_sold($sold)
235
-    {
236
-        // sold can not go below zero
237
-        $sold = max(0, $sold);
238
-        $this->set('DTT_sold', $sold);
239
-    }
240
-
241
-
242
-    /**
243
-     * increments sold by amount passed by $qty
244
-     *
245
-     * @param int $qty
246
-     * @throws ReflectionException
247
-     * @throws InvalidArgumentException
248
-     * @throws InvalidInterfaceException
249
-     * @throws InvalidDataTypeException
250
-     * @throws EE_Error
251
-     */
252
-    public function increase_sold($qty = 1)
253
-    {
254
-        $sold = $this->sold() + $qty;
255
-        // remove ticket reservation
256
-        $this->decrease_reserved($qty);
257
-        $this->set_sold($sold);
258
-        do_action(
259
-            'AHEE__EE_Datetime__increase_sold',
260
-            $this,
261
-            $qty,
262
-            $sold
263
-        );
264
-    }
265
-
266
-
267
-    /**
268
-     * decrements (subtracts) sold amount passed by $qty
269
-     *
270
-     * @param int $qty
271
-     * @throws ReflectionException
272
-     * @throws InvalidArgumentException
273
-     * @throws InvalidInterfaceException
274
-     * @throws InvalidDataTypeException
275
-     * @throws EE_Error
276
-     */
277
-    public function decrease_sold($qty = 1)
278
-    {
279
-        $sold = $this->sold() - $qty;
280
-        $this->set_sold($sold);
281
-        do_action(
282
-            'AHEE__EE_Datetime__decrease_sold',
283
-            $this,
284
-            $qty,
285
-            $sold
286
-        );
287
-    }
288
-
289
-
290
-    /**
291
-     * Gets qty of reserved tickets for this datetime
292
-     *
293
-     * @return int
294
-     * @throws ReflectionException
295
-     * @throws InvalidArgumentException
296
-     * @throws InvalidInterfaceException
297
-     * @throws InvalidDataTypeException
298
-     * @throws EE_Error
299
-     */
300
-    public function reserved()
301
-    {
302
-        return $this->get_raw('DTT_reserved');
303
-    }
304
-
305
-
306
-    /**
307
-     * Sets qty of reserved tickets for this datetime
308
-     *
309
-     * @param int $reserved
310
-     * @throws ReflectionException
311
-     * @throws InvalidArgumentException
312
-     * @throws InvalidInterfaceException
313
-     * @throws InvalidDataTypeException
314
-     * @throws EE_Error
315
-     */
316
-    public function set_reserved($reserved)
317
-    {
318
-        // reserved can not go below zero
319
-        $reserved = max(0, (int) $reserved);
320
-        $this->set('DTT_reserved', $reserved);
321
-    }
322
-
323
-
324
-    /**
325
-     * increments reserved by amount passed by $qty
326
-     *
327
-     * @param int $qty
328
-     * @return void
329
-     * @throws ReflectionException
330
-     * @throws InvalidArgumentException
331
-     * @throws InvalidInterfaceException
332
-     * @throws InvalidDataTypeException
333
-     * @throws EE_Error
334
-     */
335
-    public function increase_reserved($qty = 1)
336
-    {
337
-        $reserved = $this->reserved() + absint($qty);
338
-        do_action(
339
-            'AHEE__EE_Datetime__increase_reserved',
340
-            $this,
341
-            $qty,
342
-            $reserved
343
-        );
344
-        $this->set_reserved($reserved);
345
-    }
346
-
347
-
348
-    /**
349
-     * decrements (subtracts) reserved by amount passed by $qty
350
-     *
351
-     * @param int $qty
352
-     * @return void
353
-     * @throws ReflectionException
354
-     * @throws InvalidArgumentException
355
-     * @throws InvalidInterfaceException
356
-     * @throws InvalidDataTypeException
357
-     * @throws EE_Error
358
-     */
359
-    public function decrease_reserved($qty = 1)
360
-    {
361
-        $reserved = $this->reserved() - absint($qty);
362
-        do_action(
363
-            'AHEE__EE_Datetime__decrease_reserved',
364
-            $this,
365
-            $qty,
366
-            $reserved
367
-        );
368
-        $this->set_reserved($reserved);
369
-    }
370
-
371
-
372
-    /**
373
-     * total sold and reserved tickets
374
-     *
375
-     * @return int
376
-     * @throws ReflectionException
377
-     * @throws InvalidArgumentException
378
-     * @throws InvalidInterfaceException
379
-     * @throws InvalidDataTypeException
380
-     * @throws EE_Error
381
-     */
382
-    public function sold_and_reserved()
383
-    {
384
-        return $this->sold() + $this->reserved();
385
-    }
386
-
387
-
388
-    /**
389
-     * returns the datetime name
390
-     *
391
-     * @return string
392
-     * @throws ReflectionException
393
-     * @throws InvalidArgumentException
394
-     * @throws InvalidInterfaceException
395
-     * @throws InvalidDataTypeException
396
-     * @throws EE_Error
397
-     */
398
-    public function name()
399
-    {
400
-        return $this->get('DTT_name');
401
-    }
402
-
403
-
404
-    /**
405
-     * returns the datetime description
406
-     *
407
-     * @return string
408
-     * @throws ReflectionException
409
-     * @throws InvalidArgumentException
410
-     * @throws InvalidInterfaceException
411
-     * @throws InvalidDataTypeException
412
-     * @throws EE_Error
413
-     */
414
-    public function description()
415
-    {
416
-        return $this->get('DTT_description');
417
-    }
418
-
419
-
420
-    /**
421
-     * This helper simply returns whether the event_datetime for the current datetime is a primary datetime
422
-     *
423
-     * @return boolean  TRUE if is primary, FALSE if not.
424
-     * @throws ReflectionException
425
-     * @throws InvalidArgumentException
426
-     * @throws InvalidInterfaceException
427
-     * @throws InvalidDataTypeException
428
-     * @throws EE_Error
429
-     */
430
-    public function is_primary()
431
-    {
432
-        return $this->get('DTT_is_primary');
433
-    }
434
-
435
-
436
-    /**
437
-     * This helper simply returns the order for the datetime
438
-     *
439
-     * @return int  The order of the datetime for this event.
440
-     * @throws ReflectionException
441
-     * @throws InvalidArgumentException
442
-     * @throws InvalidInterfaceException
443
-     * @throws InvalidDataTypeException
444
-     * @throws EE_Error
445
-     */
446
-    public function order()
447
-    {
448
-        return $this->get('DTT_order');
449
-    }
450
-
451
-
452
-    /**
453
-     * This helper simply returns the parent id for the datetime
454
-     *
455
-     * @return int
456
-     * @throws ReflectionException
457
-     * @throws InvalidArgumentException
458
-     * @throws InvalidInterfaceException
459
-     * @throws InvalidDataTypeException
460
-     * @throws EE_Error
461
-     */
462
-    public function parent()
463
-    {
464
-        return $this->get('DTT_parent');
465
-    }
466
-
467
-
468
-    /**
469
-     * show date and/or time
470
-     *
471
-     * @param string $date_or_time    whether to display a date or time or both
472
-     * @param string $start_or_end    whether to display start or end datetimes
473
-     * @param string $dt_frmt
474
-     * @param string $tm_frmt
475
-     * @param bool   $echo            whether we echo or return (note echoing uses "pretty" formats,
476
-     *                                otherwise we use the standard formats)
477
-     * @return string|bool  string on success, FALSE on fail
478
-     * @throws ReflectionException
479
-     * @throws InvalidArgumentException
480
-     * @throws InvalidInterfaceException
481
-     * @throws InvalidDataTypeException
482
-     * @throws EE_Error
483
-     */
484
-    private function _show_datetime(
485
-        $date_or_time = null,
486
-        $start_or_end = 'start',
487
-        $dt_frmt = '',
488
-        $tm_frmt = '',
489
-        $echo = false
490
-    ) {
491
-        $field_name = "DTT_EVT_{$start_or_end}";
492
-        $dtt        = $this->_get_datetime(
493
-            $field_name,
494
-            $dt_frmt,
495
-            $tm_frmt,
496
-            $date_or_time,
497
-            $echo
498
-        );
499
-        if (! $echo) {
500
-            return $dtt;
501
-        }
502
-        return '';
503
-    }
504
-
505
-
506
-    /**
507
-     * get event start date.  Provide either the date format, or NULL to re-use the
508
-     * last-used format, or '' to use the default date format
509
-     *
510
-     * @param string $dt_frmt   string representation of date format defaults to 'F j, Y'
511
-     * @return mixed            string on success, FALSE on fail
512
-     * @throws ReflectionException
513
-     * @throws InvalidArgumentException
514
-     * @throws InvalidInterfaceException
515
-     * @throws InvalidDataTypeException
516
-     * @throws EE_Error
517
-     */
518
-    public function start_date($dt_frmt = '')
519
-    {
520
-        return $this->_show_datetime('D', 'start', $dt_frmt);
521
-    }
522
-
523
-
524
-    /**
525
-     * Echoes start_date()
526
-     *
527
-     * @param string $dt_frmt
528
-     * @throws ReflectionException
529
-     * @throws InvalidArgumentException
530
-     * @throws InvalidInterfaceException
531
-     * @throws InvalidDataTypeException
532
-     * @throws EE_Error
533
-     */
534
-    public function e_start_date($dt_frmt = '')
535
-    {
536
-        $this->_show_datetime('D', 'start', $dt_frmt, null, true);
537
-    }
538
-
539
-
540
-    /**
541
-     * get end date. Provide either the date format, or NULL to re-use the
542
-     * last-used format, or '' to use the default date format
543
-     *
544
-     * @param string $dt_frmt   string representation of date format defaults to 'F j, Y'
545
-     * @return mixed            string on success, FALSE on fail
546
-     * @throws ReflectionException
547
-     * @throws InvalidArgumentException
548
-     * @throws InvalidInterfaceException
549
-     * @throws InvalidDataTypeException
550
-     * @throws EE_Error
551
-     */
552
-    public function end_date($dt_frmt = '')
553
-    {
554
-        return $this->_show_datetime('D', 'end', $dt_frmt);
555
-    }
556
-
557
-
558
-    /**
559
-     * Echoes the end date. See end_date()
560
-     *
561
-     * @param string $dt_frmt
562
-     * @throws ReflectionException
563
-     * @throws InvalidArgumentException
564
-     * @throws InvalidInterfaceException
565
-     * @throws InvalidDataTypeException
566
-     * @throws EE_Error
567
-     */
568
-    public function e_end_date($dt_frmt = '')
569
-    {
570
-        $this->_show_datetime('D', 'end', $dt_frmt, null, true);
571
-    }
572
-
573
-
574
-    /**
575
-     * get date_range - meaning the start AND end date
576
-     *
577
-     * @access public
578
-     * @param string $dt_frmt     string representation of date format defaults to WP settings
579
-     * @param string $conjunction conjunction junction what's your function ?
580
-     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
581
-     * @return mixed              string on success, FALSE on fail
582
-     * @throws ReflectionException
583
-     * @throws InvalidArgumentException
584
-     * @throws InvalidInterfaceException
585
-     * @throws InvalidDataTypeException
586
-     * @throws EE_Error
587
-     */
588
-    public function date_range($dt_frmt = '', $conjunction = ' - ')
589
-    {
590
-        $dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
591
-        $start   = str_replace(
592
-            ' ',
593
-            '&nbsp;',
594
-            $this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
595
-        );
596
-        $end     = str_replace(
597
-            ' ',
598
-            '&nbsp;',
599
-            $this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
600
-        );
601
-        return $start !== $end ? $start . $conjunction . $end : $start;
602
-    }
603
-
604
-
605
-    /**
606
-     * @param string $dt_frmt
607
-     * @param string $conjunction
608
-     * @throws ReflectionException
609
-     * @throws InvalidArgumentException
610
-     * @throws InvalidInterfaceException
611
-     * @throws InvalidDataTypeException
612
-     * @throws EE_Error
613
-     */
614
-    public function e_date_range($dt_frmt = '', $conjunction = ' - ')
615
-    {
616
-        echo $this->date_range($dt_frmt, $conjunction);
617
-    }
618
-
619
-
620
-    /**
621
-     * get start time
622
-     *
623
-     * @param string $tm_format - string representation of time format defaults to 'g:i a'
624
-     * @return mixed        string on success, FALSE on fail
625
-     * @throws ReflectionException
626
-     * @throws InvalidArgumentException
627
-     * @throws InvalidInterfaceException
628
-     * @throws InvalidDataTypeException
629
-     * @throws EE_Error
630
-     */
631
-    public function start_time($tm_format = '')
632
-    {
633
-        return $this->_show_datetime('T', 'start', null, $tm_format);
634
-    }
635
-
636
-
637
-    /**
638
-     * @param string $tm_format
639
-     * @throws ReflectionException
640
-     * @throws InvalidArgumentException
641
-     * @throws InvalidInterfaceException
642
-     * @throws InvalidDataTypeException
643
-     * @throws EE_Error
644
-     */
645
-    public function e_start_time($tm_format = '')
646
-    {
647
-        $this->_show_datetime('T', 'start', null, $tm_format, true);
648
-    }
649
-
650
-
651
-    /**
652
-     * get end time
653
-     *
654
-     * @param string $tm_format     string representation of time format defaults to 'g:i a'
655
-     * @return mixed                string on success, FALSE on fail
656
-     * @throws ReflectionException
657
-     * @throws InvalidArgumentException
658
-     * @throws InvalidInterfaceException
659
-     * @throws InvalidDataTypeException
660
-     * @throws EE_Error
661
-     */
662
-    public function end_time($tm_format = '')
663
-    {
664
-        return $this->_show_datetime('T', 'end', null, $tm_format);
665
-    }
666
-
667
-
668
-    /**
669
-     * @param string $tm_format
670
-     * @throws ReflectionException
671
-     * @throws InvalidArgumentException
672
-     * @throws InvalidInterfaceException
673
-     * @throws InvalidDataTypeException
674
-     * @throws EE_Error
675
-     */
676
-    public function e_end_time($tm_format = '')
677
-    {
678
-        $this->_show_datetime('T', 'end', null, $tm_format, true);
679
-    }
680
-
681
-
682
-    /**
683
-     * get time_range
684
-     *
685
-     * @access public
686
-     * @param string $tm_format   string representation of time format defaults to 'g:i a'
687
-     * @param string $conjunction conjunction junction what's your function ?
688
-     *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
689
-     * @return mixed              string on success, FALSE on fail
690
-     * @throws ReflectionException
691
-     * @throws InvalidArgumentException
692
-     * @throws InvalidInterfaceException
693
-     * @throws InvalidDataTypeException
694
-     * @throws EE_Error
695
-     */
696
-    public function time_range($tm_format = '', $conjunction = ' - ')
697
-    {
698
-        $tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
699
-        $start     = str_replace(
700
-            ' ',
701
-            '&nbsp;',
702
-            $this->get_i18n_datetime('DTT_EVT_start', $tm_format)
703
-        );
704
-        $end       = str_replace(
705
-            ' ',
706
-            '&nbsp;',
707
-            $this->get_i18n_datetime('DTT_EVT_end', $tm_format)
708
-        );
709
-        return $start !== $end ? $start . $conjunction . $end : $start;
710
-    }
711
-
712
-
713
-    /**
714
-     * @param string $tm_format
715
-     * @param string $conjunction
716
-     * @throws ReflectionException
717
-     * @throws InvalidArgumentException
718
-     * @throws InvalidInterfaceException
719
-     * @throws InvalidDataTypeException
720
-     * @throws EE_Error
721
-     */
722
-    public function e_time_range($tm_format = '', $conjunction = ' - ')
723
-    {
724
-        echo $this->time_range($tm_format, $conjunction);
725
-    }
726
-
727
-
728
-    /**
729
-     * This returns a range representation of the date and times.
730
-     * Output is dependent on the difference (or similarity) between DTT_EVT_start and DTT_EVT_end.
731
-     * Also, the return value is localized.
732
-     *
733
-     * @param string $dt_format
734
-     * @param string $tm_format
735
-     * @param string $conjunction used between two different dates or times.
736
-     *                            ex: Dec 1{$conjunction}}Dec 6, or 2pm{$conjunction}3pm
737
-     * @param string $separator   used between the date and time formats.
738
-     *                            ex: Dec 1, 2016{$separator}2pm
739
-     * @return string
740
-     * @throws ReflectionException
741
-     * @throws InvalidArgumentException
742
-     * @throws InvalidInterfaceException
743
-     * @throws InvalidDataTypeException
744
-     * @throws EE_Error
745
-     */
746
-    public function date_and_time_range(
747
-        $dt_format = '',
748
-        $tm_format = '',
749
-        $conjunction = ' - ',
750
-        $separator = ' '
751
-    ) {
752
-        $dt_format   = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
753
-        $tm_format   = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
754
-        $full_format = $dt_format . $separator . $tm_format;
755
-        //the range output depends on various conditions
756
-        switch (true) {
757
-            //start date timestamp and end date timestamp are the same.
758
-            case ($this->get_raw('DTT_EVT_start') === $this->get_raw('DTT_EVT_end')) :
759
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format);
760
-                break;
761
-            //start and end date are the same but times are different
762
-            case ($this->start_date() === $this->end_date()) :
763
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
764
-                          . $conjunction
765
-                          . $this->get_i18n_datetime('DTT_EVT_end', $tm_format);
766
-                break;
767
-            //all other conditions
768
-            default :
769
-                $output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
770
-                          . $conjunction
771
-                          . $this->get_i18n_datetime('DTT_EVT_end', $full_format);
772
-                break;
773
-        }
774
-        return $output;
775
-    }
776
-
777
-
778
-    /**
779
-     * This echos the results of date and time range.
780
-     *
781
-     * @see date_and_time_range() for more details on purpose.
782
-     * @param string $dt_format
783
-     * @param string $tm_format
784
-     * @param string $conjunction
785
-     * @return void
786
-     * @throws ReflectionException
787
-     * @throws InvalidArgumentException
788
-     * @throws InvalidInterfaceException
789
-     * @throws InvalidDataTypeException
790
-     * @throws EE_Error
791
-     */
792
-    public function e_date_and_time_range($dt_format = '', $tm_format = '', $conjunction = ' - ')
793
-    {
794
-        echo $this->date_and_time_range($dt_format, $tm_format, $conjunction);
795
-    }
796
-
797
-
798
-    /**
799
-     * get start date and start time
800
-     *
801
-     * @param    string $dt_format - string representation of date format defaults to 'F j, Y'
802
-     * @param    string $tm_format - string representation of time format defaults to 'g:i a'
803
-     * @return    mixed    string on success, FALSE on fail
804
-     * @throws ReflectionException
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidInterfaceException
807
-     * @throws InvalidDataTypeException
808
-     * @throws EE_Error
809
-     */
810
-    public function start_date_and_time($dt_format = '', $tm_format = '')
811
-    {
812
-        return $this->_show_datetime('', 'start', $dt_format, $tm_format);
813
-    }
814
-
815
-
816
-    /**
817
-     * @param string $dt_frmt
818
-     * @param string $tm_format
819
-     * @throws ReflectionException
820
-     * @throws InvalidArgumentException
821
-     * @throws InvalidInterfaceException
822
-     * @throws InvalidDataTypeException
823
-     * @throws EE_Error
824
-     */
825
-    public function e_start_date_and_time($dt_frmt = '', $tm_format = '')
826
-    {
827
-        $this->_show_datetime('', 'start', $dt_frmt, $tm_format, true);
828
-    }
829
-
830
-
831
-    /**
832
-     * Shows the length of the event (start to end time).
833
-     * Can be shown in 'seconds','minutes','hours', or 'days'.
834
-     * By default, rounds up. (So if you use 'days', and then event
835
-     * only occurs for 1 hour, it will return 1 day).
836
-     *
837
-     * @param string $units 'seconds','minutes','hours','days'
838
-     * @param bool   $round_up
839
-     * @return float|int|mixed
840
-     * @throws ReflectionException
841
-     * @throws InvalidArgumentException
842
-     * @throws InvalidInterfaceException
843
-     * @throws InvalidDataTypeException
844
-     * @throws EE_Error
845
-     */
846
-    public function length($units = 'seconds', $round_up = false)
847
-    {
848
-        $start           = $this->get_raw('DTT_EVT_start');
849
-        $end             = $this->get_raw('DTT_EVT_end');
850
-        $length_in_units = $end - $start;
851
-        switch ($units) {
852
-            //NOTE: We purposefully don't use "break;" in order to chain the divisions
853
-            /** @noinspection PhpMissingBreakStatementInspection */
854
-            case 'days':
855
-                $length_in_units /= 24;
856
-            /** @noinspection PhpMissingBreakStatementInspection */
857
-            case 'hours':
858
-                $length_in_units /= 60;
859
-            /** @noinspection PhpMissingBreakStatementInspection */
860
-            case 'minutes':
861
-                $length_in_units /= 60;
862
-            case 'seconds':
863
-            default:
864
-                $length_in_units = ceil($length_in_units);
865
-        }
866
-        if ($round_up) {
867
-            $length_in_units = max($length_in_units, 1);
868
-        }
869
-        return $length_in_units;
870
-    }
871
-
872
-
873
-    /**
874
-     *        get end date and time
875
-     *
876
-     * @param string $dt_frmt   - string representation of date format defaults to 'F j, Y'
877
-     * @param string $tm_format - string representation of time format defaults to 'g:i a'
878
-     * @return    mixed                string on success, FALSE on fail
879
-     * @throws ReflectionException
880
-     * @throws InvalidArgumentException
881
-     * @throws InvalidInterfaceException
882
-     * @throws InvalidDataTypeException
883
-     * @throws EE_Error
884
-     */
885
-    public function end_date_and_time($dt_frmt = '', $tm_format = '')
886
-    {
887
-        return $this->_show_datetime('', 'end', $dt_frmt, $tm_format);
888
-    }
889
-
890
-
891
-    /**
892
-     * @param string $dt_frmt
893
-     * @param string $tm_format
894
-     * @throws ReflectionException
895
-     * @throws InvalidArgumentException
896
-     * @throws InvalidInterfaceException
897
-     * @throws InvalidDataTypeException
898
-     * @throws EE_Error
899
-     */
900
-    public function e_end_date_and_time($dt_frmt = '', $tm_format = '')
901
-    {
902
-        $this->_show_datetime('', 'end', $dt_frmt, $tm_format, true);
903
-    }
904
-
905
-
906
-    /**
907
-     *        get start timestamp
908
-     *
909
-     * @return        int
910
-     * @throws ReflectionException
911
-     * @throws InvalidArgumentException
912
-     * @throws InvalidInterfaceException
913
-     * @throws InvalidDataTypeException
914
-     * @throws EE_Error
915
-     */
916
-    public function start()
917
-    {
918
-        return $this->get_raw('DTT_EVT_start');
919
-    }
920
-
921
-
922
-    /**
923
-     *        get end timestamp
924
-     *
925
-     * @return        int
926
-     * @throws ReflectionException
927
-     * @throws InvalidArgumentException
928
-     * @throws InvalidInterfaceException
929
-     * @throws InvalidDataTypeException
930
-     * @throws EE_Error
931
-     */
932
-    public function end()
933
-    {
934
-        return $this->get_raw('DTT_EVT_end');
935
-    }
936
-
937
-
938
-    /**
939
-     *    get the registration limit for this datetime slot
940
-     *
941
-     * @return        mixed        int on success, FALSE on fail
942
-     * @throws ReflectionException
943
-     * @throws InvalidArgumentException
944
-     * @throws InvalidInterfaceException
945
-     * @throws InvalidDataTypeException
946
-     * @throws EE_Error
947
-     */
948
-    public function reg_limit()
949
-    {
950
-        return $this->get_raw('DTT_reg_limit');
951
-    }
952
-
953
-
954
-    /**
955
-     *    have the tickets sold for this datetime, met or exceed the registration limit ?
956
-     *
957
-     * @return        boolean
958
-     * @throws ReflectionException
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidInterfaceException
961
-     * @throws InvalidDataTypeException
962
-     * @throws EE_Error
963
-     */
964
-    public function sold_out()
965
-    {
966
-        return $this->reg_limit() > 0 && $this->sold() >= $this->reg_limit();
967
-    }
968
-
969
-
970
-    /**
971
-     * return the total number of spaces remaining at this venue.
972
-     * This only takes the venue's capacity into account, NOT the tickets available for sale
973
-     *
974
-     * @param bool $consider_tickets Whether to consider tickets remaining when determining if there are any spaces left
975
-     *                               Because if all tickets attached to this datetime have no spaces left,
976
-     *                               then this datetime IS effectively sold out.
977
-     *                               However, there are cases where we just want to know the spaces
978
-     *                               remaining for this particular datetime, hence the flag.
979
-     * @return int
980
-     * @throws ReflectionException
981
-     * @throws InvalidArgumentException
982
-     * @throws InvalidInterfaceException
983
-     * @throws InvalidDataTypeException
984
-     * @throws EE_Error
985
-     */
986
-    public function spaces_remaining($consider_tickets = false)
987
-    {
988
-        // tickets remaining available for purchase
989
-        //no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
990
-        $dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
991
-        if (! $consider_tickets) {
992
-            return $dtt_remaining;
993
-        }
994
-        $tickets_remaining = $this->tickets_remaining();
995
-        return min($dtt_remaining, $tickets_remaining);
996
-    }
997
-
998
-
999
-    /**
1000
-     * Counts the total tickets available
1001
-     * (from all the different types of tickets which are available for this datetime).
1002
-     *
1003
-     * @param array $query_params like EEM_Base::get_all's
1004
-     * @return int
1005
-     * @throws ReflectionException
1006
-     * @throws InvalidArgumentException
1007
-     * @throws InvalidInterfaceException
1008
-     * @throws InvalidDataTypeException
1009
-     * @throws EE_Error
1010
-     */
1011
-    public function tickets_remaining($query_params = array())
1012
-    {
1013
-        $sum     = 0;
1014
-        $tickets = $this->tickets($query_params);
1015
-        if (! empty($tickets)) {
1016
-            foreach ($tickets as $ticket) {
1017
-                if ($ticket instanceof EE_Ticket) {
1018
-                    // get the actual amount of tickets that can be sold
1019
-                    $qty = $ticket->qty('saleable');
1020
-                    if ($qty === EE_INF) {
1021
-                        return EE_INF;
1022
-                    }
1023
-                    // no negative ticket quantities plz
1024
-                    if ($qty > 0) {
1025
-                        $sum += $qty;
1026
-                    }
1027
-                }
1028
-            }
1029
-        }
1030
-        return $sum;
1031
-    }
1032
-
1033
-
1034
-    /**
1035
-     * Gets the count of all the tickets available at this datetime (not ticket types)
1036
-     * before any were sold
1037
-     *
1038
-     * @param array $query_params like EEM_Base::get_all's
1039
-     * @return int
1040
-     * @throws ReflectionException
1041
-     * @throws InvalidArgumentException
1042
-     * @throws InvalidInterfaceException
1043
-     * @throws InvalidDataTypeException
1044
-     * @throws EE_Error
1045
-     */
1046
-    public function sum_tickets_initially_available($query_params = array())
1047
-    {
1048
-        return $this->sum_related('Ticket', $query_params, 'TKT_qty');
1049
-    }
1050
-
1051
-
1052
-    /**
1053
-     * Returns the lesser-of-the two: spaces remaining at this datetime, or
1054
-     * the total tickets remaining (a sum of the tickets remaining for each ticket type
1055
-     * that is available for this datetime).
1056
-     *
1057
-     * @return int
1058
-     * @throws ReflectionException
1059
-     * @throws InvalidArgumentException
1060
-     * @throws InvalidInterfaceException
1061
-     * @throws InvalidDataTypeException
1062
-     * @throws EE_Error
1063
-     */
1064
-    public function total_tickets_available_at_this_datetime()
1065
-    {
1066
-        return $this->spaces_remaining(true);
1067
-    }
1068
-
1069
-
1070
-    /**
1071
-     * This simply compares the internal dtt for the given string with NOW
1072
-     * and determines if the date is upcoming or not.
1073
-     *
1074
-     * @access public
1075
-     * @return boolean
1076
-     * @throws ReflectionException
1077
-     * @throws InvalidArgumentException
1078
-     * @throws InvalidInterfaceException
1079
-     * @throws InvalidDataTypeException
1080
-     * @throws EE_Error
1081
-     */
1082
-    public function is_upcoming()
1083
-    {
1084
-        return ($this->get_raw('DTT_EVT_start') > time());
1085
-    }
1086
-
1087
-
1088
-    /**
1089
-     * This simply compares the internal datetime for the given string with NOW
1090
-     * and returns if the date is active (i.e. start and end time)
1091
-     *
1092
-     * @return boolean
1093
-     * @throws ReflectionException
1094
-     * @throws InvalidArgumentException
1095
-     * @throws InvalidInterfaceException
1096
-     * @throws InvalidDataTypeException
1097
-     * @throws EE_Error
1098
-     */
1099
-    public function is_active()
1100
-    {
1101
-        return ($this->get_raw('DTT_EVT_start') < time() && $this->get_raw('DTT_EVT_end') > time());
1102
-    }
1103
-
1104
-
1105
-    /**
1106
-     * This simply compares the internal dtt for the given string with NOW
1107
-     * and determines if the date is expired or not.
1108
-     *
1109
-     * @return boolean
1110
-     * @throws ReflectionException
1111
-     * @throws InvalidArgumentException
1112
-     * @throws InvalidInterfaceException
1113
-     * @throws InvalidDataTypeException
1114
-     * @throws EE_Error
1115
-     */
1116
-    public function is_expired()
1117
-    {
1118
-        return ($this->get_raw('DTT_EVT_end') < time());
1119
-    }
1120
-
1121
-
1122
-    /**
1123
-     * This returns the active status for whether an event is active, upcoming, or expired
1124
-     *
1125
-     * @return int return value will be one of the EE_Datetime status constants.
1126
-     * @throws ReflectionException
1127
-     * @throws InvalidArgumentException
1128
-     * @throws InvalidInterfaceException
1129
-     * @throws InvalidDataTypeException
1130
-     * @throws EE_Error
1131
-     */
1132
-    public function get_active_status()
1133
-    {
1134
-        $total_tickets_for_this_dtt = $this->total_tickets_available_at_this_datetime();
1135
-        if ($total_tickets_for_this_dtt !== false && $total_tickets_for_this_dtt < 1) {
1136
-            return EE_Datetime::sold_out;
1137
-        }
1138
-        if ($this->is_expired()) {
1139
-            return EE_Datetime::expired;
1140
-        }
1141
-        if ($this->is_upcoming()) {
1142
-            return EE_Datetime::upcoming;
1143
-        }
1144
-        if ($this->is_active()) {
1145
-            return EE_Datetime::active;
1146
-        }
1147
-        return null;
1148
-    }
1149
-
1150
-
1151
-    /**
1152
-     * This returns a nice display name for the datetime that is contingent on the span between the dates and times.
1153
-     *
1154
-     * @param  boolean $use_dtt_name if TRUE then we'll use DTT->name() if its not empty.
1155
-     * @return string
1156
-     * @throws ReflectionException
1157
-     * @throws InvalidArgumentException
1158
-     * @throws InvalidInterfaceException
1159
-     * @throws InvalidDataTypeException
1160
-     * @throws EE_Error
1161
-     */
1162
-    public function get_dtt_display_name($use_dtt_name = false)
1163
-    {
1164
-        if ($use_dtt_name) {
1165
-            $dtt_name = $this->name();
1166
-            if (! empty($dtt_name)) {
1167
-                return $dtt_name;
1168
-            }
1169
-        }
1170
-        //first condition is to see if the months are different
1171
-        if (
1172
-            date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1173
-        ) {
1174
-            $display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1175
-            //next condition is if its the same month but different day
1176
-        } else {
1177
-            if (
1178
-                date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1179
-                && date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1180
-            ) {
1181
-                $display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1182
-            } else {
1183
-                $display_date = $this->start_date('F j\, Y')
1184
-                                . ' @ '
1185
-                                . $this->start_date('g:i a')
1186
-                                . ' - '
1187
-                                . $this->end_date('g:i a');
1188
-            }
1189
-        }
1190
-        return $display_date;
1191
-    }
1192
-
1193
-
1194
-    /**
1195
-     * Gets all the tickets for this datetime
1196
-     *
1197
-     * @param array $query_params see EEM_Base::get_all()
1198
-     * @return EE_Base_Class[]|EE_Ticket[]
1199
-     * @throws ReflectionException
1200
-     * @throws InvalidArgumentException
1201
-     * @throws InvalidInterfaceException
1202
-     * @throws InvalidDataTypeException
1203
-     * @throws EE_Error
1204
-     */
1205
-    public function tickets($query_params = array())
1206
-    {
1207
-        return $this->get_many_related('Ticket', $query_params);
1208
-    }
1209
-
1210
-
1211
-    /**
1212
-     * Gets all the ticket types currently available for purchase
1213
-     *
1214
-     * @param array $query_params like EEM_Base::get_all's
1215
-     * @return EE_Ticket[]
1216
-     * @throws ReflectionException
1217
-     * @throws InvalidArgumentException
1218
-     * @throws InvalidInterfaceException
1219
-     * @throws InvalidDataTypeException
1220
-     * @throws EE_Error
1221
-     */
1222
-    public function ticket_types_available_for_purchase($query_params = array())
1223
-    {
1224
-        // first check if datetime is valid
1225
-        if ($this->sold_out() || ! ($this->is_upcoming() || $this->is_active())) {
1226
-            return array();
1227
-        }
1228
-        if (empty($query_params)) {
1229
-            $query_params = array(
1230
-                array(
1231
-                    'TKT_start_date' => array('<=', EEM_Ticket::instance()->current_time_for_query('TKT_start_date')),
1232
-                    'TKT_end_date'   => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
1233
-                    'TKT_deleted'    => false,
1234
-                ),
1235
-            );
1236
-        }
1237
-        return $this->tickets($query_params);
1238
-    }
1239
-
1240
-
1241
-    /**
1242
-     * @return EE_Base_Class|EE_Event
1243
-     * @throws ReflectionException
1244
-     * @throws InvalidArgumentException
1245
-     * @throws InvalidInterfaceException
1246
-     * @throws InvalidDataTypeException
1247
-     * @throws EE_Error
1248
-     */
1249
-    public function event()
1250
-    {
1251
-        return $this->get_first_related('Event');
1252
-    }
1253
-
1254
-
1255
-    /**
1256
-     * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime
1257
-     * (via the tickets). into account
1258
-     *
1259
-     * @return int
1260
-     * @throws ReflectionException
1261
-     * @throws InvalidArgumentException
1262
-     * @throws InvalidInterfaceException
1263
-     * @throws InvalidDataTypeException
1264
-     * @throws EE_Error
1265
-     */
1266
-    public function update_sold()
1267
-    {
1268
-        $count_regs_for_this_datetime = EEM_Registration::instance()->count(
1269
-            array(
1270
-                array(
1271
-                    'STS_ID'                 => EEM_Registration::status_id_approved,
1272
-                    'REG_deleted'            => 0,
1273
-                    'Ticket.Datetime.DTT_ID' => $this->ID(),
1274
-                ),
1275
-            )
1276
-        );
1277
-        $sold                         = $this->sold();
1278
-        if ($count_regs_for_this_datetime > $sold) {
1279
-            $this->increase_sold($count_regs_for_this_datetime - $sold);
1280
-            $this->save();
1281
-        } elseif ($count_regs_for_this_datetime < $sold) {
1282
-            $this->decrease_sold($count_regs_for_this_datetime - $sold);
1283
-            $this->save();
1284
-        }
1285
-        return $count_regs_for_this_datetime;
1286
-    }
17
+	/**
18
+	 * constant used by get_active_status, indicates datetime has no more available spaces
19
+	 */
20
+	const sold_out = 'DTS';
21
+
22
+	/**
23
+	 * constant used by get_active_status, indicating datetime is still active (even is not over, can be registered-for)
24
+	 */
25
+	const active = 'DTA';
26
+
27
+	/**
28
+	 * constant used by get_active_status, indicating the datetime cannot be used for registrations yet, but has not
29
+	 * expired
30
+	 */
31
+	const upcoming = 'DTU';
32
+
33
+	/**
34
+	 * Datetime is postponed
35
+	 */
36
+	const postponed = 'DTP';
37
+
38
+	/**
39
+	 * Datetime is cancelled
40
+	 */
41
+	const cancelled = 'DTC';
42
+
43
+	/**
44
+	 * constant used by get_active_status, indicates datetime has expired (event is over)
45
+	 */
46
+	const expired = 'DTE';
47
+
48
+	/**
49
+	 * constant used in various places indicating that an event is INACTIVE (not yet ready to be published)
50
+	 */
51
+	const inactive = 'DTI';
52
+
53
+
54
+	/**
55
+	 * @param array  $props_n_values    incoming values
56
+	 * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
57
+	 * @param array $date_formats       incoming date_formats in an array where the first value is the date_format
58
+	 *                                  and the second value is the time format
59
+	 * @return EE_Datetime
60
+	 * @throws ReflectionException
61
+	 * @throws InvalidArgumentException
62
+	 * @throws InvalidInterfaceException
63
+	 * @throws InvalidDataTypeException
64
+	 * @throws EE_Error
65
+	 */
66
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
67
+	{
68
+		$has_object = parent::_check_for_object(
69
+			$props_n_values,
70
+			__CLASS__,
71
+			$timezone,
72
+			$date_formats
73
+		);
74
+		return $has_object
75
+			? $has_object
76
+			: new self($props_n_values, false, $timezone, $date_formats);
77
+	}
78
+
79
+
80
+	/**
81
+	 * @param array  $props_n_values  incoming values from the database
82
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
83
+	 *                                the website will be used.
84
+	 * @return EE_Datetime
85
+	 * @throws ReflectionException
86
+	 * @throws InvalidArgumentException
87
+	 * @throws InvalidInterfaceException
88
+	 * @throws InvalidDataTypeException
89
+	 * @throws EE_Error
90
+	 */
91
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
92
+	{
93
+		return new self($props_n_values, true, $timezone);
94
+	}
95
+
96
+
97
+	/**
98
+	 * @param $name
99
+	 * @throws ReflectionException
100
+	 * @throws InvalidArgumentException
101
+	 * @throws InvalidInterfaceException
102
+	 * @throws InvalidDataTypeException
103
+	 * @throws EE_Error
104
+	 */
105
+	public function set_name($name)
106
+	{
107
+		$this->set('DTT_name', $name);
108
+	}
109
+
110
+
111
+	/**
112
+	 * @param $description
113
+	 * @throws ReflectionException
114
+	 * @throws InvalidArgumentException
115
+	 * @throws InvalidInterfaceException
116
+	 * @throws InvalidDataTypeException
117
+	 * @throws EE_Error
118
+	 */
119
+	public function set_description($description)
120
+	{
121
+		$this->set('DTT_description', $description);
122
+	}
123
+
124
+
125
+	/**
126
+	 * Set event start date
127
+	 * set the start date for an event
128
+	 *
129
+	 * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
130
+	 * @throws ReflectionException
131
+	 * @throws InvalidArgumentException
132
+	 * @throws InvalidInterfaceException
133
+	 * @throws InvalidDataTypeException
134
+	 * @throws EE_Error
135
+	 */
136
+	public function set_start_date($date)
137
+	{
138
+		$this->_set_date_for($date, 'DTT_EVT_start');
139
+	}
140
+
141
+
142
+	/**
143
+	 * Set event start time
144
+	 * set the start time for an event
145
+	 *
146
+	 * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
147
+	 * @throws ReflectionException
148
+	 * @throws InvalidArgumentException
149
+	 * @throws InvalidInterfaceException
150
+	 * @throws InvalidDataTypeException
151
+	 * @throws EE_Error
152
+	 */
153
+	public function set_start_time($time)
154
+	{
155
+		$this->_set_time_for($time, 'DTT_EVT_start');
156
+	}
157
+
158
+
159
+	/**
160
+	 * Set event end date
161
+	 * set the end date for an event
162
+	 *
163
+	 * @param string $date a string representation of the event's date ex:  Dec. 25, 2025 or 12-25-2025
164
+	 * @throws ReflectionException
165
+	 * @throws InvalidArgumentException
166
+	 * @throws InvalidInterfaceException
167
+	 * @throws InvalidDataTypeException
168
+	 * @throws EE_Error
169
+	 */
170
+	public function set_end_date($date)
171
+	{
172
+		$this->_set_date_for($date, 'DTT_EVT_end');
173
+	}
174
+
175
+
176
+	/**
177
+	 * Set event end time
178
+	 * set the end time for an event
179
+	 *
180
+	 * @param string $time a string representation of the event time ex:  9am  or  7:30 PM
181
+	 * @throws ReflectionException
182
+	 * @throws InvalidArgumentException
183
+	 * @throws InvalidInterfaceException
184
+	 * @throws InvalidDataTypeException
185
+	 * @throws EE_Error
186
+	 */
187
+	public function set_end_time($time)
188
+	{
189
+		$this->_set_time_for($time, 'DTT_EVT_end');
190
+	}
191
+
192
+
193
+	/**
194
+	 * Set registration limit
195
+	 * set the maximum number of attendees that can be registered for this datetime slot
196
+	 *
197
+	 * @param int $reg_limit
198
+	 * @throws ReflectionException
199
+	 * @throws InvalidArgumentException
200
+	 * @throws InvalidInterfaceException
201
+	 * @throws InvalidDataTypeException
202
+	 * @throws EE_Error
203
+	 */
204
+	public function set_reg_limit($reg_limit)
205
+	{
206
+		$this->set('DTT_reg_limit', $reg_limit);
207
+	}
208
+
209
+
210
+	/**
211
+	 * get the number of tickets sold for this datetime slot
212
+	 *
213
+	 * @return mixed int on success, FALSE on fail
214
+	 * @throws ReflectionException
215
+	 * @throws InvalidArgumentException
216
+	 * @throws InvalidInterfaceException
217
+	 * @throws InvalidDataTypeException
218
+	 * @throws EE_Error
219
+	 */
220
+	public function sold()
221
+	{
222
+		return $this->get_raw('DTT_sold');
223
+	}
224
+
225
+
226
+	/**
227
+	 * @param int $sold
228
+	 * @throws ReflectionException
229
+	 * @throws InvalidArgumentException
230
+	 * @throws InvalidInterfaceException
231
+	 * @throws InvalidDataTypeException
232
+	 * @throws EE_Error
233
+	 */
234
+	public function set_sold($sold)
235
+	{
236
+		// sold can not go below zero
237
+		$sold = max(0, $sold);
238
+		$this->set('DTT_sold', $sold);
239
+	}
240
+
241
+
242
+	/**
243
+	 * increments sold by amount passed by $qty
244
+	 *
245
+	 * @param int $qty
246
+	 * @throws ReflectionException
247
+	 * @throws InvalidArgumentException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws InvalidDataTypeException
250
+	 * @throws EE_Error
251
+	 */
252
+	public function increase_sold($qty = 1)
253
+	{
254
+		$sold = $this->sold() + $qty;
255
+		// remove ticket reservation
256
+		$this->decrease_reserved($qty);
257
+		$this->set_sold($sold);
258
+		do_action(
259
+			'AHEE__EE_Datetime__increase_sold',
260
+			$this,
261
+			$qty,
262
+			$sold
263
+		);
264
+	}
265
+
266
+
267
+	/**
268
+	 * decrements (subtracts) sold amount passed by $qty
269
+	 *
270
+	 * @param int $qty
271
+	 * @throws ReflectionException
272
+	 * @throws InvalidArgumentException
273
+	 * @throws InvalidInterfaceException
274
+	 * @throws InvalidDataTypeException
275
+	 * @throws EE_Error
276
+	 */
277
+	public function decrease_sold($qty = 1)
278
+	{
279
+		$sold = $this->sold() - $qty;
280
+		$this->set_sold($sold);
281
+		do_action(
282
+			'AHEE__EE_Datetime__decrease_sold',
283
+			$this,
284
+			$qty,
285
+			$sold
286
+		);
287
+	}
288
+
289
+
290
+	/**
291
+	 * Gets qty of reserved tickets for this datetime
292
+	 *
293
+	 * @return int
294
+	 * @throws ReflectionException
295
+	 * @throws InvalidArgumentException
296
+	 * @throws InvalidInterfaceException
297
+	 * @throws InvalidDataTypeException
298
+	 * @throws EE_Error
299
+	 */
300
+	public function reserved()
301
+	{
302
+		return $this->get_raw('DTT_reserved');
303
+	}
304
+
305
+
306
+	/**
307
+	 * Sets qty of reserved tickets for this datetime
308
+	 *
309
+	 * @param int $reserved
310
+	 * @throws ReflectionException
311
+	 * @throws InvalidArgumentException
312
+	 * @throws InvalidInterfaceException
313
+	 * @throws InvalidDataTypeException
314
+	 * @throws EE_Error
315
+	 */
316
+	public function set_reserved($reserved)
317
+	{
318
+		// reserved can not go below zero
319
+		$reserved = max(0, (int) $reserved);
320
+		$this->set('DTT_reserved', $reserved);
321
+	}
322
+
323
+
324
+	/**
325
+	 * increments reserved by amount passed by $qty
326
+	 *
327
+	 * @param int $qty
328
+	 * @return void
329
+	 * @throws ReflectionException
330
+	 * @throws InvalidArgumentException
331
+	 * @throws InvalidInterfaceException
332
+	 * @throws InvalidDataTypeException
333
+	 * @throws EE_Error
334
+	 */
335
+	public function increase_reserved($qty = 1)
336
+	{
337
+		$reserved = $this->reserved() + absint($qty);
338
+		do_action(
339
+			'AHEE__EE_Datetime__increase_reserved',
340
+			$this,
341
+			$qty,
342
+			$reserved
343
+		);
344
+		$this->set_reserved($reserved);
345
+	}
346
+
347
+
348
+	/**
349
+	 * decrements (subtracts) reserved by amount passed by $qty
350
+	 *
351
+	 * @param int $qty
352
+	 * @return void
353
+	 * @throws ReflectionException
354
+	 * @throws InvalidArgumentException
355
+	 * @throws InvalidInterfaceException
356
+	 * @throws InvalidDataTypeException
357
+	 * @throws EE_Error
358
+	 */
359
+	public function decrease_reserved($qty = 1)
360
+	{
361
+		$reserved = $this->reserved() - absint($qty);
362
+		do_action(
363
+			'AHEE__EE_Datetime__decrease_reserved',
364
+			$this,
365
+			$qty,
366
+			$reserved
367
+		);
368
+		$this->set_reserved($reserved);
369
+	}
370
+
371
+
372
+	/**
373
+	 * total sold and reserved tickets
374
+	 *
375
+	 * @return int
376
+	 * @throws ReflectionException
377
+	 * @throws InvalidArgumentException
378
+	 * @throws InvalidInterfaceException
379
+	 * @throws InvalidDataTypeException
380
+	 * @throws EE_Error
381
+	 */
382
+	public function sold_and_reserved()
383
+	{
384
+		return $this->sold() + $this->reserved();
385
+	}
386
+
387
+
388
+	/**
389
+	 * returns the datetime name
390
+	 *
391
+	 * @return string
392
+	 * @throws ReflectionException
393
+	 * @throws InvalidArgumentException
394
+	 * @throws InvalidInterfaceException
395
+	 * @throws InvalidDataTypeException
396
+	 * @throws EE_Error
397
+	 */
398
+	public function name()
399
+	{
400
+		return $this->get('DTT_name');
401
+	}
402
+
403
+
404
+	/**
405
+	 * returns the datetime description
406
+	 *
407
+	 * @return string
408
+	 * @throws ReflectionException
409
+	 * @throws InvalidArgumentException
410
+	 * @throws InvalidInterfaceException
411
+	 * @throws InvalidDataTypeException
412
+	 * @throws EE_Error
413
+	 */
414
+	public function description()
415
+	{
416
+		return $this->get('DTT_description');
417
+	}
418
+
419
+
420
+	/**
421
+	 * This helper simply returns whether the event_datetime for the current datetime is a primary datetime
422
+	 *
423
+	 * @return boolean  TRUE if is primary, FALSE if not.
424
+	 * @throws ReflectionException
425
+	 * @throws InvalidArgumentException
426
+	 * @throws InvalidInterfaceException
427
+	 * @throws InvalidDataTypeException
428
+	 * @throws EE_Error
429
+	 */
430
+	public function is_primary()
431
+	{
432
+		return $this->get('DTT_is_primary');
433
+	}
434
+
435
+
436
+	/**
437
+	 * This helper simply returns the order for the datetime
438
+	 *
439
+	 * @return int  The order of the datetime for this event.
440
+	 * @throws ReflectionException
441
+	 * @throws InvalidArgumentException
442
+	 * @throws InvalidInterfaceException
443
+	 * @throws InvalidDataTypeException
444
+	 * @throws EE_Error
445
+	 */
446
+	public function order()
447
+	{
448
+		return $this->get('DTT_order');
449
+	}
450
+
451
+
452
+	/**
453
+	 * This helper simply returns the parent id for the datetime
454
+	 *
455
+	 * @return int
456
+	 * @throws ReflectionException
457
+	 * @throws InvalidArgumentException
458
+	 * @throws InvalidInterfaceException
459
+	 * @throws InvalidDataTypeException
460
+	 * @throws EE_Error
461
+	 */
462
+	public function parent()
463
+	{
464
+		return $this->get('DTT_parent');
465
+	}
466
+
467
+
468
+	/**
469
+	 * show date and/or time
470
+	 *
471
+	 * @param string $date_or_time    whether to display a date or time or both
472
+	 * @param string $start_or_end    whether to display start or end datetimes
473
+	 * @param string $dt_frmt
474
+	 * @param string $tm_frmt
475
+	 * @param bool   $echo            whether we echo or return (note echoing uses "pretty" formats,
476
+	 *                                otherwise we use the standard formats)
477
+	 * @return string|bool  string on success, FALSE on fail
478
+	 * @throws ReflectionException
479
+	 * @throws InvalidArgumentException
480
+	 * @throws InvalidInterfaceException
481
+	 * @throws InvalidDataTypeException
482
+	 * @throws EE_Error
483
+	 */
484
+	private function _show_datetime(
485
+		$date_or_time = null,
486
+		$start_or_end = 'start',
487
+		$dt_frmt = '',
488
+		$tm_frmt = '',
489
+		$echo = false
490
+	) {
491
+		$field_name = "DTT_EVT_{$start_or_end}";
492
+		$dtt        = $this->_get_datetime(
493
+			$field_name,
494
+			$dt_frmt,
495
+			$tm_frmt,
496
+			$date_or_time,
497
+			$echo
498
+		);
499
+		if (! $echo) {
500
+			return $dtt;
501
+		}
502
+		return '';
503
+	}
504
+
505
+
506
+	/**
507
+	 * get event start date.  Provide either the date format, or NULL to re-use the
508
+	 * last-used format, or '' to use the default date format
509
+	 *
510
+	 * @param string $dt_frmt   string representation of date format defaults to 'F j, Y'
511
+	 * @return mixed            string on success, FALSE on fail
512
+	 * @throws ReflectionException
513
+	 * @throws InvalidArgumentException
514
+	 * @throws InvalidInterfaceException
515
+	 * @throws InvalidDataTypeException
516
+	 * @throws EE_Error
517
+	 */
518
+	public function start_date($dt_frmt = '')
519
+	{
520
+		return $this->_show_datetime('D', 'start', $dt_frmt);
521
+	}
522
+
523
+
524
+	/**
525
+	 * Echoes start_date()
526
+	 *
527
+	 * @param string $dt_frmt
528
+	 * @throws ReflectionException
529
+	 * @throws InvalidArgumentException
530
+	 * @throws InvalidInterfaceException
531
+	 * @throws InvalidDataTypeException
532
+	 * @throws EE_Error
533
+	 */
534
+	public function e_start_date($dt_frmt = '')
535
+	{
536
+		$this->_show_datetime('D', 'start', $dt_frmt, null, true);
537
+	}
538
+
539
+
540
+	/**
541
+	 * get end date. Provide either the date format, or NULL to re-use the
542
+	 * last-used format, or '' to use the default date format
543
+	 *
544
+	 * @param string $dt_frmt   string representation of date format defaults to 'F j, Y'
545
+	 * @return mixed            string on success, FALSE on fail
546
+	 * @throws ReflectionException
547
+	 * @throws InvalidArgumentException
548
+	 * @throws InvalidInterfaceException
549
+	 * @throws InvalidDataTypeException
550
+	 * @throws EE_Error
551
+	 */
552
+	public function end_date($dt_frmt = '')
553
+	{
554
+		return $this->_show_datetime('D', 'end', $dt_frmt);
555
+	}
556
+
557
+
558
+	/**
559
+	 * Echoes the end date. See end_date()
560
+	 *
561
+	 * @param string $dt_frmt
562
+	 * @throws ReflectionException
563
+	 * @throws InvalidArgumentException
564
+	 * @throws InvalidInterfaceException
565
+	 * @throws InvalidDataTypeException
566
+	 * @throws EE_Error
567
+	 */
568
+	public function e_end_date($dt_frmt = '')
569
+	{
570
+		$this->_show_datetime('D', 'end', $dt_frmt, null, true);
571
+	}
572
+
573
+
574
+	/**
575
+	 * get date_range - meaning the start AND end date
576
+	 *
577
+	 * @access public
578
+	 * @param string $dt_frmt     string representation of date format defaults to WP settings
579
+	 * @param string $conjunction conjunction junction what's your function ?
580
+	 *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
581
+	 * @return mixed              string on success, FALSE on fail
582
+	 * @throws ReflectionException
583
+	 * @throws InvalidArgumentException
584
+	 * @throws InvalidInterfaceException
585
+	 * @throws InvalidDataTypeException
586
+	 * @throws EE_Error
587
+	 */
588
+	public function date_range($dt_frmt = '', $conjunction = ' - ')
589
+	{
590
+		$dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
591
+		$start   = str_replace(
592
+			' ',
593
+			'&nbsp;',
594
+			$this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
595
+		);
596
+		$end     = str_replace(
597
+			' ',
598
+			'&nbsp;',
599
+			$this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
600
+		);
601
+		return $start !== $end ? $start . $conjunction . $end : $start;
602
+	}
603
+
604
+
605
+	/**
606
+	 * @param string $dt_frmt
607
+	 * @param string $conjunction
608
+	 * @throws ReflectionException
609
+	 * @throws InvalidArgumentException
610
+	 * @throws InvalidInterfaceException
611
+	 * @throws InvalidDataTypeException
612
+	 * @throws EE_Error
613
+	 */
614
+	public function e_date_range($dt_frmt = '', $conjunction = ' - ')
615
+	{
616
+		echo $this->date_range($dt_frmt, $conjunction);
617
+	}
618
+
619
+
620
+	/**
621
+	 * get start time
622
+	 *
623
+	 * @param string $tm_format - string representation of time format defaults to 'g:i a'
624
+	 * @return mixed        string on success, FALSE on fail
625
+	 * @throws ReflectionException
626
+	 * @throws InvalidArgumentException
627
+	 * @throws InvalidInterfaceException
628
+	 * @throws InvalidDataTypeException
629
+	 * @throws EE_Error
630
+	 */
631
+	public function start_time($tm_format = '')
632
+	{
633
+		return $this->_show_datetime('T', 'start', null, $tm_format);
634
+	}
635
+
636
+
637
+	/**
638
+	 * @param string $tm_format
639
+	 * @throws ReflectionException
640
+	 * @throws InvalidArgumentException
641
+	 * @throws InvalidInterfaceException
642
+	 * @throws InvalidDataTypeException
643
+	 * @throws EE_Error
644
+	 */
645
+	public function e_start_time($tm_format = '')
646
+	{
647
+		$this->_show_datetime('T', 'start', null, $tm_format, true);
648
+	}
649
+
650
+
651
+	/**
652
+	 * get end time
653
+	 *
654
+	 * @param string $tm_format     string representation of time format defaults to 'g:i a'
655
+	 * @return mixed                string on success, FALSE on fail
656
+	 * @throws ReflectionException
657
+	 * @throws InvalidArgumentException
658
+	 * @throws InvalidInterfaceException
659
+	 * @throws InvalidDataTypeException
660
+	 * @throws EE_Error
661
+	 */
662
+	public function end_time($tm_format = '')
663
+	{
664
+		return $this->_show_datetime('T', 'end', null, $tm_format);
665
+	}
666
+
667
+
668
+	/**
669
+	 * @param string $tm_format
670
+	 * @throws ReflectionException
671
+	 * @throws InvalidArgumentException
672
+	 * @throws InvalidInterfaceException
673
+	 * @throws InvalidDataTypeException
674
+	 * @throws EE_Error
675
+	 */
676
+	public function e_end_time($tm_format = '')
677
+	{
678
+		$this->_show_datetime('T', 'end', null, $tm_format, true);
679
+	}
680
+
681
+
682
+	/**
683
+	 * get time_range
684
+	 *
685
+	 * @access public
686
+	 * @param string $tm_format   string representation of time format defaults to 'g:i a'
687
+	 * @param string $conjunction conjunction junction what's your function ?
688
+	 *                            this string joins the start date with the end date ie: Jan 01 "to" Dec 31
689
+	 * @return mixed              string on success, FALSE on fail
690
+	 * @throws ReflectionException
691
+	 * @throws InvalidArgumentException
692
+	 * @throws InvalidInterfaceException
693
+	 * @throws InvalidDataTypeException
694
+	 * @throws EE_Error
695
+	 */
696
+	public function time_range($tm_format = '', $conjunction = ' - ')
697
+	{
698
+		$tm_format = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
699
+		$start     = str_replace(
700
+			' ',
701
+			'&nbsp;',
702
+			$this->get_i18n_datetime('DTT_EVT_start', $tm_format)
703
+		);
704
+		$end       = str_replace(
705
+			' ',
706
+			'&nbsp;',
707
+			$this->get_i18n_datetime('DTT_EVT_end', $tm_format)
708
+		);
709
+		return $start !== $end ? $start . $conjunction . $end : $start;
710
+	}
711
+
712
+
713
+	/**
714
+	 * @param string $tm_format
715
+	 * @param string $conjunction
716
+	 * @throws ReflectionException
717
+	 * @throws InvalidArgumentException
718
+	 * @throws InvalidInterfaceException
719
+	 * @throws InvalidDataTypeException
720
+	 * @throws EE_Error
721
+	 */
722
+	public function e_time_range($tm_format = '', $conjunction = ' - ')
723
+	{
724
+		echo $this->time_range($tm_format, $conjunction);
725
+	}
726
+
727
+
728
+	/**
729
+	 * This returns a range representation of the date and times.
730
+	 * Output is dependent on the difference (or similarity) between DTT_EVT_start and DTT_EVT_end.
731
+	 * Also, the return value is localized.
732
+	 *
733
+	 * @param string $dt_format
734
+	 * @param string $tm_format
735
+	 * @param string $conjunction used between two different dates or times.
736
+	 *                            ex: Dec 1{$conjunction}}Dec 6, or 2pm{$conjunction}3pm
737
+	 * @param string $separator   used between the date and time formats.
738
+	 *                            ex: Dec 1, 2016{$separator}2pm
739
+	 * @return string
740
+	 * @throws ReflectionException
741
+	 * @throws InvalidArgumentException
742
+	 * @throws InvalidInterfaceException
743
+	 * @throws InvalidDataTypeException
744
+	 * @throws EE_Error
745
+	 */
746
+	public function date_and_time_range(
747
+		$dt_format = '',
748
+		$tm_format = '',
749
+		$conjunction = ' - ',
750
+		$separator = ' '
751
+	) {
752
+		$dt_format   = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
753
+		$tm_format   = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
754
+		$full_format = $dt_format . $separator . $tm_format;
755
+		//the range output depends on various conditions
756
+		switch (true) {
757
+			//start date timestamp and end date timestamp are the same.
758
+			case ($this->get_raw('DTT_EVT_start') === $this->get_raw('DTT_EVT_end')) :
759
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format);
760
+				break;
761
+			//start and end date are the same but times are different
762
+			case ($this->start_date() === $this->end_date()) :
763
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
764
+						  . $conjunction
765
+						  . $this->get_i18n_datetime('DTT_EVT_end', $tm_format);
766
+				break;
767
+			//all other conditions
768
+			default :
769
+				$output = $this->get_i18n_datetime('DTT_EVT_start', $full_format)
770
+						  . $conjunction
771
+						  . $this->get_i18n_datetime('DTT_EVT_end', $full_format);
772
+				break;
773
+		}
774
+		return $output;
775
+	}
776
+
777
+
778
+	/**
779
+	 * This echos the results of date and time range.
780
+	 *
781
+	 * @see date_and_time_range() for more details on purpose.
782
+	 * @param string $dt_format
783
+	 * @param string $tm_format
784
+	 * @param string $conjunction
785
+	 * @return void
786
+	 * @throws ReflectionException
787
+	 * @throws InvalidArgumentException
788
+	 * @throws InvalidInterfaceException
789
+	 * @throws InvalidDataTypeException
790
+	 * @throws EE_Error
791
+	 */
792
+	public function e_date_and_time_range($dt_format = '', $tm_format = '', $conjunction = ' - ')
793
+	{
794
+		echo $this->date_and_time_range($dt_format, $tm_format, $conjunction);
795
+	}
796
+
797
+
798
+	/**
799
+	 * get start date and start time
800
+	 *
801
+	 * @param    string $dt_format - string representation of date format defaults to 'F j, Y'
802
+	 * @param    string $tm_format - string representation of time format defaults to 'g:i a'
803
+	 * @return    mixed    string on success, FALSE on fail
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws EE_Error
809
+	 */
810
+	public function start_date_and_time($dt_format = '', $tm_format = '')
811
+	{
812
+		return $this->_show_datetime('', 'start', $dt_format, $tm_format);
813
+	}
814
+
815
+
816
+	/**
817
+	 * @param string $dt_frmt
818
+	 * @param string $tm_format
819
+	 * @throws ReflectionException
820
+	 * @throws InvalidArgumentException
821
+	 * @throws InvalidInterfaceException
822
+	 * @throws InvalidDataTypeException
823
+	 * @throws EE_Error
824
+	 */
825
+	public function e_start_date_and_time($dt_frmt = '', $tm_format = '')
826
+	{
827
+		$this->_show_datetime('', 'start', $dt_frmt, $tm_format, true);
828
+	}
829
+
830
+
831
+	/**
832
+	 * Shows the length of the event (start to end time).
833
+	 * Can be shown in 'seconds','minutes','hours', or 'days'.
834
+	 * By default, rounds up. (So if you use 'days', and then event
835
+	 * only occurs for 1 hour, it will return 1 day).
836
+	 *
837
+	 * @param string $units 'seconds','minutes','hours','days'
838
+	 * @param bool   $round_up
839
+	 * @return float|int|mixed
840
+	 * @throws ReflectionException
841
+	 * @throws InvalidArgumentException
842
+	 * @throws InvalidInterfaceException
843
+	 * @throws InvalidDataTypeException
844
+	 * @throws EE_Error
845
+	 */
846
+	public function length($units = 'seconds', $round_up = false)
847
+	{
848
+		$start           = $this->get_raw('DTT_EVT_start');
849
+		$end             = $this->get_raw('DTT_EVT_end');
850
+		$length_in_units = $end - $start;
851
+		switch ($units) {
852
+			//NOTE: We purposefully don't use "break;" in order to chain the divisions
853
+			/** @noinspection PhpMissingBreakStatementInspection */
854
+			case 'days':
855
+				$length_in_units /= 24;
856
+			/** @noinspection PhpMissingBreakStatementInspection */
857
+			case 'hours':
858
+				$length_in_units /= 60;
859
+			/** @noinspection PhpMissingBreakStatementInspection */
860
+			case 'minutes':
861
+				$length_in_units /= 60;
862
+			case 'seconds':
863
+			default:
864
+				$length_in_units = ceil($length_in_units);
865
+		}
866
+		if ($round_up) {
867
+			$length_in_units = max($length_in_units, 1);
868
+		}
869
+		return $length_in_units;
870
+	}
871
+
872
+
873
+	/**
874
+	 *        get end date and time
875
+	 *
876
+	 * @param string $dt_frmt   - string representation of date format defaults to 'F j, Y'
877
+	 * @param string $tm_format - string representation of time format defaults to 'g:i a'
878
+	 * @return    mixed                string on success, FALSE on fail
879
+	 * @throws ReflectionException
880
+	 * @throws InvalidArgumentException
881
+	 * @throws InvalidInterfaceException
882
+	 * @throws InvalidDataTypeException
883
+	 * @throws EE_Error
884
+	 */
885
+	public function end_date_and_time($dt_frmt = '', $tm_format = '')
886
+	{
887
+		return $this->_show_datetime('', 'end', $dt_frmt, $tm_format);
888
+	}
889
+
890
+
891
+	/**
892
+	 * @param string $dt_frmt
893
+	 * @param string $tm_format
894
+	 * @throws ReflectionException
895
+	 * @throws InvalidArgumentException
896
+	 * @throws InvalidInterfaceException
897
+	 * @throws InvalidDataTypeException
898
+	 * @throws EE_Error
899
+	 */
900
+	public function e_end_date_and_time($dt_frmt = '', $tm_format = '')
901
+	{
902
+		$this->_show_datetime('', 'end', $dt_frmt, $tm_format, true);
903
+	}
904
+
905
+
906
+	/**
907
+	 *        get start timestamp
908
+	 *
909
+	 * @return        int
910
+	 * @throws ReflectionException
911
+	 * @throws InvalidArgumentException
912
+	 * @throws InvalidInterfaceException
913
+	 * @throws InvalidDataTypeException
914
+	 * @throws EE_Error
915
+	 */
916
+	public function start()
917
+	{
918
+		return $this->get_raw('DTT_EVT_start');
919
+	}
920
+
921
+
922
+	/**
923
+	 *        get end timestamp
924
+	 *
925
+	 * @return        int
926
+	 * @throws ReflectionException
927
+	 * @throws InvalidArgumentException
928
+	 * @throws InvalidInterfaceException
929
+	 * @throws InvalidDataTypeException
930
+	 * @throws EE_Error
931
+	 */
932
+	public function end()
933
+	{
934
+		return $this->get_raw('DTT_EVT_end');
935
+	}
936
+
937
+
938
+	/**
939
+	 *    get the registration limit for this datetime slot
940
+	 *
941
+	 * @return        mixed        int on success, FALSE on fail
942
+	 * @throws ReflectionException
943
+	 * @throws InvalidArgumentException
944
+	 * @throws InvalidInterfaceException
945
+	 * @throws InvalidDataTypeException
946
+	 * @throws EE_Error
947
+	 */
948
+	public function reg_limit()
949
+	{
950
+		return $this->get_raw('DTT_reg_limit');
951
+	}
952
+
953
+
954
+	/**
955
+	 *    have the tickets sold for this datetime, met or exceed the registration limit ?
956
+	 *
957
+	 * @return        boolean
958
+	 * @throws ReflectionException
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidInterfaceException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws EE_Error
963
+	 */
964
+	public function sold_out()
965
+	{
966
+		return $this->reg_limit() > 0 && $this->sold() >= $this->reg_limit();
967
+	}
968
+
969
+
970
+	/**
971
+	 * return the total number of spaces remaining at this venue.
972
+	 * This only takes the venue's capacity into account, NOT the tickets available for sale
973
+	 *
974
+	 * @param bool $consider_tickets Whether to consider tickets remaining when determining if there are any spaces left
975
+	 *                               Because if all tickets attached to this datetime have no spaces left,
976
+	 *                               then this datetime IS effectively sold out.
977
+	 *                               However, there are cases where we just want to know the spaces
978
+	 *                               remaining for this particular datetime, hence the flag.
979
+	 * @return int
980
+	 * @throws ReflectionException
981
+	 * @throws InvalidArgumentException
982
+	 * @throws InvalidInterfaceException
983
+	 * @throws InvalidDataTypeException
984
+	 * @throws EE_Error
985
+	 */
986
+	public function spaces_remaining($consider_tickets = false)
987
+	{
988
+		// tickets remaining available for purchase
989
+		//no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
990
+		$dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
991
+		if (! $consider_tickets) {
992
+			return $dtt_remaining;
993
+		}
994
+		$tickets_remaining = $this->tickets_remaining();
995
+		return min($dtt_remaining, $tickets_remaining);
996
+	}
997
+
998
+
999
+	/**
1000
+	 * Counts the total tickets available
1001
+	 * (from all the different types of tickets which are available for this datetime).
1002
+	 *
1003
+	 * @param array $query_params like EEM_Base::get_all's
1004
+	 * @return int
1005
+	 * @throws ReflectionException
1006
+	 * @throws InvalidArgumentException
1007
+	 * @throws InvalidInterfaceException
1008
+	 * @throws InvalidDataTypeException
1009
+	 * @throws EE_Error
1010
+	 */
1011
+	public function tickets_remaining($query_params = array())
1012
+	{
1013
+		$sum     = 0;
1014
+		$tickets = $this->tickets($query_params);
1015
+		if (! empty($tickets)) {
1016
+			foreach ($tickets as $ticket) {
1017
+				if ($ticket instanceof EE_Ticket) {
1018
+					// get the actual amount of tickets that can be sold
1019
+					$qty = $ticket->qty('saleable');
1020
+					if ($qty === EE_INF) {
1021
+						return EE_INF;
1022
+					}
1023
+					// no negative ticket quantities plz
1024
+					if ($qty > 0) {
1025
+						$sum += $qty;
1026
+					}
1027
+				}
1028
+			}
1029
+		}
1030
+		return $sum;
1031
+	}
1032
+
1033
+
1034
+	/**
1035
+	 * Gets the count of all the tickets available at this datetime (not ticket types)
1036
+	 * before any were sold
1037
+	 *
1038
+	 * @param array $query_params like EEM_Base::get_all's
1039
+	 * @return int
1040
+	 * @throws ReflectionException
1041
+	 * @throws InvalidArgumentException
1042
+	 * @throws InvalidInterfaceException
1043
+	 * @throws InvalidDataTypeException
1044
+	 * @throws EE_Error
1045
+	 */
1046
+	public function sum_tickets_initially_available($query_params = array())
1047
+	{
1048
+		return $this->sum_related('Ticket', $query_params, 'TKT_qty');
1049
+	}
1050
+
1051
+
1052
+	/**
1053
+	 * Returns the lesser-of-the two: spaces remaining at this datetime, or
1054
+	 * the total tickets remaining (a sum of the tickets remaining for each ticket type
1055
+	 * that is available for this datetime).
1056
+	 *
1057
+	 * @return int
1058
+	 * @throws ReflectionException
1059
+	 * @throws InvalidArgumentException
1060
+	 * @throws InvalidInterfaceException
1061
+	 * @throws InvalidDataTypeException
1062
+	 * @throws EE_Error
1063
+	 */
1064
+	public function total_tickets_available_at_this_datetime()
1065
+	{
1066
+		return $this->spaces_remaining(true);
1067
+	}
1068
+
1069
+
1070
+	/**
1071
+	 * This simply compares the internal dtt for the given string with NOW
1072
+	 * and determines if the date is upcoming or not.
1073
+	 *
1074
+	 * @access public
1075
+	 * @return boolean
1076
+	 * @throws ReflectionException
1077
+	 * @throws InvalidArgumentException
1078
+	 * @throws InvalidInterfaceException
1079
+	 * @throws InvalidDataTypeException
1080
+	 * @throws EE_Error
1081
+	 */
1082
+	public function is_upcoming()
1083
+	{
1084
+		return ($this->get_raw('DTT_EVT_start') > time());
1085
+	}
1086
+
1087
+
1088
+	/**
1089
+	 * This simply compares the internal datetime for the given string with NOW
1090
+	 * and returns if the date is active (i.e. start and end time)
1091
+	 *
1092
+	 * @return boolean
1093
+	 * @throws ReflectionException
1094
+	 * @throws InvalidArgumentException
1095
+	 * @throws InvalidInterfaceException
1096
+	 * @throws InvalidDataTypeException
1097
+	 * @throws EE_Error
1098
+	 */
1099
+	public function is_active()
1100
+	{
1101
+		return ($this->get_raw('DTT_EVT_start') < time() && $this->get_raw('DTT_EVT_end') > time());
1102
+	}
1103
+
1104
+
1105
+	/**
1106
+	 * This simply compares the internal dtt for the given string with NOW
1107
+	 * and determines if the date is expired or not.
1108
+	 *
1109
+	 * @return boolean
1110
+	 * @throws ReflectionException
1111
+	 * @throws InvalidArgumentException
1112
+	 * @throws InvalidInterfaceException
1113
+	 * @throws InvalidDataTypeException
1114
+	 * @throws EE_Error
1115
+	 */
1116
+	public function is_expired()
1117
+	{
1118
+		return ($this->get_raw('DTT_EVT_end') < time());
1119
+	}
1120
+
1121
+
1122
+	/**
1123
+	 * This returns the active status for whether an event is active, upcoming, or expired
1124
+	 *
1125
+	 * @return int return value will be one of the EE_Datetime status constants.
1126
+	 * @throws ReflectionException
1127
+	 * @throws InvalidArgumentException
1128
+	 * @throws InvalidInterfaceException
1129
+	 * @throws InvalidDataTypeException
1130
+	 * @throws EE_Error
1131
+	 */
1132
+	public function get_active_status()
1133
+	{
1134
+		$total_tickets_for_this_dtt = $this->total_tickets_available_at_this_datetime();
1135
+		if ($total_tickets_for_this_dtt !== false && $total_tickets_for_this_dtt < 1) {
1136
+			return EE_Datetime::sold_out;
1137
+		}
1138
+		if ($this->is_expired()) {
1139
+			return EE_Datetime::expired;
1140
+		}
1141
+		if ($this->is_upcoming()) {
1142
+			return EE_Datetime::upcoming;
1143
+		}
1144
+		if ($this->is_active()) {
1145
+			return EE_Datetime::active;
1146
+		}
1147
+		return null;
1148
+	}
1149
+
1150
+
1151
+	/**
1152
+	 * This returns a nice display name for the datetime that is contingent on the span between the dates and times.
1153
+	 *
1154
+	 * @param  boolean $use_dtt_name if TRUE then we'll use DTT->name() if its not empty.
1155
+	 * @return string
1156
+	 * @throws ReflectionException
1157
+	 * @throws InvalidArgumentException
1158
+	 * @throws InvalidInterfaceException
1159
+	 * @throws InvalidDataTypeException
1160
+	 * @throws EE_Error
1161
+	 */
1162
+	public function get_dtt_display_name($use_dtt_name = false)
1163
+	{
1164
+		if ($use_dtt_name) {
1165
+			$dtt_name = $this->name();
1166
+			if (! empty($dtt_name)) {
1167
+				return $dtt_name;
1168
+			}
1169
+		}
1170
+		//first condition is to see if the months are different
1171
+		if (
1172
+			date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1173
+		) {
1174
+			$display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1175
+			//next condition is if its the same month but different day
1176
+		} else {
1177
+			if (
1178
+				date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1179
+				&& date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1180
+			) {
1181
+				$display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1182
+			} else {
1183
+				$display_date = $this->start_date('F j\, Y')
1184
+								. ' @ '
1185
+								. $this->start_date('g:i a')
1186
+								. ' - '
1187
+								. $this->end_date('g:i a');
1188
+			}
1189
+		}
1190
+		return $display_date;
1191
+	}
1192
+
1193
+
1194
+	/**
1195
+	 * Gets all the tickets for this datetime
1196
+	 *
1197
+	 * @param array $query_params see EEM_Base::get_all()
1198
+	 * @return EE_Base_Class[]|EE_Ticket[]
1199
+	 * @throws ReflectionException
1200
+	 * @throws InvalidArgumentException
1201
+	 * @throws InvalidInterfaceException
1202
+	 * @throws InvalidDataTypeException
1203
+	 * @throws EE_Error
1204
+	 */
1205
+	public function tickets($query_params = array())
1206
+	{
1207
+		return $this->get_many_related('Ticket', $query_params);
1208
+	}
1209
+
1210
+
1211
+	/**
1212
+	 * Gets all the ticket types currently available for purchase
1213
+	 *
1214
+	 * @param array $query_params like EEM_Base::get_all's
1215
+	 * @return EE_Ticket[]
1216
+	 * @throws ReflectionException
1217
+	 * @throws InvalidArgumentException
1218
+	 * @throws InvalidInterfaceException
1219
+	 * @throws InvalidDataTypeException
1220
+	 * @throws EE_Error
1221
+	 */
1222
+	public function ticket_types_available_for_purchase($query_params = array())
1223
+	{
1224
+		// first check if datetime is valid
1225
+		if ($this->sold_out() || ! ($this->is_upcoming() || $this->is_active())) {
1226
+			return array();
1227
+		}
1228
+		if (empty($query_params)) {
1229
+			$query_params = array(
1230
+				array(
1231
+					'TKT_start_date' => array('<=', EEM_Ticket::instance()->current_time_for_query('TKT_start_date')),
1232
+					'TKT_end_date'   => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
1233
+					'TKT_deleted'    => false,
1234
+				),
1235
+			);
1236
+		}
1237
+		return $this->tickets($query_params);
1238
+	}
1239
+
1240
+
1241
+	/**
1242
+	 * @return EE_Base_Class|EE_Event
1243
+	 * @throws ReflectionException
1244
+	 * @throws InvalidArgumentException
1245
+	 * @throws InvalidInterfaceException
1246
+	 * @throws InvalidDataTypeException
1247
+	 * @throws EE_Error
1248
+	 */
1249
+	public function event()
1250
+	{
1251
+		return $this->get_first_related('Event');
1252
+	}
1253
+
1254
+
1255
+	/**
1256
+	 * Updates the DTT_sold attribute (and saves) based on the number of registrations for this datetime
1257
+	 * (via the tickets). into account
1258
+	 *
1259
+	 * @return int
1260
+	 * @throws ReflectionException
1261
+	 * @throws InvalidArgumentException
1262
+	 * @throws InvalidInterfaceException
1263
+	 * @throws InvalidDataTypeException
1264
+	 * @throws EE_Error
1265
+	 */
1266
+	public function update_sold()
1267
+	{
1268
+		$count_regs_for_this_datetime = EEM_Registration::instance()->count(
1269
+			array(
1270
+				array(
1271
+					'STS_ID'                 => EEM_Registration::status_id_approved,
1272
+					'REG_deleted'            => 0,
1273
+					'Ticket.Datetime.DTT_ID' => $this->ID(),
1274
+				),
1275
+			)
1276
+		);
1277
+		$sold                         = $this->sold();
1278
+		if ($count_regs_for_this_datetime > $sold) {
1279
+			$this->increase_sold($count_regs_for_this_datetime - $sold);
1280
+			$this->save();
1281
+		} elseif ($count_regs_for_this_datetime < $sold) {
1282
+			$this->decrease_sold($count_regs_for_this_datetime - $sold);
1283
+			$this->save();
1284
+		}
1285
+		return $count_regs_for_this_datetime;
1286
+	}
1287 1287
 }
1288 1288
 
1289 1289
 /* End of file EE_Datetime.class.php */
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -496,7 +496,7 @@  discard block
 block discarded – undo
496 496
             $date_or_time,
497 497
             $echo
498 498
         );
499
-        if (! $echo) {
499
+        if ( ! $echo) {
500 500
             return $dtt;
501 501
         }
502 502
         return '';
@@ -593,12 +593,12 @@  discard block
 block discarded – undo
593 593
             '&nbsp;',
594 594
             $this->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
595 595
         );
596
-        $end     = str_replace(
596
+        $end = str_replace(
597 597
             ' ',
598 598
             '&nbsp;',
599 599
             $this->get_i18n_datetime('DTT_EVT_end', $dt_frmt)
600 600
         );
601
-        return $start !== $end ? $start . $conjunction . $end : $start;
601
+        return $start !== $end ? $start.$conjunction.$end : $start;
602 602
     }
603 603
 
604 604
 
@@ -701,12 +701,12 @@  discard block
 block discarded – undo
701 701
             '&nbsp;',
702 702
             $this->get_i18n_datetime('DTT_EVT_start', $tm_format)
703 703
         );
704
-        $end       = str_replace(
704
+        $end = str_replace(
705 705
             ' ',
706 706
             '&nbsp;',
707 707
             $this->get_i18n_datetime('DTT_EVT_end', $tm_format)
708 708
         );
709
-        return $start !== $end ? $start . $conjunction . $end : $start;
709
+        return $start !== $end ? $start.$conjunction.$end : $start;
710 710
     }
711 711
 
712 712
 
@@ -751,7 +751,7 @@  discard block
 block discarded – undo
751 751
     ) {
752 752
         $dt_format   = ! empty($dt_format) ? $dt_format : $this->_dt_frmt;
753 753
         $tm_format   = ! empty($tm_format) ? $tm_format : $this->_tm_frmt;
754
-        $full_format = $dt_format . $separator . $tm_format;
754
+        $full_format = $dt_format.$separator.$tm_format;
755 755
         //the range output depends on various conditions
756 756
         switch (true) {
757 757
             //start date timestamp and end date timestamp are the same.
@@ -988,7 +988,7 @@  discard block
 block discarded – undo
988 988
         // tickets remaining available for purchase
989 989
         //no need for special checks for infinite, because if DTT_reg_limit == EE_INF, then EE_INF - x = EE_INF
990 990
         $dtt_remaining = $this->reg_limit() - $this->sold_and_reserved();
991
-        if (! $consider_tickets) {
991
+        if ( ! $consider_tickets) {
992 992
             return $dtt_remaining;
993 993
         }
994 994
         $tickets_remaining = $this->tickets_remaining();
@@ -1012,7 +1012,7 @@  discard block
 block discarded – undo
1012 1012
     {
1013 1013
         $sum     = 0;
1014 1014
         $tickets = $this->tickets($query_params);
1015
-        if (! empty($tickets)) {
1015
+        if ( ! empty($tickets)) {
1016 1016
             foreach ($tickets as $ticket) {
1017 1017
                 if ($ticket instanceof EE_Ticket) {
1018 1018
                     // get the actual amount of tickets that can be sold
@@ -1163,7 +1163,7 @@  discard block
 block discarded – undo
1163 1163
     {
1164 1164
         if ($use_dtt_name) {
1165 1165
             $dtt_name = $this->name();
1166
-            if (! empty($dtt_name)) {
1166
+            if ( ! empty($dtt_name)) {
1167 1167
                 return $dtt_name;
1168 1168
             }
1169 1169
         }
@@ -1171,14 +1171,14 @@  discard block
 block discarded – undo
1171 1171
         if (
1172 1172
             date('m', $this->get_raw('DTT_EVT_start')) !== date('m', $this->get_raw('DTT_EVT_end'))
1173 1173
         ) {
1174
-            $display_date = $this->start_date('M j\, Y g:i a') . ' - ' . $this->end_date('M j\, Y g:i a');
1174
+            $display_date = $this->start_date('M j\, Y g:i a').' - '.$this->end_date('M j\, Y g:i a');
1175 1175
             //next condition is if its the same month but different day
1176 1176
         } else {
1177 1177
             if (
1178 1178
                 date('m', $this->get_raw('DTT_EVT_start')) === date('m', $this->get_raw('DTT_EVT_end'))
1179 1179
                 && date('d', $this->get_raw('DTT_EVT_start')) !== date('d', $this->get_raw('DTT_EVT_end'))
1180 1180
             ) {
1181
-                $display_date = $this->start_date('M j\, g:i a') . ' - ' . $this->end_date('M j\, g:i a Y');
1181
+                $display_date = $this->start_date('M j\, g:i a').' - '.$this->end_date('M j\, g:i a Y');
1182 1182
             } else {
1183 1183
                 $display_date = $this->start_date('F j\, Y')
1184 1184
                                 . ' @ '
@@ -1274,7 +1274,7 @@  discard block
 block discarded – undo
1274 1274
                 ),
1275 1275
             )
1276 1276
         );
1277
-        $sold                         = $this->sold();
1277
+        $sold = $this->sold();
1278 1278
         if ($count_regs_for_this_datetime > $sold) {
1279 1279
             $this->increase_sold($count_regs_for_this_datetime - $sold);
1280 1280
             $this->save();
Please login to merge, or discard this patch.
core/db_models/EEM_Datetime.model.php 2 patches
Indentation   +652 added lines, -652 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if (! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 
5 5
 
@@ -14,657 +14,657 @@  discard block
 block discarded – undo
14 14
 class EEM_Datetime extends EEM_Soft_Delete_Base
15 15
 {
16 16
 
17
-    /**
18
-     * @var EEM_Datetime $_instance
19
-     */
20
-    protected static $_instance;
21
-
22
-
23
-    /**
24
-     * private constructor to prevent direct creation
25
-     *
26
-     * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings
27
-     *                         (and any incoming timezone data that gets saved).
28
-     *                         Note this just sends the timezone info to the date time model field objects.
29
-     *                         Default is NULL
30
-     *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
31
-     * @throws EE_Error
32
-     * @throws InvalidArgumentException
33
-     * @throws InvalidArgumentException
34
-     */
35
-    protected function __construct($timezone)
36
-    {
37
-        $this->singular_item           = esc_html__('Datetime', 'event_espresso');
38
-        $this->plural_item             = esc_html__('Datetimes', 'event_espresso');
39
-        $this->_tables                 = array(
40
-            'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'),
41
-        );
42
-        $this->_fields                 = array(
43
-            'Datetime' => array(
44
-                'DTT_ID'          => new EE_Primary_Key_Int_Field(
45
-                    'DTT_ID',
46
-                    esc_html__('Datetime ID', 'event_espresso')
47
-                ),
48
-                'EVT_ID'          => new EE_Foreign_Key_Int_Field(
49
-                    'EVT_ID',
50
-                    esc_html__('Event ID', 'event_espresso'),
51
-                    false,
52
-                    0,
53
-                    'Event'
54
-                ),
55
-                'DTT_name'        => new EE_Plain_Text_Field(
56
-                    'DTT_name',
57
-                    esc_html__('Datetime Name', 'event_espresso'),
58
-                    false,
59
-                    ''
60
-                ),
61
-                'DTT_description' => new EE_Post_Content_Field(
62
-                    'DTT_description',
63
-                    esc_html__('Description for Datetime', 'event_espresso'),
64
-                    false,
65
-                    ''
66
-                ),
67
-                'DTT_EVT_start'   => new EE_Datetime_Field(
68
-                    'DTT_EVT_start',
69
-                    esc_html__('Start time/date of Event', 'event_espresso'),
70
-                    false,
71
-                    EE_Datetime_Field::now,
72
-                    $timezone
73
-                ),
74
-                'DTT_EVT_end'     => new EE_Datetime_Field(
75
-                    'DTT_EVT_end',
76
-                    esc_html__('End time/date of Event', 'event_espresso'),
77
-                    false,
78
-                    EE_Datetime_Field::now,
79
-                    $timezone
80
-                ),
81
-                'DTT_reg_limit'   => new EE_Infinite_Integer_Field(
82
-                    'DTT_reg_limit',
83
-                    esc_html__('Registration Limit for this time', 'event_espresso'),
84
-                    true,
85
-                    EE_INF
86
-                ),
87
-                'DTT_sold'        => new EE_Integer_Field(
88
-                    'DTT_sold',
89
-                    esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'),
90
-                    true,
91
-                    0
92
-                ),
93
-                'DTT_reserved'    => new EE_Integer_Field(
94
-                    'DTT_reserved',
95
-                    esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'),
96
-                    false,
97
-                    0
98
-                ),
99
-                'DTT_is_primary'  => new EE_Boolean_Field(
100
-                    'DTT_is_primary',
101
-                    esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'),
102
-                    false,
103
-                    false
104
-                ),
105
-                'DTT_order'       => new EE_Integer_Field(
106
-                    'DTT_order',
107
-                    esc_html__('The order in which the Datetime is displayed', 'event_espresso'),
108
-                    false,
109
-                    0
110
-                ),
111
-                'DTT_parent'      => new EE_Integer_Field(
112
-                    'DTT_parent',
113
-                    esc_html__('Indicates what DTT_ID is the parent of this DTT_ID'),
114
-                    true,
115
-                    0
116
-                ),
117
-                'DTT_deleted'     => new EE_Trashed_Flag_Field(
118
-                    'DTT_deleted',
119
-                    esc_html__('Flag indicating datetime is archived', 'event_espresso'),
120
-                    false,
121
-                    false
122
-                ),
123
-            ),
124
-        );
125
-        $this->_model_relations        = array(
126
-            'Ticket'  => new EE_HABTM_Relation('Datetime_Ticket'),
127
-            'Event'   => new EE_Belongs_To_Relation(),
128
-            'Checkin' => new EE_Has_Many_Relation(),
129
-        );
130
-        $this->_model_chain_to_wp_user = 'Event';
131
-        //this model is generally available for reading
132
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public(
133
-            'Event'
134
-        );
135
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected(
136
-            'Event'
137
-        );
138
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected(
139
-            'Event'
140
-        );
141
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
142
-            'Event',
143
-            EEM_Base::caps_edit
144
-        );
145
-        parent::__construct($timezone);
146
-    }
147
-
148
-
149
-    /**
150
-     * create new blank datetime
151
-     *
152
-     * @access public
153
-     * @return EE_Datetime[] array on success, FALSE on fail
154
-     * @throws EE_Error
155
-     */
156
-    public function create_new_blank_datetime()
157
-    {
158
-        //makes sure timezone is always set.
159
-        $timezone_string = $this->get_timezone();
160
-        $blank_datetime  = EE_Datetime::new_instance(
161
-            array(
162
-                'DTT_EVT_start' => $this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS,
163
-                'DTT_EVT_end'   => $this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS,
164
-                'DTT_order'     => 1,
165
-                'DTT_reg_limit' => EE_INF,
166
-            ),
167
-            $timezone_string
168
-        );
169
-        $blank_datetime->set_start_time(
170
-            $this->convert_datetime_for_query(
171
-                'DTT_EVT_start',
172
-                '8am',
173
-                'ga',
174
-                $timezone_string
175
-            )
176
-        );
177
-        $blank_datetime->set_end_time(
178
-            $this->convert_datetime_for_query(
179
-                'DTT_EVT_end',
180
-                '5pm',
181
-                'ga',
182
-                $timezone_string
183
-            )
184
-        );
185
-        return array($blank_datetime);
186
-    }
187
-
188
-
189
-    /**
190
-     * get event start date from db
191
-     *
192
-     * @access public
193
-     * @param  int $EVT_ID
194
-     * @return EE_Datetime[] array on success, FALSE on fail
195
-     * @throws EE_Error
196
-     */
197
-    public function get_all_event_dates($EVT_ID = 0)
198
-    {
199
-        if (! $EVT_ID) { // on add_new_event event_id gets set to 0
200
-            return $this->create_new_blank_datetime();
201
-        }
202
-        $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
203
-        if (empty($results)) {
204
-            return $this->create_new_blank_datetime();
205
-        }
206
-        return $results;
207
-    }
208
-
209
-
210
-    /**
211
-     * get all datetimes attached to an event ordered by the DTT_order field
212
-     *
213
-     * @public
214
-     * @param  int    $EVT_ID     event id
215
-     * @param boolean $include_expired
216
-     * @param boolean $include_deleted
217
-     * @param  int    $limit      If included then limit the count of results by
218
-     *                            the given number
219
-     * @return EE_Datetime[]
220
-     * @throws EE_Error
221
-     */
222
-    public function get_datetimes_for_event_ordered_by_DTT_order(
223
-        $EVT_ID,
224
-        $include_expired = true,
225
-        $include_deleted = true,
226
-        $limit = null
227
-    ) {
228
-        //sanitize EVT_ID
229
-        $EVT_ID         = absint($EVT_ID);
230
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
231
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
232
-        $where_params = array('Event.EVT_ID' => $EVT_ID);
233
-        $query_params = ! empty($limit)
234
-            ? array(
235
-                $where_params,
236
-                'limit'                    => $limit,
237
-                'order_by'                 => array('DTT_order' => 'ASC'),
238
-                'default_where_conditions' => 'none',
239
-            )
240
-            : array(
241
-                $where_params,
242
-                'order_by'                 => array('DTT_order' => 'ASC'),
243
-                'default_where_conditions' => 'none',
244
-            );
245
-        if (! $include_expired) {
246
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
247
-        }
248
-        if ($include_deleted) {
249
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
250
-        }
251
-        /** @var EE_Datetime[] $result */
252
-        $result = $this->get_all($query_params);
253
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
254
-        return $result;
255
-    }
256
-
257
-
258
-    /**
259
-     * Gets the datetimes for the event (with the given limit), and orders them by "importance".
260
-     * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW),
261
-     * and then the earlier datetimes are the most important.
262
-     * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet.
263
-     *
264
-     * @param int $EVT_ID
265
-     * @param int $limit
266
-     * @return EE_Datetime[]|EE_Base_Class[]
267
-     * @throws EE_Error
268
-     */
269
-    public function get_datetimes_for_event_ordered_by_importance($EVT_ID = 0, $limit = null)
270
-    {
271
-        return $this->get_all(
272
-            array(
273
-                array('Event.EVT_ID' => $EVT_ID),
274
-                'limit'                    => $limit,
275
-                'order_by'                 => array('DTT_EVT_start' => 'ASC'),
276
-                'default_where_conditions' => 'none',
277
-            )
278
-        );
279
-    }
280
-
281
-
282
-    /**
283
-     * @param int     $EVT_ID
284
-     * @param boolean $include_expired
285
-     * @param boolean $include_deleted
286
-     * @return EE_Datetime
287
-     * @throws EE_Error
288
-     */
289
-    public function get_oldest_datetime_for_event($EVT_ID, $include_expired = false, $include_deleted = false)
290
-    {
291
-        $results = $this->get_datetimes_for_event_ordered_by_start_time(
292
-            $EVT_ID,
293
-            $include_expired,
294
-            $include_deleted,
295
-            1
296
-        );
297
-        if ($results) {
298
-            return array_shift($results);
299
-        }
300
-        return null;
301
-    }
302
-
303
-
304
-    /**
305
-     * Gets the 'primary' datetime for an event.
306
-     *
307
-     * @param int  $EVT_ID
308
-     * @param bool $try_to_exclude_expired
309
-     * @param bool $try_to_exclude_deleted
310
-     * @return \EE_Datetime
311
-     * @throws EE_Error
312
-     */
313
-    public function get_primary_datetime_for_event(
314
-        $EVT_ID,
315
-        $try_to_exclude_expired = true,
316
-        $try_to_exclude_deleted = true
317
-    ) {
318
-        if ($try_to_exclude_expired) {
319
-            $non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false);
320
-            if ($non_expired) {
321
-                return $non_expired;
322
-            }
323
-        }
324
-        if ($try_to_exclude_deleted) {
325
-            $expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true);
326
-            if ($expired_even) {
327
-                return $expired_even;
328
-            }
329
-        }
330
-        return $this->get_oldest_datetime_for_event($EVT_ID, true, true);
331
-    }
332
-
333
-
334
-    /**
335
-     * Gets ALL the datetimes for an event (including trashed ones, for now), ordered
336
-     * only by start date
337
-     *
338
-     * @param int     $EVT_ID
339
-     * @param boolean $include_expired
340
-     * @param boolean $include_deleted
341
-     * @param int     $limit
342
-     * @return EE_Datetime[]
343
-     * @throws EE_Error
344
-     */
345
-    public function get_datetimes_for_event_ordered_by_start_time(
346
-        $EVT_ID,
347
-        $include_expired = true,
348
-        $include_deleted = true,
349
-        $limit = null
350
-    ) {
351
-        //sanitize EVT_ID
352
-        $EVT_ID         = absint($EVT_ID);
353
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
354
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
355
-        $query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
356
-        if (! $include_expired) {
357
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
358
-        }
359
-        if ($include_deleted) {
360
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
361
-        }
362
-        if ($limit) {
363
-            $query_params['limit'] = $limit;
364
-        }
365
-        /** @var EE_Datetime[] $result */
366
-        $result = $this->get_all($query_params);
367
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
368
-        return $result;
369
-    }
370
-
371
-
372
-    /**
373
-     * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered
374
-     * only by start date
375
-     *
376
-     * @param int     $TKT_ID
377
-     * @param boolean $include_expired
378
-     * @param boolean $include_deleted
379
-     * @param int     $limit
380
-     * @return EE_Datetime[]
381
-     * @throws EE_Error
382
-     */
383
-    public function get_datetimes_for_ticket_ordered_by_start_time(
384
-        $TKT_ID,
385
-        $include_expired = true,
386
-        $include_deleted = true,
387
-        $limit = null
388
-    ) {
389
-        //sanitize TKT_ID
390
-        $TKT_ID         = absint($TKT_ID);
391
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
392
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
393
-        $query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
394
-        if (! $include_expired) {
395
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
396
-        }
397
-        if ($include_deleted) {
398
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
399
-        }
400
-        if ($limit) {
401
-            $query_params['limit'] = $limit;
402
-        }
403
-        /** @var EE_Datetime[] $result */
404
-        $result = $this->get_all($query_params);
405
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
406
-        return $result;
407
-    }
408
-
409
-
410
-    /**
411
-     * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the
412
-     * datetimes.
413
-     *
414
-     * @param  int      $TKT_ID          ID of ticket to retrieve the datetimes for
415
-     * @param  boolean  $include_expired whether to include expired datetimes or not
416
-     * @param  boolean  $include_deleted whether to include trashed datetimes or not.
417
-     * @param  int|null $limit           if null, no limit, if int then limit results by
418
-     *                                   that number
419
-     * @return EE_Datetime[]
420
-     * @throws EE_Error
421
-     */
422
-    public function get_datetimes_for_ticket_ordered_by_DTT_order(
423
-        $TKT_ID,
424
-        $include_expired = true,
425
-        $include_deleted = true,
426
-        $limit = null
427
-    ) {
428
-        //sanitize id.
429
-        $TKT_ID         = absint($TKT_ID);
430
-        $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
431
-        $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
432
-        $where_params = array('Ticket.TKT_ID' => $TKT_ID);
433
-        $query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC'));
434
-        if (! $include_expired) {
435
-            $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
436
-        }
437
-        if ($include_deleted) {
438
-            $query_params[0]['DTT_deleted'] = array('IN', array(true, false));
439
-        }
440
-        if ($limit) {
441
-            $query_params['limit'] = $limit;
442
-        }
443
-        /** @var EE_Datetime[] $result */
444
-        $result = $this->get_all($query_params);
445
-        $this->assume_values_already_prepared_by_model_object($old_assumption);
446
-        return $result;
447
-    }
448
-
449
-
450
-    /**
451
-     * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK
452
-     * reason it doesn't exist, we consider the earliest event the most important)
453
-     *
454
-     * @param int $EVT_ID
455
-     * @return EE_Datetime
456
-     * @throws EE_Error
457
-     */
458
-    public function get_most_important_datetime_for_event($EVT_ID)
459
-    {
460
-        $results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1);
461
-        if ($results) {
462
-            return array_shift($results);
463
-        }
464
-        return null;
465
-    }
466
-
467
-
468
-    /**
469
-     * This returns a wpdb->results        Array of all DTT month and years matching the incoming query params and
470
-     * grouped by month and year.
471
-     *
472
-     * @param  array  $where_params      Array of query_params as described in the comments for EEM_Base::get_all()
473
-     * @param  string $evt_active_status A string representing the evt active status to filter the months by.
474
-     *                                   Can be:
475
-     *                                   - '' = no filter
476
-     *                                   - upcoming = Published events with at least one upcoming datetime.
477
-     *                                   - expired = Events with all datetimes expired.
478
-     *                                   - active = Events that are published and have at least one datetime that
479
-     *                                   starts before now and ends after now.
480
-     *                                   - inactive = Events that are either not published.
481
-     * @return EE_Base_Class[]
482
-     * @throws EE_Error
483
-     * @throws InvalidArgumentException
484
-     * @throws InvalidArgumentException
485
-     */
486
-    public function get_dtt_months_and_years($where_params, $evt_active_status = '')
487
-    {
488
-        $current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start');
489
-        $current_time_for_DTT_EVT_end   = $this->current_time_for_query('DTT_EVT_end');
490
-        switch ($evt_active_status) {
491
-            case 'upcoming' :
492
-                $where_params['Event.status'] = 'publish';
493
-                //if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
494
-                if (isset($where_params['DTT_EVT_start'])) {
495
-                    $where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start'];
496
-                }
497
-                $where_params['DTT_EVT_start'] = array('>', $current_time_for_DTT_EVT_start);
498
-                break;
499
-            case 'expired' :
500
-                if (isset($where_params['Event.status'])) {
501
-                    unset($where_params['Event.status']);
502
-                }
503
-                //get events to exclude
504
-                $exclude_query[0] = array_merge($where_params,
505
-                    array('DTT_EVT_end' => array('>', $current_time_for_DTT_EVT_end)));
506
-                //first get all events that have datetimes where its not expired.
507
-                $event_ids = $this->_get_all_wpdb_results(
508
-                    $exclude_query,
509
-                    OBJECT_K,
510
-                    'Datetime.EVT_ID'
511
-                );
512
-                $event_ids = array_keys($event_ids);
513
-                if (isset($where_params['DTT_EVT_end'])) {
514
-                    $where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
515
-                }
516
-                $where_params['DTT_EVT_end']  = array('<', $current_time_for_DTT_EVT_end);
517
-                $where_params['Event.EVT_ID'] = array('NOT IN', $event_ids);
518
-                break;
519
-            case 'active' :
520
-                $where_params['Event.status'] = 'publish';
521
-                if (isset($where_params['DTT_EVT_start'])) {
522
-                    $where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start'];
523
-                }
524
-                if (isset($where_params['Datetime.DTT_EVT_end'])) {
525
-                    $where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end'];
526
-                }
527
-                $where_params['DTT_EVT_start'] = array('<', $current_time_for_DTT_EVT_start);
528
-                $where_params['DTT_EVT_end']   = array('>', $current_time_for_DTT_EVT_end);
529
-                break;
530
-            case 'inactive' :
531
-                if (isset($where_params['Event.status'])) {
532
-                    unset($where_params['Event.status']);
533
-                }
534
-                if (isset($where_params['OR'])) {
535
-                    $where_params['AND']['OR'] = $where_params['OR'];
536
-                }
537
-                if (isset($where_params['DTT_EVT_end'])) {
538
-                    $where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
539
-                    unset($where_params['DTT_EVT_end']);
540
-                }
541
-                if (isset($where_params['DTT_EVT_start'])) {
542
-                    $where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start'];
543
-                    unset($where_params['DTT_EVT_start']);
544
-                }
545
-                $where_params['AND']['Event.status'] = array('!=', 'publish');
546
-                break;
547
-        }
548
-        $query_params[0]          = $where_params;
549
-        $query_params['group_by'] = array('dtt_year', 'dtt_month');
550
-        $query_params['order_by'] = array('DTT_EVT_start' => 'DESC');
551
-        $query_interval           = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(),
552
-            'DTT_EVT_start');
553
-        $columns_to_select        = array(
554
-            'dtt_year'      => array('YEAR(' . $query_interval . ')', '%s'),
555
-            'dtt_month'     => array('MONTHNAME(' . $query_interval . ')', '%s'),
556
-            'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'),
557
-        );
558
-        return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
559
-    }
560
-
561
-
562
-    /**
563
-     * Updates the DTT_sold attribute on each datetime (based on the registrations
564
-     * for the tickets for each datetime)
565
-     *
566
-     * @param EE_Base_Class[]|EE_Datetime[] $datetimes
567
-     * @throws EE_Error
568
-     */
569
-    public function update_sold($datetimes)
570
-    {
571
-        EE_Error::doing_it_wrong(
572
-            __FUNCTION__,
573
-            esc_html__(
574
-                'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.',
575
-                'event_espresso'
576
-            ),
577
-            '4.9.32.rc.005'
578
-        );
579
-        foreach ($datetimes as $datetime) {
580
-            $datetime->update_sold();
581
-        }
582
-    }
583
-
584
-
585
-    /**
586
-     *    Gets the total number of tickets available at a particular datetime
587
-     *    (does NOT take into account the datetime's spaces available)
588
-     *
589
-     * @param int   $DTT_ID
590
-     * @param array $query_params
591
-     * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF,  IF there are NO
592
-     *             tickets attached to datetime then FALSE is returned.
593
-     */
594
-    public function sum_tickets_currently_available_at_datetime($DTT_ID, array $query_params = array())
595
-    {
596
-        $datetime = $this->get_one_by_ID($DTT_ID);
597
-        if ($datetime instanceof EE_Datetime) {
598
-            return $datetime->tickets_remaining($query_params);
599
-        }
600
-        return 0;
601
-    }
602
-
603
-
604
-    /**
605
-     * This returns an array of counts of datetimes in the database for each Datetime status that can be queried.
606
-     *
607
-     * @param  array $stati_to_include If included you can restrict the statuses we return counts for by including the
608
-     *                                 stati you want counts for as values in the array.  An empty array returns counts
609
-     *                                 for all valid stati.
610
-     * @param  array $query_params     If included can be used to refine the conditions for returning the count (i.e.
611
-     *                                 only for Datetimes connected to a specific event, or specific ticket.
612
-     * @return array  The value returned is an array indexed by Datetime Status and the values are the counts.  The
613
-     * @throws EE_Error
614
-     *                                 stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming
615
-     *                                 EE_Datetime::expired
616
-     */
617
-    public function get_datetime_counts_by_status(array $stati_to_include = array(), array $query_params = array())
618
-    {
619
-        //only accept where conditions for this query.
620
-        $_where            = isset($query_params[0]) ? $query_params[0] : array();
621
-        $status_query_args = array(
622
-            EE_Datetime::active   => array_merge(
623
-                $_where,
624
-                array('DTT_EVT_start' => array('<', time()), 'DTT_EVT_end' => array('>', time()))
625
-            ),
626
-            EE_Datetime::upcoming => array_merge(
627
-                $_where,
628
-                array('DTT_EVT_start' => array('>', time()))
629
-            ),
630
-            EE_Datetime::expired  => array_merge(
631
-                $_where,
632
-                array('DTT_EVT_end' => array('<', time()))
633
-            ),
634
-        );
635
-        if (! empty($stati_to_include)) {
636
-            foreach (array_keys($status_query_args) as $status) {
637
-                if (! in_array($status, $stati_to_include, true)) {
638
-                    unset($status_query_args[ $status ]);
639
-                }
640
-            }
641
-        }
642
-        //loop through and query counts for each stati.
643
-        $status_query_results = array();
644
-        foreach ($status_query_args as $status => $status_where_conditions) {
645
-            $status_query_results[ $status ] = EEM_Datetime::count(
646
-                array($status_where_conditions),
647
-                'DTT_ID',
648
-                true
649
-            );
650
-        }
651
-        return $status_query_results;
652
-    }
653
-
654
-
655
-    /**
656
-     * Returns the specific count for a given Datetime status matching any given query_params.
657
-     *
658
-     * @param string $status Valid string representation for Datetime status requested. (Defaults to Active).
659
-     * @param array  $query_params
660
-     * @return int
661
-     * @throws EE_Error
662
-     */
663
-    public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array())
664
-    {
665
-        $count = $this->get_datetime_counts_by_status(array($status), $query_params);
666
-        return ! empty($count[ $status ]) ? $count[ $status ] : 0;
667
-    }
17
+	/**
18
+	 * @var EEM_Datetime $_instance
19
+	 */
20
+	protected static $_instance;
21
+
22
+
23
+	/**
24
+	 * private constructor to prevent direct creation
25
+	 *
26
+	 * @param string $timezone A string representing the timezone we want to set for returned Date Time Strings
27
+	 *                         (and any incoming timezone data that gets saved).
28
+	 *                         Note this just sends the timezone info to the date time model field objects.
29
+	 *                         Default is NULL
30
+	 *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
31
+	 * @throws EE_Error
32
+	 * @throws InvalidArgumentException
33
+	 * @throws InvalidArgumentException
34
+	 */
35
+	protected function __construct($timezone)
36
+	{
37
+		$this->singular_item           = esc_html__('Datetime', 'event_espresso');
38
+		$this->plural_item             = esc_html__('Datetimes', 'event_espresso');
39
+		$this->_tables                 = array(
40
+			'Datetime' => new EE_Primary_Table('esp_datetime', 'DTT_ID'),
41
+		);
42
+		$this->_fields                 = array(
43
+			'Datetime' => array(
44
+				'DTT_ID'          => new EE_Primary_Key_Int_Field(
45
+					'DTT_ID',
46
+					esc_html__('Datetime ID', 'event_espresso')
47
+				),
48
+				'EVT_ID'          => new EE_Foreign_Key_Int_Field(
49
+					'EVT_ID',
50
+					esc_html__('Event ID', 'event_espresso'),
51
+					false,
52
+					0,
53
+					'Event'
54
+				),
55
+				'DTT_name'        => new EE_Plain_Text_Field(
56
+					'DTT_name',
57
+					esc_html__('Datetime Name', 'event_espresso'),
58
+					false,
59
+					''
60
+				),
61
+				'DTT_description' => new EE_Post_Content_Field(
62
+					'DTT_description',
63
+					esc_html__('Description for Datetime', 'event_espresso'),
64
+					false,
65
+					''
66
+				),
67
+				'DTT_EVT_start'   => new EE_Datetime_Field(
68
+					'DTT_EVT_start',
69
+					esc_html__('Start time/date of Event', 'event_espresso'),
70
+					false,
71
+					EE_Datetime_Field::now,
72
+					$timezone
73
+				),
74
+				'DTT_EVT_end'     => new EE_Datetime_Field(
75
+					'DTT_EVT_end',
76
+					esc_html__('End time/date of Event', 'event_espresso'),
77
+					false,
78
+					EE_Datetime_Field::now,
79
+					$timezone
80
+				),
81
+				'DTT_reg_limit'   => new EE_Infinite_Integer_Field(
82
+					'DTT_reg_limit',
83
+					esc_html__('Registration Limit for this time', 'event_espresso'),
84
+					true,
85
+					EE_INF
86
+				),
87
+				'DTT_sold'        => new EE_Integer_Field(
88
+					'DTT_sold',
89
+					esc_html__('How many sales for this Datetime that have occurred', 'event_espresso'),
90
+					true,
91
+					0
92
+				),
93
+				'DTT_reserved'    => new EE_Integer_Field(
94
+					'DTT_reserved',
95
+					esc_html__('Quantity of tickets reserved, but not yet fully purchased', 'event_espresso'),
96
+					false,
97
+					0
98
+				),
99
+				'DTT_is_primary'  => new EE_Boolean_Field(
100
+					'DTT_is_primary',
101
+					esc_html__('Flag indicating datetime is primary one for event', 'event_espresso'),
102
+					false,
103
+					false
104
+				),
105
+				'DTT_order'       => new EE_Integer_Field(
106
+					'DTT_order',
107
+					esc_html__('The order in which the Datetime is displayed', 'event_espresso'),
108
+					false,
109
+					0
110
+				),
111
+				'DTT_parent'      => new EE_Integer_Field(
112
+					'DTT_parent',
113
+					esc_html__('Indicates what DTT_ID is the parent of this DTT_ID'),
114
+					true,
115
+					0
116
+				),
117
+				'DTT_deleted'     => new EE_Trashed_Flag_Field(
118
+					'DTT_deleted',
119
+					esc_html__('Flag indicating datetime is archived', 'event_espresso'),
120
+					false,
121
+					false
122
+				),
123
+			),
124
+		);
125
+		$this->_model_relations        = array(
126
+			'Ticket'  => new EE_HABTM_Relation('Datetime_Ticket'),
127
+			'Event'   => new EE_Belongs_To_Relation(),
128
+			'Checkin' => new EE_Has_Many_Relation(),
129
+		);
130
+		$this->_model_chain_to_wp_user = 'Event';
131
+		//this model is generally available for reading
132
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public(
133
+			'Event'
134
+		);
135
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected(
136
+			'Event'
137
+		);
138
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected(
139
+			'Event'
140
+		);
141
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
142
+			'Event',
143
+			EEM_Base::caps_edit
144
+		);
145
+		parent::__construct($timezone);
146
+	}
147
+
148
+
149
+	/**
150
+	 * create new blank datetime
151
+	 *
152
+	 * @access public
153
+	 * @return EE_Datetime[] array on success, FALSE on fail
154
+	 * @throws EE_Error
155
+	 */
156
+	public function create_new_blank_datetime()
157
+	{
158
+		//makes sure timezone is always set.
159
+		$timezone_string = $this->get_timezone();
160
+		$blank_datetime  = EE_Datetime::new_instance(
161
+			array(
162
+				'DTT_EVT_start' => $this->current_time_for_query('DTT_EVT_start', true) + MONTH_IN_SECONDS,
163
+				'DTT_EVT_end'   => $this->current_time_for_query('DTT_EVT_end', true) + MONTH_IN_SECONDS,
164
+				'DTT_order'     => 1,
165
+				'DTT_reg_limit' => EE_INF,
166
+			),
167
+			$timezone_string
168
+		);
169
+		$blank_datetime->set_start_time(
170
+			$this->convert_datetime_for_query(
171
+				'DTT_EVT_start',
172
+				'8am',
173
+				'ga',
174
+				$timezone_string
175
+			)
176
+		);
177
+		$blank_datetime->set_end_time(
178
+			$this->convert_datetime_for_query(
179
+				'DTT_EVT_end',
180
+				'5pm',
181
+				'ga',
182
+				$timezone_string
183
+			)
184
+		);
185
+		return array($blank_datetime);
186
+	}
187
+
188
+
189
+	/**
190
+	 * get event start date from db
191
+	 *
192
+	 * @access public
193
+	 * @param  int $EVT_ID
194
+	 * @return EE_Datetime[] array on success, FALSE on fail
195
+	 * @throws EE_Error
196
+	 */
197
+	public function get_all_event_dates($EVT_ID = 0)
198
+	{
199
+		if (! $EVT_ID) { // on add_new_event event_id gets set to 0
200
+			return $this->create_new_blank_datetime();
201
+		}
202
+		$results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
203
+		if (empty($results)) {
204
+			return $this->create_new_blank_datetime();
205
+		}
206
+		return $results;
207
+	}
208
+
209
+
210
+	/**
211
+	 * get all datetimes attached to an event ordered by the DTT_order field
212
+	 *
213
+	 * @public
214
+	 * @param  int    $EVT_ID     event id
215
+	 * @param boolean $include_expired
216
+	 * @param boolean $include_deleted
217
+	 * @param  int    $limit      If included then limit the count of results by
218
+	 *                            the given number
219
+	 * @return EE_Datetime[]
220
+	 * @throws EE_Error
221
+	 */
222
+	public function get_datetimes_for_event_ordered_by_DTT_order(
223
+		$EVT_ID,
224
+		$include_expired = true,
225
+		$include_deleted = true,
226
+		$limit = null
227
+	) {
228
+		//sanitize EVT_ID
229
+		$EVT_ID         = absint($EVT_ID);
230
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
231
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
232
+		$where_params = array('Event.EVT_ID' => $EVT_ID);
233
+		$query_params = ! empty($limit)
234
+			? array(
235
+				$where_params,
236
+				'limit'                    => $limit,
237
+				'order_by'                 => array('DTT_order' => 'ASC'),
238
+				'default_where_conditions' => 'none',
239
+			)
240
+			: array(
241
+				$where_params,
242
+				'order_by'                 => array('DTT_order' => 'ASC'),
243
+				'default_where_conditions' => 'none',
244
+			);
245
+		if (! $include_expired) {
246
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
247
+		}
248
+		if ($include_deleted) {
249
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
250
+		}
251
+		/** @var EE_Datetime[] $result */
252
+		$result = $this->get_all($query_params);
253
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
254
+		return $result;
255
+	}
256
+
257
+
258
+	/**
259
+	 * Gets the datetimes for the event (with the given limit), and orders them by "importance".
260
+	 * By importance, we mean that the primary datetimes are most important (DEPRECATED FOR NOW),
261
+	 * and then the earlier datetimes are the most important.
262
+	 * Maybe we'll want this to take into account datetimes that haven't already passed, but we don't yet.
263
+	 *
264
+	 * @param int $EVT_ID
265
+	 * @param int $limit
266
+	 * @return EE_Datetime[]|EE_Base_Class[]
267
+	 * @throws EE_Error
268
+	 */
269
+	public function get_datetimes_for_event_ordered_by_importance($EVT_ID = 0, $limit = null)
270
+	{
271
+		return $this->get_all(
272
+			array(
273
+				array('Event.EVT_ID' => $EVT_ID),
274
+				'limit'                    => $limit,
275
+				'order_by'                 => array('DTT_EVT_start' => 'ASC'),
276
+				'default_where_conditions' => 'none',
277
+			)
278
+		);
279
+	}
280
+
281
+
282
+	/**
283
+	 * @param int     $EVT_ID
284
+	 * @param boolean $include_expired
285
+	 * @param boolean $include_deleted
286
+	 * @return EE_Datetime
287
+	 * @throws EE_Error
288
+	 */
289
+	public function get_oldest_datetime_for_event($EVT_ID, $include_expired = false, $include_deleted = false)
290
+	{
291
+		$results = $this->get_datetimes_for_event_ordered_by_start_time(
292
+			$EVT_ID,
293
+			$include_expired,
294
+			$include_deleted,
295
+			1
296
+		);
297
+		if ($results) {
298
+			return array_shift($results);
299
+		}
300
+		return null;
301
+	}
302
+
303
+
304
+	/**
305
+	 * Gets the 'primary' datetime for an event.
306
+	 *
307
+	 * @param int  $EVT_ID
308
+	 * @param bool $try_to_exclude_expired
309
+	 * @param bool $try_to_exclude_deleted
310
+	 * @return \EE_Datetime
311
+	 * @throws EE_Error
312
+	 */
313
+	public function get_primary_datetime_for_event(
314
+		$EVT_ID,
315
+		$try_to_exclude_expired = true,
316
+		$try_to_exclude_deleted = true
317
+	) {
318
+		if ($try_to_exclude_expired) {
319
+			$non_expired = $this->get_oldest_datetime_for_event($EVT_ID, false, false);
320
+			if ($non_expired) {
321
+				return $non_expired;
322
+			}
323
+		}
324
+		if ($try_to_exclude_deleted) {
325
+			$expired_even = $this->get_oldest_datetime_for_event($EVT_ID, true);
326
+			if ($expired_even) {
327
+				return $expired_even;
328
+			}
329
+		}
330
+		return $this->get_oldest_datetime_for_event($EVT_ID, true, true);
331
+	}
332
+
333
+
334
+	/**
335
+	 * Gets ALL the datetimes for an event (including trashed ones, for now), ordered
336
+	 * only by start date
337
+	 *
338
+	 * @param int     $EVT_ID
339
+	 * @param boolean $include_expired
340
+	 * @param boolean $include_deleted
341
+	 * @param int     $limit
342
+	 * @return EE_Datetime[]
343
+	 * @throws EE_Error
344
+	 */
345
+	public function get_datetimes_for_event_ordered_by_start_time(
346
+		$EVT_ID,
347
+		$include_expired = true,
348
+		$include_deleted = true,
349
+		$limit = null
350
+	) {
351
+		//sanitize EVT_ID
352
+		$EVT_ID         = absint($EVT_ID);
353
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
354
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
355
+		$query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
356
+		if (! $include_expired) {
357
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
358
+		}
359
+		if ($include_deleted) {
360
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
361
+		}
362
+		if ($limit) {
363
+			$query_params['limit'] = $limit;
364
+		}
365
+		/** @var EE_Datetime[] $result */
366
+		$result = $this->get_all($query_params);
367
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
368
+		return $result;
369
+	}
370
+
371
+
372
+	/**
373
+	 * Gets ALL the datetimes for an ticket (including trashed ones, for now), ordered
374
+	 * only by start date
375
+	 *
376
+	 * @param int     $TKT_ID
377
+	 * @param boolean $include_expired
378
+	 * @param boolean $include_deleted
379
+	 * @param int     $limit
380
+	 * @return EE_Datetime[]
381
+	 * @throws EE_Error
382
+	 */
383
+	public function get_datetimes_for_ticket_ordered_by_start_time(
384
+		$TKT_ID,
385
+		$include_expired = true,
386
+		$include_deleted = true,
387
+		$limit = null
388
+	) {
389
+		//sanitize TKT_ID
390
+		$TKT_ID         = absint($TKT_ID);
391
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
392
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
393
+		$query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
394
+		if (! $include_expired) {
395
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
396
+		}
397
+		if ($include_deleted) {
398
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
399
+		}
400
+		if ($limit) {
401
+			$query_params['limit'] = $limit;
402
+		}
403
+		/** @var EE_Datetime[] $result */
404
+		$result = $this->get_all($query_params);
405
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
406
+		return $result;
407
+	}
408
+
409
+
410
+	/**
411
+	 * Gets all the datetimes for a ticket (including trashed ones, for now), ordered by the DTT_order for the
412
+	 * datetimes.
413
+	 *
414
+	 * @param  int      $TKT_ID          ID of ticket to retrieve the datetimes for
415
+	 * @param  boolean  $include_expired whether to include expired datetimes or not
416
+	 * @param  boolean  $include_deleted whether to include trashed datetimes or not.
417
+	 * @param  int|null $limit           if null, no limit, if int then limit results by
418
+	 *                                   that number
419
+	 * @return EE_Datetime[]
420
+	 * @throws EE_Error
421
+	 */
422
+	public function get_datetimes_for_ticket_ordered_by_DTT_order(
423
+		$TKT_ID,
424
+		$include_expired = true,
425
+		$include_deleted = true,
426
+		$limit = null
427
+	) {
428
+		//sanitize id.
429
+		$TKT_ID         = absint($TKT_ID);
430
+		$old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
431
+		$this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
432
+		$where_params = array('Ticket.TKT_ID' => $TKT_ID);
433
+		$query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC'));
434
+		if (! $include_expired) {
435
+			$query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
436
+		}
437
+		if ($include_deleted) {
438
+			$query_params[0]['DTT_deleted'] = array('IN', array(true, false));
439
+		}
440
+		if ($limit) {
441
+			$query_params['limit'] = $limit;
442
+		}
443
+		/** @var EE_Datetime[] $result */
444
+		$result = $this->get_all($query_params);
445
+		$this->assume_values_already_prepared_by_model_object($old_assumption);
446
+		return $result;
447
+	}
448
+
449
+
450
+	/**
451
+	 * Gets the most important datetime for a particular event (ie, the primary event usually. But if for some WACK
452
+	 * reason it doesn't exist, we consider the earliest event the most important)
453
+	 *
454
+	 * @param int $EVT_ID
455
+	 * @return EE_Datetime
456
+	 * @throws EE_Error
457
+	 */
458
+	public function get_most_important_datetime_for_event($EVT_ID)
459
+	{
460
+		$results = $this->get_datetimes_for_event_ordered_by_importance($EVT_ID, 1);
461
+		if ($results) {
462
+			return array_shift($results);
463
+		}
464
+		return null;
465
+	}
466
+
467
+
468
+	/**
469
+	 * This returns a wpdb->results        Array of all DTT month and years matching the incoming query params and
470
+	 * grouped by month and year.
471
+	 *
472
+	 * @param  array  $where_params      Array of query_params as described in the comments for EEM_Base::get_all()
473
+	 * @param  string $evt_active_status A string representing the evt active status to filter the months by.
474
+	 *                                   Can be:
475
+	 *                                   - '' = no filter
476
+	 *                                   - upcoming = Published events with at least one upcoming datetime.
477
+	 *                                   - expired = Events with all datetimes expired.
478
+	 *                                   - active = Events that are published and have at least one datetime that
479
+	 *                                   starts before now and ends after now.
480
+	 *                                   - inactive = Events that are either not published.
481
+	 * @return EE_Base_Class[]
482
+	 * @throws EE_Error
483
+	 * @throws InvalidArgumentException
484
+	 * @throws InvalidArgumentException
485
+	 */
486
+	public function get_dtt_months_and_years($where_params, $evt_active_status = '')
487
+	{
488
+		$current_time_for_DTT_EVT_start = $this->current_time_for_query('DTT_EVT_start');
489
+		$current_time_for_DTT_EVT_end   = $this->current_time_for_query('DTT_EVT_end');
490
+		switch ($evt_active_status) {
491
+			case 'upcoming' :
492
+				$where_params['Event.status'] = 'publish';
493
+				//if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
494
+				if (isset($where_params['DTT_EVT_start'])) {
495
+					$where_params['DTT_EVT_start*****'] = $where_params['DTT_EVT_start'];
496
+				}
497
+				$where_params['DTT_EVT_start'] = array('>', $current_time_for_DTT_EVT_start);
498
+				break;
499
+			case 'expired' :
500
+				if (isset($where_params['Event.status'])) {
501
+					unset($where_params['Event.status']);
502
+				}
503
+				//get events to exclude
504
+				$exclude_query[0] = array_merge($where_params,
505
+					array('DTT_EVT_end' => array('>', $current_time_for_DTT_EVT_end)));
506
+				//first get all events that have datetimes where its not expired.
507
+				$event_ids = $this->_get_all_wpdb_results(
508
+					$exclude_query,
509
+					OBJECT_K,
510
+					'Datetime.EVT_ID'
511
+				);
512
+				$event_ids = array_keys($event_ids);
513
+				if (isset($where_params['DTT_EVT_end'])) {
514
+					$where_params['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
515
+				}
516
+				$where_params['DTT_EVT_end']  = array('<', $current_time_for_DTT_EVT_end);
517
+				$where_params['Event.EVT_ID'] = array('NOT IN', $event_ids);
518
+				break;
519
+			case 'active' :
520
+				$where_params['Event.status'] = 'publish';
521
+				if (isset($where_params['DTT_EVT_start'])) {
522
+					$where_params['Datetime.DTT_EVT_start******'] = $where_params['DTT_EVT_start'];
523
+				}
524
+				if (isset($where_params['Datetime.DTT_EVT_end'])) {
525
+					$where_params['Datetime.DTT_EVT_end*****'] = $where_params['DTT_EVT_end'];
526
+				}
527
+				$where_params['DTT_EVT_start'] = array('<', $current_time_for_DTT_EVT_start);
528
+				$where_params['DTT_EVT_end']   = array('>', $current_time_for_DTT_EVT_end);
529
+				break;
530
+			case 'inactive' :
531
+				if (isset($where_params['Event.status'])) {
532
+					unset($where_params['Event.status']);
533
+				}
534
+				if (isset($where_params['OR'])) {
535
+					$where_params['AND']['OR'] = $where_params['OR'];
536
+				}
537
+				if (isset($where_params['DTT_EVT_end'])) {
538
+					$where_params['AND']['DTT_EVT_end****'] = $where_params['DTT_EVT_end'];
539
+					unset($where_params['DTT_EVT_end']);
540
+				}
541
+				if (isset($where_params['DTT_EVT_start'])) {
542
+					$where_params['AND']['DTT_EVT_start'] = $where_params['DTT_EVT_start'];
543
+					unset($where_params['DTT_EVT_start']);
544
+				}
545
+				$where_params['AND']['Event.status'] = array('!=', 'publish');
546
+				break;
547
+		}
548
+		$query_params[0]          = $where_params;
549
+		$query_params['group_by'] = array('dtt_year', 'dtt_month');
550
+		$query_params['order_by'] = array('DTT_EVT_start' => 'DESC');
551
+		$query_interval           = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(),
552
+			'DTT_EVT_start');
553
+		$columns_to_select        = array(
554
+			'dtt_year'      => array('YEAR(' . $query_interval . ')', '%s'),
555
+			'dtt_month'     => array('MONTHNAME(' . $query_interval . ')', '%s'),
556
+			'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'),
557
+		);
558
+		return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
559
+	}
560
+
561
+
562
+	/**
563
+	 * Updates the DTT_sold attribute on each datetime (based on the registrations
564
+	 * for the tickets for each datetime)
565
+	 *
566
+	 * @param EE_Base_Class[]|EE_Datetime[] $datetimes
567
+	 * @throws EE_Error
568
+	 */
569
+	public function update_sold($datetimes)
570
+	{
571
+		EE_Error::doing_it_wrong(
572
+			__FUNCTION__,
573
+			esc_html__(
574
+				'Please use \EEM_Ticket::update_tickets_sold() instead which will in turn correctly update both the Ticket AND Datetime counts.',
575
+				'event_espresso'
576
+			),
577
+			'4.9.32.rc.005'
578
+		);
579
+		foreach ($datetimes as $datetime) {
580
+			$datetime->update_sold();
581
+		}
582
+	}
583
+
584
+
585
+	/**
586
+	 *    Gets the total number of tickets available at a particular datetime
587
+	 *    (does NOT take into account the datetime's spaces available)
588
+	 *
589
+	 * @param int   $DTT_ID
590
+	 * @param array $query_params
591
+	 * @return int of tickets available. If sold out, return less than 1. If infinite, returns EE_INF,  IF there are NO
592
+	 *             tickets attached to datetime then FALSE is returned.
593
+	 */
594
+	public function sum_tickets_currently_available_at_datetime($DTT_ID, array $query_params = array())
595
+	{
596
+		$datetime = $this->get_one_by_ID($DTT_ID);
597
+		if ($datetime instanceof EE_Datetime) {
598
+			return $datetime->tickets_remaining($query_params);
599
+		}
600
+		return 0;
601
+	}
602
+
603
+
604
+	/**
605
+	 * This returns an array of counts of datetimes in the database for each Datetime status that can be queried.
606
+	 *
607
+	 * @param  array $stati_to_include If included you can restrict the statuses we return counts for by including the
608
+	 *                                 stati you want counts for as values in the array.  An empty array returns counts
609
+	 *                                 for all valid stati.
610
+	 * @param  array $query_params     If included can be used to refine the conditions for returning the count (i.e.
611
+	 *                                 only for Datetimes connected to a specific event, or specific ticket.
612
+	 * @return array  The value returned is an array indexed by Datetime Status and the values are the counts.  The
613
+	 * @throws EE_Error
614
+	 *                                 stati used as index keys are: EE_Datetime::active EE_Datetime::upcoming
615
+	 *                                 EE_Datetime::expired
616
+	 */
617
+	public function get_datetime_counts_by_status(array $stati_to_include = array(), array $query_params = array())
618
+	{
619
+		//only accept where conditions for this query.
620
+		$_where            = isset($query_params[0]) ? $query_params[0] : array();
621
+		$status_query_args = array(
622
+			EE_Datetime::active   => array_merge(
623
+				$_where,
624
+				array('DTT_EVT_start' => array('<', time()), 'DTT_EVT_end' => array('>', time()))
625
+			),
626
+			EE_Datetime::upcoming => array_merge(
627
+				$_where,
628
+				array('DTT_EVT_start' => array('>', time()))
629
+			),
630
+			EE_Datetime::expired  => array_merge(
631
+				$_where,
632
+				array('DTT_EVT_end' => array('<', time()))
633
+			),
634
+		);
635
+		if (! empty($stati_to_include)) {
636
+			foreach (array_keys($status_query_args) as $status) {
637
+				if (! in_array($status, $stati_to_include, true)) {
638
+					unset($status_query_args[ $status ]);
639
+				}
640
+			}
641
+		}
642
+		//loop through and query counts for each stati.
643
+		$status_query_results = array();
644
+		foreach ($status_query_args as $status => $status_where_conditions) {
645
+			$status_query_results[ $status ] = EEM_Datetime::count(
646
+				array($status_where_conditions),
647
+				'DTT_ID',
648
+				true
649
+			);
650
+		}
651
+		return $status_query_results;
652
+	}
653
+
654
+
655
+	/**
656
+	 * Returns the specific count for a given Datetime status matching any given query_params.
657
+	 *
658
+	 * @param string $status Valid string representation for Datetime status requested. (Defaults to Active).
659
+	 * @param array  $query_params
660
+	 * @return int
661
+	 * @throws EE_Error
662
+	 */
663
+	public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array())
664
+	{
665
+		$count = $this->get_datetime_counts_by_status(array($status), $query_params);
666
+		return ! empty($count[ $status ]) ? $count[ $status ] : 0;
667
+	}
668 668
 }
669 669
 // End of file EEM_Datetime.model.php
670 670
 // Location: /includes/models/EEM_Datetime.model.php
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -1,4 +1,4 @@  discard block
 block discarded – undo
1
-<?php if (! defined('EVENT_ESPRESSO_VERSION')) {
1
+<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2 2
     exit('No direct script access allowed');
3 3
 }
4 4
 
@@ -122,23 +122,23 @@  discard block
 block discarded – undo
122 122
                 ),
123 123
             ),
124 124
         );
125
-        $this->_model_relations        = array(
125
+        $this->_model_relations = array(
126 126
             'Ticket'  => new EE_HABTM_Relation('Datetime_Ticket'),
127 127
             'Event'   => new EE_Belongs_To_Relation(),
128 128
             'Checkin' => new EE_Has_Many_Relation(),
129 129
         );
130 130
         $this->_model_chain_to_wp_user = 'Event';
131 131
         //this model is generally available for reading
132
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public(
132
+        $this->_cap_restriction_generators[EEM_Base::caps_read]       = new EE_Restriction_Generator_Event_Related_Public(
133 133
             'Event'
134 134
         );
135
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected(
135
+        $this->_cap_restriction_generators[EEM_Base::caps_read_admin] = new EE_Restriction_Generator_Event_Related_Protected(
136 136
             'Event'
137 137
         );
138
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected(
138
+        $this->_cap_restriction_generators[EEM_Base::caps_edit]       = new EE_Restriction_Generator_Event_Related_Protected(
139 139
             'Event'
140 140
         );
141
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
141
+        $this->_cap_restriction_generators[EEM_Base::caps_delete]     = new EE_Restriction_Generator_Event_Related_Protected(
142 142
             'Event',
143 143
             EEM_Base::caps_edit
144 144
         );
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
      */
197 197
     public function get_all_event_dates($EVT_ID = 0)
198 198
     {
199
-        if (! $EVT_ID) { // on add_new_event event_id gets set to 0
199
+        if ( ! $EVT_ID) { // on add_new_event event_id gets set to 0
200 200
             return $this->create_new_blank_datetime();
201 201
         }
202 202
         $results = $this->get_datetimes_for_event_ordered_by_DTT_order($EVT_ID);
@@ -242,7 +242,7 @@  discard block
 block discarded – undo
242 242
                 'order_by'                 => array('DTT_order' => 'ASC'),
243 243
                 'default_where_conditions' => 'none',
244 244
             );
245
-        if (! $include_expired) {
245
+        if ( ! $include_expired) {
246 246
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
247 247
         }
248 248
         if ($include_deleted) {
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
         $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
354 354
         $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
355 355
         $query_params = array(array('Event.EVT_ID' => $EVT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
356
-        if (! $include_expired) {
356
+        if ( ! $include_expired) {
357 357
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
358 358
         }
359 359
         if ($include_deleted) {
@@ -391,7 +391,7 @@  discard block
 block discarded – undo
391 391
         $old_assumption = $this->get_assumption_concerning_values_already_prepared_by_model_object();
392 392
         $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
393 393
         $query_params = array(array('Ticket.TKT_ID' => $TKT_ID), 'order_by' => array('DTT_EVT_start' => 'asc'));
394
-        if (! $include_expired) {
394
+        if ( ! $include_expired) {
395 395
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
396 396
         }
397 397
         if ($include_deleted) {
@@ -431,7 +431,7 @@  discard block
 block discarded – undo
431 431
         $this->assume_values_already_prepared_by_model_object(EEM_Base::prepared_for_use_in_db);
432 432
         $where_params = array('Ticket.TKT_ID' => $TKT_ID);
433 433
         $query_params = array($where_params, 'order_by' => array('DTT_order' => 'ASC'));
434
-        if (! $include_expired) {
434
+        if ( ! $include_expired) {
435 435
             $query_params[0]['DTT_EVT_end'] = array('>=', current_time('mysql', true));
436 436
         }
437 437
         if ($include_deleted) {
@@ -551,9 +551,9 @@  discard block
 block discarded – undo
551 551
         $query_interval           = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(),
552 552
             'DTT_EVT_start');
553 553
         $columns_to_select        = array(
554
-            'dtt_year'      => array('YEAR(' . $query_interval . ')', '%s'),
555
-            'dtt_month'     => array('MONTHNAME(' . $query_interval . ')', '%s'),
556
-            'dtt_month_num' => array('MONTH(' . $query_interval . ')', '%s'),
554
+            'dtt_year'      => array('YEAR('.$query_interval.')', '%s'),
555
+            'dtt_month'     => array('MONTHNAME('.$query_interval.')', '%s'),
556
+            'dtt_month_num' => array('MONTH('.$query_interval.')', '%s'),
557 557
         );
558 558
         return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select);
559 559
     }
@@ -632,17 +632,17 @@  discard block
 block discarded – undo
632 632
                 array('DTT_EVT_end' => array('<', time()))
633 633
             ),
634 634
         );
635
-        if (! empty($stati_to_include)) {
635
+        if ( ! empty($stati_to_include)) {
636 636
             foreach (array_keys($status_query_args) as $status) {
637
-                if (! in_array($status, $stati_to_include, true)) {
638
-                    unset($status_query_args[ $status ]);
637
+                if ( ! in_array($status, $stati_to_include, true)) {
638
+                    unset($status_query_args[$status]);
639 639
                 }
640 640
             }
641 641
         }
642 642
         //loop through and query counts for each stati.
643 643
         $status_query_results = array();
644 644
         foreach ($status_query_args as $status => $status_where_conditions) {
645
-            $status_query_results[ $status ] = EEM_Datetime::count(
645
+            $status_query_results[$status] = EEM_Datetime::count(
646 646
                 array($status_where_conditions),
647 647
                 'DTT_ID',
648 648
                 true
@@ -663,7 +663,7 @@  discard block
 block discarded – undo
663 663
     public function get_datetime_count_for_status($status = EE_Datetime::active, array $query_params = array())
664 664
     {
665 665
         $count = $this->get_datetime_counts_by_status(array($status), $query_params);
666
-        return ! empty($count[ $status ]) ? $count[ $status ] : 0;
666
+        return ! empty($count[$status]) ? $count[$status] : 0;
667 667
     }
668 668
 }
669 669
 // End of file EEM_Datetime.model.php
Please login to merge, or discard this patch.
core/EE_Config.core.php 1 patch
Indentation   +3061 added lines, -3061 removed lines patch added patch discarded remove patch
@@ -17,2443 +17,2443 @@  discard block
 block discarded – undo
17 17
 final class EE_Config implements ResettableInterface
18 18
 {
19 19
 
20
-    const OPTION_NAME        = 'ee_config';
20
+	const OPTION_NAME        = 'ee_config';
21
+
22
+	const LOG_NAME           = 'ee_config_log';
23
+
24
+	const LOG_LENGTH         = 100;
25
+
26
+	const ADDON_OPTION_NAMES = 'ee_config_option_names';
27
+
28
+
29
+	/**
30
+	 *    instance of the EE_Config object
31
+	 *
32
+	 * @var    EE_Config $_instance
33
+	 * @access    private
34
+	 */
35
+	private static $_instance;
36
+
37
+	/**
38
+	 * @var boolean $_logging_enabled
39
+	 */
40
+	private static $_logging_enabled = false;
41
+
42
+	/**
43
+	 * @var LegacyShortcodesManager $legacy_shortcodes_manager
44
+	 */
45
+	private $legacy_shortcodes_manager;
46
+
47
+	/**
48
+	 * An StdClass whose property names are addon slugs,
49
+	 * and values are their config classes
50
+	 *
51
+	 * @var StdClass
52
+	 */
53
+	public $addons;
54
+
55
+	/**
56
+	 * @var EE_Admin_Config
57
+	 */
58
+	public $admin;
59
+
60
+	/**
61
+	 * @var EE_Core_Config
62
+	 */
63
+	public $core;
64
+
65
+	/**
66
+	 * @var EE_Currency_Config
67
+	 */
68
+	public $currency;
69
+
70
+	/**
71
+	 * @var EE_Organization_Config
72
+	 */
73
+	public $organization;
74
+
75
+	/**
76
+	 * @var EE_Registration_Config
77
+	 */
78
+	public $registration;
79
+
80
+	/**
81
+	 * @var EE_Template_Config
82
+	 */
83
+	public $template_settings;
84
+
85
+	/**
86
+	 * Holds EE environment values.
87
+	 *
88
+	 * @var EE_Environment_Config
89
+	 */
90
+	public $environment;
91
+
92
+	/**
93
+	 * settings pertaining to Google maps
94
+	 *
95
+	 * @var EE_Map_Config
96
+	 */
97
+	public $map_settings;
98
+
99
+	/**
100
+	 * settings pertaining to Taxes
101
+	 *
102
+	 * @var EE_Tax_Config
103
+	 */
104
+	public $tax_settings;
105
+
106
+
107
+	/**
108
+	 * Settings pertaining to global messages settings.
109
+	 *
110
+	 * @var EE_Messages_Config
111
+	 */
112
+	public $messages;
113
+
114
+	/**
115
+	 * @deprecated
116
+	 * @var EE_Gateway_Config
117
+	 */
118
+	public $gateway;
119
+
120
+	/**
121
+	 * @var    array $_addon_option_names
122
+	 * @access    private
123
+	 */
124
+	private $_addon_option_names = array();
125
+
126
+	/**
127
+	 * @var    array $_module_route_map
128
+	 * @access    private
129
+	 */
130
+	private static $_module_route_map = array();
131
+
132
+	/**
133
+	 * @var    array $_module_forward_map
134
+	 * @access    private
135
+	 */
136
+	private static $_module_forward_map = array();
137
+
138
+	/**
139
+	 * @var    array $_module_view_map
140
+	 * @access    private
141
+	 */
142
+	private static $_module_view_map = array();
143
+
144
+
145
+
146
+	/**
147
+	 * @singleton method used to instantiate class object
148
+	 * @access    public
149
+	 * @return EE_Config instance
150
+	 */
151
+	public static function instance()
152
+	{
153
+		// check if class object is instantiated, and instantiated properly
154
+		if (! self::$_instance instanceof EE_Config) {
155
+			self::$_instance = new self();
156
+		}
157
+		return self::$_instance;
158
+	}
159
+
160
+
161
+
162
+	/**
163
+	 * Resets the config
164
+	 *
165
+	 * @param bool    $hard_reset    if TRUE, sets EE_CONFig back to its original settings in the database. If FALSE
166
+	 *                               (default) leaves the database alone, and merely resets the EE_Config object to
167
+	 *                               reflect its state in the database
168
+	 * @param boolean $reinstantiate if TRUE (default) call instance() and return it. Otherwise, just leave
169
+	 *                               $_instance as NULL. Useful in case you want to forget about the old instance on
170
+	 *                               EE_Config, but might not be ready to instantiate EE_Config currently (eg if the
171
+	 *                               site was put into maintenance mode)
172
+	 * @return EE_Config
173
+	 */
174
+	public static function reset($hard_reset = false, $reinstantiate = true)
175
+	{
176
+		if (self::$_instance instanceof EE_Config) {
177
+			if ($hard_reset) {
178
+				self::$_instance->legacy_shortcodes_manager = null;
179
+				self::$_instance->_addon_option_names = array();
180
+				self::$_instance->_initialize_config();
181
+				self::$_instance->update_espresso_config();
182
+			}
183
+			self::$_instance->update_addon_option_names();
184
+		}
185
+		self::$_instance = null;
186
+		//we don't need to reset the static properties imo because those should
187
+		//only change when a module is added or removed. Currently we don't
188
+		//support removing a module during a request when it previously existed
189
+		if ($reinstantiate) {
190
+			return self::instance();
191
+		} else {
192
+			return null;
193
+		}
194
+	}
195
+
196
+
197
+
198
+	/**
199
+	 *    class constructor
200
+	 *
201
+	 * @access    private
202
+	 */
203
+	private function __construct()
204
+	{
205
+		do_action('AHEE__EE_Config__construct__begin', $this);
206
+		EE_Config::$_logging_enabled = apply_filters('FHEE__EE_Config___construct__logging_enabled', false);
207
+		// setup empty config classes
208
+		$this->_initialize_config();
209
+		// load existing EE site settings
210
+		$this->_load_core_config();
211
+		// confirm everything loaded correctly and set filtered defaults if not
212
+		$this->_verify_config();
213
+		//  register shortcodes and modules
214
+		add_action(
215
+			'AHEE__EE_System__register_shortcodes_modules_and_widgets',
216
+			array($this, 'register_shortcodes_and_modules'),
217
+			999
218
+		);
219
+		//  initialize shortcodes and modules
220
+		add_action('AHEE__EE_System__core_loaded_and_ready', array($this, 'initialize_shortcodes_and_modules'));
221
+		// register widgets
222
+		add_action('widgets_init', array($this, 'widgets_init'), 10);
223
+		// shutdown
224
+		add_action('shutdown', array($this, 'shutdown'), 10);
225
+		// construct__end hook
226
+		do_action('AHEE__EE_Config__construct__end', $this);
227
+		// hardcoded hack
228
+		$this->template_settings->current_espresso_theme = 'Espresso_Arabica_2014';
229
+	}
230
+
231
+
232
+
233
+	/**
234
+	 * @return boolean
235
+	 */
236
+	public static function logging_enabled()
237
+	{
238
+		return self::$_logging_enabled;
239
+	}
240
+
241
+
242
+
243
+	/**
244
+	 * use to get the current theme if needed from static context
245
+	 *
246
+	 * @return string current theme set.
247
+	 */
248
+	public static function get_current_theme()
249
+	{
250
+		return isset(self::$_instance->template_settings->current_espresso_theme)
251
+			? self::$_instance->template_settings->current_espresso_theme : 'Espresso_Arabica_2014';
252
+	}
253
+
254
+
255
+
256
+	/**
257
+	 *        _initialize_config
258
+	 *
259
+	 * @access private
260
+	 * @return void
261
+	 */
262
+	private function _initialize_config()
263
+	{
264
+		EE_Config::trim_log();
265
+		//set defaults
266
+		$this->_addon_option_names = get_option(EE_Config::ADDON_OPTION_NAMES, array());
267
+		$this->addons = new stdClass();
268
+		// set _module_route_map
269
+		EE_Config::$_module_route_map = array();
270
+		// set _module_forward_map
271
+		EE_Config::$_module_forward_map = array();
272
+		// set _module_view_map
273
+		EE_Config::$_module_view_map = array();
274
+	}
275
+
276
+
277
+
278
+	/**
279
+	 *        load core plugin configuration
280
+	 *
281
+	 * @access private
282
+	 * @return void
283
+	 */
284
+	private function _load_core_config()
285
+	{
286
+		// load_core_config__start hook
287
+		do_action('AHEE__EE_Config___load_core_config__start', $this);
288
+		$espresso_config = $this->get_espresso_config();
289
+		foreach ($espresso_config as $config => $settings) {
290
+			// load_core_config__start hook
291
+			$settings = apply_filters(
292
+				'FHEE__EE_Config___load_core_config__config_settings',
293
+				$settings,
294
+				$config,
295
+				$this
296
+			);
297
+			if (is_object($settings) && property_exists($this, $config)) {
298
+				$this->{$config} = apply_filters('FHEE__EE_Config___load_core_config__' . $config, $settings);
299
+				//call configs populate method to ensure any defaults are set for empty values.
300
+				if (method_exists($settings, 'populate')) {
301
+					$this->{$config}->populate();
302
+				}
303
+				if (method_exists($settings, 'do_hooks')) {
304
+					$this->{$config}->do_hooks();
305
+				}
306
+			}
307
+		}
308
+		if (apply_filters('FHEE__EE_Config___load_core_config__update_espresso_config', false)) {
309
+			$this->update_espresso_config();
310
+		}
311
+		// load_core_config__end hook
312
+		do_action('AHEE__EE_Config___load_core_config__end', $this);
313
+	}
314
+
315
+
316
+
317
+	/**
318
+	 *    _verify_config
319
+	 *
320
+	 * @access    protected
321
+	 * @return    void
322
+	 */
323
+	protected function _verify_config()
324
+	{
325
+		$this->core = $this->core instanceof EE_Core_Config
326
+			? $this->core
327
+			: new EE_Core_Config();
328
+		$this->core = apply_filters('FHEE__EE_Config___initialize_config__core', $this->core);
329
+		$this->organization = $this->organization instanceof EE_Organization_Config
330
+			? $this->organization
331
+			: new EE_Organization_Config();
332
+		$this->organization = apply_filters(
333
+			'FHEE__EE_Config___initialize_config__organization',
334
+			$this->organization
335
+		);
336
+		$this->currency = $this->currency instanceof EE_Currency_Config
337
+			? $this->currency
338
+			: new EE_Currency_Config();
339
+		$this->currency = apply_filters('FHEE__EE_Config___initialize_config__currency', $this->currency);
340
+		$this->registration = $this->registration instanceof EE_Registration_Config
341
+			? $this->registration
342
+			: new EE_Registration_Config();
343
+		$this->registration = apply_filters(
344
+			'FHEE__EE_Config___initialize_config__registration',
345
+			$this->registration
346
+		);
347
+		$this->admin = $this->admin instanceof EE_Admin_Config
348
+			? $this->admin
349
+			: new EE_Admin_Config();
350
+		$this->admin = apply_filters('FHEE__EE_Config___initialize_config__admin', $this->admin);
351
+		$this->template_settings = $this->template_settings instanceof EE_Template_Config
352
+			? $this->template_settings
353
+			: new EE_Template_Config();
354
+		$this->template_settings = apply_filters(
355
+			'FHEE__EE_Config___initialize_config__template_settings',
356
+			$this->template_settings
357
+		);
358
+		$this->map_settings = $this->map_settings instanceof EE_Map_Config
359
+			? $this->map_settings
360
+			: new EE_Map_Config();
361
+		$this->map_settings = apply_filters('FHEE__EE_Config___initialize_config__map_settings',
362
+			$this->map_settings);
363
+		$this->environment = $this->environment instanceof EE_Environment_Config
364
+			? $this->environment
365
+			: new EE_Environment_Config();
366
+		$this->environment = apply_filters('FHEE__EE_Config___initialize_config__environment',
367
+			$this->environment);
368
+		$this->tax_settings = $this->tax_settings instanceof EE_Tax_Config
369
+			? $this->tax_settings
370
+			: new EE_Tax_Config();
371
+		$this->tax_settings = apply_filters('FHEE__EE_Config___initialize_config__tax_settings',
372
+			$this->tax_settings);
373
+		$this->messages = apply_filters('FHEE__EE_Config__initialize_config__messages', $this->messages);
374
+		$this->messages = $this->messages instanceof EE_Messages_Config
375
+			? $this->messages
376
+			: new EE_Messages_Config();
377
+		$this->gateway = $this->gateway instanceof EE_Gateway_Config
378
+			? $this->gateway
379
+			: new EE_Gateway_Config();
380
+		$this->gateway = apply_filters('FHEE__EE_Config___initialize_config__gateway', $this->gateway);
381
+		$this->legacy_shortcodes_manager = null;
382
+	}
383
+
384
+
385
+	/**
386
+	 *    get_espresso_config
387
+	 *
388
+	 * @access    public
389
+	 * @return    array of espresso config stuff
390
+	 */
391
+	public function get_espresso_config()
392
+	{
393
+		// grab espresso configuration
394
+		return apply_filters(
395
+			'FHEE__EE_Config__get_espresso_config__CFG',
396
+			get_option(EE_Config::OPTION_NAME, array())
397
+		);
398
+	}
399
+
400
+
401
+
402
+	/**
403
+	 *    double_check_config_comparison
404
+	 *
405
+	 * @access    public
406
+	 * @param string $option
407
+	 * @param        $old_value
408
+	 * @param        $value
409
+	 */
410
+	public function double_check_config_comparison($option = '', $old_value, $value)
411
+	{
412
+		// make sure we're checking the ee config
413
+		if ($option === EE_Config::OPTION_NAME) {
414
+			// run a loose comparison of the old value against the new value for type and properties,
415
+			// but NOT exact instance like WP update_option does (ie: NOT type safe comparison)
416
+			if ($value != $old_value) {
417
+				// if they are NOT the same, then remove the hook,
418
+				// which means the subsequent update results will be based solely on the update query results
419
+				// the reason we do this is because, as stated above,
420
+				// WP update_option performs an exact instance comparison (===) on any update values passed to it
421
+				// this happens PRIOR to serialization and any subsequent update.
422
+				// If values are found to match their previous old value,
423
+				// then WP bails before performing any update.
424
+				// Since we are passing the EE_Config object, it is comparing the EXACT instance of the saved version
425
+				// it just pulled from the db, with the one being passed to it (which will not match).
426
+				// HOWEVER, once the object is serialized and passed off to MySQL to update,
427
+				// MySQL MAY ALSO NOT perform the update because
428
+				// the string it sees in the db looks the same as the new one it has been passed!!!
429
+				// This results in the query returning an "affected rows" value of ZERO,
430
+				// which gets returned immediately by WP update_option and looks like an error.
431
+				remove_action('update_option', array($this, 'check_config_updated'));
432
+			}
433
+		}
434
+	}
435
+
436
+
437
+
438
+	/**
439
+	 *    update_espresso_config
440
+	 *
441
+	 * @access   public
442
+	 */
443
+	protected function _reset_espresso_addon_config()
444
+	{
445
+		$this->_addon_option_names = array();
446
+		foreach ($this->addons as $addon_name => $addon_config_obj) {
447
+			$addon_config_obj = maybe_unserialize($addon_config_obj);
448
+			if ($addon_config_obj instanceof EE_Config_Base) {
449
+				$this->update_config('addons', $addon_name, $addon_config_obj, false);
450
+			}
451
+			$this->addons->{$addon_name} = null;
452
+		}
453
+	}
454
+
455
+
456
+
457
+	/**
458
+	 *    update_espresso_config
459
+	 *
460
+	 * @access   public
461
+	 * @param   bool $add_success
462
+	 * @param   bool $add_error
463
+	 * @return   bool
464
+	 */
465
+	public function update_espresso_config($add_success = false, $add_error = true)
466
+	{
467
+		// don't allow config updates during WP heartbeats
468
+		if (\EE_Registry::instance()->REQ->get('action', '') === 'heartbeat') {
469
+			return false;
470
+		}
471
+		// commented out the following re: https://events.codebasehq.com/projects/event-espresso/tickets/8197
472
+		//$clone = clone( self::$_instance );
473
+		//self::$_instance = NULL;
474
+		do_action('AHEE__EE_Config__update_espresso_config__begin', $this);
475
+		$this->_reset_espresso_addon_config();
476
+		// hook into update_option because that happens AFTER the ( $value === $old_value ) conditional
477
+		// but BEFORE the actual update occurs
478
+		add_action('update_option', array($this, 'double_check_config_comparison'), 1, 3);
479
+		// don't want to persist legacy_shortcodes_manager, but don't want to lose it either
480
+		$legacy_shortcodes_manager = $this->legacy_shortcodes_manager;
481
+		$this->legacy_shortcodes_manager = null;
482
+		// now update "ee_config"
483
+		$saved = update_option(EE_Config::OPTION_NAME, $this);
484
+		$this->legacy_shortcodes_manager = $legacy_shortcodes_manager;
485
+		EE_Config::log(EE_Config::OPTION_NAME);
486
+		// if not saved... check if the hook we just added still exists;
487
+		// if it does, it means one of two things:
488
+		// 		that update_option bailed at the ( $value === $old_value ) conditional,
489
+		//		 or...
490
+		// 		the db update query returned 0 rows affected
491
+		// 		(probably because the data  value was the same from it's perspective)
492
+		// so the existence of the hook means that a negative result from update_option is NOT an error,
493
+		// but just means no update occurred, so don't display an error to the user.
494
+		// BUT... if update_option returns FALSE, AND the hook is missing,
495
+		// then it means that something truly went wrong
496
+		$saved = ! $saved ? has_action('update_option', array($this, 'double_check_config_comparison')) : $saved;
497
+		// remove our action since we don't want it in the system anymore
498
+		remove_action('update_option', array($this, 'double_check_config_comparison'), 1);
499
+		do_action('AHEE__EE_Config__update_espresso_config__end', $this, $saved);
500
+		//self::$_instance = $clone;
501
+		//unset( $clone );
502
+		// if config remains the same or was updated successfully
503
+		if ($saved) {
504
+			if ($add_success) {
505
+				EE_Error::add_success(
506
+					__('The Event Espresso Configuration Settings have been successfully updated.', 'event_espresso'),
507
+					__FILE__,
508
+					__FUNCTION__,
509
+					__LINE__
510
+				);
511
+			}
512
+			return true;
513
+		} else {
514
+			if ($add_error) {
515
+				EE_Error::add_error(
516
+					__('The Event Espresso Configuration Settings were not updated.', 'event_espresso'),
517
+					__FILE__,
518
+					__FUNCTION__,
519
+					__LINE__
520
+				);
521
+			}
522
+			return false;
523
+		}
524
+	}
525
+
526
+
527
+
528
+	/**
529
+	 *    _verify_config_params
530
+	 *
531
+	 * @access    private
532
+	 * @param    string         $section
533
+	 * @param    string         $name
534
+	 * @param    string         $config_class
535
+	 * @param    EE_Config_Base $config_obj
536
+	 * @param    array          $tests_to_run
537
+	 * @param    bool           $display_errors
538
+	 * @return    bool    TRUE on success, FALSE on fail
539
+	 */
540
+	private function _verify_config_params(
541
+		$section = '',
542
+		$name = '',
543
+		$config_class = '',
544
+		$config_obj = null,
545
+		$tests_to_run = array(1, 2, 3, 4, 5, 6, 7, 8),
546
+		$display_errors = true
547
+	) {
548
+		try {
549
+			foreach ($tests_to_run as $test) {
550
+				switch ($test) {
551
+					// TEST #1 : check that section was set
552
+					case 1 :
553
+						if (empty($section)) {
554
+							if ($display_errors) {
555
+								throw new EE_Error(
556
+									sprintf(
557
+										__(
558
+											'No configuration section has been provided while attempting to save "%s".',
559
+											'event_espresso'
560
+										),
561
+										$config_class
562
+									)
563
+								);
564
+							}
565
+							return false;
566
+						}
567
+						break;
568
+					// TEST #2 : check that settings section exists
569
+					case 2 :
570
+						if (! isset($this->{$section})) {
571
+							if ($display_errors) {
572
+								throw new EE_Error(
573
+									sprintf(
574
+										__('The "%s" configuration section does not exist.', 'event_espresso'),
575
+										$section
576
+									)
577
+								);
578
+							}
579
+							return false;
580
+						}
581
+						break;
582
+					// TEST #3 : check that section is the proper format
583
+					case 3 :
584
+						if (
585
+						! ($this->{$section} instanceof EE_Config_Base || $this->{$section} instanceof stdClass)
586
+						) {
587
+							if ($display_errors) {
588
+								throw new EE_Error(
589
+									sprintf(
590
+										__(
591
+											'The "%s" configuration settings have not been formatted correctly.',
592
+											'event_espresso'
593
+										),
594
+										$section
595
+									)
596
+								);
597
+							}
598
+							return false;
599
+						}
600
+						break;
601
+					// TEST #4 : check that config section name has been set
602
+					case 4 :
603
+						if (empty($name)) {
604
+							if ($display_errors) {
605
+								throw new EE_Error(
606
+									__(
607
+										'No name has been provided for the specific configuration section.',
608
+										'event_espresso'
609
+									)
610
+								);
611
+							}
612
+							return false;
613
+						}
614
+						break;
615
+					// TEST #5 : check that a config class name has been set
616
+					case 5 :
617
+						if (empty($config_class)) {
618
+							if ($display_errors) {
619
+								throw new EE_Error(
620
+									__(
621
+										'No class name has been provided for the specific configuration section.',
622
+										'event_espresso'
623
+									)
624
+								);
625
+							}
626
+							return false;
627
+						}
628
+						break;
629
+					// TEST #6 : verify config class is accessible
630
+					case 6 :
631
+						if (! class_exists($config_class)) {
632
+							if ($display_errors) {
633
+								throw new EE_Error(
634
+									sprintf(
635
+										__(
636
+											'The "%s" class does not exist. Please ensure that an autoloader has been set for it.',
637
+											'event_espresso'
638
+										),
639
+										$config_class
640
+									)
641
+								);
642
+							}
643
+							return false;
644
+						}
645
+						break;
646
+					// TEST #7 : check that config has even been set
647
+					case 7 :
648
+						if (! isset($this->{$section}->{$name})) {
649
+							if ($display_errors) {
650
+								throw new EE_Error(
651
+									sprintf(
652
+										__('No configuration has been set for "%1$s->%2$s".', 'event_espresso'),
653
+										$section,
654
+										$name
655
+									)
656
+								);
657
+							}
658
+							return false;
659
+						} else {
660
+							// and make sure it's not serialized
661
+							$this->{$section}->{$name} = maybe_unserialize($this->{$section}->{$name});
662
+						}
663
+						break;
664
+					// TEST #8 : check that config is the requested type
665
+					case 8 :
666
+						if (! $this->{$section}->{$name} instanceof $config_class) {
667
+							if ($display_errors) {
668
+								throw new EE_Error(
669
+									sprintf(
670
+										__(
671
+											'The configuration for "%1$s->%2$s" is not of the "%3$s" class.',
672
+											'event_espresso'
673
+										),
674
+										$section,
675
+										$name,
676
+										$config_class
677
+									)
678
+								);
679
+							}
680
+							return false;
681
+						}
682
+						break;
683
+					// TEST #9 : verify config object
684
+					case 9 :
685
+						if (! $config_obj instanceof EE_Config_Base) {
686
+							if ($display_errors) {
687
+								throw new EE_Error(
688
+									sprintf(
689
+										__('The "%s" class is not an instance of EE_Config_Base.', 'event_espresso'),
690
+										print_r($config_obj, true)
691
+									)
692
+								);
693
+							}
694
+							return false;
695
+						}
696
+						break;
697
+				}
698
+			}
699
+		} catch (EE_Error $e) {
700
+			$e->get_error();
701
+		}
702
+		// you have successfully run the gauntlet
703
+		return true;
704
+	}
705
+
706
+
707
+
708
+	/**
709
+	 *    _generate_config_option_name
710
+	 *
711
+	 * @access        protected
712
+	 * @param        string $section
713
+	 * @param        string $name
714
+	 * @return        string
715
+	 */
716
+	private function _generate_config_option_name($section = '', $name = '')
717
+	{
718
+		return 'ee_config-' . strtolower($section . '-' . str_replace(array('EE_', 'EED_'), '', $name));
719
+	}
720
+
721
+
722
+
723
+	/**
724
+	 *    _set_config_class
725
+	 * ensures that a config class is set, either from a passed config class or one generated from the config name
726
+	 *
727
+	 * @access    private
728
+	 * @param    string $config_class
729
+	 * @param    string $name
730
+	 * @return    string
731
+	 */
732
+	private function _set_config_class($config_class = '', $name = '')
733
+	{
734
+		return ! empty($config_class)
735
+			? $config_class
736
+			: str_replace(' ', '_', ucwords(str_replace('_', ' ', $name))) . '_Config';
737
+	}
738
+
739
+
740
+
741
+	/**
742
+	 *    set_config
743
+	 *
744
+	 * @access    protected
745
+	 * @param    string         $section
746
+	 * @param    string         $name
747
+	 * @param    string         $config_class
748
+	 * @param    EE_Config_Base $config_obj
749
+	 * @return    EE_Config_Base
750
+	 */
751
+	public function set_config($section = '', $name = '', $config_class = '', EE_Config_Base $config_obj = null)
752
+	{
753
+		// ensure config class is set to something
754
+		$config_class = $this->_set_config_class($config_class, $name);
755
+		// run tests 1-4, 6, and 7 to verify all config params are set and valid
756
+		if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
757
+			return null;
758
+		}
759
+		$config_option_name = $this->_generate_config_option_name($section, $name);
760
+		// if the config option name hasn't been added yet to the list of option names we're tracking, then do so now
761
+		if (! isset($this->_addon_option_names[$config_option_name])) {
762
+			$this->_addon_option_names[$config_option_name] = $config_class;
763
+			$this->update_addon_option_names();
764
+		}
765
+		// verify the incoming config object but suppress errors
766
+		if (! $this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
767
+			$config_obj = new $config_class();
768
+		}
769
+		if (get_option($config_option_name)) {
770
+			EE_Config::log($config_option_name);
771
+			update_option($config_option_name, $config_obj);
772
+			$this->{$section}->{$name} = $config_obj;
773
+			return $this->{$section}->{$name};
774
+		} else {
775
+			// create a wp-option for this config
776
+			if (add_option($config_option_name, $config_obj, '', 'no')) {
777
+				$this->{$section}->{$name} = maybe_unserialize($config_obj);
778
+				return $this->{$section}->{$name};
779
+			} else {
780
+				EE_Error::add_error(
781
+					sprintf(__('The "%s" could not be saved to the database.', 'event_espresso'), $config_class),
782
+					__FILE__,
783
+					__FUNCTION__,
784
+					__LINE__
785
+				);
786
+				return null;
787
+			}
788
+		}
789
+	}
790
+
791
+
792
+
793
+	/**
794
+	 *    update_config
795
+	 * Important: the config object must ALREADY be set, otherwise this will produce an error.
796
+	 *
797
+	 * @access    public
798
+	 * @param    string                $section
799
+	 * @param    string                $name
800
+	 * @param    EE_Config_Base|string $config_obj
801
+	 * @param    bool                  $throw_errors
802
+	 * @return    bool
803
+	 */
804
+	public function update_config($section = '', $name = '', $config_obj = '', $throw_errors = true)
805
+	{
806
+		// don't allow config updates during WP heartbeats
807
+		if (\EE_Registry::instance()->REQ->get('action', '') === 'heartbeat') {
808
+			return false;
809
+		}
810
+		$config_obj = maybe_unserialize($config_obj);
811
+		// get class name of the incoming object
812
+		$config_class = get_class($config_obj);
813
+		// run tests 1-5 and 9 to verify config
814
+		if (! $this->_verify_config_params(
815
+			$section,
816
+			$name,
817
+			$config_class,
818
+			$config_obj,
819
+			array(1, 2, 3, 4, 7, 9)
820
+		)
821
+		) {
822
+			return false;
823
+		}
824
+		$config_option_name = $this->_generate_config_option_name($section, $name);
825
+		// check if config object has been added to db by seeing if config option name is in $this->_addon_option_names array
826
+		if (! isset($this->_addon_option_names[$config_option_name])) {
827
+			// save new config to db
828
+			if ($this->set_config($section, $name, $config_class, $config_obj)) {
829
+				return true;
830
+			}
831
+		} else {
832
+			// first check if the record already exists
833
+			$existing_config = get_option($config_option_name);
834
+			$config_obj = serialize($config_obj);
835
+			// just return if db record is already up to date (NOT type safe comparison)
836
+			if ($existing_config == $config_obj) {
837
+				$this->{$section}->{$name} = $config_obj;
838
+				return true;
839
+			} else if (update_option($config_option_name, $config_obj)) {
840
+				EE_Config::log($config_option_name);
841
+				// update wp-option for this config class
842
+				$this->{$section}->{$name} = $config_obj;
843
+				return true;
844
+			} elseif ($throw_errors) {
845
+				EE_Error::add_error(
846
+					sprintf(
847
+						__(
848
+							'The "%1$s" object stored at"%2$s" was not successfully updated in the database.',
849
+							'event_espresso'
850
+						),
851
+						$config_class,
852
+						'EE_Config->' . $section . '->' . $name
853
+					),
854
+					__FILE__,
855
+					__FUNCTION__,
856
+					__LINE__
857
+				);
858
+			}
859
+		}
860
+		return false;
861
+	}
862
+
863
+
864
+
865
+	/**
866
+	 *    get_config
867
+	 *
868
+	 * @access    public
869
+	 * @param    string $section
870
+	 * @param    string $name
871
+	 * @param    string $config_class
872
+	 * @return    mixed EE_Config_Base | NULL
873
+	 */
874
+	public function get_config($section = '', $name = '', $config_class = '')
875
+	{
876
+		// ensure config class is set to something
877
+		$config_class = $this->_set_config_class($config_class, $name);
878
+		// run tests 1-4, 6 and 7 to verify that all params have been set
879
+		if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
880
+			return null;
881
+		}
882
+		// now test if the requested config object exists, but suppress errors
883
+		if ($this->_verify_config_params($section, $name, $config_class, null, array(7, 8), false)) {
884
+			// config already exists, so pass it back
885
+			return $this->{$section}->{$name};
886
+		}
887
+		// load config option from db if it exists
888
+		$config_obj = $this->get_config_option($this->_generate_config_option_name($section, $name));
889
+		// verify the newly retrieved config object, but suppress errors
890
+		if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
891
+			// config is good, so set it and pass it back
892
+			$this->{$section}->{$name} = $config_obj;
893
+			return $this->{$section}->{$name};
894
+		}
895
+		// oops! $config_obj is not already set and does not exist in the db, so create a new one
896
+		$config_obj = $this->set_config($section, $name, $config_class);
897
+		// verify the newly created config object
898
+		if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9))) {
899
+			return $this->{$section}->{$name};
900
+		} else {
901
+			EE_Error::add_error(
902
+				sprintf(__('The "%s" could not be retrieved from the database.', 'event_espresso'), $config_class),
903
+				__FILE__,
904
+				__FUNCTION__,
905
+				__LINE__
906
+			);
907
+		}
908
+		return null;
909
+	}
910
+
911
+
912
+
913
+	/**
914
+	 *    get_config_option
915
+	 *
916
+	 * @access    public
917
+	 * @param    string $config_option_name
918
+	 * @return    mixed EE_Config_Base | FALSE
919
+	 */
920
+	public function get_config_option($config_option_name = '')
921
+	{
922
+		// retrieve the wp-option for this config class.
923
+		$config_option = maybe_unserialize(get_option($config_option_name, array()));
924
+		if (empty($config_option)) {
925
+			EE_Config::log($config_option_name . '-NOT-FOUND');
926
+		}
927
+		return $config_option;
928
+	}
929
+
930
+
931
+
932
+	/**
933
+	 * log
934
+	 *
935
+	 * @param string $config_option_name
936
+	 */
937
+	public static function log($config_option_name = '')
938
+	{
939
+		if (EE_Config::logging_enabled() && ! empty($config_option_name)) {
940
+			$config_log = get_option(EE_Config::LOG_NAME, array());
941
+			//copy incoming $_REQUEST and sanitize it so we can save it
942
+			$_request = $_REQUEST;
943
+			array_walk_recursive($_request, 'sanitize_text_field');
944
+			$config_log[(string)microtime(true)] = array(
945
+				'config_name' => $config_option_name,
946
+				'request'     => $_request,
947
+			);
948
+			update_option(EE_Config::LOG_NAME, $config_log);
949
+		}
950
+	}
951
+
952
+
953
+
954
+	/**
955
+	 * trim_log
956
+	 * reduces the size of the config log to the length specified by EE_Config::LOG_LENGTH
957
+	 */
958
+	public static function trim_log()
959
+	{
960
+		if (! EE_Config::logging_enabled()) {
961
+			return;
962
+		}
963
+		$config_log = maybe_unserialize(get_option(EE_Config::LOG_NAME, array()));
964
+		$log_length = count($config_log);
965
+		if ($log_length > EE_Config::LOG_LENGTH) {
966
+			ksort($config_log);
967
+			$config_log = array_slice($config_log, $log_length - EE_Config::LOG_LENGTH, null, true);
968
+			update_option(EE_Config::LOG_NAME, $config_log);
969
+		}
970
+	}
971
+
972
+
973
+
974
+	/**
975
+	 *    get_page_for_posts
976
+	 *    if the wp-option "show_on_front" is set to "page", then this is the post_name for the post set in the
977
+	 *    wp-option "page_for_posts", or "posts" if no page is selected
978
+	 *
979
+	 * @access    public
980
+	 * @return    string
981
+	 */
982
+	public static function get_page_for_posts()
983
+	{
984
+		$page_for_posts = get_option('page_for_posts');
985
+		if (! $page_for_posts) {
986
+			return 'posts';
987
+		}
988
+		/** @type WPDB $wpdb */
989
+		global $wpdb;
990
+		$SQL = "SELECT post_name from $wpdb->posts WHERE post_type='posts' OR post_type='page' AND post_status='publish' AND ID=%d";
991
+		return $wpdb->get_var($wpdb->prepare($SQL, $page_for_posts));
992
+	}
993
+
994
+
995
+
996
+	/**
997
+	 *    register_shortcodes_and_modules.
998
+	 *    At this point, it's too early to tell if we're maintenance mode or not.
999
+	 *    In fact, this is where we give modules a chance to let core know they exist
1000
+	 *    so they can help trigger maintenance mode if it's needed
1001
+	 *
1002
+	 * @access    public
1003
+	 * @return    void
1004
+	 */
1005
+	public function register_shortcodes_and_modules()
1006
+	{
1007
+		// allow modules to set hooks for the rest of the system
1008
+		EE_Registry::instance()->modules = $this->_register_modules();
1009
+	}
1010
+
1011
+
1012
+
1013
+	/**
1014
+	 *    initialize_shortcodes_and_modules
1015
+	 *    meaning they can start adding their hooks to get stuff done
1016
+	 *
1017
+	 * @access    public
1018
+	 * @return    void
1019
+	 */
1020
+	public function initialize_shortcodes_and_modules()
1021
+	{
1022
+		// allow modules to set hooks for the rest of the system
1023
+		$this->_initialize_modules();
1024
+	}
1025
+
1026
+
1027
+
1028
+	/**
1029
+	 *    widgets_init
1030
+	 *
1031
+	 * @access private
1032
+	 * @return void
1033
+	 */
1034
+	public function widgets_init()
1035
+	{
1036
+		//only init widgets on admin pages when not in complete maintenance, and
1037
+		//on frontend when not in any maintenance mode
1038
+		if (
1039
+			! EE_Maintenance_Mode::instance()->level()
1040
+			|| (
1041
+				is_admin()
1042
+				&& EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance
1043
+			)
1044
+		) {
1045
+			// grab list of installed widgets
1046
+			$widgets_to_register = glob(EE_WIDGETS . '*', GLOB_ONLYDIR);
1047
+			// filter list of modules to register
1048
+			$widgets_to_register = apply_filters(
1049
+				'FHEE__EE_Config__register_widgets__widgets_to_register',
1050
+				$widgets_to_register
1051
+			);
1052
+			if (! empty($widgets_to_register)) {
1053
+				// cycle thru widget folders
1054
+				foreach ($widgets_to_register as $widget_path) {
1055
+					// add to list of installed widget modules
1056
+					EE_Config::register_ee_widget($widget_path);
1057
+				}
1058
+			}
1059
+			// filter list of installed modules
1060
+			EE_Registry::instance()->widgets = apply_filters(
1061
+				'FHEE__EE_Config__register_widgets__installed_widgets',
1062
+				EE_Registry::instance()->widgets
1063
+			);
1064
+		}
1065
+	}
1066
+
1067
+
1068
+
1069
+	/**
1070
+	 *    register_ee_widget - makes core aware of this widget
1071
+	 *
1072
+	 * @access    public
1073
+	 * @param    string $widget_path - full path up to and including widget folder
1074
+	 * @return    void
1075
+	 */
1076
+	public static function register_ee_widget($widget_path = null)
1077
+	{
1078
+		do_action('AHEE__EE_Config__register_widget__begin', $widget_path);
1079
+		$widget_ext = '.widget.php';
1080
+		// make all separators match
1081
+		$widget_path = rtrim(str_replace('/\\', DS, $widget_path), DS);
1082
+		// does the file path INCLUDE the actual file name as part of the path ?
1083
+		if (strpos($widget_path, $widget_ext) !== false) {
1084
+			// grab and shortcode file name from directory name and break apart at dots
1085
+			$file_name = explode('.', basename($widget_path));
1086
+			// take first segment from file name pieces and remove class prefix if it exists
1087
+			$widget = strpos($file_name[0], 'EEW_') === 0 ? substr($file_name[0], 4) : $file_name[0];
1088
+			// sanitize shortcode directory name
1089
+			$widget = sanitize_key($widget);
1090
+			// now we need to rebuild the shortcode path
1091
+			$widget_path = explode(DS, $widget_path);
1092
+			// remove last segment
1093
+			array_pop($widget_path);
1094
+			// glue it back together
1095
+			$widget_path = implode(DS, $widget_path);
1096
+		} else {
1097
+			// grab and sanitize widget directory name
1098
+			$widget = sanitize_key(basename($widget_path));
1099
+		}
1100
+		// create classname from widget directory name
1101
+		$widget = str_replace(' ', '_', ucwords(str_replace('_', ' ', $widget)));
1102
+		// add class prefix
1103
+		$widget_class = 'EEW_' . $widget;
1104
+		// does the widget exist ?
1105
+		if (! is_readable($widget_path . DS . $widget_class . $widget_ext)) {
1106
+			$msg = sprintf(
1107
+				__(
1108
+					'The requested %s widget file could not be found or is not readable due to file permissions. Please ensure the following path is correct: %s',
1109
+					'event_espresso'
1110
+				),
1111
+				$widget_class,
1112
+				$widget_path . DS . $widget_class . $widget_ext
1113
+			);
1114
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1115
+			return;
1116
+		}
1117
+		// load the widget class file
1118
+		require_once($widget_path . DS . $widget_class . $widget_ext);
1119
+		// verify that class exists
1120
+		if (! class_exists($widget_class)) {
1121
+			$msg = sprintf(__('The requested %s widget class does not exist.', 'event_espresso'), $widget_class);
1122
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1123
+			return;
1124
+		}
1125
+		register_widget($widget_class);
1126
+		// add to array of registered widgets
1127
+		EE_Registry::instance()->widgets->{$widget_class} = $widget_path . DS . $widget_class . $widget_ext;
1128
+	}
1129
+
1130
+
1131
+
1132
+	/**
1133
+	 *        _register_modules
1134
+	 *
1135
+	 * @access private
1136
+	 * @return array
1137
+	 */
1138
+	private function _register_modules()
1139
+	{
1140
+		// grab list of installed modules
1141
+		$modules_to_register = glob(EE_MODULES . '*', GLOB_ONLYDIR);
1142
+		// filter list of modules to register
1143
+		$modules_to_register = apply_filters(
1144
+			'FHEE__EE_Config__register_modules__modules_to_register',
1145
+			$modules_to_register
1146
+		);
1147
+		if (! empty($modules_to_register)) {
1148
+			// loop through folders
1149
+			foreach ($modules_to_register as $module_path) {
1150
+				/**TEMPORARILY EXCLUDE gateways from modules for time being**/
1151
+				if (
1152
+					$module_path !== EE_MODULES . 'zzz-copy-this-module-template'
1153
+					&& $module_path !== EE_MODULES . 'gateways'
1154
+				) {
1155
+					// add to list of installed modules
1156
+					EE_Config::register_module($module_path);
1157
+				}
1158
+			}
1159
+		}
1160
+		// filter list of installed modules
1161
+		return apply_filters(
1162
+			'FHEE__EE_Config___register_modules__installed_modules',
1163
+			EE_Registry::instance()->modules
1164
+		);
1165
+	}
1166
+
1167
+
1168
+
1169
+	/**
1170
+	 *    register_module - makes core aware of this module
1171
+	 *
1172
+	 * @access    public
1173
+	 * @param    string $module_path - full path up to and including module folder
1174
+	 * @return    bool
1175
+	 */
1176
+	public static function register_module($module_path = null)
1177
+	{
1178
+		do_action('AHEE__EE_Config__register_module__begin', $module_path);
1179
+		$module_ext = '.module.php';
1180
+		// make all separators match
1181
+		$module_path = str_replace(array('\\', '/'), DS, $module_path);
1182
+		// does the file path INCLUDE the actual file name as part of the path ?
1183
+		if (strpos($module_path, $module_ext) !== false) {
1184
+			// grab and shortcode file name from directory name and break apart at dots
1185
+			$module_file = explode('.', basename($module_path));
1186
+			// now we need to rebuild the shortcode path
1187
+			$module_path = explode(DS, $module_path);
1188
+			// remove last segment
1189
+			array_pop($module_path);
1190
+			// glue it back together
1191
+			$module_path = implode(DS, $module_path) . DS;
1192
+			// take first segment from file name pieces and sanitize it
1193
+			$module = preg_replace('/[^a-zA-Z0-9_\-]/', '', $module_file[0]);
1194
+			// ensure class prefix is added
1195
+			$module_class = strpos($module, 'EED_') !== 0 ? 'EED_' . $module : $module;
1196
+		} else {
1197
+			// we need to generate the filename based off of the folder name
1198
+			// grab and sanitize module name
1199
+			$module = strtolower(basename($module_path));
1200
+			$module = preg_replace('/[^a-z0-9_\-]/', '', $module);
1201
+			// like trailingslashit()
1202
+			$module_path = rtrim($module_path, DS) . DS;
1203
+			// create classname from module directory name
1204
+			$module = str_replace(' ', '_', ucwords(str_replace('_', ' ', $module)));
1205
+			// add class prefix
1206
+			$module_class = 'EED_' . $module;
1207
+		}
1208
+		// does the module exist ?
1209
+		if (! is_readable($module_path . DS . $module_class . $module_ext)) {
1210
+			$msg = sprintf(
1211
+				__(
1212
+					'The requested %s module file could not be found or is not readable due to file permissions.',
1213
+					'event_espresso'
1214
+				),
1215
+				$module
1216
+			);
1217
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1218
+			return false;
1219
+		}
1220
+		// load the module class file
1221
+		require_once($module_path . $module_class . $module_ext);
1222
+		// verify that class exists
1223
+		if (! class_exists($module_class)) {
1224
+			$msg = sprintf(__('The requested %s module class does not exist.', 'event_espresso'), $module_class);
1225
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1226
+			return false;
1227
+		}
1228
+		// add to array of registered modules
1229
+		EE_Registry::instance()->modules->{$module_class} = $module_path . $module_class . $module_ext;
1230
+		do_action(
1231
+			'AHEE__EE_Config__register_module__complete',
1232
+			$module_class,
1233
+			EE_Registry::instance()->modules->{$module_class}
1234
+		);
1235
+		return true;
1236
+	}
1237
+
1238
+
1239
+
1240
+	/**
1241
+	 *    _initialize_modules
1242
+	 *    allow modules to set hooks for the rest of the system
1243
+	 *
1244
+	 * @access private
1245
+	 * @return void
1246
+	 */
1247
+	private function _initialize_modules()
1248
+	{
1249
+		// cycle thru shortcode folders
1250
+		foreach (EE_Registry::instance()->modules as $module_class => $module_path) {
1251
+			// fire the shortcode class's set_hooks methods in case it needs to hook into other parts of the system
1252
+			// which set hooks ?
1253
+			if (is_admin()) {
1254
+				// fire immediately
1255
+				call_user_func(array($module_class, 'set_hooks_admin'));
1256
+			} else {
1257
+				// delay until other systems are online
1258
+				add_action(
1259
+					'AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons',
1260
+					array($module_class, 'set_hooks')
1261
+				);
1262
+			}
1263
+		}
1264
+	}
1265
+
1266
+
1267
+
1268
+	/**
1269
+	 *    register_route - adds module method routes to route_map
1270
+	 *
1271
+	 * @access    public
1272
+	 * @param    string $route       - "pretty" public alias for module method
1273
+	 * @param    string $module      - module name (classname without EED_ prefix)
1274
+	 * @param    string $method_name - the actual module method to be routed to
1275
+	 * @param    string $key         - url param key indicating a route is being called
1276
+	 * @return    bool
1277
+	 */
1278
+	public static function register_route($route = null, $module = null, $method_name = null, $key = 'ee')
1279
+	{
1280
+		do_action('AHEE__EE_Config__register_route__begin', $route, $module, $method_name);
1281
+		$module = str_replace('EED_', '', $module);
1282
+		$module_class = 'EED_' . $module;
1283
+		if (! isset(EE_Registry::instance()->modules->{$module_class})) {
1284
+			$msg = sprintf(__('The module %s has not been registered.', 'event_espresso'), $module);
1285
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1286
+			return false;
1287
+		}
1288
+		if (empty($route)) {
1289
+			$msg = sprintf(__('No route has been supplied.', 'event_espresso'), $route);
1290
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1291
+			return false;
1292
+		}
1293
+		if (! method_exists('EED_' . $module, $method_name)) {
1294
+			$msg = sprintf(
1295
+				__('A valid class method for the %s route has not been supplied.', 'event_espresso'),
1296
+				$route
1297
+			);
1298
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1299
+			return false;
1300
+		}
1301
+		EE_Config::$_module_route_map[$key][$route] = array('EED_' . $module, $method_name);
1302
+		return true;
1303
+	}
1304
+
1305
+
1306
+
1307
+	/**
1308
+	 *    get_route - get module method route
1309
+	 *
1310
+	 * @access    public
1311
+	 * @param    string $route - "pretty" public alias for module method
1312
+	 * @param    string $key   - url param key indicating a route is being called
1313
+	 * @return    string
1314
+	 */
1315
+	public static function get_route($route = null, $key = 'ee')
1316
+	{
1317
+		do_action('AHEE__EE_Config__get_route__begin', $route);
1318
+		$route = (string)apply_filters('FHEE__EE_Config__get_route', $route);
1319
+		if (isset(EE_Config::$_module_route_map[$key][$route])) {
1320
+			return EE_Config::$_module_route_map[$key][$route];
1321
+		}
1322
+		return null;
1323
+	}
1324
+
1325
+
1326
+
1327
+	/**
1328
+	 *    get_routes - get ALL module method routes
1329
+	 *
1330
+	 * @access    public
1331
+	 * @return    array
1332
+	 */
1333
+	public static function get_routes()
1334
+	{
1335
+		return EE_Config::$_module_route_map;
1336
+	}
1337
+
1338
+
1339
+
1340
+	/**
1341
+	 *    register_forward - allows modules to forward request to another module for further processing
1342
+	 *
1343
+	 * @access    public
1344
+	 * @param    string       $route   - "pretty" public alias for module method
1345
+	 * @param    integer      $status  - integer value corresponding  to status constant strings set in module parent
1346
+	 *                                 class, allows different forwards to be served based on status
1347
+	 * @param    array|string $forward - function name or array( class, method )
1348
+	 * @param    string       $key     - url param key indicating a route is being called
1349
+	 * @return    bool
1350
+	 */
1351
+	public static function register_forward($route = null, $status = 0, $forward = null, $key = 'ee')
1352
+	{
1353
+		do_action('AHEE__EE_Config__register_forward', $route, $status, $forward);
1354
+		if (! isset(EE_Config::$_module_route_map[$key][$route]) || empty($route)) {
1355
+			$msg = sprintf(
1356
+				__('The module route %s for this forward has not been registered.', 'event_espresso'),
1357
+				$route
1358
+			);
1359
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1360
+			return false;
1361
+		}
1362
+		if (empty($forward)) {
1363
+			$msg = sprintf(__('No forwarding route has been supplied.', 'event_espresso'), $route);
1364
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1365
+			return false;
1366
+		}
1367
+		if (is_array($forward)) {
1368
+			if (! isset($forward[1])) {
1369
+				$msg = sprintf(
1370
+					__('A class method for the %s forwarding route has not been supplied.', 'event_espresso'),
1371
+					$route
1372
+				);
1373
+				EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1374
+				return false;
1375
+			}
1376
+			if (! method_exists($forward[0], $forward[1])) {
1377
+				$msg = sprintf(
1378
+					__('The class method %s for the %s forwarding route is in invalid.', 'event_espresso'),
1379
+					$forward[1],
1380
+					$route
1381
+				);
1382
+				EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1383
+				return false;
1384
+			}
1385
+		} else if (! function_exists($forward)) {
1386
+			$msg = sprintf(
1387
+				__('The function %s for the %s forwarding route is in invalid.', 'event_espresso'),
1388
+				$forward,
1389
+				$route
1390
+			);
1391
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1392
+			return false;
1393
+		}
1394
+		EE_Config::$_module_forward_map[$key][$route][absint($status)] = $forward;
1395
+		return true;
1396
+	}
1397
+
1398
+
1399
+
1400
+	/**
1401
+	 *    get_forward - get forwarding route
1402
+	 *
1403
+	 * @access    public
1404
+	 * @param    string  $route  - "pretty" public alias for module method
1405
+	 * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1406
+	 *                           allows different forwards to be served based on status
1407
+	 * @param    string  $key    - url param key indicating a route is being called
1408
+	 * @return    string
1409
+	 */
1410
+	public static function get_forward($route = null, $status = 0, $key = 'ee')
1411
+	{
1412
+		do_action('AHEE__EE_Config__get_forward__begin', $route, $status);
1413
+		if (isset(EE_Config::$_module_forward_map[$key][$route][$status])) {
1414
+			return apply_filters(
1415
+				'FHEE__EE_Config__get_forward',
1416
+				EE_Config::$_module_forward_map[$key][$route][$status],
1417
+				$route,
1418
+				$status
1419
+			);
1420
+		}
1421
+		return null;
1422
+	}
1423
+
1424
+
1425
+
1426
+	/**
1427
+	 *    register_forward - allows modules to specify different view templates for different method routes and status
1428
+	 *    results
1429
+	 *
1430
+	 * @access    public
1431
+	 * @param    string  $route  - "pretty" public alias for module method
1432
+	 * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1433
+	 *                           allows different views to be served based on status
1434
+	 * @param    string  $view
1435
+	 * @param    string  $key    - url param key indicating a route is being called
1436
+	 * @return    bool
1437
+	 */
1438
+	public static function register_view($route = null, $status = 0, $view = null, $key = 'ee')
1439
+	{
1440
+		do_action('AHEE__EE_Config__register_view__begin', $route, $status, $view);
1441
+		if (! isset(EE_Config::$_module_route_map[$key][$route]) || empty($route)) {
1442
+			$msg = sprintf(
1443
+				__('The module route %s for this view has not been registered.', 'event_espresso'),
1444
+				$route
1445
+			);
1446
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1447
+			return false;
1448
+		}
1449
+		if (! is_readable($view)) {
1450
+			$msg = sprintf(
1451
+				__(
1452
+					'The %s view file could not be found or is not readable due to file permissions.',
1453
+					'event_espresso'
1454
+				),
1455
+				$view
1456
+			);
1457
+			EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1458
+			return false;
1459
+		}
1460
+		EE_Config::$_module_view_map[$key][$route][absint($status)] = $view;
1461
+		return true;
1462
+	}
1463
+
1464
+
1465
+
1466
+	/**
1467
+	 *    get_view - get view for route and status
1468
+	 *
1469
+	 * @access    public
1470
+	 * @param    string  $route  - "pretty" public alias for module method
1471
+	 * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1472
+	 *                           allows different views to be served based on status
1473
+	 * @param    string  $key    - url param key indicating a route is being called
1474
+	 * @return    string
1475
+	 */
1476
+	public static function get_view($route = null, $status = 0, $key = 'ee')
1477
+	{
1478
+		do_action('AHEE__EE_Config__get_view__begin', $route, $status);
1479
+		if (isset(EE_Config::$_module_view_map[$key][$route][$status])) {
1480
+			return apply_filters(
1481
+				'FHEE__EE_Config__get_view',
1482
+				EE_Config::$_module_view_map[$key][$route][$status],
1483
+				$route,
1484
+				$status
1485
+			);
1486
+		}
1487
+		return null;
1488
+	}
1489
+
1490
+
1491
+
1492
+	public function update_addon_option_names()
1493
+	{
1494
+		update_option(EE_Config::ADDON_OPTION_NAMES, $this->_addon_option_names);
1495
+	}
1496
+
1497
+
1498
+
1499
+	public function shutdown()
1500
+	{
1501
+		$this->update_addon_option_names();
1502
+	}
1503
+
1504
+
1505
+
1506
+	/**
1507
+	 * @return LegacyShortcodesManager
1508
+	 */
1509
+	public static function getLegacyShortcodesManager()
1510
+	{
1511
+
1512
+		if ( ! EE_Config::instance()->legacy_shortcodes_manager instanceof LegacyShortcodesManager) {
1513
+			EE_Config::instance()->legacy_shortcodes_manager = new LegacyShortcodesManager(
1514
+				EE_Registry::instance()
1515
+			);
1516
+		}
1517
+		return EE_Config::instance()->legacy_shortcodes_manager;
1518
+	}
1519
+
1520
+
1521
+
1522
+	/**
1523
+	 * register_shortcode - makes core aware of this shortcode
1524
+	 *
1525
+	 * @deprecated 4.9.26
1526
+	 * @param    string $shortcode_path - full path up to and including shortcode folder
1527
+	 * @return    bool
1528
+	 */
1529
+	public static function register_shortcode($shortcode_path = null)
1530
+	{
1531
+		EE_Error::doing_it_wrong(
1532
+			__METHOD__,
1533
+			__(
1534
+				'Usage is deprecated. Use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::registerShortcode() as direct replacement, or better yet, please see the new \EventEspresso\core\services\shortcodes\ShortcodesManager class.',
1535
+				'event_espresso'
1536
+			),
1537
+			'4.9.26'
1538
+		);
1539
+		return EE_Config::instance()->getLegacyShortcodesManager()->registerShortcode($shortcode_path);
1540
+	}
21 1541
 
22
-    const LOG_NAME           = 'ee_config_log';
23 1542
 
24
-    const LOG_LENGTH         = 100;
25 1543
 
26
-    const ADDON_OPTION_NAMES = 'ee_config_option_names';
27
-
28
-
29
-    /**
30
-     *    instance of the EE_Config object
31
-     *
32
-     * @var    EE_Config $_instance
33
-     * @access    private
34
-     */
35
-    private static $_instance;
36
-
37
-    /**
38
-     * @var boolean $_logging_enabled
39
-     */
40
-    private static $_logging_enabled = false;
41
-
42
-    /**
43
-     * @var LegacyShortcodesManager $legacy_shortcodes_manager
44
-     */
45
-    private $legacy_shortcodes_manager;
46
-
47
-    /**
48
-     * An StdClass whose property names are addon slugs,
49
-     * and values are their config classes
50
-     *
51
-     * @var StdClass
52
-     */
53
-    public $addons;
54
-
55
-    /**
56
-     * @var EE_Admin_Config
57
-     */
58
-    public $admin;
59
-
60
-    /**
61
-     * @var EE_Core_Config
62
-     */
63
-    public $core;
64
-
65
-    /**
66
-     * @var EE_Currency_Config
67
-     */
68
-    public $currency;
69
-
70
-    /**
71
-     * @var EE_Organization_Config
72
-     */
73
-    public $organization;
74
-
75
-    /**
76
-     * @var EE_Registration_Config
77
-     */
78
-    public $registration;
79
-
80
-    /**
81
-     * @var EE_Template_Config
82
-     */
83
-    public $template_settings;
84
-
85
-    /**
86
-     * Holds EE environment values.
87
-     *
88
-     * @var EE_Environment_Config
89
-     */
90
-    public $environment;
91
-
92
-    /**
93
-     * settings pertaining to Google maps
94
-     *
95
-     * @var EE_Map_Config
96
-     */
97
-    public $map_settings;
98
-
99
-    /**
100
-     * settings pertaining to Taxes
101
-     *
102
-     * @var EE_Tax_Config
103
-     */
104
-    public $tax_settings;
105
-
106
-
107
-    /**
108
-     * Settings pertaining to global messages settings.
109
-     *
110
-     * @var EE_Messages_Config
111
-     */
112
-    public $messages;
113
-
114
-    /**
115
-     * @deprecated
116
-     * @var EE_Gateway_Config
117
-     */
118
-    public $gateway;
119
-
120
-    /**
121
-     * @var    array $_addon_option_names
122
-     * @access    private
123
-     */
124
-    private $_addon_option_names = array();
125
-
126
-    /**
127
-     * @var    array $_module_route_map
128
-     * @access    private
129
-     */
130
-    private static $_module_route_map = array();
131
-
132
-    /**
133
-     * @var    array $_module_forward_map
134
-     * @access    private
135
-     */
136
-    private static $_module_forward_map = array();
137
-
138
-    /**
139
-     * @var    array $_module_view_map
140
-     * @access    private
141
-     */
142
-    private static $_module_view_map = array();
143
-
144
-
145
-
146
-    /**
147
-     * @singleton method used to instantiate class object
148
-     * @access    public
149
-     * @return EE_Config instance
150
-     */
151
-    public static function instance()
152
-    {
153
-        // check if class object is instantiated, and instantiated properly
154
-        if (! self::$_instance instanceof EE_Config) {
155
-            self::$_instance = new self();
156
-        }
157
-        return self::$_instance;
158
-    }
159
-
160
-
161
-
162
-    /**
163
-     * Resets the config
164
-     *
165
-     * @param bool    $hard_reset    if TRUE, sets EE_CONFig back to its original settings in the database. If FALSE
166
-     *                               (default) leaves the database alone, and merely resets the EE_Config object to
167
-     *                               reflect its state in the database
168
-     * @param boolean $reinstantiate if TRUE (default) call instance() and return it. Otherwise, just leave
169
-     *                               $_instance as NULL. Useful in case you want to forget about the old instance on
170
-     *                               EE_Config, but might not be ready to instantiate EE_Config currently (eg if the
171
-     *                               site was put into maintenance mode)
172
-     * @return EE_Config
173
-     */
174
-    public static function reset($hard_reset = false, $reinstantiate = true)
175
-    {
176
-        if (self::$_instance instanceof EE_Config) {
177
-            if ($hard_reset) {
178
-                self::$_instance->legacy_shortcodes_manager = null;
179
-                self::$_instance->_addon_option_names = array();
180
-                self::$_instance->_initialize_config();
181
-                self::$_instance->update_espresso_config();
182
-            }
183
-            self::$_instance->update_addon_option_names();
184
-        }
185
-        self::$_instance = null;
186
-        //we don't need to reset the static properties imo because those should
187
-        //only change when a module is added or removed. Currently we don't
188
-        //support removing a module during a request when it previously existed
189
-        if ($reinstantiate) {
190
-            return self::instance();
191
-        } else {
192
-            return null;
193
-        }
194
-    }
195
-
196
-
197
-
198
-    /**
199
-     *    class constructor
200
-     *
201
-     * @access    private
202
-     */
203
-    private function __construct()
204
-    {
205
-        do_action('AHEE__EE_Config__construct__begin', $this);
206
-        EE_Config::$_logging_enabled = apply_filters('FHEE__EE_Config___construct__logging_enabled', false);
207
-        // setup empty config classes
208
-        $this->_initialize_config();
209
-        // load existing EE site settings
210
-        $this->_load_core_config();
211
-        // confirm everything loaded correctly and set filtered defaults if not
212
-        $this->_verify_config();
213
-        //  register shortcodes and modules
214
-        add_action(
215
-            'AHEE__EE_System__register_shortcodes_modules_and_widgets',
216
-            array($this, 'register_shortcodes_and_modules'),
217
-            999
218
-        );
219
-        //  initialize shortcodes and modules
220
-        add_action('AHEE__EE_System__core_loaded_and_ready', array($this, 'initialize_shortcodes_and_modules'));
221
-        // register widgets
222
-        add_action('widgets_init', array($this, 'widgets_init'), 10);
223
-        // shutdown
224
-        add_action('shutdown', array($this, 'shutdown'), 10);
225
-        // construct__end hook
226
-        do_action('AHEE__EE_Config__construct__end', $this);
227
-        // hardcoded hack
228
-        $this->template_settings->current_espresso_theme = 'Espresso_Arabica_2014';
229
-    }
230
-
231
-
232
-
233
-    /**
234
-     * @return boolean
235
-     */
236
-    public static function logging_enabled()
237
-    {
238
-        return self::$_logging_enabled;
239
-    }
240
-
241
-
242
-
243
-    /**
244
-     * use to get the current theme if needed from static context
245
-     *
246
-     * @return string current theme set.
247
-     */
248
-    public static function get_current_theme()
249
-    {
250
-        return isset(self::$_instance->template_settings->current_espresso_theme)
251
-            ? self::$_instance->template_settings->current_espresso_theme : 'Espresso_Arabica_2014';
252
-    }
253
-
254
-
255
-
256
-    /**
257
-     *        _initialize_config
258
-     *
259
-     * @access private
260
-     * @return void
261
-     */
262
-    private function _initialize_config()
263
-    {
264
-        EE_Config::trim_log();
265
-        //set defaults
266
-        $this->_addon_option_names = get_option(EE_Config::ADDON_OPTION_NAMES, array());
267
-        $this->addons = new stdClass();
268
-        // set _module_route_map
269
-        EE_Config::$_module_route_map = array();
270
-        // set _module_forward_map
271
-        EE_Config::$_module_forward_map = array();
272
-        // set _module_view_map
273
-        EE_Config::$_module_view_map = array();
274
-    }
275
-
276
-
277
-
278
-    /**
279
-     *        load core plugin configuration
280
-     *
281
-     * @access private
282
-     * @return void
283
-     */
284
-    private function _load_core_config()
285
-    {
286
-        // load_core_config__start hook
287
-        do_action('AHEE__EE_Config___load_core_config__start', $this);
288
-        $espresso_config = $this->get_espresso_config();
289
-        foreach ($espresso_config as $config => $settings) {
290
-            // load_core_config__start hook
291
-            $settings = apply_filters(
292
-                'FHEE__EE_Config___load_core_config__config_settings',
293
-                $settings,
294
-                $config,
295
-                $this
296
-            );
297
-            if (is_object($settings) && property_exists($this, $config)) {
298
-                $this->{$config} = apply_filters('FHEE__EE_Config___load_core_config__' . $config, $settings);
299
-                //call configs populate method to ensure any defaults are set for empty values.
300
-                if (method_exists($settings, 'populate')) {
301
-                    $this->{$config}->populate();
302
-                }
303
-                if (method_exists($settings, 'do_hooks')) {
304
-                    $this->{$config}->do_hooks();
305
-                }
306
-            }
307
-        }
308
-        if (apply_filters('FHEE__EE_Config___load_core_config__update_espresso_config', false)) {
309
-            $this->update_espresso_config();
310
-        }
311
-        // load_core_config__end hook
312
-        do_action('AHEE__EE_Config___load_core_config__end', $this);
313
-    }
314
-
315
-
316
-
317
-    /**
318
-     *    _verify_config
319
-     *
320
-     * @access    protected
321
-     * @return    void
322
-     */
323
-    protected function _verify_config()
324
-    {
325
-        $this->core = $this->core instanceof EE_Core_Config
326
-            ? $this->core
327
-            : new EE_Core_Config();
328
-        $this->core = apply_filters('FHEE__EE_Config___initialize_config__core', $this->core);
329
-        $this->organization = $this->organization instanceof EE_Organization_Config
330
-            ? $this->organization
331
-            : new EE_Organization_Config();
332
-        $this->organization = apply_filters(
333
-            'FHEE__EE_Config___initialize_config__organization',
334
-            $this->organization
335
-        );
336
-        $this->currency = $this->currency instanceof EE_Currency_Config
337
-            ? $this->currency
338
-            : new EE_Currency_Config();
339
-        $this->currency = apply_filters('FHEE__EE_Config___initialize_config__currency', $this->currency);
340
-        $this->registration = $this->registration instanceof EE_Registration_Config
341
-            ? $this->registration
342
-            : new EE_Registration_Config();
343
-        $this->registration = apply_filters(
344
-            'FHEE__EE_Config___initialize_config__registration',
345
-            $this->registration
346
-        );
347
-        $this->admin = $this->admin instanceof EE_Admin_Config
348
-            ? $this->admin
349
-            : new EE_Admin_Config();
350
-        $this->admin = apply_filters('FHEE__EE_Config___initialize_config__admin', $this->admin);
351
-        $this->template_settings = $this->template_settings instanceof EE_Template_Config
352
-            ? $this->template_settings
353
-            : new EE_Template_Config();
354
-        $this->template_settings = apply_filters(
355
-            'FHEE__EE_Config___initialize_config__template_settings',
356
-            $this->template_settings
357
-        );
358
-        $this->map_settings = $this->map_settings instanceof EE_Map_Config
359
-            ? $this->map_settings
360
-            : new EE_Map_Config();
361
-        $this->map_settings = apply_filters('FHEE__EE_Config___initialize_config__map_settings',
362
-            $this->map_settings);
363
-        $this->environment = $this->environment instanceof EE_Environment_Config
364
-            ? $this->environment
365
-            : new EE_Environment_Config();
366
-        $this->environment = apply_filters('FHEE__EE_Config___initialize_config__environment',
367
-            $this->environment);
368
-        $this->tax_settings = $this->tax_settings instanceof EE_Tax_Config
369
-            ? $this->tax_settings
370
-            : new EE_Tax_Config();
371
-        $this->tax_settings = apply_filters('FHEE__EE_Config___initialize_config__tax_settings',
372
-            $this->tax_settings);
373
-        $this->messages = apply_filters('FHEE__EE_Config__initialize_config__messages', $this->messages);
374
-        $this->messages = $this->messages instanceof EE_Messages_Config
375
-            ? $this->messages
376
-            : new EE_Messages_Config();
377
-        $this->gateway = $this->gateway instanceof EE_Gateway_Config
378
-            ? $this->gateway
379
-            : new EE_Gateway_Config();
380
-        $this->gateway = apply_filters('FHEE__EE_Config___initialize_config__gateway', $this->gateway);
381
-        $this->legacy_shortcodes_manager = null;
382
-    }
383
-
384
-
385
-    /**
386
-     *    get_espresso_config
387
-     *
388
-     * @access    public
389
-     * @return    array of espresso config stuff
390
-     */
391
-    public function get_espresso_config()
392
-    {
393
-        // grab espresso configuration
394
-        return apply_filters(
395
-            'FHEE__EE_Config__get_espresso_config__CFG',
396
-            get_option(EE_Config::OPTION_NAME, array())
397
-        );
398
-    }
399
-
400
-
401
-
402
-    /**
403
-     *    double_check_config_comparison
404
-     *
405
-     * @access    public
406
-     * @param string $option
407
-     * @param        $old_value
408
-     * @param        $value
409
-     */
410
-    public function double_check_config_comparison($option = '', $old_value, $value)
411
-    {
412
-        // make sure we're checking the ee config
413
-        if ($option === EE_Config::OPTION_NAME) {
414
-            // run a loose comparison of the old value against the new value for type and properties,
415
-            // but NOT exact instance like WP update_option does (ie: NOT type safe comparison)
416
-            if ($value != $old_value) {
417
-                // if they are NOT the same, then remove the hook,
418
-                // which means the subsequent update results will be based solely on the update query results
419
-                // the reason we do this is because, as stated above,
420
-                // WP update_option performs an exact instance comparison (===) on any update values passed to it
421
-                // this happens PRIOR to serialization and any subsequent update.
422
-                // If values are found to match their previous old value,
423
-                // then WP bails before performing any update.
424
-                // Since we are passing the EE_Config object, it is comparing the EXACT instance of the saved version
425
-                // it just pulled from the db, with the one being passed to it (which will not match).
426
-                // HOWEVER, once the object is serialized and passed off to MySQL to update,
427
-                // MySQL MAY ALSO NOT perform the update because
428
-                // the string it sees in the db looks the same as the new one it has been passed!!!
429
-                // This results in the query returning an "affected rows" value of ZERO,
430
-                // which gets returned immediately by WP update_option and looks like an error.
431
-                remove_action('update_option', array($this, 'check_config_updated'));
432
-            }
433
-        }
434
-    }
435
-
436
-
437
-
438
-    /**
439
-     *    update_espresso_config
440
-     *
441
-     * @access   public
442
-     */
443
-    protected function _reset_espresso_addon_config()
444
-    {
445
-        $this->_addon_option_names = array();
446
-        foreach ($this->addons as $addon_name => $addon_config_obj) {
447
-            $addon_config_obj = maybe_unserialize($addon_config_obj);
448
-            if ($addon_config_obj instanceof EE_Config_Base) {
449
-                $this->update_config('addons', $addon_name, $addon_config_obj, false);
450
-            }
451
-            $this->addons->{$addon_name} = null;
452
-        }
453
-    }
454
-
455
-
456
-
457
-    /**
458
-     *    update_espresso_config
459
-     *
460
-     * @access   public
461
-     * @param   bool $add_success
462
-     * @param   bool $add_error
463
-     * @return   bool
464
-     */
465
-    public function update_espresso_config($add_success = false, $add_error = true)
466
-    {
467
-        // don't allow config updates during WP heartbeats
468
-        if (\EE_Registry::instance()->REQ->get('action', '') === 'heartbeat') {
469
-            return false;
470
-        }
471
-        // commented out the following re: https://events.codebasehq.com/projects/event-espresso/tickets/8197
472
-        //$clone = clone( self::$_instance );
473
-        //self::$_instance = NULL;
474
-        do_action('AHEE__EE_Config__update_espresso_config__begin', $this);
475
-        $this->_reset_espresso_addon_config();
476
-        // hook into update_option because that happens AFTER the ( $value === $old_value ) conditional
477
-        // but BEFORE the actual update occurs
478
-        add_action('update_option', array($this, 'double_check_config_comparison'), 1, 3);
479
-        // don't want to persist legacy_shortcodes_manager, but don't want to lose it either
480
-        $legacy_shortcodes_manager = $this->legacy_shortcodes_manager;
481
-        $this->legacy_shortcodes_manager = null;
482
-        // now update "ee_config"
483
-        $saved = update_option(EE_Config::OPTION_NAME, $this);
484
-        $this->legacy_shortcodes_manager = $legacy_shortcodes_manager;
485
-        EE_Config::log(EE_Config::OPTION_NAME);
486
-        // if not saved... check if the hook we just added still exists;
487
-        // if it does, it means one of two things:
488
-        // 		that update_option bailed at the ( $value === $old_value ) conditional,
489
-        //		 or...
490
-        // 		the db update query returned 0 rows affected
491
-        // 		(probably because the data  value was the same from it's perspective)
492
-        // so the existence of the hook means that a negative result from update_option is NOT an error,
493
-        // but just means no update occurred, so don't display an error to the user.
494
-        // BUT... if update_option returns FALSE, AND the hook is missing,
495
-        // then it means that something truly went wrong
496
-        $saved = ! $saved ? has_action('update_option', array($this, 'double_check_config_comparison')) : $saved;
497
-        // remove our action since we don't want it in the system anymore
498
-        remove_action('update_option', array($this, 'double_check_config_comparison'), 1);
499
-        do_action('AHEE__EE_Config__update_espresso_config__end', $this, $saved);
500
-        //self::$_instance = $clone;
501
-        //unset( $clone );
502
-        // if config remains the same or was updated successfully
503
-        if ($saved) {
504
-            if ($add_success) {
505
-                EE_Error::add_success(
506
-                    __('The Event Espresso Configuration Settings have been successfully updated.', 'event_espresso'),
507
-                    __FILE__,
508
-                    __FUNCTION__,
509
-                    __LINE__
510
-                );
511
-            }
512
-            return true;
513
-        } else {
514
-            if ($add_error) {
515
-                EE_Error::add_error(
516
-                    __('The Event Espresso Configuration Settings were not updated.', 'event_espresso'),
517
-                    __FILE__,
518
-                    __FUNCTION__,
519
-                    __LINE__
520
-                );
521
-            }
522
-            return false;
523
-        }
524
-    }
525
-
526
-
527
-
528
-    /**
529
-     *    _verify_config_params
530
-     *
531
-     * @access    private
532
-     * @param    string         $section
533
-     * @param    string         $name
534
-     * @param    string         $config_class
535
-     * @param    EE_Config_Base $config_obj
536
-     * @param    array          $tests_to_run
537
-     * @param    bool           $display_errors
538
-     * @return    bool    TRUE on success, FALSE on fail
539
-     */
540
-    private function _verify_config_params(
541
-        $section = '',
542
-        $name = '',
543
-        $config_class = '',
544
-        $config_obj = null,
545
-        $tests_to_run = array(1, 2, 3, 4, 5, 6, 7, 8),
546
-        $display_errors = true
547
-    ) {
548
-        try {
549
-            foreach ($tests_to_run as $test) {
550
-                switch ($test) {
551
-                    // TEST #1 : check that section was set
552
-                    case 1 :
553
-                        if (empty($section)) {
554
-                            if ($display_errors) {
555
-                                throw new EE_Error(
556
-                                    sprintf(
557
-                                        __(
558
-                                            'No configuration section has been provided while attempting to save "%s".',
559
-                                            'event_espresso'
560
-                                        ),
561
-                                        $config_class
562
-                                    )
563
-                                );
564
-                            }
565
-                            return false;
566
-                        }
567
-                        break;
568
-                    // TEST #2 : check that settings section exists
569
-                    case 2 :
570
-                        if (! isset($this->{$section})) {
571
-                            if ($display_errors) {
572
-                                throw new EE_Error(
573
-                                    sprintf(
574
-                                        __('The "%s" configuration section does not exist.', 'event_espresso'),
575
-                                        $section
576
-                                    )
577
-                                );
578
-                            }
579
-                            return false;
580
-                        }
581
-                        break;
582
-                    // TEST #3 : check that section is the proper format
583
-                    case 3 :
584
-                        if (
585
-                        ! ($this->{$section} instanceof EE_Config_Base || $this->{$section} instanceof stdClass)
586
-                        ) {
587
-                            if ($display_errors) {
588
-                                throw new EE_Error(
589
-                                    sprintf(
590
-                                        __(
591
-                                            'The "%s" configuration settings have not been formatted correctly.',
592
-                                            'event_espresso'
593
-                                        ),
594
-                                        $section
595
-                                    )
596
-                                );
597
-                            }
598
-                            return false;
599
-                        }
600
-                        break;
601
-                    // TEST #4 : check that config section name has been set
602
-                    case 4 :
603
-                        if (empty($name)) {
604
-                            if ($display_errors) {
605
-                                throw new EE_Error(
606
-                                    __(
607
-                                        'No name has been provided for the specific configuration section.',
608
-                                        'event_espresso'
609
-                                    )
610
-                                );
611
-                            }
612
-                            return false;
613
-                        }
614
-                        break;
615
-                    // TEST #5 : check that a config class name has been set
616
-                    case 5 :
617
-                        if (empty($config_class)) {
618
-                            if ($display_errors) {
619
-                                throw new EE_Error(
620
-                                    __(
621
-                                        'No class name has been provided for the specific configuration section.',
622
-                                        'event_espresso'
623
-                                    )
624
-                                );
625
-                            }
626
-                            return false;
627
-                        }
628
-                        break;
629
-                    // TEST #6 : verify config class is accessible
630
-                    case 6 :
631
-                        if (! class_exists($config_class)) {
632
-                            if ($display_errors) {
633
-                                throw new EE_Error(
634
-                                    sprintf(
635
-                                        __(
636
-                                            'The "%s" class does not exist. Please ensure that an autoloader has been set for it.',
637
-                                            'event_espresso'
638
-                                        ),
639
-                                        $config_class
640
-                                    )
641
-                                );
642
-                            }
643
-                            return false;
644
-                        }
645
-                        break;
646
-                    // TEST #7 : check that config has even been set
647
-                    case 7 :
648
-                        if (! isset($this->{$section}->{$name})) {
649
-                            if ($display_errors) {
650
-                                throw new EE_Error(
651
-                                    sprintf(
652
-                                        __('No configuration has been set for "%1$s->%2$s".', 'event_espresso'),
653
-                                        $section,
654
-                                        $name
655
-                                    )
656
-                                );
657
-                            }
658
-                            return false;
659
-                        } else {
660
-                            // and make sure it's not serialized
661
-                            $this->{$section}->{$name} = maybe_unserialize($this->{$section}->{$name});
662
-                        }
663
-                        break;
664
-                    // TEST #8 : check that config is the requested type
665
-                    case 8 :
666
-                        if (! $this->{$section}->{$name} instanceof $config_class) {
667
-                            if ($display_errors) {
668
-                                throw new EE_Error(
669
-                                    sprintf(
670
-                                        __(
671
-                                            'The configuration for "%1$s->%2$s" is not of the "%3$s" class.',
672
-                                            'event_espresso'
673
-                                        ),
674
-                                        $section,
675
-                                        $name,
676
-                                        $config_class
677
-                                    )
678
-                                );
679
-                            }
680
-                            return false;
681
-                        }
682
-                        break;
683
-                    // TEST #9 : verify config object
684
-                    case 9 :
685
-                        if (! $config_obj instanceof EE_Config_Base) {
686
-                            if ($display_errors) {
687
-                                throw new EE_Error(
688
-                                    sprintf(
689
-                                        __('The "%s" class is not an instance of EE_Config_Base.', 'event_espresso'),
690
-                                        print_r($config_obj, true)
691
-                                    )
692
-                                );
693
-                            }
694
-                            return false;
695
-                        }
696
-                        break;
697
-                }
698
-            }
699
-        } catch (EE_Error $e) {
700
-            $e->get_error();
701
-        }
702
-        // you have successfully run the gauntlet
703
-        return true;
704
-    }
705
-
706
-
707
-
708
-    /**
709
-     *    _generate_config_option_name
710
-     *
711
-     * @access        protected
712
-     * @param        string $section
713
-     * @param        string $name
714
-     * @return        string
715
-     */
716
-    private function _generate_config_option_name($section = '', $name = '')
717
-    {
718
-        return 'ee_config-' . strtolower($section . '-' . str_replace(array('EE_', 'EED_'), '', $name));
719
-    }
720
-
721
-
722
-
723
-    /**
724
-     *    _set_config_class
725
-     * ensures that a config class is set, either from a passed config class or one generated from the config name
726
-     *
727
-     * @access    private
728
-     * @param    string $config_class
729
-     * @param    string $name
730
-     * @return    string
731
-     */
732
-    private function _set_config_class($config_class = '', $name = '')
733
-    {
734
-        return ! empty($config_class)
735
-            ? $config_class
736
-            : str_replace(' ', '_', ucwords(str_replace('_', ' ', $name))) . '_Config';
737
-    }
738
-
739
-
740
-
741
-    /**
742
-     *    set_config
743
-     *
744
-     * @access    protected
745
-     * @param    string         $section
746
-     * @param    string         $name
747
-     * @param    string         $config_class
748
-     * @param    EE_Config_Base $config_obj
749
-     * @return    EE_Config_Base
750
-     */
751
-    public function set_config($section = '', $name = '', $config_class = '', EE_Config_Base $config_obj = null)
752
-    {
753
-        // ensure config class is set to something
754
-        $config_class = $this->_set_config_class($config_class, $name);
755
-        // run tests 1-4, 6, and 7 to verify all config params are set and valid
756
-        if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
757
-            return null;
758
-        }
759
-        $config_option_name = $this->_generate_config_option_name($section, $name);
760
-        // if the config option name hasn't been added yet to the list of option names we're tracking, then do so now
761
-        if (! isset($this->_addon_option_names[$config_option_name])) {
762
-            $this->_addon_option_names[$config_option_name] = $config_class;
763
-            $this->update_addon_option_names();
764
-        }
765
-        // verify the incoming config object but suppress errors
766
-        if (! $this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
767
-            $config_obj = new $config_class();
768
-        }
769
-        if (get_option($config_option_name)) {
770
-            EE_Config::log($config_option_name);
771
-            update_option($config_option_name, $config_obj);
772
-            $this->{$section}->{$name} = $config_obj;
773
-            return $this->{$section}->{$name};
774
-        } else {
775
-            // create a wp-option for this config
776
-            if (add_option($config_option_name, $config_obj, '', 'no')) {
777
-                $this->{$section}->{$name} = maybe_unserialize($config_obj);
778
-                return $this->{$section}->{$name};
779
-            } else {
780
-                EE_Error::add_error(
781
-                    sprintf(__('The "%s" could not be saved to the database.', 'event_espresso'), $config_class),
782
-                    __FILE__,
783
-                    __FUNCTION__,
784
-                    __LINE__
785
-                );
786
-                return null;
787
-            }
788
-        }
789
-    }
790
-
791
-
792
-
793
-    /**
794
-     *    update_config
795
-     * Important: the config object must ALREADY be set, otherwise this will produce an error.
796
-     *
797
-     * @access    public
798
-     * @param    string                $section
799
-     * @param    string                $name
800
-     * @param    EE_Config_Base|string $config_obj
801
-     * @param    bool                  $throw_errors
802
-     * @return    bool
803
-     */
804
-    public function update_config($section = '', $name = '', $config_obj = '', $throw_errors = true)
805
-    {
806
-        // don't allow config updates during WP heartbeats
807
-        if (\EE_Registry::instance()->REQ->get('action', '') === 'heartbeat') {
808
-            return false;
809
-        }
810
-        $config_obj = maybe_unserialize($config_obj);
811
-        // get class name of the incoming object
812
-        $config_class = get_class($config_obj);
813
-        // run tests 1-5 and 9 to verify config
814
-        if (! $this->_verify_config_params(
815
-            $section,
816
-            $name,
817
-            $config_class,
818
-            $config_obj,
819
-            array(1, 2, 3, 4, 7, 9)
820
-        )
821
-        ) {
822
-            return false;
823
-        }
824
-        $config_option_name = $this->_generate_config_option_name($section, $name);
825
-        // check if config object has been added to db by seeing if config option name is in $this->_addon_option_names array
826
-        if (! isset($this->_addon_option_names[$config_option_name])) {
827
-            // save new config to db
828
-            if ($this->set_config($section, $name, $config_class, $config_obj)) {
829
-                return true;
830
-            }
831
-        } else {
832
-            // first check if the record already exists
833
-            $existing_config = get_option($config_option_name);
834
-            $config_obj = serialize($config_obj);
835
-            // just return if db record is already up to date (NOT type safe comparison)
836
-            if ($existing_config == $config_obj) {
837
-                $this->{$section}->{$name} = $config_obj;
838
-                return true;
839
-            } else if (update_option($config_option_name, $config_obj)) {
840
-                EE_Config::log($config_option_name);
841
-                // update wp-option for this config class
842
-                $this->{$section}->{$name} = $config_obj;
843
-                return true;
844
-            } elseif ($throw_errors) {
845
-                EE_Error::add_error(
846
-                    sprintf(
847
-                        __(
848
-                            'The "%1$s" object stored at"%2$s" was not successfully updated in the database.',
849
-                            'event_espresso'
850
-                        ),
851
-                        $config_class,
852
-                        'EE_Config->' . $section . '->' . $name
853
-                    ),
854
-                    __FILE__,
855
-                    __FUNCTION__,
856
-                    __LINE__
857
-                );
858
-            }
859
-        }
860
-        return false;
861
-    }
862
-
863
-
864
-
865
-    /**
866
-     *    get_config
867
-     *
868
-     * @access    public
869
-     * @param    string $section
870
-     * @param    string $name
871
-     * @param    string $config_class
872
-     * @return    mixed EE_Config_Base | NULL
873
-     */
874
-    public function get_config($section = '', $name = '', $config_class = '')
875
-    {
876
-        // ensure config class is set to something
877
-        $config_class = $this->_set_config_class($config_class, $name);
878
-        // run tests 1-4, 6 and 7 to verify that all params have been set
879
-        if (! $this->_verify_config_params($section, $name, $config_class, null, array(1, 2, 3, 4, 5, 6))) {
880
-            return null;
881
-        }
882
-        // now test if the requested config object exists, but suppress errors
883
-        if ($this->_verify_config_params($section, $name, $config_class, null, array(7, 8), false)) {
884
-            // config already exists, so pass it back
885
-            return $this->{$section}->{$name};
886
-        }
887
-        // load config option from db if it exists
888
-        $config_obj = $this->get_config_option($this->_generate_config_option_name($section, $name));
889
-        // verify the newly retrieved config object, but suppress errors
890
-        if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9), false)) {
891
-            // config is good, so set it and pass it back
892
-            $this->{$section}->{$name} = $config_obj;
893
-            return $this->{$section}->{$name};
894
-        }
895
-        // oops! $config_obj is not already set and does not exist in the db, so create a new one
896
-        $config_obj = $this->set_config($section, $name, $config_class);
897
-        // verify the newly created config object
898
-        if ($this->_verify_config_params($section, $name, $config_class, $config_obj, array(9))) {
899
-            return $this->{$section}->{$name};
900
-        } else {
901
-            EE_Error::add_error(
902
-                sprintf(__('The "%s" could not be retrieved from the database.', 'event_espresso'), $config_class),
903
-                __FILE__,
904
-                __FUNCTION__,
905
-                __LINE__
906
-            );
907
-        }
908
-        return null;
909
-    }
910
-
911
-
912
-
913
-    /**
914
-     *    get_config_option
915
-     *
916
-     * @access    public
917
-     * @param    string $config_option_name
918
-     * @return    mixed EE_Config_Base | FALSE
919
-     */
920
-    public function get_config_option($config_option_name = '')
921
-    {
922
-        // retrieve the wp-option for this config class.
923
-        $config_option = maybe_unserialize(get_option($config_option_name, array()));
924
-        if (empty($config_option)) {
925
-            EE_Config::log($config_option_name . '-NOT-FOUND');
926
-        }
927
-        return $config_option;
928
-    }
929
-
930
-
931
-
932
-    /**
933
-     * log
934
-     *
935
-     * @param string $config_option_name
936
-     */
937
-    public static function log($config_option_name = '')
938
-    {
939
-        if (EE_Config::logging_enabled() && ! empty($config_option_name)) {
940
-            $config_log = get_option(EE_Config::LOG_NAME, array());
941
-            //copy incoming $_REQUEST and sanitize it so we can save it
942
-            $_request = $_REQUEST;
943
-            array_walk_recursive($_request, 'sanitize_text_field');
944
-            $config_log[(string)microtime(true)] = array(
945
-                'config_name' => $config_option_name,
946
-                'request'     => $_request,
947
-            );
948
-            update_option(EE_Config::LOG_NAME, $config_log);
949
-        }
950
-    }
951
-
952
-
953
-
954
-    /**
955
-     * trim_log
956
-     * reduces the size of the config log to the length specified by EE_Config::LOG_LENGTH
957
-     */
958
-    public static function trim_log()
959
-    {
960
-        if (! EE_Config::logging_enabled()) {
961
-            return;
962
-        }
963
-        $config_log = maybe_unserialize(get_option(EE_Config::LOG_NAME, array()));
964
-        $log_length = count($config_log);
965
-        if ($log_length > EE_Config::LOG_LENGTH) {
966
-            ksort($config_log);
967
-            $config_log = array_slice($config_log, $log_length - EE_Config::LOG_LENGTH, null, true);
968
-            update_option(EE_Config::LOG_NAME, $config_log);
969
-        }
970
-    }
971
-
972
-
973
-
974
-    /**
975
-     *    get_page_for_posts
976
-     *    if the wp-option "show_on_front" is set to "page", then this is the post_name for the post set in the
977
-     *    wp-option "page_for_posts", or "posts" if no page is selected
978
-     *
979
-     * @access    public
980
-     * @return    string
981
-     */
982
-    public static function get_page_for_posts()
983
-    {
984
-        $page_for_posts = get_option('page_for_posts');
985
-        if (! $page_for_posts) {
986
-            return 'posts';
987
-        }
988
-        /** @type WPDB $wpdb */
989
-        global $wpdb;
990
-        $SQL = "SELECT post_name from $wpdb->posts WHERE post_type='posts' OR post_type='page' AND post_status='publish' AND ID=%d";
991
-        return $wpdb->get_var($wpdb->prepare($SQL, $page_for_posts));
992
-    }
993
-
994
-
995
-
996
-    /**
997
-     *    register_shortcodes_and_modules.
998
-     *    At this point, it's too early to tell if we're maintenance mode or not.
999
-     *    In fact, this is where we give modules a chance to let core know they exist
1000
-     *    so they can help trigger maintenance mode if it's needed
1001
-     *
1002
-     * @access    public
1003
-     * @return    void
1004
-     */
1005
-    public function register_shortcodes_and_modules()
1006
-    {
1007
-        // allow modules to set hooks for the rest of the system
1008
-        EE_Registry::instance()->modules = $this->_register_modules();
1009
-    }
1010
-
1011
-
1012
-
1013
-    /**
1014
-     *    initialize_shortcodes_and_modules
1015
-     *    meaning they can start adding their hooks to get stuff done
1016
-     *
1017
-     * @access    public
1018
-     * @return    void
1019
-     */
1020
-    public function initialize_shortcodes_and_modules()
1021
-    {
1022
-        // allow modules to set hooks for the rest of the system
1023
-        $this->_initialize_modules();
1024
-    }
1025
-
1026
-
1027
-
1028
-    /**
1029
-     *    widgets_init
1030
-     *
1031
-     * @access private
1032
-     * @return void
1033
-     */
1034
-    public function widgets_init()
1035
-    {
1036
-        //only init widgets on admin pages when not in complete maintenance, and
1037
-        //on frontend when not in any maintenance mode
1038
-        if (
1039
-            ! EE_Maintenance_Mode::instance()->level()
1040
-            || (
1041
-                is_admin()
1042
-                && EE_Maintenance_Mode::instance()->level() !== EE_Maintenance_Mode::level_2_complete_maintenance
1043
-            )
1044
-        ) {
1045
-            // grab list of installed widgets
1046
-            $widgets_to_register = glob(EE_WIDGETS . '*', GLOB_ONLYDIR);
1047
-            // filter list of modules to register
1048
-            $widgets_to_register = apply_filters(
1049
-                'FHEE__EE_Config__register_widgets__widgets_to_register',
1050
-                $widgets_to_register
1051
-            );
1052
-            if (! empty($widgets_to_register)) {
1053
-                // cycle thru widget folders
1054
-                foreach ($widgets_to_register as $widget_path) {
1055
-                    // add to list of installed widget modules
1056
-                    EE_Config::register_ee_widget($widget_path);
1057
-                }
1058
-            }
1059
-            // filter list of installed modules
1060
-            EE_Registry::instance()->widgets = apply_filters(
1061
-                'FHEE__EE_Config__register_widgets__installed_widgets',
1062
-                EE_Registry::instance()->widgets
1063
-            );
1064
-        }
1065
-    }
1066
-
1067
-
1068
-
1069
-    /**
1070
-     *    register_ee_widget - makes core aware of this widget
1071
-     *
1072
-     * @access    public
1073
-     * @param    string $widget_path - full path up to and including widget folder
1074
-     * @return    void
1075
-     */
1076
-    public static function register_ee_widget($widget_path = null)
1077
-    {
1078
-        do_action('AHEE__EE_Config__register_widget__begin', $widget_path);
1079
-        $widget_ext = '.widget.php';
1080
-        // make all separators match
1081
-        $widget_path = rtrim(str_replace('/\\', DS, $widget_path), DS);
1082
-        // does the file path INCLUDE the actual file name as part of the path ?
1083
-        if (strpos($widget_path, $widget_ext) !== false) {
1084
-            // grab and shortcode file name from directory name and break apart at dots
1085
-            $file_name = explode('.', basename($widget_path));
1086
-            // take first segment from file name pieces and remove class prefix if it exists
1087
-            $widget = strpos($file_name[0], 'EEW_') === 0 ? substr($file_name[0], 4) : $file_name[0];
1088
-            // sanitize shortcode directory name
1089
-            $widget = sanitize_key($widget);
1090
-            // now we need to rebuild the shortcode path
1091
-            $widget_path = explode(DS, $widget_path);
1092
-            // remove last segment
1093
-            array_pop($widget_path);
1094
-            // glue it back together
1095
-            $widget_path = implode(DS, $widget_path);
1096
-        } else {
1097
-            // grab and sanitize widget directory name
1098
-            $widget = sanitize_key(basename($widget_path));
1099
-        }
1100
-        // create classname from widget directory name
1101
-        $widget = str_replace(' ', '_', ucwords(str_replace('_', ' ', $widget)));
1102
-        // add class prefix
1103
-        $widget_class = 'EEW_' . $widget;
1104
-        // does the widget exist ?
1105
-        if (! is_readable($widget_path . DS . $widget_class . $widget_ext)) {
1106
-            $msg = sprintf(
1107
-                __(
1108
-                    'The requested %s widget file could not be found or is not readable due to file permissions. Please ensure the following path is correct: %s',
1109
-                    'event_espresso'
1110
-                ),
1111
-                $widget_class,
1112
-                $widget_path . DS . $widget_class . $widget_ext
1113
-            );
1114
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1115
-            return;
1116
-        }
1117
-        // load the widget class file
1118
-        require_once($widget_path . DS . $widget_class . $widget_ext);
1119
-        // verify that class exists
1120
-        if (! class_exists($widget_class)) {
1121
-            $msg = sprintf(__('The requested %s widget class does not exist.', 'event_espresso'), $widget_class);
1122
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1123
-            return;
1124
-        }
1125
-        register_widget($widget_class);
1126
-        // add to array of registered widgets
1127
-        EE_Registry::instance()->widgets->{$widget_class} = $widget_path . DS . $widget_class . $widget_ext;
1128
-    }
1129
-
1130
-
1131
-
1132
-    /**
1133
-     *        _register_modules
1134
-     *
1135
-     * @access private
1136
-     * @return array
1137
-     */
1138
-    private function _register_modules()
1139
-    {
1140
-        // grab list of installed modules
1141
-        $modules_to_register = glob(EE_MODULES . '*', GLOB_ONLYDIR);
1142
-        // filter list of modules to register
1143
-        $modules_to_register = apply_filters(
1144
-            'FHEE__EE_Config__register_modules__modules_to_register',
1145
-            $modules_to_register
1146
-        );
1147
-        if (! empty($modules_to_register)) {
1148
-            // loop through folders
1149
-            foreach ($modules_to_register as $module_path) {
1150
-                /**TEMPORARILY EXCLUDE gateways from modules for time being**/
1151
-                if (
1152
-                    $module_path !== EE_MODULES . 'zzz-copy-this-module-template'
1153
-                    && $module_path !== EE_MODULES . 'gateways'
1154
-                ) {
1155
-                    // add to list of installed modules
1156
-                    EE_Config::register_module($module_path);
1157
-                }
1158
-            }
1159
-        }
1160
-        // filter list of installed modules
1161
-        return apply_filters(
1162
-            'FHEE__EE_Config___register_modules__installed_modules',
1163
-            EE_Registry::instance()->modules
1164
-        );
1165
-    }
1166
-
1167
-
1168
-
1169
-    /**
1170
-     *    register_module - makes core aware of this module
1171
-     *
1172
-     * @access    public
1173
-     * @param    string $module_path - full path up to and including module folder
1174
-     * @return    bool
1175
-     */
1176
-    public static function register_module($module_path = null)
1177
-    {
1178
-        do_action('AHEE__EE_Config__register_module__begin', $module_path);
1179
-        $module_ext = '.module.php';
1180
-        // make all separators match
1181
-        $module_path = str_replace(array('\\', '/'), DS, $module_path);
1182
-        // does the file path INCLUDE the actual file name as part of the path ?
1183
-        if (strpos($module_path, $module_ext) !== false) {
1184
-            // grab and shortcode file name from directory name and break apart at dots
1185
-            $module_file = explode('.', basename($module_path));
1186
-            // now we need to rebuild the shortcode path
1187
-            $module_path = explode(DS, $module_path);
1188
-            // remove last segment
1189
-            array_pop($module_path);
1190
-            // glue it back together
1191
-            $module_path = implode(DS, $module_path) . DS;
1192
-            // take first segment from file name pieces and sanitize it
1193
-            $module = preg_replace('/[^a-zA-Z0-9_\-]/', '', $module_file[0]);
1194
-            // ensure class prefix is added
1195
-            $module_class = strpos($module, 'EED_') !== 0 ? 'EED_' . $module : $module;
1196
-        } else {
1197
-            // we need to generate the filename based off of the folder name
1198
-            // grab and sanitize module name
1199
-            $module = strtolower(basename($module_path));
1200
-            $module = preg_replace('/[^a-z0-9_\-]/', '', $module);
1201
-            // like trailingslashit()
1202
-            $module_path = rtrim($module_path, DS) . DS;
1203
-            // create classname from module directory name
1204
-            $module = str_replace(' ', '_', ucwords(str_replace('_', ' ', $module)));
1205
-            // add class prefix
1206
-            $module_class = 'EED_' . $module;
1207
-        }
1208
-        // does the module exist ?
1209
-        if (! is_readable($module_path . DS . $module_class . $module_ext)) {
1210
-            $msg = sprintf(
1211
-                __(
1212
-                    'The requested %s module file could not be found or is not readable due to file permissions.',
1213
-                    'event_espresso'
1214
-                ),
1215
-                $module
1216
-            );
1217
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1218
-            return false;
1219
-        }
1220
-        // load the module class file
1221
-        require_once($module_path . $module_class . $module_ext);
1222
-        // verify that class exists
1223
-        if (! class_exists($module_class)) {
1224
-            $msg = sprintf(__('The requested %s module class does not exist.', 'event_espresso'), $module_class);
1225
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1226
-            return false;
1227
-        }
1228
-        // add to array of registered modules
1229
-        EE_Registry::instance()->modules->{$module_class} = $module_path . $module_class . $module_ext;
1230
-        do_action(
1231
-            'AHEE__EE_Config__register_module__complete',
1232
-            $module_class,
1233
-            EE_Registry::instance()->modules->{$module_class}
1234
-        );
1235
-        return true;
1236
-    }
1237
-
1238
-
1239
-
1240
-    /**
1241
-     *    _initialize_modules
1242
-     *    allow modules to set hooks for the rest of the system
1243
-     *
1244
-     * @access private
1245
-     * @return void
1246
-     */
1247
-    private function _initialize_modules()
1248
-    {
1249
-        // cycle thru shortcode folders
1250
-        foreach (EE_Registry::instance()->modules as $module_class => $module_path) {
1251
-            // fire the shortcode class's set_hooks methods in case it needs to hook into other parts of the system
1252
-            // which set hooks ?
1253
-            if (is_admin()) {
1254
-                // fire immediately
1255
-                call_user_func(array($module_class, 'set_hooks_admin'));
1256
-            } else {
1257
-                // delay until other systems are online
1258
-                add_action(
1259
-                    'AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons',
1260
-                    array($module_class, 'set_hooks')
1261
-                );
1262
-            }
1263
-        }
1264
-    }
1265
-
1266
-
1267
-
1268
-    /**
1269
-     *    register_route - adds module method routes to route_map
1270
-     *
1271
-     * @access    public
1272
-     * @param    string $route       - "pretty" public alias for module method
1273
-     * @param    string $module      - module name (classname without EED_ prefix)
1274
-     * @param    string $method_name - the actual module method to be routed to
1275
-     * @param    string $key         - url param key indicating a route is being called
1276
-     * @return    bool
1277
-     */
1278
-    public static function register_route($route = null, $module = null, $method_name = null, $key = 'ee')
1279
-    {
1280
-        do_action('AHEE__EE_Config__register_route__begin', $route, $module, $method_name);
1281
-        $module = str_replace('EED_', '', $module);
1282
-        $module_class = 'EED_' . $module;
1283
-        if (! isset(EE_Registry::instance()->modules->{$module_class})) {
1284
-            $msg = sprintf(__('The module %s has not been registered.', 'event_espresso'), $module);
1285
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1286
-            return false;
1287
-        }
1288
-        if (empty($route)) {
1289
-            $msg = sprintf(__('No route has been supplied.', 'event_espresso'), $route);
1290
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1291
-            return false;
1292
-        }
1293
-        if (! method_exists('EED_' . $module, $method_name)) {
1294
-            $msg = sprintf(
1295
-                __('A valid class method for the %s route has not been supplied.', 'event_espresso'),
1296
-                $route
1297
-            );
1298
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1299
-            return false;
1300
-        }
1301
-        EE_Config::$_module_route_map[$key][$route] = array('EED_' . $module, $method_name);
1302
-        return true;
1303
-    }
1304
-
1305
-
1306
-
1307
-    /**
1308
-     *    get_route - get module method route
1309
-     *
1310
-     * @access    public
1311
-     * @param    string $route - "pretty" public alias for module method
1312
-     * @param    string $key   - url param key indicating a route is being called
1313
-     * @return    string
1314
-     */
1315
-    public static function get_route($route = null, $key = 'ee')
1316
-    {
1317
-        do_action('AHEE__EE_Config__get_route__begin', $route);
1318
-        $route = (string)apply_filters('FHEE__EE_Config__get_route', $route);
1319
-        if (isset(EE_Config::$_module_route_map[$key][$route])) {
1320
-            return EE_Config::$_module_route_map[$key][$route];
1321
-        }
1322
-        return null;
1323
-    }
1324
-
1325
-
1326
-
1327
-    /**
1328
-     *    get_routes - get ALL module method routes
1329
-     *
1330
-     * @access    public
1331
-     * @return    array
1332
-     */
1333
-    public static function get_routes()
1334
-    {
1335
-        return EE_Config::$_module_route_map;
1336
-    }
1337
-
1338
-
1339
-
1340
-    /**
1341
-     *    register_forward - allows modules to forward request to another module for further processing
1342
-     *
1343
-     * @access    public
1344
-     * @param    string       $route   - "pretty" public alias for module method
1345
-     * @param    integer      $status  - integer value corresponding  to status constant strings set in module parent
1346
-     *                                 class, allows different forwards to be served based on status
1347
-     * @param    array|string $forward - function name or array( class, method )
1348
-     * @param    string       $key     - url param key indicating a route is being called
1349
-     * @return    bool
1350
-     */
1351
-    public static function register_forward($route = null, $status = 0, $forward = null, $key = 'ee')
1352
-    {
1353
-        do_action('AHEE__EE_Config__register_forward', $route, $status, $forward);
1354
-        if (! isset(EE_Config::$_module_route_map[$key][$route]) || empty($route)) {
1355
-            $msg = sprintf(
1356
-                __('The module route %s for this forward has not been registered.', 'event_espresso'),
1357
-                $route
1358
-            );
1359
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1360
-            return false;
1361
-        }
1362
-        if (empty($forward)) {
1363
-            $msg = sprintf(__('No forwarding route has been supplied.', 'event_espresso'), $route);
1364
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1365
-            return false;
1366
-        }
1367
-        if (is_array($forward)) {
1368
-            if (! isset($forward[1])) {
1369
-                $msg = sprintf(
1370
-                    __('A class method for the %s forwarding route has not been supplied.', 'event_espresso'),
1371
-                    $route
1372
-                );
1373
-                EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1374
-                return false;
1375
-            }
1376
-            if (! method_exists($forward[0], $forward[1])) {
1377
-                $msg = sprintf(
1378
-                    __('The class method %s for the %s forwarding route is in invalid.', 'event_espresso'),
1379
-                    $forward[1],
1380
-                    $route
1381
-                );
1382
-                EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1383
-                return false;
1384
-            }
1385
-        } else if (! function_exists($forward)) {
1386
-            $msg = sprintf(
1387
-                __('The function %s for the %s forwarding route is in invalid.', 'event_espresso'),
1388
-                $forward,
1389
-                $route
1390
-            );
1391
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1392
-            return false;
1393
-        }
1394
-        EE_Config::$_module_forward_map[$key][$route][absint($status)] = $forward;
1395
-        return true;
1396
-    }
1397
-
1398
-
1399
-
1400
-    /**
1401
-     *    get_forward - get forwarding route
1402
-     *
1403
-     * @access    public
1404
-     * @param    string  $route  - "pretty" public alias for module method
1405
-     * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1406
-     *                           allows different forwards to be served based on status
1407
-     * @param    string  $key    - url param key indicating a route is being called
1408
-     * @return    string
1409
-     */
1410
-    public static function get_forward($route = null, $status = 0, $key = 'ee')
1411
-    {
1412
-        do_action('AHEE__EE_Config__get_forward__begin', $route, $status);
1413
-        if (isset(EE_Config::$_module_forward_map[$key][$route][$status])) {
1414
-            return apply_filters(
1415
-                'FHEE__EE_Config__get_forward',
1416
-                EE_Config::$_module_forward_map[$key][$route][$status],
1417
-                $route,
1418
-                $status
1419
-            );
1420
-        }
1421
-        return null;
1422
-    }
1423
-
1424
-
1425
-
1426
-    /**
1427
-     *    register_forward - allows modules to specify different view templates for different method routes and status
1428
-     *    results
1429
-     *
1430
-     * @access    public
1431
-     * @param    string  $route  - "pretty" public alias for module method
1432
-     * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1433
-     *                           allows different views to be served based on status
1434
-     * @param    string  $view
1435
-     * @param    string  $key    - url param key indicating a route is being called
1436
-     * @return    bool
1437
-     */
1438
-    public static function register_view($route = null, $status = 0, $view = null, $key = 'ee')
1439
-    {
1440
-        do_action('AHEE__EE_Config__register_view__begin', $route, $status, $view);
1441
-        if (! isset(EE_Config::$_module_route_map[$key][$route]) || empty($route)) {
1442
-            $msg = sprintf(
1443
-                __('The module route %s for this view has not been registered.', 'event_espresso'),
1444
-                $route
1445
-            );
1446
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1447
-            return false;
1448
-        }
1449
-        if (! is_readable($view)) {
1450
-            $msg = sprintf(
1451
-                __(
1452
-                    'The %s view file could not be found or is not readable due to file permissions.',
1453
-                    'event_espresso'
1454
-                ),
1455
-                $view
1456
-            );
1457
-            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
1458
-            return false;
1459
-        }
1460
-        EE_Config::$_module_view_map[$key][$route][absint($status)] = $view;
1461
-        return true;
1462
-    }
1463
-
1464
-
1465
-
1466
-    /**
1467
-     *    get_view - get view for route and status
1468
-     *
1469
-     * @access    public
1470
-     * @param    string  $route  - "pretty" public alias for module method
1471
-     * @param    integer $status - integer value corresponding  to status constant strings set in module parent class,
1472
-     *                           allows different views to be served based on status
1473
-     * @param    string  $key    - url param key indicating a route is being called
1474
-     * @return    string
1475
-     */
1476
-    public static function get_view($route = null, $status = 0, $key = 'ee')
1477
-    {
1478
-        do_action('AHEE__EE_Config__get_view__begin', $route, $status);
1479
-        if (isset(EE_Config::$_module_view_map[$key][$route][$status])) {
1480
-            return apply_filters(
1481
-                'FHEE__EE_Config__get_view',
1482
-                EE_Config::$_module_view_map[$key][$route][$status],
1483
-                $route,
1484
-                $status
1485
-            );
1486
-        }
1487
-        return null;
1488
-    }
1489
-
1490
-
1491
-
1492
-    public function update_addon_option_names()
1493
-    {
1494
-        update_option(EE_Config::ADDON_OPTION_NAMES, $this->_addon_option_names);
1495
-    }
1496
-
1497
-
1498
-
1499
-    public function shutdown()
1500
-    {
1501
-        $this->update_addon_option_names();
1502
-    }
1503
-
1504
-
1505
-
1506
-    /**
1507
-     * @return LegacyShortcodesManager
1508
-     */
1509
-    public static function getLegacyShortcodesManager()
1510
-    {
1511
-
1512
-        if ( ! EE_Config::instance()->legacy_shortcodes_manager instanceof LegacyShortcodesManager) {
1513
-            EE_Config::instance()->legacy_shortcodes_manager = new LegacyShortcodesManager(
1514
-                EE_Registry::instance()
1515
-            );
1516
-        }
1517
-        return EE_Config::instance()->legacy_shortcodes_manager;
1518
-    }
1519
-
1520
-
1521
-
1522
-    /**
1523
-     * register_shortcode - makes core aware of this shortcode
1524
-     *
1525
-     * @deprecated 4.9.26
1526
-     * @param    string $shortcode_path - full path up to and including shortcode folder
1527
-     * @return    bool
1528
-     */
1529
-    public static function register_shortcode($shortcode_path = null)
1530
-    {
1531
-        EE_Error::doing_it_wrong(
1532
-            __METHOD__,
1533
-            __(
1534
-                'Usage is deprecated. Use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::registerShortcode() as direct replacement, or better yet, please see the new \EventEspresso\core\services\shortcodes\ShortcodesManager class.',
1535
-                'event_espresso'
1536
-            ),
1537
-            '4.9.26'
1538
-        );
1539
-        return EE_Config::instance()->getLegacyShortcodesManager()->registerShortcode($shortcode_path);
1540
-    }
1541
-
1542
-
1543
-
1544
-}
1545
-
1546
-
1547
-
1548
-/**
1549
- * Base class used for config classes. These classes should generally not have
1550
- * magic functions in use, except we'll allow them to magically set and get stuff...
1551
- * basically, they should just be well-defined stdClasses
1552
- */
1553
-class EE_Config_Base
1554
-{
1555
-
1556
-    /**
1557
-     * Utility function for escaping the value of a property and returning.
1558
-     *
1559
-     * @param string $property property name (checks to see if exists).
1560
-     * @return mixed if a detected type found return the escaped value, otherwise just the raw value is returned.
1561
-     * @throws \EE_Error
1562
-     */
1563
-    public function get_pretty($property)
1564
-    {
1565
-        if (! property_exists($this, $property)) {
1566
-            throw new EE_Error(
1567
-                sprintf(
1568
-                    __(
1569
-                        '%1$s::get_pretty() has been called with the property %2$s which does not exist on the %1$s config class.',
1570
-                        'event_espresso'
1571
-                    ),
1572
-                    get_class($this),
1573
-                    $property
1574
-                )
1575
-            );
1576
-        }
1577
-        //just handling escaping of strings for now.
1578
-        if (is_string($this->{$property})) {
1579
-            return stripslashes($this->{$property});
1580
-        }
1581
-        return $this->{$property};
1582
-    }
1583
-
1584
-
1585
-
1586
-    public function populate()
1587
-    {
1588
-        //grab defaults via a new instance of this class.
1589
-        $class_name = get_class($this);
1590
-        $defaults = new $class_name;
1591
-        //loop through the properties for this class and see if they are set.  If they are NOT, then grab the
1592
-        //default from our $defaults object.
1593
-        foreach (get_object_vars($defaults) as $property => $value) {
1594
-            if ($this->{$property} === null) {
1595
-                $this->{$property} = $value;
1596
-            }
1597
-        }
1598
-        //cleanup
1599
-        unset($defaults);
1600
-    }
1601
-
1602
-
1603
-
1604
-    /**
1605
-     *        __isset
1606
-     *
1607
-     * @param $a
1608
-     * @return bool
1609
-     */
1610
-    public function __isset($a)
1611
-    {
1612
-        return false;
1613
-    }
1614
-
1615
-
1616
-
1617
-    /**
1618
-     *        __unset
1619
-     *
1620
-     * @param $a
1621
-     * @return bool
1622
-     */
1623
-    public function __unset($a)
1624
-    {
1625
-        return false;
1626
-    }
1627
-
1628
-
1629
-
1630
-    /**
1631
-     *        __clone
1632
-     */
1633
-    public function __clone()
1634
-    {
1635
-    }
1636
-
1637
-
1638
-
1639
-    /**
1640
-     *        __wakeup
1641
-     */
1642
-    public function __wakeup()
1643
-    {
1644
-    }
1645
-
1646
-
1647
-
1648
-    /**
1649
-     *        __destruct
1650
-     */
1651
-    public function __destruct()
1652
-    {
1653
-    }
1654
-}
1655
-
1656
-
1657
-
1658
-/**
1659
- * Class for defining what's in the EE_Config relating to registration settings
1660
- */
1661
-class EE_Core_Config extends EE_Config_Base
1662
-{
1663
-
1664
-    public $current_blog_id;
1665
-
1666
-    public $ee_ueip_optin;
1667
-
1668
-    public $ee_ueip_has_notified;
1669
-
1670
-    /**
1671
-     * Not to be confused with the 4 critical page variables (See
1672
-     * get_critical_pages_array()), this is just an array of wp posts that have EE
1673
-     * shortcodes in them. Keys are slugs, values are arrays with only 1 element: where the key is the shortcode
1674
-     * in the page, and the value is the page's ID. The key 'posts' is basically a duplicate of this same array.
1675
-     *
1676
-     * @var array
1677
-     */
1678
-    public $post_shortcodes;
1679
-
1680
-    public $module_route_map;
1681
-
1682
-    public $module_forward_map;
1683
-
1684
-    public $module_view_map;
1685
-
1686
-    /**
1687
-     * The next 4 vars are the IDs of critical EE pages.
1688
-     *
1689
-     * @var int
1690
-     */
1691
-    public $reg_page_id;
1692
-
1693
-    public $txn_page_id;
1694
-
1695
-    public $thank_you_page_id;
1696
-
1697
-    public $cancel_page_id;
1698
-
1699
-    /**
1700
-     * The next 4 vars are the URLs of critical EE pages.
1701
-     *
1702
-     * @var int
1703
-     */
1704
-    public $reg_page_url;
1705
-
1706
-    public $txn_page_url;
1707
-
1708
-    public $thank_you_page_url;
1709
-
1710
-    public $cancel_page_url;
1711
-
1712
-    /**
1713
-     * The next vars relate to the custom slugs for EE CPT routes
1714
-     */
1715
-    public $event_cpt_slug;
1716
-
1717
-
1718
-    /**
1719
-     * This caches the _ee_ueip_option in case this config is reset in the same
1720
-     * request across blog switches in a multisite context.
1721
-     * Avoids extra queries to the db for this option.
1722
-     *
1723
-     * @var bool
1724
-     */
1725
-    public static $ee_ueip_option;
1726
-
1727
-
1728
-
1729
-    /**
1730
-     *    class constructor
1731
-     *
1732
-     * @access    public
1733
-     */
1734
-    public function __construct()
1735
-    {
1736
-        // set default organization settings
1737
-        $this->current_blog_id = get_current_blog_id();
1738
-        $this->current_blog_id = $this->current_blog_id === null ? 1 : $this->current_blog_id;
1739
-        $this->ee_ueip_optin = $this->_get_main_ee_ueip_optin();
1740
-        $this->ee_ueip_has_notified = is_main_site() ? get_option('ee_ueip_has_notified', false) : true;
1741
-        $this->post_shortcodes = array();
1742
-        $this->module_route_map = array();
1743
-        $this->module_forward_map = array();
1744
-        $this->module_view_map = array();
1745
-        // critical EE page IDs
1746
-        $this->reg_page_id = 0;
1747
-        $this->txn_page_id = 0;
1748
-        $this->thank_you_page_id = 0;
1749
-        $this->cancel_page_id = 0;
1750
-        // critical EE page URLs
1751
-        $this->reg_page_url = '';
1752
-        $this->txn_page_url = '';
1753
-        $this->thank_you_page_url = '';
1754
-        $this->cancel_page_url = '';
1755
-        //cpt slugs
1756
-        $this->event_cpt_slug = __('events', 'event_espresso');
1757
-        //ueip constant check
1758
-        if (defined('EE_DISABLE_UXIP') && EE_DISABLE_UXIP) {
1759
-            $this->ee_ueip_optin = false;
1760
-            $this->ee_ueip_has_notified = true;
1761
-        }
1762
-    }
1763
-
1764
-
1765
-
1766
-    /**
1767
-     * @return array
1768
-     */
1769
-    public function get_critical_pages_array()
1770
-    {
1771
-        return array(
1772
-            $this->reg_page_id,
1773
-            $this->txn_page_id,
1774
-            $this->thank_you_page_id,
1775
-            $this->cancel_page_id,
1776
-        );
1777
-    }
1778
-
1779
-
1780
-
1781
-    /**
1782
-     * @return array
1783
-     */
1784
-    public function get_critical_pages_shortcodes_array()
1785
-    {
1786
-        return array(
1787
-            $this->reg_page_id       => 'ESPRESSO_CHECKOUT',
1788
-            $this->txn_page_id       => 'ESPRESSO_TXN_PAGE',
1789
-            $this->thank_you_page_id => 'ESPRESSO_THANK_YOU',
1790
-            $this->cancel_page_id    => 'ESPRESSO_CANCELLED',
1791
-        );
1792
-    }
1793
-
1794
-
1795
-
1796
-    /**
1797
-     *  gets/returns URL for EE reg_page
1798
-     *
1799
-     * @access    public
1800
-     * @return    string
1801
-     */
1802
-    public function reg_page_url()
1803
-    {
1804
-        if (! $this->reg_page_url) {
1805
-            $this->reg_page_url = add_query_arg(
1806
-                                      array('uts' => time()),
1807
-                                      get_permalink($this->reg_page_id)
1808
-                                  ) . '#checkout';
1809
-        }
1810
-        return $this->reg_page_url;
1811
-    }
1812
-
1813
-
1814
-
1815
-    /**
1816
-     *  gets/returns URL for EE txn_page
1817
-     *
1818
-     * @param array $query_args like what gets passed to
1819
-     *                          add_query_arg() as the first argument
1820
-     * @access    public
1821
-     * @return    string
1822
-     */
1823
-    public function txn_page_url($query_args = array())
1824
-    {
1825
-        if (! $this->txn_page_url) {
1826
-            $this->txn_page_url = get_permalink($this->txn_page_id);
1827
-        }
1828
-        if ($query_args) {
1829
-            return add_query_arg($query_args, $this->txn_page_url);
1830
-        } else {
1831
-            return $this->txn_page_url;
1832
-        }
1833
-    }
1834
-
1835
-
1836
-
1837
-    /**
1838
-     *  gets/returns URL for EE thank_you_page
1839
-     *
1840
-     * @param array $query_args like what gets passed to
1841
-     *                          add_query_arg() as the first argument
1842
-     * @access    public
1843
-     * @return    string
1844
-     */
1845
-    public function thank_you_page_url($query_args = array())
1846
-    {
1847
-        if (! $this->thank_you_page_url) {
1848
-            $this->thank_you_page_url = get_permalink($this->thank_you_page_id);
1849
-        }
1850
-        if ($query_args) {
1851
-            return add_query_arg($query_args, $this->thank_you_page_url);
1852
-        } else {
1853
-            return $this->thank_you_page_url;
1854
-        }
1855
-    }
1856
-
1857
-
1858
-
1859
-    /**
1860
-     *  gets/returns URL for EE cancel_page
1861
-     *
1862
-     * @access    public
1863
-     * @return    string
1864
-     */
1865
-    public function cancel_page_url()
1866
-    {
1867
-        if (! $this->cancel_page_url) {
1868
-            $this->cancel_page_url = get_permalink($this->cancel_page_id);
1869
-        }
1870
-        return $this->cancel_page_url;
1871
-    }
1872
-
1873
-
1874
-
1875
-    /**
1876
-     * Resets all critical page urls to their original state.  Used primarily by the __sleep() magic method currently.
1877
-     *
1878
-     * @since 4.7.5
1879
-     */
1880
-    protected function _reset_urls()
1881
-    {
1882
-        $this->reg_page_url = '';
1883
-        $this->txn_page_url = '';
1884
-        $this->cancel_page_url = '';
1885
-        $this->thank_you_page_url = '';
1886
-    }
1887
-
1888
-
1889
-
1890
-    /**
1891
-     * Used to return what the optin value is set for the EE User Experience Program.
1892
-     * This accounts for multisite and this value being requested for a subsite.  In multisite, the value is set
1893
-     * on the main site only.
1894
-     *
1895
-     * @return mixed|void
1896
-     */
1897
-    protected function _get_main_ee_ueip_optin()
1898
-    {
1899
-        //if this is the main site then we can just bypass our direct query.
1900
-        if (is_main_site()) {
1901
-            return get_option('ee_ueip_optin', false);
1902
-        }
1903
-        //is this already cached for this request?  If so use it.
1904
-        if ( ! empty(EE_Core_Config::$ee_ueip_option)) {
1905
-            return EE_Core_Config::$ee_ueip_option;
1906
-        }
1907
-        global $wpdb;
1908
-        $current_network_main_site = is_multisite() ? get_current_site() : null;
1909
-        $current_main_site_id = ! empty($current_network_main_site) ? $current_network_main_site->blog_id : 1;
1910
-        $option = 'ee_ueip_optin';
1911
-        //set correct table for query
1912
-        $table_name = $wpdb->get_blog_prefix($current_main_site_id) . 'options';
1913
-        //rather than getting blog option for the $current_main_site_id, we do a direct $wpdb query because
1914
-        //get_blog_option() does a switch_to_blog an that could cause infinite recursion because EE_Core_Config might be
1915
-        //re-constructed on the blog switch.  Note, we are still executing any core wp filters on this option retrieval.
1916
-        //this bit of code is basically a direct copy of get_option without any caching because we are NOT switched to the blog
1917
-        //for the purpose of caching.
1918
-        $pre = apply_filters('pre_option_' . $option, false, $option);
1919
-        if (false !== $pre) {
1920
-            EE_Core_Config::$ee_ueip_option = $pre;
1921
-            return EE_Core_Config::$ee_ueip_option;
1922
-        }
1923
-        $row = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM $table_name WHERE option_name = %s LIMIT 1",
1924
-            $option));
1925
-        if (is_object($row)) {
1926
-            $value = $row->option_value;
1927
-        } else { //option does not exist so use default.
1928
-            return apply_filters('default_option_' . $option, false, $option);
1929
-        }
1930
-        EE_Core_Config::$ee_ueip_option = apply_filters('option_' . $option, maybe_unserialize($value), $option);
1931
-        return EE_Core_Config::$ee_ueip_option;
1932
-    }
1933
-
1934
-
1935
-
1936
-    /**
1937
-     * Currently used to ensure critical page urls have initial values saved to the db instead of any current set values
1938
-     * on the object.
1939
-     *
1940
-     * @return array
1941
-     */
1942
-    public function __sleep()
1943
-    {
1944
-        //reset all url properties
1945
-        $this->_reset_urls();
1946
-        //return what to save to db
1947
-        return array_keys(get_object_vars($this));
1948
-    }
1949
-
1950
-}
1951
-
1952
-
1953
-
1954
-/**
1955
- * Config class for storing info on the Organization
1956
- */
1957
-class EE_Organization_Config extends EE_Config_Base
1958
-{
1959
-
1960
-    /**
1961
-     * @var string $name
1962
-     * eg EE4.1
1963
-     */
1964
-    public $name;
1965
-
1966
-    /**
1967
-     * @var string $address_1
1968
-     * eg 123 Onna Road
1969
-     */
1970
-    public $address_1;
1971
-
1972
-    /**
1973
-     * @var string $address_2
1974
-     * eg PO Box 123
1975
-     */
1976
-    public $address_2;
1977
-
1978
-    /**
1979
-     * @var string $city
1980
-     * eg Inna City
1981
-     */
1982
-    public $city;
1983
-
1984
-    /**
1985
-     * @var int $STA_ID
1986
-     * eg 4
1987
-     */
1988
-    public $STA_ID;
1989
-
1990
-    /**
1991
-     * @var string $CNT_ISO
1992
-     * eg US
1993
-     */
1994
-    public $CNT_ISO;
1995
-
1996
-    /**
1997
-     * @var string $zip
1998
-     * eg 12345  or V1A 2B3
1999
-     */
2000
-    public $zip;
2001
-
2002
-    /**
2003
-     * @var string $email
2004
-     * eg [email protected]
2005
-     */
2006
-    public $email;
2007
-
2008
-
2009
-    /**
2010
-     * @var string $phone
2011
-     * eg. 111-111-1111
2012
-     */
2013
-    public $phone;
2014
-
2015
-
2016
-    /**
2017
-     * @var string $vat
2018
-     * VAT/Tax Number
2019
-     */
2020
-    public $vat;
2021
-
2022
-    /**
2023
-     * @var string $logo_url
2024
-     * eg http://www.somedomain.com/wp-content/uploads/kittehs.jpg
2025
-     */
2026
-    public $logo_url;
2027
-
2028
-
2029
-    /**
2030
-     * The below are all various properties for holding links to organization social network profiles
2031
-     *
2032
-     * @var string
2033
-     */
2034
-    /**
2035
-     * facebook (facebook.com/profile.name)
2036
-     *
2037
-     * @var string
2038
-     */
2039
-    public $facebook;
2040
-
2041
-
2042
-    /**
2043
-     * twitter (twitter.com/twitter_handle)
2044
-     *
2045
-     * @var string
2046
-     */
2047
-    public $twitter;
2048
-
2049
-
2050
-    /**
2051
-     * linkedin (linkedin.com/in/profile_name)
2052
-     *
2053
-     * @var string
2054
-     */
2055
-    public $linkedin;
2056
-
2057
-
2058
-    /**
2059
-     * pinterest (www.pinterest.com/profile_name)
2060
-     *
2061
-     * @var string
2062
-     */
2063
-    public $pinterest;
2064
-
2065
-
2066
-    /**
2067
-     * google+ (google.com/+profileName)
2068
-     *
2069
-     * @var string
2070
-     */
2071
-    public $google;
2072
-
2073
-
2074
-    /**
2075
-     * instagram (instagram.com/handle)
2076
-     *
2077
-     * @var string
2078
-     */
2079
-    public $instagram;
2080
-
2081
-
2082
-
2083
-    /**
2084
-     *    class constructor
2085
-     *
2086
-     * @access    public
2087
-     */
2088
-    public function __construct()
2089
-    {
2090
-        // set default organization settings
2091
-        //decode HTML entities from the WP blogname, because it's stored in the DB with HTML entities encoded
2092
-        $this->name = wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES);
2093
-        $this->address_1 = '123 Onna Road';
2094
-        $this->address_2 = 'PO Box 123';
2095
-        $this->city = 'Inna City';
2096
-        $this->STA_ID = 4;
2097
-        $this->CNT_ISO = 'US';
2098
-        $this->zip = '12345';
2099
-        $this->email = get_bloginfo('admin_email');
2100
-        $this->phone = '';
2101
-        $this->vat = '123456789';
2102
-        $this->logo_url = '';
2103
-        $this->facebook = '';
2104
-        $this->twitter = '';
2105
-        $this->linkedin = '';
2106
-        $this->pinterest = '';
2107
-        $this->google = '';
2108
-        $this->instagram = '';
2109
-    }
2110
-
2111
-}
2112
-
2113
-
2114
-
2115
-/**
2116
- * Class for defining what's in the EE_Config relating to currency
2117
- */
2118
-class EE_Currency_Config extends EE_Config_Base
2119
-{
2120
-
2121
-    /**
2122
-     * @var string $code
2123
-     * eg 'US'
2124
-     */
2125
-    public $code;
2126
-
2127
-    /**
2128
-     * @var string $name
2129
-     * eg 'Dollar'
2130
-     */
2131
-    public $name;
2132
-
2133
-    /**
2134
-     * plural name
2135
-     *
2136
-     * @var string $plural
2137
-     * eg 'Dollars'
2138
-     */
2139
-    public $plural;
2140
-
2141
-    /**
2142
-     * currency sign
2143
-     *
2144
-     * @var string $sign
2145
-     * eg '$'
2146
-     */
2147
-    public $sign;
2148
-
2149
-    /**
2150
-     * Whether the currency sign should come before the number or not
2151
-     *
2152
-     * @var boolean $sign_b4
2153
-     */
2154
-    public $sign_b4;
2155
-
2156
-    /**
2157
-     * How many digits should come after the decimal place
2158
-     *
2159
-     * @var int $dec_plc
2160
-     */
2161
-    public $dec_plc;
2162
-
2163
-    /**
2164
-     * Symbol to use for decimal mark
2165
-     *
2166
-     * @var string $dec_mrk
2167
-     * eg '.'
2168
-     */
2169
-    public $dec_mrk;
2170
-
2171
-    /**
2172
-     * Symbol to use for thousands
2173
-     *
2174
-     * @var string $thsnds
2175
-     * eg ','
2176
-     */
2177
-    public $thsnds;
2178
-
2179
-
2180
-
2181
-    /**
2182
-     *    class constructor
2183
-     *
2184
-     * @access    public
2185
-     * @param string $CNT_ISO
2186
-     * @throws \EE_Error
2187
-     */
2188
-    public function __construct($CNT_ISO = '')
2189
-    {
2190
-        /** @var \EventEspresso\core\services\database\TableAnalysis $table_analysis */
2191
-        $table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
2192
-        // get country code from organization settings or use default
2193
-        $ORG_CNT = isset(EE_Registry::instance()->CFG->organization)
2194
-                   && EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config
2195
-            ? EE_Registry::instance()->CFG->organization->CNT_ISO
2196
-            : '';
2197
-        // but override if requested
2198
-        $CNT_ISO = ! empty($CNT_ISO) ? $CNT_ISO : $ORG_CNT;
2199
-        // so if that all went well, and we are not in M-Mode (cuz you can't query the db in M-Mode) and double-check the countries table exists
2200
-        if (
2201
-            ! empty($CNT_ISO)
2202
-            && EE_Maintenance_Mode::instance()->models_can_query()
2203
-            && $table_analysis->tableExists(EE_Registry::instance()->load_model('Country')->table())
2204
-        ) {
2205
-            // retrieve the country settings from the db, just in case they have been customized
2206
-            $country = EE_Registry::instance()->load_model('Country')->get_one_by_ID($CNT_ISO);
2207
-            if ($country instanceof EE_Country) {
2208
-                $this->code = $country->currency_code();    // currency code: USD, CAD, EUR
2209
-                $this->name = $country->currency_name_single();    // Dollar
2210
-                $this->plural = $country->currency_name_plural();    // Dollars
2211
-                $this->sign = $country->currency_sign();            // currency sign: $
2212
-                $this->sign_b4 = $country->currency_sign_before();        // currency sign before or after: $TRUE  or  FALSE$
2213
-                $this->dec_plc = $country->currency_decimal_places();    // decimal places: 2 = 0.00  3 = 0.000
2214
-                $this->dec_mrk = $country->currency_decimal_mark();    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2215
-                $this->thsnds = $country->currency_thousands_separator();    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2216
-            }
2217
-        }
2218
-        // fallback to hardcoded defaults, in case the above failed
2219
-        if (empty($this->code)) {
2220
-            // set default currency settings
2221
-            $this->code = 'USD';    // currency code: USD, CAD, EUR
2222
-            $this->name = __('Dollar', 'event_espresso');    // Dollar
2223
-            $this->plural = __('Dollars', 'event_espresso');    // Dollars
2224
-            $this->sign = '$';    // currency sign: $
2225
-            $this->sign_b4 = true;    // currency sign before or after: $TRUE  or  FALSE$
2226
-            $this->dec_plc = 2;    // decimal places: 2 = 0.00  3 = 0.000
2227
-            $this->dec_mrk = '.';    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2228
-            $this->thsnds = ',';    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2229
-        }
2230
-    }
2231
-}
2232
-
2233
-
2234
-
2235
-/**
2236
- * Class for defining what's in the EE_Config relating to registration settings
2237
- */
2238
-class EE_Registration_Config extends EE_Config_Base
2239
-{
2240
-
2241
-    /**
2242
-     * Default registration status
2243
-     *
2244
-     * @var string $default_STS_ID
2245
-     * eg 'RPP'
2246
-     */
2247
-    public $default_STS_ID;
2248
-
2249
-
2250
-    /**
2251
-     * For new events, this will be the default value for the maximum number of tickets (equivalent to maximum number of
2252
-     * registrations)
2253
-     * @var int
2254
-     */
2255
-    public $default_maximum_number_of_tickets;
2256
-
2257
-
2258
-    /**
2259
-     * level of validation to apply to email addresses
2260
-     *
2261
-     * @var string $email_validation_level
2262
-     * options: 'basic', 'wp_default', 'i18n', 'i18n_dns'
2263
-     */
2264
-    public $email_validation_level;
2265
-
2266
-    /**
2267
-     *    whether or not to show alternate payment options during the reg process if payment status is pending
2268
-     *
2269
-     * @var boolean $show_pending_payment_options
2270
-     */
2271
-    public $show_pending_payment_options;
2272
-
2273
-    /**
2274
-     * Whether to skip the registration confirmation page
2275
-     *
2276
-     * @var boolean $skip_reg_confirmation
2277
-     */
2278
-    public $skip_reg_confirmation;
2279
-
2280
-    /**
2281
-     * an array of SPCO reg steps where:
2282
-     *        the keys denotes the reg step order
2283
-     *        each element consists of an array with the following elements:
2284
-     *            "file_path" => the file path to the EE_SPCO_Reg_Step class
2285
-     *            "class_name" => the specific EE_SPCO_Reg_Step child class name
2286
-     *            "slug" => the URL param used to trigger the reg step
2287
-     *
2288
-     * @var array $reg_steps
2289
-     */
2290
-    public $reg_steps;
2291
-
2292
-    /**
2293
-     * Whether registration confirmation should be the last page of SPCO
2294
-     *
2295
-     * @var boolean $reg_confirmation_last
2296
-     */
2297
-    public $reg_confirmation_last;
2298
-
2299
-    /**
2300
-     * Whether or not to enable the EE Bot Trap
2301
-     *
2302
-     * @var boolean $use_bot_trap
2303
-     */
2304
-    public $use_bot_trap;
2305
-
2306
-    /**
2307
-     * Whether or not to encrypt some data sent by the EE Bot Trap
2308
-     *
2309
-     * @var boolean $use_encryption
2310
-     */
2311
-    public $use_encryption;
1544
+}
2312 1545
 
2313
-    /**
2314
-     * Whether or not to use ReCaptcha
2315
-     *
2316
-     * @var boolean $use_captcha
2317
-     */
2318
-    public $use_captcha;
2319 1546
 
2320
-    /**
2321
-     * ReCaptcha Theme
2322
-     *
2323
-     * @var string $recaptcha_theme
2324
-     *    options: 'dark    ', 'light'
2325
-     */
2326
-    public $recaptcha_theme;
2327 1547
 
2328
-    /**
2329
-     * ReCaptcha Type
2330
-     *
2331
-     * @var string $recaptcha_type
2332
-     *    options: 'audio', 'image'
2333
-     */
2334
-    public $recaptcha_type;
1548
+/**
1549
+ * Base class used for config classes. These classes should generally not have
1550
+ * magic functions in use, except we'll allow them to magically set and get stuff...
1551
+ * basically, they should just be well-defined stdClasses
1552
+ */
1553
+class EE_Config_Base
1554
+{
2335 1555
 
2336
-    /**
2337
-     * ReCaptcha language
2338
-     *
2339
-     * @var string $recaptcha_language
2340
-     * eg 'en'
2341
-     */
2342
-    public $recaptcha_language;
1556
+	/**
1557
+	 * Utility function for escaping the value of a property and returning.
1558
+	 *
1559
+	 * @param string $property property name (checks to see if exists).
1560
+	 * @return mixed if a detected type found return the escaped value, otherwise just the raw value is returned.
1561
+	 * @throws \EE_Error
1562
+	 */
1563
+	public function get_pretty($property)
1564
+	{
1565
+		if (! property_exists($this, $property)) {
1566
+			throw new EE_Error(
1567
+				sprintf(
1568
+					__(
1569
+						'%1$s::get_pretty() has been called with the property %2$s which does not exist on the %1$s config class.',
1570
+						'event_espresso'
1571
+					),
1572
+					get_class($this),
1573
+					$property
1574
+				)
1575
+			);
1576
+		}
1577
+		//just handling escaping of strings for now.
1578
+		if (is_string($this->{$property})) {
1579
+			return stripslashes($this->{$property});
1580
+		}
1581
+		return $this->{$property};
1582
+	}
1583
+
1584
+
1585
+
1586
+	public function populate()
1587
+	{
1588
+		//grab defaults via a new instance of this class.
1589
+		$class_name = get_class($this);
1590
+		$defaults = new $class_name;
1591
+		//loop through the properties for this class and see if they are set.  If they are NOT, then grab the
1592
+		//default from our $defaults object.
1593
+		foreach (get_object_vars($defaults) as $property => $value) {
1594
+			if ($this->{$property} === null) {
1595
+				$this->{$property} = $value;
1596
+			}
1597
+		}
1598
+		//cleanup
1599
+		unset($defaults);
1600
+	}
1601
+
1602
+
1603
+
1604
+	/**
1605
+	 *        __isset
1606
+	 *
1607
+	 * @param $a
1608
+	 * @return bool
1609
+	 */
1610
+	public function __isset($a)
1611
+	{
1612
+		return false;
1613
+	}
1614
+
1615
+
1616
+
1617
+	/**
1618
+	 *        __unset
1619
+	 *
1620
+	 * @param $a
1621
+	 * @return bool
1622
+	 */
1623
+	public function __unset($a)
1624
+	{
1625
+		return false;
1626
+	}
1627
+
1628
+
1629
+
1630
+	/**
1631
+	 *        __clone
1632
+	 */
1633
+	public function __clone()
1634
+	{
1635
+	}
1636
+
1637
+
1638
+
1639
+	/**
1640
+	 *        __wakeup
1641
+	 */
1642
+	public function __wakeup()
1643
+	{
1644
+	}
1645
+
1646
+
1647
+
1648
+	/**
1649
+	 *        __destruct
1650
+	 */
1651
+	public function __destruct()
1652
+	{
1653
+	}
1654
+}
2343 1655
 
2344
-    /**
2345
-     * ReCaptcha public key
2346
-     *
2347
-     * @var string $recaptcha_publickey
2348
-     */
2349
-    public $recaptcha_publickey;
2350 1656
 
2351
-    /**
2352
-     * ReCaptcha private key
2353
-     *
2354
-     * @var string $recaptcha_privatekey
2355
-     */
2356
-    public $recaptcha_privatekey;
2357 1657
 
2358
-    /**
2359
-     * ReCaptcha width
2360
-     *
2361
-     * @var int $recaptcha_width
2362
-     * @deprecated
2363
-     */
2364
-    public $recaptcha_width;
1658
+/**
1659
+ * Class for defining what's in the EE_Config relating to registration settings
1660
+ */
1661
+class EE_Core_Config extends EE_Config_Base
1662
+{
2365 1663
 
2366
-    /**
2367
-     * Whether or not invalid attempts to directly access the registration checkout page should be tracked.
2368
-     *
2369
-     * @var boolean $track_invalid_checkout_access
2370
-     */
2371
-    protected $track_invalid_checkout_access = true;
1664
+	public $current_blog_id;
1665
+
1666
+	public $ee_ueip_optin;
1667
+
1668
+	public $ee_ueip_has_notified;
1669
+
1670
+	/**
1671
+	 * Not to be confused with the 4 critical page variables (See
1672
+	 * get_critical_pages_array()), this is just an array of wp posts that have EE
1673
+	 * shortcodes in them. Keys are slugs, values are arrays with only 1 element: where the key is the shortcode
1674
+	 * in the page, and the value is the page's ID. The key 'posts' is basically a duplicate of this same array.
1675
+	 *
1676
+	 * @var array
1677
+	 */
1678
+	public $post_shortcodes;
1679
+
1680
+	public $module_route_map;
1681
+
1682
+	public $module_forward_map;
1683
+
1684
+	public $module_view_map;
1685
+
1686
+	/**
1687
+	 * The next 4 vars are the IDs of critical EE pages.
1688
+	 *
1689
+	 * @var int
1690
+	 */
1691
+	public $reg_page_id;
1692
+
1693
+	public $txn_page_id;
1694
+
1695
+	public $thank_you_page_id;
1696
+
1697
+	public $cancel_page_id;
1698
+
1699
+	/**
1700
+	 * The next 4 vars are the URLs of critical EE pages.
1701
+	 *
1702
+	 * @var int
1703
+	 */
1704
+	public $reg_page_url;
1705
+
1706
+	public $txn_page_url;
1707
+
1708
+	public $thank_you_page_url;
1709
+
1710
+	public $cancel_page_url;
1711
+
1712
+	/**
1713
+	 * The next vars relate to the custom slugs for EE CPT routes
1714
+	 */
1715
+	public $event_cpt_slug;
1716
+
1717
+
1718
+	/**
1719
+	 * This caches the _ee_ueip_option in case this config is reset in the same
1720
+	 * request across blog switches in a multisite context.
1721
+	 * Avoids extra queries to the db for this option.
1722
+	 *
1723
+	 * @var bool
1724
+	 */
1725
+	public static $ee_ueip_option;
1726
+
1727
+
1728
+
1729
+	/**
1730
+	 *    class constructor
1731
+	 *
1732
+	 * @access    public
1733
+	 */
1734
+	public function __construct()
1735
+	{
1736
+		// set default organization settings
1737
+		$this->current_blog_id = get_current_blog_id();
1738
+		$this->current_blog_id = $this->current_blog_id === null ? 1 : $this->current_blog_id;
1739
+		$this->ee_ueip_optin = $this->_get_main_ee_ueip_optin();
1740
+		$this->ee_ueip_has_notified = is_main_site() ? get_option('ee_ueip_has_notified', false) : true;
1741
+		$this->post_shortcodes = array();
1742
+		$this->module_route_map = array();
1743
+		$this->module_forward_map = array();
1744
+		$this->module_view_map = array();
1745
+		// critical EE page IDs
1746
+		$this->reg_page_id = 0;
1747
+		$this->txn_page_id = 0;
1748
+		$this->thank_you_page_id = 0;
1749
+		$this->cancel_page_id = 0;
1750
+		// critical EE page URLs
1751
+		$this->reg_page_url = '';
1752
+		$this->txn_page_url = '';
1753
+		$this->thank_you_page_url = '';
1754
+		$this->cancel_page_url = '';
1755
+		//cpt slugs
1756
+		$this->event_cpt_slug = __('events', 'event_espresso');
1757
+		//ueip constant check
1758
+		if (defined('EE_DISABLE_UXIP') && EE_DISABLE_UXIP) {
1759
+			$this->ee_ueip_optin = false;
1760
+			$this->ee_ueip_has_notified = true;
1761
+		}
1762
+	}
1763
+
1764
+
1765
+
1766
+	/**
1767
+	 * @return array
1768
+	 */
1769
+	public function get_critical_pages_array()
1770
+	{
1771
+		return array(
1772
+			$this->reg_page_id,
1773
+			$this->txn_page_id,
1774
+			$this->thank_you_page_id,
1775
+			$this->cancel_page_id,
1776
+		);
1777
+	}
1778
+
1779
+
1780
+
1781
+	/**
1782
+	 * @return array
1783
+	 */
1784
+	public function get_critical_pages_shortcodes_array()
1785
+	{
1786
+		return array(
1787
+			$this->reg_page_id       => 'ESPRESSO_CHECKOUT',
1788
+			$this->txn_page_id       => 'ESPRESSO_TXN_PAGE',
1789
+			$this->thank_you_page_id => 'ESPRESSO_THANK_YOU',
1790
+			$this->cancel_page_id    => 'ESPRESSO_CANCELLED',
1791
+		);
1792
+	}
1793
+
1794
+
1795
+
1796
+	/**
1797
+	 *  gets/returns URL for EE reg_page
1798
+	 *
1799
+	 * @access    public
1800
+	 * @return    string
1801
+	 */
1802
+	public function reg_page_url()
1803
+	{
1804
+		if (! $this->reg_page_url) {
1805
+			$this->reg_page_url = add_query_arg(
1806
+									  array('uts' => time()),
1807
+									  get_permalink($this->reg_page_id)
1808
+								  ) . '#checkout';
1809
+		}
1810
+		return $this->reg_page_url;
1811
+	}
1812
+
1813
+
1814
+
1815
+	/**
1816
+	 *  gets/returns URL for EE txn_page
1817
+	 *
1818
+	 * @param array $query_args like what gets passed to
1819
+	 *                          add_query_arg() as the first argument
1820
+	 * @access    public
1821
+	 * @return    string
1822
+	 */
1823
+	public function txn_page_url($query_args = array())
1824
+	{
1825
+		if (! $this->txn_page_url) {
1826
+			$this->txn_page_url = get_permalink($this->txn_page_id);
1827
+		}
1828
+		if ($query_args) {
1829
+			return add_query_arg($query_args, $this->txn_page_url);
1830
+		} else {
1831
+			return $this->txn_page_url;
1832
+		}
1833
+	}
1834
+
1835
+
1836
+
1837
+	/**
1838
+	 *  gets/returns URL for EE thank_you_page
1839
+	 *
1840
+	 * @param array $query_args like what gets passed to
1841
+	 *                          add_query_arg() as the first argument
1842
+	 * @access    public
1843
+	 * @return    string
1844
+	 */
1845
+	public function thank_you_page_url($query_args = array())
1846
+	{
1847
+		if (! $this->thank_you_page_url) {
1848
+			$this->thank_you_page_url = get_permalink($this->thank_you_page_id);
1849
+		}
1850
+		if ($query_args) {
1851
+			return add_query_arg($query_args, $this->thank_you_page_url);
1852
+		} else {
1853
+			return $this->thank_you_page_url;
1854
+		}
1855
+	}
1856
+
1857
+
1858
+
1859
+	/**
1860
+	 *  gets/returns URL for EE cancel_page
1861
+	 *
1862
+	 * @access    public
1863
+	 * @return    string
1864
+	 */
1865
+	public function cancel_page_url()
1866
+	{
1867
+		if (! $this->cancel_page_url) {
1868
+			$this->cancel_page_url = get_permalink($this->cancel_page_id);
1869
+		}
1870
+		return $this->cancel_page_url;
1871
+	}
1872
+
1873
+
1874
+
1875
+	/**
1876
+	 * Resets all critical page urls to their original state.  Used primarily by the __sleep() magic method currently.
1877
+	 *
1878
+	 * @since 4.7.5
1879
+	 */
1880
+	protected function _reset_urls()
1881
+	{
1882
+		$this->reg_page_url = '';
1883
+		$this->txn_page_url = '';
1884
+		$this->cancel_page_url = '';
1885
+		$this->thank_you_page_url = '';
1886
+	}
1887
+
1888
+
1889
+
1890
+	/**
1891
+	 * Used to return what the optin value is set for the EE User Experience Program.
1892
+	 * This accounts for multisite and this value being requested for a subsite.  In multisite, the value is set
1893
+	 * on the main site only.
1894
+	 *
1895
+	 * @return mixed|void
1896
+	 */
1897
+	protected function _get_main_ee_ueip_optin()
1898
+	{
1899
+		//if this is the main site then we can just bypass our direct query.
1900
+		if (is_main_site()) {
1901
+			return get_option('ee_ueip_optin', false);
1902
+		}
1903
+		//is this already cached for this request?  If so use it.
1904
+		if ( ! empty(EE_Core_Config::$ee_ueip_option)) {
1905
+			return EE_Core_Config::$ee_ueip_option;
1906
+		}
1907
+		global $wpdb;
1908
+		$current_network_main_site = is_multisite() ? get_current_site() : null;
1909
+		$current_main_site_id = ! empty($current_network_main_site) ? $current_network_main_site->blog_id : 1;
1910
+		$option = 'ee_ueip_optin';
1911
+		//set correct table for query
1912
+		$table_name = $wpdb->get_blog_prefix($current_main_site_id) . 'options';
1913
+		//rather than getting blog option for the $current_main_site_id, we do a direct $wpdb query because
1914
+		//get_blog_option() does a switch_to_blog an that could cause infinite recursion because EE_Core_Config might be
1915
+		//re-constructed on the blog switch.  Note, we are still executing any core wp filters on this option retrieval.
1916
+		//this bit of code is basically a direct copy of get_option without any caching because we are NOT switched to the blog
1917
+		//for the purpose of caching.
1918
+		$pre = apply_filters('pre_option_' . $option, false, $option);
1919
+		if (false !== $pre) {
1920
+			EE_Core_Config::$ee_ueip_option = $pre;
1921
+			return EE_Core_Config::$ee_ueip_option;
1922
+		}
1923
+		$row = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM $table_name WHERE option_name = %s LIMIT 1",
1924
+			$option));
1925
+		if (is_object($row)) {
1926
+			$value = $row->option_value;
1927
+		} else { //option does not exist so use default.
1928
+			return apply_filters('default_option_' . $option, false, $option);
1929
+		}
1930
+		EE_Core_Config::$ee_ueip_option = apply_filters('option_' . $option, maybe_unserialize($value), $option);
1931
+		return EE_Core_Config::$ee_ueip_option;
1932
+	}
1933
+
1934
+
1935
+
1936
+	/**
1937
+	 * Currently used to ensure critical page urls have initial values saved to the db instead of any current set values
1938
+	 * on the object.
1939
+	 *
1940
+	 * @return array
1941
+	 */
1942
+	public function __sleep()
1943
+	{
1944
+		//reset all url properties
1945
+		$this->_reset_urls();
1946
+		//return what to save to db
1947
+		return array_keys(get_object_vars($this));
1948
+	}
2372 1949
 
1950
+}
2373 1951
 
2374 1952
 
2375
-    /**
2376
-     *    class constructor
2377
-     *
2378
-     * @access    public
2379
-     */
2380
-    public function __construct()
2381
-    {
2382
-        // set default registration settings
2383
-        $this->default_STS_ID = EEM_Registration::status_id_pending_payment;
2384
-        $this->email_validation_level = 'wp_default';
2385
-        $this->show_pending_payment_options = true;
2386
-        $this->skip_reg_confirmation = false;
2387
-        $this->reg_steps = array();
2388
-        $this->reg_confirmation_last = false;
2389
-        $this->use_bot_trap = true;
2390
-        $this->use_encryption = true;
2391
-        $this->use_captcha = false;
2392
-        $this->recaptcha_theme = 'light';
2393
-        $this->recaptcha_type = 'image';
2394
-        $this->recaptcha_language = 'en';
2395
-        $this->recaptcha_publickey = null;
2396
-        $this->recaptcha_privatekey = null;
2397
-        $this->recaptcha_width = 500;
2398
-        $this->default_maximum_number_of_tickets = 10;
2399
-    }
2400
-
2401
-
2402
-
2403
-    /**
2404
-     * This is called by the config loader and hooks are initialized AFTER the config has been populated.
2405
-     *
2406
-     * @since 4.8.8.rc.019
2407
-     */
2408
-    public function do_hooks()
2409
-    {
2410
-        add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_reg_status_on_EEM_Event'));
2411
-        add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_max_ticket_on_EEM_Event'));
2412
-    }
2413 1953
 
1954
+/**
1955
+ * Config class for storing info on the Organization
1956
+ */
1957
+class EE_Organization_Config extends EE_Config_Base
1958
+{
2414 1959
 
1960
+	/**
1961
+	 * @var string $name
1962
+	 * eg EE4.1
1963
+	 */
1964
+	public $name;
1965
+
1966
+	/**
1967
+	 * @var string $address_1
1968
+	 * eg 123 Onna Road
1969
+	 */
1970
+	public $address_1;
1971
+
1972
+	/**
1973
+	 * @var string $address_2
1974
+	 * eg PO Box 123
1975
+	 */
1976
+	public $address_2;
1977
+
1978
+	/**
1979
+	 * @var string $city
1980
+	 * eg Inna City
1981
+	 */
1982
+	public $city;
1983
+
1984
+	/**
1985
+	 * @var int $STA_ID
1986
+	 * eg 4
1987
+	 */
1988
+	public $STA_ID;
1989
+
1990
+	/**
1991
+	 * @var string $CNT_ISO
1992
+	 * eg US
1993
+	 */
1994
+	public $CNT_ISO;
1995
+
1996
+	/**
1997
+	 * @var string $zip
1998
+	 * eg 12345  or V1A 2B3
1999
+	 */
2000
+	public $zip;
2001
+
2002
+	/**
2003
+	 * @var string $email
2004
+	 * eg [email protected]
2005
+	 */
2006
+	public $email;
2007
+
2008
+
2009
+	/**
2010
+	 * @var string $phone
2011
+	 * eg. 111-111-1111
2012
+	 */
2013
+	public $phone;
2014
+
2015
+
2016
+	/**
2017
+	 * @var string $vat
2018
+	 * VAT/Tax Number
2019
+	 */
2020
+	public $vat;
2021
+
2022
+	/**
2023
+	 * @var string $logo_url
2024
+	 * eg http://www.somedomain.com/wp-content/uploads/kittehs.jpg
2025
+	 */
2026
+	public $logo_url;
2027
+
2028
+
2029
+	/**
2030
+	 * The below are all various properties for holding links to organization social network profiles
2031
+	 *
2032
+	 * @var string
2033
+	 */
2034
+	/**
2035
+	 * facebook (facebook.com/profile.name)
2036
+	 *
2037
+	 * @var string
2038
+	 */
2039
+	public $facebook;
2040
+
2041
+
2042
+	/**
2043
+	 * twitter (twitter.com/twitter_handle)
2044
+	 *
2045
+	 * @var string
2046
+	 */
2047
+	public $twitter;
2048
+
2049
+
2050
+	/**
2051
+	 * linkedin (linkedin.com/in/profile_name)
2052
+	 *
2053
+	 * @var string
2054
+	 */
2055
+	public $linkedin;
2056
+
2057
+
2058
+	/**
2059
+	 * pinterest (www.pinterest.com/profile_name)
2060
+	 *
2061
+	 * @var string
2062
+	 */
2063
+	public $pinterest;
2064
+
2065
+
2066
+	/**
2067
+	 * google+ (google.com/+profileName)
2068
+	 *
2069
+	 * @var string
2070
+	 */
2071
+	public $google;
2072
+
2073
+
2074
+	/**
2075
+	 * instagram (instagram.com/handle)
2076
+	 *
2077
+	 * @var string
2078
+	 */
2079
+	public $instagram;
2080
+
2081
+
2082
+
2083
+	/**
2084
+	 *    class constructor
2085
+	 *
2086
+	 * @access    public
2087
+	 */
2088
+	public function __construct()
2089
+	{
2090
+		// set default organization settings
2091
+		//decode HTML entities from the WP blogname, because it's stored in the DB with HTML entities encoded
2092
+		$this->name = wp_specialchars_decode(get_bloginfo('name'), ENT_QUOTES);
2093
+		$this->address_1 = '123 Onna Road';
2094
+		$this->address_2 = 'PO Box 123';
2095
+		$this->city = 'Inna City';
2096
+		$this->STA_ID = 4;
2097
+		$this->CNT_ISO = 'US';
2098
+		$this->zip = '12345';
2099
+		$this->email = get_bloginfo('admin_email');
2100
+		$this->phone = '';
2101
+		$this->vat = '123456789';
2102
+		$this->logo_url = '';
2103
+		$this->facebook = '';
2104
+		$this->twitter = '';
2105
+		$this->linkedin = '';
2106
+		$this->pinterest = '';
2107
+		$this->google = '';
2108
+		$this->instagram = '';
2109
+	}
2415 2110
 
2416
-    /**
2417
-     * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the EVT_default_registration_status
2418
-     * field matches the config setting for default_STS_ID.
2419
-     */
2420
-    public function set_default_reg_status_on_EEM_Event()
2421
-    {
2422
-        EEM_Event::set_default_reg_status($this->default_STS_ID);
2423
-    }
2111
+}
2424 2112
 
2425 2113
 
2426
-    /**
2427
-     * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the EVT_additional_limit field
2428
-     * for Events matches the config setting for default_maximum_number_of_tickets
2429
-     */
2430
-    public function set_default_max_ticket_on_EEM_Event()
2431
-    {
2432
-        EEM_Event::set_default_additional_limit($this->default_maximum_number_of_tickets);
2433
-    }
2434 2114
 
2115
+/**
2116
+ * Class for defining what's in the EE_Config relating to currency
2117
+ */
2118
+class EE_Currency_Config extends EE_Config_Base
2119
+{
2435 2120
 
2121
+	/**
2122
+	 * @var string $code
2123
+	 * eg 'US'
2124
+	 */
2125
+	public $code;
2126
+
2127
+	/**
2128
+	 * @var string $name
2129
+	 * eg 'Dollar'
2130
+	 */
2131
+	public $name;
2132
+
2133
+	/**
2134
+	 * plural name
2135
+	 *
2136
+	 * @var string $plural
2137
+	 * eg 'Dollars'
2138
+	 */
2139
+	public $plural;
2140
+
2141
+	/**
2142
+	 * currency sign
2143
+	 *
2144
+	 * @var string $sign
2145
+	 * eg '$'
2146
+	 */
2147
+	public $sign;
2148
+
2149
+	/**
2150
+	 * Whether the currency sign should come before the number or not
2151
+	 *
2152
+	 * @var boolean $sign_b4
2153
+	 */
2154
+	public $sign_b4;
2155
+
2156
+	/**
2157
+	 * How many digits should come after the decimal place
2158
+	 *
2159
+	 * @var int $dec_plc
2160
+	 */
2161
+	public $dec_plc;
2162
+
2163
+	/**
2164
+	 * Symbol to use for decimal mark
2165
+	 *
2166
+	 * @var string $dec_mrk
2167
+	 * eg '.'
2168
+	 */
2169
+	public $dec_mrk;
2170
+
2171
+	/**
2172
+	 * Symbol to use for thousands
2173
+	 *
2174
+	 * @var string $thsnds
2175
+	 * eg ','
2176
+	 */
2177
+	public $thsnds;
2178
+
2179
+
2180
+
2181
+	/**
2182
+	 *    class constructor
2183
+	 *
2184
+	 * @access    public
2185
+	 * @param string $CNT_ISO
2186
+	 * @throws \EE_Error
2187
+	 */
2188
+	public function __construct($CNT_ISO = '')
2189
+	{
2190
+		/** @var \EventEspresso\core\services\database\TableAnalysis $table_analysis */
2191
+		$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
2192
+		// get country code from organization settings or use default
2193
+		$ORG_CNT = isset(EE_Registry::instance()->CFG->organization)
2194
+				   && EE_Registry::instance()->CFG->organization instanceof EE_Organization_Config
2195
+			? EE_Registry::instance()->CFG->organization->CNT_ISO
2196
+			: '';
2197
+		// but override if requested
2198
+		$CNT_ISO = ! empty($CNT_ISO) ? $CNT_ISO : $ORG_CNT;
2199
+		// so if that all went well, and we are not in M-Mode (cuz you can't query the db in M-Mode) and double-check the countries table exists
2200
+		if (
2201
+			! empty($CNT_ISO)
2202
+			&& EE_Maintenance_Mode::instance()->models_can_query()
2203
+			&& $table_analysis->tableExists(EE_Registry::instance()->load_model('Country')->table())
2204
+		) {
2205
+			// retrieve the country settings from the db, just in case they have been customized
2206
+			$country = EE_Registry::instance()->load_model('Country')->get_one_by_ID($CNT_ISO);
2207
+			if ($country instanceof EE_Country) {
2208
+				$this->code = $country->currency_code();    // currency code: USD, CAD, EUR
2209
+				$this->name = $country->currency_name_single();    // Dollar
2210
+				$this->plural = $country->currency_name_plural();    // Dollars
2211
+				$this->sign = $country->currency_sign();            // currency sign: $
2212
+				$this->sign_b4 = $country->currency_sign_before();        // currency sign before or after: $TRUE  or  FALSE$
2213
+				$this->dec_plc = $country->currency_decimal_places();    // decimal places: 2 = 0.00  3 = 0.000
2214
+				$this->dec_mrk = $country->currency_decimal_mark();    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2215
+				$this->thsnds = $country->currency_thousands_separator();    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2216
+			}
2217
+		}
2218
+		// fallback to hardcoded defaults, in case the above failed
2219
+		if (empty($this->code)) {
2220
+			// set default currency settings
2221
+			$this->code = 'USD';    // currency code: USD, CAD, EUR
2222
+			$this->name = __('Dollar', 'event_espresso');    // Dollar
2223
+			$this->plural = __('Dollars', 'event_espresso');    // Dollars
2224
+			$this->sign = '$';    // currency sign: $
2225
+			$this->sign_b4 = true;    // currency sign before or after: $TRUE  or  FALSE$
2226
+			$this->dec_plc = 2;    // decimal places: 2 = 0.00  3 = 0.000
2227
+			$this->dec_mrk = '.';    // decimal mark: (comma) ',' = 0,01   or (decimal) '.' = 0.01
2228
+			$this->thsnds = ',';    // thousands separator: (comma) ',' = 1,000   or (decimal) '.' = 1.000
2229
+		}
2230
+	}
2231
+}
2436 2232
 
2437
-    /**
2438
-     * @return boolean
2439
-     */
2440
-    public function track_invalid_checkout_access()
2441
-    {
2442
-        return $this->track_invalid_checkout_access;
2443
-    }
2444 2233
 
2445 2234
 
2235
+/**
2236
+ * Class for defining what's in the EE_Config relating to registration settings
2237
+ */
2238
+class EE_Registration_Config extends EE_Config_Base
2239
+{
2446 2240
 
2447
-    /**
2448
-     * @param boolean $track_invalid_checkout_access
2449
-     */
2450
-    public function set_track_invalid_checkout_access($track_invalid_checkout_access)
2451
-    {
2452
-        $this->track_invalid_checkout_access = filter_var(
2453
-            $track_invalid_checkout_access,
2454
-            FILTER_VALIDATE_BOOLEAN
2455
-        );
2456
-    }
2241
+	/**
2242
+	 * Default registration status
2243
+	 *
2244
+	 * @var string $default_STS_ID
2245
+	 * eg 'RPP'
2246
+	 */
2247
+	public $default_STS_ID;
2248
+
2249
+
2250
+	/**
2251
+	 * For new events, this will be the default value for the maximum number of tickets (equivalent to maximum number of
2252
+	 * registrations)
2253
+	 * @var int
2254
+	 */
2255
+	public $default_maximum_number_of_tickets;
2256
+
2257
+
2258
+	/**
2259
+	 * level of validation to apply to email addresses
2260
+	 *
2261
+	 * @var string $email_validation_level
2262
+	 * options: 'basic', 'wp_default', 'i18n', 'i18n_dns'
2263
+	 */
2264
+	public $email_validation_level;
2265
+
2266
+	/**
2267
+	 *    whether or not to show alternate payment options during the reg process if payment status is pending
2268
+	 *
2269
+	 * @var boolean $show_pending_payment_options
2270
+	 */
2271
+	public $show_pending_payment_options;
2272
+
2273
+	/**
2274
+	 * Whether to skip the registration confirmation page
2275
+	 *
2276
+	 * @var boolean $skip_reg_confirmation
2277
+	 */
2278
+	public $skip_reg_confirmation;
2279
+
2280
+	/**
2281
+	 * an array of SPCO reg steps where:
2282
+	 *        the keys denotes the reg step order
2283
+	 *        each element consists of an array with the following elements:
2284
+	 *            "file_path" => the file path to the EE_SPCO_Reg_Step class
2285
+	 *            "class_name" => the specific EE_SPCO_Reg_Step child class name
2286
+	 *            "slug" => the URL param used to trigger the reg step
2287
+	 *
2288
+	 * @var array $reg_steps
2289
+	 */
2290
+	public $reg_steps;
2291
+
2292
+	/**
2293
+	 * Whether registration confirmation should be the last page of SPCO
2294
+	 *
2295
+	 * @var boolean $reg_confirmation_last
2296
+	 */
2297
+	public $reg_confirmation_last;
2298
+
2299
+	/**
2300
+	 * Whether or not to enable the EE Bot Trap
2301
+	 *
2302
+	 * @var boolean $use_bot_trap
2303
+	 */
2304
+	public $use_bot_trap;
2305
+
2306
+	/**
2307
+	 * Whether or not to encrypt some data sent by the EE Bot Trap
2308
+	 *
2309
+	 * @var boolean $use_encryption
2310
+	 */
2311
+	public $use_encryption;
2312
+
2313
+	/**
2314
+	 * Whether or not to use ReCaptcha
2315
+	 *
2316
+	 * @var boolean $use_captcha
2317
+	 */
2318
+	public $use_captcha;
2319
+
2320
+	/**
2321
+	 * ReCaptcha Theme
2322
+	 *
2323
+	 * @var string $recaptcha_theme
2324
+	 *    options: 'dark    ', 'light'
2325
+	 */
2326
+	public $recaptcha_theme;
2327
+
2328
+	/**
2329
+	 * ReCaptcha Type
2330
+	 *
2331
+	 * @var string $recaptcha_type
2332
+	 *    options: 'audio', 'image'
2333
+	 */
2334
+	public $recaptcha_type;
2335
+
2336
+	/**
2337
+	 * ReCaptcha language
2338
+	 *
2339
+	 * @var string $recaptcha_language
2340
+	 * eg 'en'
2341
+	 */
2342
+	public $recaptcha_language;
2343
+
2344
+	/**
2345
+	 * ReCaptcha public key
2346
+	 *
2347
+	 * @var string $recaptcha_publickey
2348
+	 */
2349
+	public $recaptcha_publickey;
2350
+
2351
+	/**
2352
+	 * ReCaptcha private key
2353
+	 *
2354
+	 * @var string $recaptcha_privatekey
2355
+	 */
2356
+	public $recaptcha_privatekey;
2357
+
2358
+	/**
2359
+	 * ReCaptcha width
2360
+	 *
2361
+	 * @var int $recaptcha_width
2362
+	 * @deprecated
2363
+	 */
2364
+	public $recaptcha_width;
2365
+
2366
+	/**
2367
+	 * Whether or not invalid attempts to directly access the registration checkout page should be tracked.
2368
+	 *
2369
+	 * @var boolean $track_invalid_checkout_access
2370
+	 */
2371
+	protected $track_invalid_checkout_access = true;
2372
+
2373
+
2374
+
2375
+	/**
2376
+	 *    class constructor
2377
+	 *
2378
+	 * @access    public
2379
+	 */
2380
+	public function __construct()
2381
+	{
2382
+		// set default registration settings
2383
+		$this->default_STS_ID = EEM_Registration::status_id_pending_payment;
2384
+		$this->email_validation_level = 'wp_default';
2385
+		$this->show_pending_payment_options = true;
2386
+		$this->skip_reg_confirmation = false;
2387
+		$this->reg_steps = array();
2388
+		$this->reg_confirmation_last = false;
2389
+		$this->use_bot_trap = true;
2390
+		$this->use_encryption = true;
2391
+		$this->use_captcha = false;
2392
+		$this->recaptcha_theme = 'light';
2393
+		$this->recaptcha_type = 'image';
2394
+		$this->recaptcha_language = 'en';
2395
+		$this->recaptcha_publickey = null;
2396
+		$this->recaptcha_privatekey = null;
2397
+		$this->recaptcha_width = 500;
2398
+		$this->default_maximum_number_of_tickets = 10;
2399
+	}
2400
+
2401
+
2402
+
2403
+	/**
2404
+	 * This is called by the config loader and hooks are initialized AFTER the config has been populated.
2405
+	 *
2406
+	 * @since 4.8.8.rc.019
2407
+	 */
2408
+	public function do_hooks()
2409
+	{
2410
+		add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_reg_status_on_EEM_Event'));
2411
+		add_action('AHEE__EE_Config___load_core_config__end', array($this, 'set_default_max_ticket_on_EEM_Event'));
2412
+	}
2413
+
2414
+
2415
+
2416
+	/**
2417
+	 * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the EVT_default_registration_status
2418
+	 * field matches the config setting for default_STS_ID.
2419
+	 */
2420
+	public function set_default_reg_status_on_EEM_Event()
2421
+	{
2422
+		EEM_Event::set_default_reg_status($this->default_STS_ID);
2423
+	}
2424
+
2425
+
2426
+	/**
2427
+	 * Hooked into `AHEE__EE_Config___load_core_config__end` to ensure the default for the EVT_additional_limit field
2428
+	 * for Events matches the config setting for default_maximum_number_of_tickets
2429
+	 */
2430
+	public function set_default_max_ticket_on_EEM_Event()
2431
+	{
2432
+		EEM_Event::set_default_additional_limit($this->default_maximum_number_of_tickets);
2433
+	}
2434
+
2435
+
2436
+
2437
+	/**
2438
+	 * @return boolean
2439
+	 */
2440
+	public function track_invalid_checkout_access()
2441
+	{
2442
+		return $this->track_invalid_checkout_access;
2443
+	}
2444
+
2445
+
2446
+
2447
+	/**
2448
+	 * @param boolean $track_invalid_checkout_access
2449
+	 */
2450
+	public function set_track_invalid_checkout_access($track_invalid_checkout_access)
2451
+	{
2452
+		$this->track_invalid_checkout_access = filter_var(
2453
+			$track_invalid_checkout_access,
2454
+			FILTER_VALIDATE_BOOLEAN
2455
+		);
2456
+	}
2457 2457
 
2458 2458
 
2459 2459
 
@@ -2467,160 +2467,160 @@  discard block
 block discarded – undo
2467 2467
 class EE_Admin_Config extends EE_Config_Base
2468 2468
 {
2469 2469
 
2470
-    /**
2471
-     * @var boolean $use_personnel_manager
2472
-     */
2473
-    public $use_personnel_manager;
2474
-
2475
-    /**
2476
-     * @var boolean $use_dashboard_widget
2477
-     */
2478
-    public $use_dashboard_widget;
2479
-
2480
-    /**
2481
-     * @var int $events_in_dashboard
2482
-     */
2483
-    public $events_in_dashboard;
2484
-
2485
-    /**
2486
-     * @var boolean $use_event_timezones
2487
-     */
2488
-    public $use_event_timezones;
2489
-
2490
-    /**
2491
-     * @var boolean $use_full_logging
2492
-     */
2493
-    public $use_full_logging;
2494
-
2495
-    /**
2496
-     * @var string $log_file_name
2497
-     */
2498
-    public $log_file_name;
2499
-
2500
-    /**
2501
-     * @var string $debug_file_name
2502
-     */
2503
-    public $debug_file_name;
2504
-
2505
-    /**
2506
-     * @var boolean $use_remote_logging
2507
-     */
2508
-    public $use_remote_logging;
2509
-
2510
-    /**
2511
-     * @var string $remote_logging_url
2512
-     */
2513
-    public $remote_logging_url;
2514
-
2515
-    /**
2516
-     * @var boolean $show_reg_footer
2517
-     */
2518
-    public $show_reg_footer;
2519
-
2520
-    /**
2521
-     * @var string $affiliate_id
2522
-     */
2523
-    public $affiliate_id;
2524
-
2525
-    /**
2526
-     * help tours on or off (global setting)
2527
-     *
2528
-     * @var boolean
2529
-     */
2530
-    public $help_tour_activation;
2531
-
2532
-    /**
2533
-     * adds extra layer of encoding to session data to prevent serialization errors
2534
-     * but is incompatible with some server configuration errors
2535
-     * if you get "500 internal server errors" during registration, try turning this on
2536
-     * if you get PHP fatal errors regarding base 64 methods not defined, then turn this off
2537
-     *
2538
-     * @var boolean $encode_session_data
2539
-     */
2540
-    private $encode_session_data = false;
2541
-
2542
-
2543
-
2544
-    /**
2545
-     *    class constructor
2546
-     *
2547
-     * @access    public
2548
-     */
2549
-    public function __construct()
2550
-    {
2551
-        // set default general admin settings
2552
-        $this->use_personnel_manager = true;
2553
-        $this->use_dashboard_widget = true;
2554
-        $this->events_in_dashboard = 30;
2555
-        $this->use_event_timezones = false;
2556
-        $this->use_full_logging = false;
2557
-        $this->use_remote_logging = false;
2558
-        $this->remote_logging_url = null;
2559
-        $this->show_reg_footer = true;
2560
-        $this->affiliate_id = 'default';
2561
-        $this->help_tour_activation = true;
2562
-        $this->encode_session_data = false;
2563
-    }
2564
-
2565
-
2566
-
2567
-    /**
2568
-     * @param bool $reset
2569
-     * @return string
2570
-     */
2571
-    public function log_file_name($reset = false)
2572
-    {
2573
-        if (empty($this->log_file_name) || $reset) {
2574
-            $this->log_file_name = sanitize_key('espresso_log_' . md5(uniqid('', true))) . '.txt';
2575
-            EE_Config::instance()->update_espresso_config(false, false);
2576
-        }
2577
-        return $this->log_file_name;
2578
-    }
2579
-
2580
-
2581
-
2582
-    /**
2583
-     * @param bool $reset
2584
-     * @return string
2585
-     */
2586
-    public function debug_file_name($reset = false)
2587
-    {
2588
-        if (empty($this->debug_file_name) || $reset) {
2589
-            $this->debug_file_name = sanitize_key('espresso_debug_' . md5(uniqid('', true))) . '.txt';
2590
-            EE_Config::instance()->update_espresso_config(false, false);
2591
-        }
2592
-        return $this->debug_file_name;
2593
-    }
2594
-
2595
-
2596
-
2597
-    /**
2598
-     * @return string
2599
-     */
2600
-    public function affiliate_id()
2601
-    {
2602
-        return ! empty($this->affiliate_id) ? $this->affiliate_id : 'default';
2603
-    }
2604
-
2605
-
2606
-
2607
-    /**
2608
-     * @return boolean
2609
-     */
2610
-    public function encode_session_data()
2611
-    {
2612
-        return filter_var($this->encode_session_data, FILTER_VALIDATE_BOOLEAN);
2613
-    }
2614
-
2615
-
2616
-
2617
-    /**
2618
-     * @param boolean $encode_session_data
2619
-     */
2620
-    public function set_encode_session_data($encode_session_data)
2621
-    {
2622
-        $this->encode_session_data = filter_var($encode_session_data, FILTER_VALIDATE_BOOLEAN);
2623
-    }
2470
+	/**
2471
+	 * @var boolean $use_personnel_manager
2472
+	 */
2473
+	public $use_personnel_manager;
2474
+
2475
+	/**
2476
+	 * @var boolean $use_dashboard_widget
2477
+	 */
2478
+	public $use_dashboard_widget;
2479
+
2480
+	/**
2481
+	 * @var int $events_in_dashboard
2482
+	 */
2483
+	public $events_in_dashboard;
2484
+
2485
+	/**
2486
+	 * @var boolean $use_event_timezones
2487
+	 */
2488
+	public $use_event_timezones;
2489
+
2490
+	/**
2491
+	 * @var boolean $use_full_logging
2492
+	 */
2493
+	public $use_full_logging;
2494
+
2495
+	/**
2496
+	 * @var string $log_file_name
2497
+	 */
2498
+	public $log_file_name;
2499
+
2500
+	/**
2501
+	 * @var string $debug_file_name
2502
+	 */
2503
+	public $debug_file_name;
2504
+
2505
+	/**
2506
+	 * @var boolean $use_remote_logging
2507
+	 */
2508
+	public $use_remote_logging;
2509
+
2510
+	/**
2511
+	 * @var string $remote_logging_url
2512
+	 */
2513
+	public $remote_logging_url;
2514
+
2515
+	/**
2516
+	 * @var boolean $show_reg_footer
2517
+	 */
2518
+	public $show_reg_footer;
2519
+
2520
+	/**
2521
+	 * @var string $affiliate_id
2522
+	 */
2523
+	public $affiliate_id;
2524
+
2525
+	/**
2526
+	 * help tours on or off (global setting)
2527
+	 *
2528
+	 * @var boolean
2529
+	 */
2530
+	public $help_tour_activation;
2531
+
2532
+	/**
2533
+	 * adds extra layer of encoding to session data to prevent serialization errors
2534
+	 * but is incompatible with some server configuration errors
2535
+	 * if you get "500 internal server errors" during registration, try turning this on
2536
+	 * if you get PHP fatal errors regarding base 64 methods not defined, then turn this off
2537
+	 *
2538
+	 * @var boolean $encode_session_data
2539
+	 */
2540
+	private $encode_session_data = false;
2541
+
2542
+
2543
+
2544
+	/**
2545
+	 *    class constructor
2546
+	 *
2547
+	 * @access    public
2548
+	 */
2549
+	public function __construct()
2550
+	{
2551
+		// set default general admin settings
2552
+		$this->use_personnel_manager = true;
2553
+		$this->use_dashboard_widget = true;
2554
+		$this->events_in_dashboard = 30;
2555
+		$this->use_event_timezones = false;
2556
+		$this->use_full_logging = false;
2557
+		$this->use_remote_logging = false;
2558
+		$this->remote_logging_url = null;
2559
+		$this->show_reg_footer = true;
2560
+		$this->affiliate_id = 'default';
2561
+		$this->help_tour_activation = true;
2562
+		$this->encode_session_data = false;
2563
+	}
2564
+
2565
+
2566
+
2567
+	/**
2568
+	 * @param bool $reset
2569
+	 * @return string
2570
+	 */
2571
+	public function log_file_name($reset = false)
2572
+	{
2573
+		if (empty($this->log_file_name) || $reset) {
2574
+			$this->log_file_name = sanitize_key('espresso_log_' . md5(uniqid('', true))) . '.txt';
2575
+			EE_Config::instance()->update_espresso_config(false, false);
2576
+		}
2577
+		return $this->log_file_name;
2578
+	}
2579
+
2580
+
2581
+
2582
+	/**
2583
+	 * @param bool $reset
2584
+	 * @return string
2585
+	 */
2586
+	public function debug_file_name($reset = false)
2587
+	{
2588
+		if (empty($this->debug_file_name) || $reset) {
2589
+			$this->debug_file_name = sanitize_key('espresso_debug_' . md5(uniqid('', true))) . '.txt';
2590
+			EE_Config::instance()->update_espresso_config(false, false);
2591
+		}
2592
+		return $this->debug_file_name;
2593
+	}
2594
+
2595
+
2596
+
2597
+	/**
2598
+	 * @return string
2599
+	 */
2600
+	public function affiliate_id()
2601
+	{
2602
+		return ! empty($this->affiliate_id) ? $this->affiliate_id : 'default';
2603
+	}
2604
+
2605
+
2606
+
2607
+	/**
2608
+	 * @return boolean
2609
+	 */
2610
+	public function encode_session_data()
2611
+	{
2612
+		return filter_var($this->encode_session_data, FILTER_VALIDATE_BOOLEAN);
2613
+	}
2614
+
2615
+
2616
+
2617
+	/**
2618
+	 * @param boolean $encode_session_data
2619
+	 */
2620
+	public function set_encode_session_data($encode_session_data)
2621
+	{
2622
+		$this->encode_session_data = filter_var($encode_session_data, FILTER_VALIDATE_BOOLEAN);
2623
+	}
2624 2624
 
2625 2625
 
2626 2626
 
@@ -2634,71 +2634,71 @@  discard block
 block discarded – undo
2634 2634
 class EE_Template_Config extends EE_Config_Base
2635 2635
 {
2636 2636
 
2637
-    /**
2638
-     * @var boolean $enable_default_style
2639
-     */
2640
-    public $enable_default_style;
2641
-
2642
-    /**
2643
-     * @var string $custom_style_sheet
2644
-     */
2645
-    public $custom_style_sheet;
2646
-
2647
-    /**
2648
-     * @var boolean $display_address_in_regform
2649
-     */
2650
-    public $display_address_in_regform;
2651
-
2652
-    /**
2653
-     * @var int $display_description_on_multi_reg_page
2654
-     */
2655
-    public $display_description_on_multi_reg_page;
2656
-
2657
-    /**
2658
-     * @var boolean $use_custom_templates
2659
-     */
2660
-    public $use_custom_templates;
2661
-
2662
-    /**
2663
-     * @var string $current_espresso_theme
2664
-     */
2665
-    public $current_espresso_theme;
2666
-
2667
-    /**
2668
-     * @var EE_Ticket_Selector_Config $EED_Ticket_Selector
2669
-     */
2670
-    public $EED_Ticket_Selector;
2671
-
2672
-    /**
2673
-     * @var EE_Event_Single_Config $EED_Event_Single
2674
-     */
2675
-    public $EED_Event_Single;
2676
-
2677
-    /**
2678
-     * @var EE_Events_Archive_Config $EED_Events_Archive
2679
-     */
2680
-    public $EED_Events_Archive;
2681
-
2682
-
2683
-
2684
-    /**
2685
-     *    class constructor
2686
-     *
2687
-     * @access    public
2688
-     */
2689
-    public function __construct()
2690
-    {
2691
-        // set default template settings
2692
-        $this->enable_default_style = true;
2693
-        $this->custom_style_sheet = null;
2694
-        $this->display_address_in_regform = true;
2695
-        $this->display_description_on_multi_reg_page = false;
2696
-        $this->use_custom_templates = false;
2697
-        $this->current_espresso_theme = 'Espresso_Arabica_2014';
2698
-        $this->EED_Event_Single = null;
2699
-        $this->EED_Events_Archive = null;
2700
-        $this->EED_Ticket_Selector = null;
2701
-    }
2637
+	/**
2638
+	 * @var boolean $enable_default_style
2639
+	 */
2640
+	public $enable_default_style;
2641
+
2642
+	/**
2643
+	 * @var string $custom_style_sheet
2644
+	 */
2645
+	public $custom_style_sheet;
2646
+
2647
+	/**
2648
+	 * @var boolean $display_address_in_regform
2649
+	 */
2650
+	public $display_address_in_regform;
2651
+
2652
+	/**
2653
+	 * @var int $display_description_on_multi_reg_page
2654
+	 */
2655
+	public $display_description_on_multi_reg_page;
2656
+
2657
+	/**
2658
+	 * @var boolean $use_custom_templates
2659
+	 */
2660
+	public $use_custom_templates;
2661
+
2662
+	/**
2663
+	 * @var string $current_espresso_theme
2664
+	 */
2665
+	public $current_espresso_theme;
2666
+
2667
+	/**
2668
+	 * @var EE_Ticket_Selector_Config $EED_Ticket_Selector
2669
+	 */
2670
+	public $EED_Ticket_Selector;
2671
+
2672
+	/**
2673
+	 * @var EE_Event_Single_Config $EED_Event_Single
2674
+	 */
2675
+	public $EED_Event_Single;
2676
+
2677
+	/**
2678
+	 * @var EE_Events_Archive_Config $EED_Events_Archive
2679
+	 */
2680
+	public $EED_Events_Archive;
2681
+
2682
+
2683
+
2684
+	/**
2685
+	 *    class constructor
2686
+	 *
2687
+	 * @access    public
2688
+	 */
2689
+	public function __construct()
2690
+	{
2691
+		// set default template settings
2692
+		$this->enable_default_style = true;
2693
+		$this->custom_style_sheet = null;
2694
+		$this->display_address_in_regform = true;
2695
+		$this->display_description_on_multi_reg_page = false;
2696
+		$this->use_custom_templates = false;
2697
+		$this->current_espresso_theme = 'Espresso_Arabica_2014';
2698
+		$this->EED_Event_Single = null;
2699
+		$this->EED_Events_Archive = null;
2700
+		$this->EED_Ticket_Selector = null;
2701
+	}
2702 2702
 
2703 2703
 }
2704 2704
 
@@ -2710,115 +2710,115 @@  discard block
 block discarded – undo
2710 2710
 class EE_Map_Config extends EE_Config_Base
2711 2711
 {
2712 2712
 
2713
-    /**
2714
-     * @var boolean $use_google_maps
2715
-     */
2716
-    public $use_google_maps;
2717
-
2718
-    /**
2719
-     * @var string $api_key
2720
-     */
2721
-    public $google_map_api_key;
2722
-
2723
-    /**
2724
-     * @var int $event_details_map_width
2725
-     */
2726
-    public $event_details_map_width;
2727
-
2728
-    /**
2729
-     * @var int $event_details_map_height
2730
-     */
2731
-    public $event_details_map_height;
2732
-
2733
-    /**
2734
-     * @var int $event_details_map_zoom
2735
-     */
2736
-    public $event_details_map_zoom;
2737
-
2738
-    /**
2739
-     * @var boolean $event_details_display_nav
2740
-     */
2741
-    public $event_details_display_nav;
2742
-
2743
-    /**
2744
-     * @var boolean $event_details_nav_size
2745
-     */
2746
-    public $event_details_nav_size;
2747
-
2748
-    /**
2749
-     * @var string $event_details_control_type
2750
-     */
2751
-    public $event_details_control_type;
2752
-
2753
-    /**
2754
-     * @var string $event_details_map_align
2755
-     */
2756
-    public $event_details_map_align;
2757
-
2758
-    /**
2759
-     * @var int $event_list_map_width
2760
-     */
2761
-    public $event_list_map_width;
2762
-
2763
-    /**
2764
-     * @var int $event_list_map_height
2765
-     */
2766
-    public $event_list_map_height;
2767
-
2768
-    /**
2769
-     * @var int $event_list_map_zoom
2770
-     */
2771
-    public $event_list_map_zoom;
2772
-
2773
-    /**
2774
-     * @var boolean $event_list_display_nav
2775
-     */
2776
-    public $event_list_display_nav;
2777
-
2778
-    /**
2779
-     * @var boolean $event_list_nav_size
2780
-     */
2781
-    public $event_list_nav_size;
2782
-
2783
-    /**
2784
-     * @var string $event_list_control_type
2785
-     */
2786
-    public $event_list_control_type;
2787
-
2788
-    /**
2789
-     * @var string $event_list_map_align
2790
-     */
2791
-    public $event_list_map_align;
2792
-
2793
-
2794
-
2795
-    /**
2796
-     *    class constructor
2797
-     *
2798
-     * @access    public
2799
-     */
2800
-    public function __construct()
2801
-    {
2802
-        // set default map settings
2803
-        $this->use_google_maps = true;
2804
-        $this->google_map_api_key = '';
2805
-        // for event details pages (reg page)
2806
-        $this->event_details_map_width = 585;            // ee_map_width_single
2807
-        $this->event_details_map_height = 362;            // ee_map_height_single
2808
-        $this->event_details_map_zoom = 14;            // ee_map_zoom_single
2809
-        $this->event_details_display_nav = true;            // ee_map_nav_display_single
2810
-        $this->event_details_nav_size = false;            // ee_map_nav_size_single
2811
-        $this->event_details_control_type = 'default';        // ee_map_type_control_single
2812
-        $this->event_details_map_align = 'center';            // ee_map_align_single
2813
-        // for event list pages
2814
-        $this->event_list_map_width = 300;            // ee_map_width
2815
-        $this->event_list_map_height = 185;        // ee_map_height
2816
-        $this->event_list_map_zoom = 12;            // ee_map_zoom
2817
-        $this->event_list_display_nav = false;        // ee_map_nav_display
2818
-        $this->event_list_nav_size = true;            // ee_map_nav_size
2819
-        $this->event_list_control_type = 'dropdown';        // ee_map_type_control
2820
-        $this->event_list_map_align = 'center';            // ee_map_align
2821
-    }
2713
+	/**
2714
+	 * @var boolean $use_google_maps
2715
+	 */
2716
+	public $use_google_maps;
2717
+
2718
+	/**
2719
+	 * @var string $api_key
2720
+	 */
2721
+	public $google_map_api_key;
2722
+
2723
+	/**
2724
+	 * @var int $event_details_map_width
2725
+	 */
2726
+	public $event_details_map_width;
2727
+
2728
+	/**
2729
+	 * @var int $event_details_map_height
2730
+	 */
2731
+	public $event_details_map_height;
2732
+
2733
+	/**
2734
+	 * @var int $event_details_map_zoom
2735
+	 */
2736
+	public $event_details_map_zoom;
2737
+
2738
+	/**
2739
+	 * @var boolean $event_details_display_nav
2740
+	 */
2741
+	public $event_details_display_nav;
2742
+
2743
+	/**
2744
+	 * @var boolean $event_details_nav_size
2745
+	 */
2746
+	public $event_details_nav_size;
2747
+
2748
+	/**
2749
+	 * @var string $event_details_control_type
2750
+	 */
2751
+	public $event_details_control_type;
2752
+
2753
+	/**
2754
+	 * @var string $event_details_map_align
2755
+	 */
2756
+	public $event_details_map_align;
2757
+
2758
+	/**
2759
+	 * @var int $event_list_map_width
2760
+	 */
2761
+	public $event_list_map_width;
2762
+
2763
+	/**
2764
+	 * @var int $event_list_map_height
2765
+	 */
2766
+	public $event_list_map_height;
2767
+
2768
+	/**
2769
+	 * @var int $event_list_map_zoom
2770
+	 */
2771
+	public $event_list_map_zoom;
2772
+
2773
+	/**
2774
+	 * @var boolean $event_list_display_nav
2775
+	 */
2776
+	public $event_list_display_nav;
2777
+
2778
+	/**
2779
+	 * @var boolean $event_list_nav_size
2780
+	 */
2781
+	public $event_list_nav_size;
2782
+
2783
+	/**
2784
+	 * @var string $event_list_control_type
2785
+	 */
2786
+	public $event_list_control_type;
2787
+
2788
+	/**
2789
+	 * @var string $event_list_map_align
2790
+	 */
2791
+	public $event_list_map_align;
2792
+
2793
+
2794
+
2795
+	/**
2796
+	 *    class constructor
2797
+	 *
2798
+	 * @access    public
2799
+	 */
2800
+	public function __construct()
2801
+	{
2802
+		// set default map settings
2803
+		$this->use_google_maps = true;
2804
+		$this->google_map_api_key = '';
2805
+		// for event details pages (reg page)
2806
+		$this->event_details_map_width = 585;            // ee_map_width_single
2807
+		$this->event_details_map_height = 362;            // ee_map_height_single
2808
+		$this->event_details_map_zoom = 14;            // ee_map_zoom_single
2809
+		$this->event_details_display_nav = true;            // ee_map_nav_display_single
2810
+		$this->event_details_nav_size = false;            // ee_map_nav_size_single
2811
+		$this->event_details_control_type = 'default';        // ee_map_type_control_single
2812
+		$this->event_details_map_align = 'center';            // ee_map_align_single
2813
+		// for event list pages
2814
+		$this->event_list_map_width = 300;            // ee_map_width
2815
+		$this->event_list_map_height = 185;        // ee_map_height
2816
+		$this->event_list_map_zoom = 12;            // ee_map_zoom
2817
+		$this->event_list_display_nav = false;        // ee_map_nav_display
2818
+		$this->event_list_nav_size = true;            // ee_map_nav_size
2819
+		$this->event_list_control_type = 'dropdown';        // ee_map_type_control
2820
+		$this->event_list_map_align = 'center';            // ee_map_align
2821
+	}
2822 2822
 
2823 2823
 }
2824 2824
 
@@ -2830,47 +2830,47 @@  discard block
 block discarded – undo
2830 2830
 class EE_Events_Archive_Config extends EE_Config_Base
2831 2831
 {
2832 2832
 
2833
-    public $display_status_banner;
2833
+	public $display_status_banner;
2834 2834
 
2835
-    public $display_description;
2835
+	public $display_description;
2836 2836
 
2837
-    public $display_ticket_selector;
2837
+	public $display_ticket_selector;
2838 2838
 
2839
-    public $display_datetimes;
2839
+	public $display_datetimes;
2840 2840
 
2841
-    public $display_venue;
2841
+	public $display_venue;
2842 2842
 
2843
-    public $display_expired_events;
2843
+	public $display_expired_events;
2844 2844
 
2845
-    public $use_sortable_display_order;
2845
+	public $use_sortable_display_order;
2846 2846
 
2847
-    public $display_order_tickets;
2847
+	public $display_order_tickets;
2848 2848
 
2849
-    public $display_order_datetimes;
2849
+	public $display_order_datetimes;
2850 2850
 
2851
-    public $display_order_event;
2851
+	public $display_order_event;
2852 2852
 
2853
-    public $display_order_venue;
2853
+	public $display_order_venue;
2854 2854
 
2855 2855
 
2856 2856
 
2857
-    /**
2858
-     *    class constructor
2859
-     */
2860
-    public function __construct()
2861
-    {
2862
-        $this->display_status_banner = 0;
2863
-        $this->display_description = 1;
2864
-        $this->display_ticket_selector = 0;
2865
-        $this->display_datetimes = 1;
2866
-        $this->display_venue = 0;
2867
-        $this->display_expired_events = 0;
2868
-        $this->use_sortable_display_order = false;
2869
-        $this->display_order_tickets = 100;
2870
-        $this->display_order_datetimes = 110;
2871
-        $this->display_order_event = 120;
2872
-        $this->display_order_venue = 130;
2873
-    }
2857
+	/**
2858
+	 *    class constructor
2859
+	 */
2860
+	public function __construct()
2861
+	{
2862
+		$this->display_status_banner = 0;
2863
+		$this->display_description = 1;
2864
+		$this->display_ticket_selector = 0;
2865
+		$this->display_datetimes = 1;
2866
+		$this->display_venue = 0;
2867
+		$this->display_expired_events = 0;
2868
+		$this->use_sortable_display_order = false;
2869
+		$this->display_order_tickets = 100;
2870
+		$this->display_order_datetimes = 110;
2871
+		$this->display_order_event = 120;
2872
+		$this->display_order_venue = 130;
2873
+	}
2874 2874
 }
2875 2875
 
2876 2876
 
@@ -2881,35 +2881,35 @@  discard block
 block discarded – undo
2881 2881
 class EE_Event_Single_Config extends EE_Config_Base
2882 2882
 {
2883 2883
 
2884
-    public $display_status_banner_single;
2884
+	public $display_status_banner_single;
2885 2885
 
2886
-    public $display_venue;
2886
+	public $display_venue;
2887 2887
 
2888
-    public $use_sortable_display_order;
2888
+	public $use_sortable_display_order;
2889 2889
 
2890
-    public $display_order_tickets;
2890
+	public $display_order_tickets;
2891 2891
 
2892
-    public $display_order_datetimes;
2892
+	public $display_order_datetimes;
2893 2893
 
2894
-    public $display_order_event;
2894
+	public $display_order_event;
2895 2895
 
2896
-    public $display_order_venue;
2896
+	public $display_order_venue;
2897 2897
 
2898 2898
 
2899 2899
 
2900
-    /**
2901
-     *    class constructor
2902
-     */
2903
-    public function __construct()
2904
-    {
2905
-        $this->display_status_banner_single = 0;
2906
-        $this->display_venue = 1;
2907
-        $this->use_sortable_display_order = false;
2908
-        $this->display_order_tickets = 100;
2909
-        $this->display_order_datetimes = 110;
2910
-        $this->display_order_event = 120;
2911
-        $this->display_order_venue = 130;
2912
-    }
2900
+	/**
2901
+	 *    class constructor
2902
+	 */
2903
+	public function __construct()
2904
+	{
2905
+		$this->display_status_banner_single = 0;
2906
+		$this->display_venue = 1;
2907
+		$this->use_sortable_display_order = false;
2908
+		$this->display_order_tickets = 100;
2909
+		$this->display_order_datetimes = 110;
2910
+		$this->display_order_event = 120;
2911
+		$this->display_order_venue = 130;
2912
+	}
2913 2913
 }
2914 2914
 
2915 2915
 
@@ -2920,152 +2920,152 @@  discard block
 block discarded – undo
2920 2920
 class EE_Ticket_Selector_Config extends EE_Config_Base
2921 2921
 {
2922 2922
 
2923
-    /**
2924
-     * constant to indicate that a datetime selector should NEVER be shown for ticket selectors
2925
-     */
2926
-    const DO_NOT_SHOW_DATETIME_SELECTOR = 'no_datetime_selector';
2927
-
2928
-    /**
2929
-     * constant to indicate that a datetime selector should only be shown for ticket selectors
2930
-     * when the number of datetimes for the event matches the value set for $datetime_selector_threshold
2931
-     */
2932
-    const MAYBE_SHOW_DATETIME_SELECTOR = 'maybe_datetime_selector';
2933
-
2934
-    /**
2935
-     * @var boolean $show_ticket_sale_columns
2936
-     */
2937
-    public $show_ticket_sale_columns;
2938
-
2939
-    /**
2940
-     * @var boolean $show_ticket_details
2941
-     */
2942
-    public $show_ticket_details;
2943
-
2944
-    /**
2945
-     * @var boolean $show_expired_tickets
2946
-     */
2947
-    public $show_expired_tickets;
2948
-
2949
-    /**
2950
-     * whether or not to display a dropdown box populated with event datetimes
2951
-     * that toggles which tickets are displayed for a ticket selector.
2952
-     * uses one of the *_DATETIME_SELECTOR constants defined above
2953
-     *
2954
-     * @var string $show_datetime_selector
2955
-     */
2956
-    private $show_datetime_selector = 'no_datetime_selector';
2957
-
2958
-    /**
2959
-     * the number of datetimes an event has to have before conditionally displaying a datetime selector
2960
-     *
2961
-     * @var int $datetime_selector_threshold
2962
-     */
2963
-    private $datetime_selector_threshold = 3;
2964
-
2965
-
2966
-
2967
-    /**
2968
-     *    class constructor
2969
-     */
2970
-    public function __construct()
2971
-    {
2972
-        $this->show_ticket_sale_columns = true;
2973
-        $this->show_ticket_details = true;
2974
-        $this->show_expired_tickets = true;
2975
-        $this->show_datetime_selector = \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
2976
-        $this->datetime_selector_threshold = 3;
2977
-    }
2978
-
2979
-
2980
-
2981
-    /**
2982
-     * returns true if a datetime selector should be displayed
2983
-     *
2984
-     * @param array $datetimes
2985
-     * @return bool
2986
-     */
2987
-    public function showDatetimeSelector(array $datetimes)
2988
-    {
2989
-        // if the settings are NOT: don't show OR below threshold, THEN active = true
2990
-        return ! (
2991
-            $this->getShowDatetimeSelector() === \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR
2992
-            || (
2993
-                $this->getShowDatetimeSelector() === \EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR
2994
-                && count($datetimes) < $this->getDatetimeSelectorThreshold()
2995
-            )
2996
-        );
2997
-    }
2998
-
2999
-
3000
-
3001
-    /**
3002
-     * @return string
3003
-     */
3004
-    public function getShowDatetimeSelector()
3005
-    {
3006
-        return $this->show_datetime_selector;
3007
-    }
3008
-
3009
-
3010
-
3011
-    /**
3012
-     * @param bool $keys_only
3013
-     * @return array
3014
-     */
3015
-    public function getShowDatetimeSelectorOptions($keys_only = true)
3016
-    {
3017
-        return $keys_only
3018
-            ? array(
3019
-                \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR,
3020
-                \EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR,
3021
-            )
3022
-            : array(
3023
-                \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR => esc_html__(
3024
-                    'Do not show date & time filter', 'event_espresso'
3025
-                ),
3026
-                \EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR  => esc_html__(
3027
-                    'Maybe show date & time filter', 'event_espresso'
3028
-                ),
3029
-            );
3030
-    }
3031
-
3032
-
3033
-
3034
-    /**
3035
-     * @param string $show_datetime_selector
3036
-     */
3037
-    public function setShowDatetimeSelector($show_datetime_selector)
3038
-    {
3039
-        $this->show_datetime_selector = in_array(
3040
-            $show_datetime_selector,
3041
-            $this->getShowDatetimeSelectorOptions(),
3042
-            true
3043
-        )
3044
-            ? $show_datetime_selector
3045
-            : \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
3046
-    }
3047
-
3048
-
3049
-
3050
-    /**
3051
-     * @return int
3052
-     */
3053
-    public function getDatetimeSelectorThreshold()
3054
-    {
3055
-        return $this->datetime_selector_threshold;
3056
-    }
3057
-
3058
-
3059
-
3060
-
3061
-    /**
3062
-     * @param int $datetime_selector_threshold
3063
-     */
3064
-    public function setDatetimeSelectorThreshold($datetime_selector_threshold)
3065
-    {
3066
-        $datetime_selector_threshold = absint($datetime_selector_threshold);
3067
-        $this->datetime_selector_threshold = $datetime_selector_threshold ? $datetime_selector_threshold : 3;
3068
-    }
2923
+	/**
2924
+	 * constant to indicate that a datetime selector should NEVER be shown for ticket selectors
2925
+	 */
2926
+	const DO_NOT_SHOW_DATETIME_SELECTOR = 'no_datetime_selector';
2927
+
2928
+	/**
2929
+	 * constant to indicate that a datetime selector should only be shown for ticket selectors
2930
+	 * when the number of datetimes for the event matches the value set for $datetime_selector_threshold
2931
+	 */
2932
+	const MAYBE_SHOW_DATETIME_SELECTOR = 'maybe_datetime_selector';
2933
+
2934
+	/**
2935
+	 * @var boolean $show_ticket_sale_columns
2936
+	 */
2937
+	public $show_ticket_sale_columns;
2938
+
2939
+	/**
2940
+	 * @var boolean $show_ticket_details
2941
+	 */
2942
+	public $show_ticket_details;
2943
+
2944
+	/**
2945
+	 * @var boolean $show_expired_tickets
2946
+	 */
2947
+	public $show_expired_tickets;
2948
+
2949
+	/**
2950
+	 * whether or not to display a dropdown box populated with event datetimes
2951
+	 * that toggles which tickets are displayed for a ticket selector.
2952
+	 * uses one of the *_DATETIME_SELECTOR constants defined above
2953
+	 *
2954
+	 * @var string $show_datetime_selector
2955
+	 */
2956
+	private $show_datetime_selector = 'no_datetime_selector';
2957
+
2958
+	/**
2959
+	 * the number of datetimes an event has to have before conditionally displaying a datetime selector
2960
+	 *
2961
+	 * @var int $datetime_selector_threshold
2962
+	 */
2963
+	private $datetime_selector_threshold = 3;
2964
+
2965
+
2966
+
2967
+	/**
2968
+	 *    class constructor
2969
+	 */
2970
+	public function __construct()
2971
+	{
2972
+		$this->show_ticket_sale_columns = true;
2973
+		$this->show_ticket_details = true;
2974
+		$this->show_expired_tickets = true;
2975
+		$this->show_datetime_selector = \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
2976
+		$this->datetime_selector_threshold = 3;
2977
+	}
2978
+
2979
+
2980
+
2981
+	/**
2982
+	 * returns true if a datetime selector should be displayed
2983
+	 *
2984
+	 * @param array $datetimes
2985
+	 * @return bool
2986
+	 */
2987
+	public function showDatetimeSelector(array $datetimes)
2988
+	{
2989
+		// if the settings are NOT: don't show OR below threshold, THEN active = true
2990
+		return ! (
2991
+			$this->getShowDatetimeSelector() === \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR
2992
+			|| (
2993
+				$this->getShowDatetimeSelector() === \EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR
2994
+				&& count($datetimes) < $this->getDatetimeSelectorThreshold()
2995
+			)
2996
+		);
2997
+	}
2998
+
2999
+
3000
+
3001
+	/**
3002
+	 * @return string
3003
+	 */
3004
+	public function getShowDatetimeSelector()
3005
+	{
3006
+		return $this->show_datetime_selector;
3007
+	}
3008
+
3009
+
3010
+
3011
+	/**
3012
+	 * @param bool $keys_only
3013
+	 * @return array
3014
+	 */
3015
+	public function getShowDatetimeSelectorOptions($keys_only = true)
3016
+	{
3017
+		return $keys_only
3018
+			? array(
3019
+				\EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR,
3020
+				\EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR,
3021
+			)
3022
+			: array(
3023
+				\EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR => esc_html__(
3024
+					'Do not show date & time filter', 'event_espresso'
3025
+				),
3026
+				\EE_Ticket_Selector_Config::MAYBE_SHOW_DATETIME_SELECTOR  => esc_html__(
3027
+					'Maybe show date & time filter', 'event_espresso'
3028
+				),
3029
+			);
3030
+	}
3031
+
3032
+
3033
+
3034
+	/**
3035
+	 * @param string $show_datetime_selector
3036
+	 */
3037
+	public function setShowDatetimeSelector($show_datetime_selector)
3038
+	{
3039
+		$this->show_datetime_selector = in_array(
3040
+			$show_datetime_selector,
3041
+			$this->getShowDatetimeSelectorOptions(),
3042
+			true
3043
+		)
3044
+			? $show_datetime_selector
3045
+			: \EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR;
3046
+	}
3047
+
3048
+
3049
+
3050
+	/**
3051
+	 * @return int
3052
+	 */
3053
+	public function getDatetimeSelectorThreshold()
3054
+	{
3055
+		return $this->datetime_selector_threshold;
3056
+	}
3057
+
3058
+
3059
+
3060
+
3061
+	/**
3062
+	 * @param int $datetime_selector_threshold
3063
+	 */
3064
+	public function setDatetimeSelectorThreshold($datetime_selector_threshold)
3065
+	{
3066
+		$datetime_selector_threshold = absint($datetime_selector_threshold);
3067
+		$this->datetime_selector_threshold = $datetime_selector_threshold ? $datetime_selector_threshold : 3;
3068
+	}
3069 3069
 
3070 3070
 
3071 3071
 
@@ -3083,85 +3083,85 @@  discard block
 block discarded – undo
3083 3083
 class EE_Environment_Config extends EE_Config_Base
3084 3084
 {
3085 3085
 
3086
-    /**
3087
-     * Hold any php environment variables that we want to track.
3088
-     *
3089
-     * @var stdClass;
3090
-     */
3091
-    public $php;
3092
-
3093
-
3094
-
3095
-    /**
3096
-     *    constructor
3097
-     */
3098
-    public function __construct()
3099
-    {
3100
-        $this->php = new stdClass();
3101
-        $this->_set_php_values();
3102
-    }
3103
-
3104
-
3105
-
3106
-    /**
3107
-     * This sets the php environment variables.
3108
-     *
3109
-     * @since 4.4.0
3110
-     * @return void
3111
-     */
3112
-    protected function _set_php_values()
3113
-    {
3114
-        $this->php->max_input_vars = ini_get('max_input_vars');
3115
-        $this->php->version = phpversion();
3116
-    }
3117
-
3118
-
3119
-
3120
-    /**
3121
-     * helper method for determining whether input_count is
3122
-     * reaching the potential maximum the server can handle
3123
-     * according to max_input_vars
3124
-     *
3125
-     * @param int   $input_count the count of input vars.
3126
-     * @return array {
3127
-     *                           An array that represents whether available space and if no available space the error
3128
-     *                           message.
3129
-     * @type bool   $has_space   whether more inputs can be added.
3130
-     * @type string $msg         Any message to be displayed.
3131
-     *                           }
3132
-     */
3133
-    public function max_input_vars_limit_check($input_count = 0)
3134
-    {
3135
-        if (! empty($this->php->max_input_vars)
3136
-            && ($input_count >= $this->php->max_input_vars)
3137
-            && (PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 3 && PHP_RELEASE_VERSION >= 9)
3138
-        ) {
3139
-            return sprintf(
3140
-                __(
3141
-                    'The maximum number of inputs on this page has been exceeded.  You cannot add anymore items (i.e. tickets, datetimes, custom fields) on this page because of your servers PHP "max_input_vars" setting.%1$sThere are %2$d inputs and the maximum amount currently allowed by your server is %3$d.',
3142
-                    'event_espresso'
3143
-                ),
3144
-                '<br>',
3145
-                $input_count,
3146
-                $this->php->max_input_vars
3147
-            );
3148
-        } else {
3149
-            return '';
3150
-        }
3151
-    }
3152
-
3153
-
3154
-
3155
-    /**
3156
-     * The purpose of this method is just to force rechecking php values so if they've changed, they get updated.
3157
-     *
3158
-     * @since 4.4.1
3159
-     * @return void
3160
-     */
3161
-    public function recheck_values()
3162
-    {
3163
-        $this->_set_php_values();
3164
-    }
3086
+	/**
3087
+	 * Hold any php environment variables that we want to track.
3088
+	 *
3089
+	 * @var stdClass;
3090
+	 */
3091
+	public $php;
3092
+
3093
+
3094
+
3095
+	/**
3096
+	 *    constructor
3097
+	 */
3098
+	public function __construct()
3099
+	{
3100
+		$this->php = new stdClass();
3101
+		$this->_set_php_values();
3102
+	}
3103
+
3104
+
3105
+
3106
+	/**
3107
+	 * This sets the php environment variables.
3108
+	 *
3109
+	 * @since 4.4.0
3110
+	 * @return void
3111
+	 */
3112
+	protected function _set_php_values()
3113
+	{
3114
+		$this->php->max_input_vars = ini_get('max_input_vars');
3115
+		$this->php->version = phpversion();
3116
+	}
3117
+
3118
+
3119
+
3120
+	/**
3121
+	 * helper method for determining whether input_count is
3122
+	 * reaching the potential maximum the server can handle
3123
+	 * according to max_input_vars
3124
+	 *
3125
+	 * @param int   $input_count the count of input vars.
3126
+	 * @return array {
3127
+	 *                           An array that represents whether available space and if no available space the error
3128
+	 *                           message.
3129
+	 * @type bool   $has_space   whether more inputs can be added.
3130
+	 * @type string $msg         Any message to be displayed.
3131
+	 *                           }
3132
+	 */
3133
+	public function max_input_vars_limit_check($input_count = 0)
3134
+	{
3135
+		if (! empty($this->php->max_input_vars)
3136
+			&& ($input_count >= $this->php->max_input_vars)
3137
+			&& (PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 3 && PHP_RELEASE_VERSION >= 9)
3138
+		) {
3139
+			return sprintf(
3140
+				__(
3141
+					'The maximum number of inputs on this page has been exceeded.  You cannot add anymore items (i.e. tickets, datetimes, custom fields) on this page because of your servers PHP "max_input_vars" setting.%1$sThere are %2$d inputs and the maximum amount currently allowed by your server is %3$d.',
3142
+					'event_espresso'
3143
+				),
3144
+				'<br>',
3145
+				$input_count,
3146
+				$this->php->max_input_vars
3147
+			);
3148
+		} else {
3149
+			return '';
3150
+		}
3151
+	}
3152
+
3153
+
3154
+
3155
+	/**
3156
+	 * The purpose of this method is just to force rechecking php values so if they've changed, they get updated.
3157
+	 *
3158
+	 * @since 4.4.1
3159
+	 * @return void
3160
+	 */
3161
+	public function recheck_values()
3162
+	{
3163
+		$this->_set_php_values();
3164
+	}
3165 3165
 
3166 3166
 
3167 3167
 
@@ -3179,22 +3179,22 @@  discard block
 block discarded – undo
3179 3179
 class EE_Tax_Config extends EE_Config_Base
3180 3180
 {
3181 3181
 
3182
-    /*
3182
+	/*
3183 3183
      * flag to indicate whether or not to display ticket prices with the taxes included
3184 3184
      *
3185 3185
      * @var boolean $prices_displayed_including_taxes
3186 3186
      */
3187
-    public $prices_displayed_including_taxes;
3187
+	public $prices_displayed_including_taxes;
3188 3188
 
3189 3189
 
3190 3190
 
3191
-    /**
3192
-     *    class constructor
3193
-     */
3194
-    public function __construct()
3195
-    {
3196
-        $this->prices_displayed_including_taxes = true;
3197
-    }
3191
+	/**
3192
+	 *    class constructor
3193
+	 */
3194
+	public function __construct()
3195
+	{
3196
+		$this->prices_displayed_including_taxes = true;
3197
+	}
3198 3198
 }
3199 3199
 
3200 3200
 
@@ -3209,17 +3209,17 @@  discard block
 block discarded – undo
3209 3209
 class EE_Messages_Config extends EE_Config_Base
3210 3210
 {
3211 3211
 
3212
-    /**
3213
-     * This is an integer representing the deletion threshold in months for when old messages will get deleted.
3214
-     * A value of 0 represents never deleting.  Default is 0.
3215
-     *
3216
-     * @var integer
3217
-     */
3218
-    public $delete_threshold;
3219
-
3220
-    public function __construct() {
3221
-        $this->delete_threshold = 0;
3222
-    }
3212
+	/**
3213
+	 * This is an integer representing the deletion threshold in months for when old messages will get deleted.
3214
+	 * A value of 0 represents never deleting.  Default is 0.
3215
+	 *
3216
+	 * @var integer
3217
+	 */
3218
+	public $delete_threshold;
3219
+
3220
+	public function __construct() {
3221
+		$this->delete_threshold = 0;
3222
+	}
3223 3223
 }
3224 3224
 
3225 3225
 
@@ -3231,34 +3231,34 @@  discard block
 block discarded – undo
3231 3231
 class EE_Gateway_Config extends EE_Config_Base
3232 3232
 {
3233 3233
 
3234
-    /**
3235
-     * Array with keys that are payment gateways slugs, and values are arrays
3236
-     * with any config info the gateway wants to store
3237
-     *
3238
-     * @var array
3239
-     */
3240
-    public $payment_settings;
3241
-
3242
-    /**
3243
-     * Where keys are gateway slugs, and values are booleans indicating whether or not
3244
-     * the gateway is stored in the uploads directory
3245
-     *
3246
-     * @var array
3247
-     */
3248
-    public $active_gateways;
3249
-
3250
-
3251
-
3252
-    /**
3253
-     *    class constructor
3254
-     *
3255
-     * @deprecated
3256
-     */
3257
-    public function __construct()
3258
-    {
3259
-        $this->payment_settings = array();
3260
-        $this->active_gateways = array('Invoice' => false);
3261
-    }
3234
+	/**
3235
+	 * Array with keys that are payment gateways slugs, and values are arrays
3236
+	 * with any config info the gateway wants to store
3237
+	 *
3238
+	 * @var array
3239
+	 */
3240
+	public $payment_settings;
3241
+
3242
+	/**
3243
+	 * Where keys are gateway slugs, and values are booleans indicating whether or not
3244
+	 * the gateway is stored in the uploads directory
3245
+	 *
3246
+	 * @var array
3247
+	 */
3248
+	public $active_gateways;
3249
+
3250
+
3251
+
3252
+	/**
3253
+	 *    class constructor
3254
+	 *
3255
+	 * @deprecated
3256
+	 */
3257
+	public function __construct()
3258
+	{
3259
+		$this->payment_settings = array();
3260
+		$this->active_gateways = array('Invoice' => false);
3261
+	}
3262 3262
 }
3263 3263
 
3264 3264
 // End of file EE_Config.core.php
Please login to merge, or discard this patch.
core/db_classes/EE_Base_Class.class.php 3 patches
Doc Comments   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -712,7 +712,7 @@  discard block
 block discarded – undo
712 712
      *
713 713
      * @param \EE_Datetime_Field $datetime_field
714 714
      * @param bool               $pretty
715
-     * @param null               $date_or_time
715
+     * @param string|null               $date_or_time
716 716
      * @return void
717 717
      * @throws InvalidArgumentException
718 718
      * @throws InvalidInterfaceException
@@ -1066,7 +1066,7 @@  discard block
 block discarded – undo
1066 1066
      *
1067 1067
      * @param null  $field_to_order_by  What field is being used as the reference point.
1068 1068
      * @param array $query_params       Any additional conditions on the query.
1069
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1069
+     * @param string  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070 1070
      *                                  you can indicate just the columns you want returned
1071 1071
      * @return array|EE_Base_Class
1072 1072
      * @throws ReflectionException
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
      *
1096 1096
      * @param null  $field_to_order_by  What field is being used as the reference point.
1097 1097
      * @param array $query_params       Any additional conditions on the query.
1098
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1098
+     * @param string  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099 1099
      *                                  you can indicate just the column you want returned
1100 1100
      * @return array|EE_Base_Class
1101 1101
      * @throws ReflectionException
@@ -1178,7 +1178,7 @@  discard block
 block discarded – undo
1178 1178
      * This method simply returns the RAW unprocessed value for the given property in this class
1179 1179
      *
1180 1180
      * @param  string $field_name A valid fieldname
1181
-     * @return mixed              Whatever the raw value stored on the property is.
1181
+     * @return integer|null              Whatever the raw value stored on the property is.
1182 1182
      * @throws ReflectionException
1183 1183
      * @throws InvalidArgumentException
1184 1184
      * @throws InvalidInterfaceException
@@ -1526,7 +1526,7 @@  discard block
 block discarded – undo
1526 1526
      * sets the time on a datetime property
1527 1527
      *
1528 1528
      * @access protected
1529
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1529
+     * @param string $time      a valid time string for php datetime functions (or DateTime object)
1530 1530
      * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1531 1531
      * @throws ReflectionException
1532 1532
      * @throws InvalidArgumentException
@@ -1544,7 +1544,7 @@  discard block
 block discarded – undo
1544 1544
      * sets the date on a datetime property
1545 1545
      *
1546 1546
      * @access protected
1547
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1547
+     * @param string $date      a valid date string for php datetime functions ( or DateTime object)
1548 1548
      * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1549 1549
      * @throws ReflectionException
1550 1550
      * @throws InvalidArgumentException
@@ -2066,7 +2066,7 @@  discard block
 block discarded – undo
2066 2066
      *
2067 2067
      * @param  array  $props_n_values   incoming array of properties and their values
2068 2068
      * @param  string $classname        the classname of the child class
2069
-     * @param null    $timezone
2069
+     * @param string|null    $timezone
2070 2070
      * @param array   $date_formats     incoming date_formats in an array where the first value is the
2071 2071
      *                                  date_format and the second value is the time format
2072 2072
      * @return mixed (EE_Base_Class|bool)
@@ -2153,7 +2153,7 @@  discard block
 block discarded – undo
2153 2153
      * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2154 2154
      *
2155 2155
      * @param string $model_classname
2156
-     * @param null   $timezone
2156
+     * @param string|null   $timezone
2157 2157
      * @return EEM_Base
2158 2158
      * @throws ReflectionException
2159 2159
      * @throws InvalidArgumentException
@@ -2773,7 +2773,7 @@  discard block
 block discarded – undo
2773 2773
      *
2774 2774
      * @param string $meta_key
2775 2775
      * @param mixed  $meta_value
2776
-     * @param mixed  $previous_value
2776
+     * @param boolean  $previous_value
2777 2777
      * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2778 2778
      *                  NOTE: if the values haven't changed, returns 0
2779 2779
      * @throws InvalidArgumentException
Please login to merge, or discard this patch.
Indentation   +3141 added lines, -3141 removed lines patch added patch discarded remove patch
@@ -15,3147 +15,3147 @@
 block discarded – undo
15 15
 abstract class EE_Base_Class
16 16
 {
17 17
 
18
-    /**
19
-     * This is an array of the original properties and values provided during construction
20
-     * of this model object. (keys are model field names, values are their values).
21
-     * This list is important to remember so that when we are merging data from the db, we know
22
-     * which values to override and which to not override.
23
-     *
24
-     * @var array
25
-     */
26
-    protected $_props_n_values_provided_in_constructor;
27
-
28
-    /**
29
-     * Timezone
30
-     * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
-     * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
-     * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
-     * access to it.
34
-     *
35
-     * @var string
36
-     */
37
-    protected $_timezone;
38
-
39
-    /**
40
-     * date format
41
-     * pattern or format for displaying dates
42
-     *
43
-     * @var string $_dt_frmt
44
-     */
45
-    protected $_dt_frmt;
46
-
47
-    /**
48
-     * time format
49
-     * pattern or format for displaying time
50
-     *
51
-     * @var string $_tm_frmt
52
-     */
53
-    protected $_tm_frmt;
54
-
55
-    /**
56
-     * This property is for holding a cached array of object properties indexed by property name as the key.
57
-     * The purpose of this is for setting a cache on properties that may have calculated values after a
58
-     * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
-     * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
-     *
61
-     * @var array
62
-     */
63
-    protected $_cached_properties = array();
64
-
65
-    /**
66
-     * An array containing keys of the related model, and values are either an array of related mode objects or a
67
-     * single
68
-     * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
-     * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
-     * all others have an array)
71
-     *
72
-     * @var array
73
-     */
74
-    protected $_model_relations = array();
75
-
76
-    /**
77
-     * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
-     * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
-     *
80
-     * @var array
81
-     */
82
-    protected $_fields = array();
83
-
84
-    /**
85
-     * @var boolean indicating whether or not this model object is intended to ever be saved
86
-     * For example, we might create model objects intended to only be used for the duration
87
-     * of this request and to be thrown away, and if they were accidentally saved
88
-     * it would be a bug.
89
-     */
90
-    protected $_allow_persist = true;
91
-
92
-    /**
93
-     * @var boolean indicating whether or not this model object's properties have changed since construction
94
-     */
95
-    protected $_has_changes = false;
96
-
97
-    /**
98
-     * @var EEM_Base
99
-     */
100
-    protected $_model;
101
-
102
-    /**
103
-     * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
-     * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
-     * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
-     * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
-     * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
-     * array as:
109
-     * array(
110
-     *  'Registration_Count' => 24
111
-     * );
112
-     * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
-     * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
-     * info)
115
-     *
116
-     * @var array
117
-     */
118
-    protected $custom_selection_results = array();
119
-
120
-
121
-    /**
122
-     * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
-     * play nice
124
-     *
125
-     * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
-     *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
-     *                                                         TXN_amount, QST_name, etc) and values are their values
128
-     * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
-     *                                                         corresponding db model or not.
130
-     * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
-     *                                                         be in when instantiating a EE_Base_Class object.
132
-     * @param array   $date_formats                            An array of date formats to set on construct where first
133
-     *                                                         value is the date_format and second value is the time
134
-     *                                                         format.
135
-     * @throws InvalidArgumentException
136
-     * @throws InvalidInterfaceException
137
-     * @throws InvalidDataTypeException
138
-     * @throws EE_Error
139
-     * @throws ReflectionException
140
-     */
141
-    protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
-    {
143
-        $className = get_class($this);
144
-        do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
-        $model        = $this->get_model();
146
-        $model_fields = $model->field_settings(false);
147
-        // ensure $fieldValues is an array
148
-        $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
-        // verify client code has not passed any invalid field names
150
-        foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
152
-                throw new EE_Error(
153
-                    sprintf(
154
-                        esc_html__(
155
-                            'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
-                            'event_espresso'
157
-                        ),
158
-                        $field_name,
159
-                        get_class($this),
160
-                        implode(', ', array_keys($model_fields))
161
-                    )
162
-                );
163
-            }
164
-        }
165
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
167
-            list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
-        } else {
169
-            //set default formats for date and time
170
-            $this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
-            $this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
-        }
173
-        //if db model is instantiating
174
-        if ($bydb) {
175
-            //client code has indicated these field values are from the database
176
-            foreach ($model_fields as $fieldName => $field) {
177
-                $this->set_from_db(
178
-                    $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
-                );
181
-            }
182
-        } else {
183
-            //we're constructing a brand
184
-            //new instance of the model object. Generally, this means we'll need to do more field validation
185
-            foreach ($model_fields as $fieldName => $field) {
186
-                $this->set(
187
-                    $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
-                );
190
-            }
191
-        }
192
-        //remember what values were passed to this constructor
193
-        $this->_props_n_values_provided_in_constructor = $fieldValues;
194
-        //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
-            $model->add_to_entity_map($this);
197
-        }
198
-        //setup all the relations
199
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
202
-            } else {
203
-                $this->_model_relations[ $relation_name ] = array();
204
-            }
205
-        }
206
-        /**
207
-         * Action done at the end of each model object construction
208
-         *
209
-         * @param EE_Base_Class $this the model object just created
210
-         */
211
-        do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
-    }
213
-
214
-
215
-    /**
216
-     * Gets whether or not this model object is allowed to persist/be saved to the database.
217
-     *
218
-     * @return boolean
219
-     */
220
-    public function allow_persist()
221
-    {
222
-        return $this->_allow_persist;
223
-    }
224
-
225
-
226
-    /**
227
-     * Sets whether or not this model object should be allowed to be saved to the DB.
228
-     * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
-     * you got new information that somehow made you change your mind.
230
-     *
231
-     * @param boolean $allow_persist
232
-     * @return boolean
233
-     */
234
-    public function set_allow_persist($allow_persist)
235
-    {
236
-        return $this->_allow_persist = $allow_persist;
237
-    }
238
-
239
-
240
-    /**
241
-     * Gets the field's original value when this object was constructed during this request.
242
-     * This can be helpful when determining if a model object has changed or not
243
-     *
244
-     * @param string $field_name
245
-     * @return mixed|null
246
-     * @throws ReflectionException
247
-     * @throws InvalidArgumentException
248
-     * @throws InvalidInterfaceException
249
-     * @throws InvalidDataTypeException
250
-     * @throws EE_Error
251
-     */
252
-    public function get_original($field_name)
253
-    {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
-            && $field_settings = $this->get_model()->field_settings_for($field_name)
256
-        ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
-        }
259
-        return null;
260
-    }
261
-
262
-
263
-    /**
264
-     * @param EE_Base_Class $obj
265
-     * @return string
266
-     */
267
-    public function get_class($obj)
268
-    {
269
-        return get_class($obj);
270
-    }
271
-
272
-
273
-    /**
274
-     * Overrides parent because parent expects old models.
275
-     * This also doesn't do any validation, and won't work for serialized arrays
276
-     *
277
-     * @param    string $field_name
278
-     * @param    mixed  $field_value
279
-     * @param bool      $use_default
280
-     * @throws InvalidArgumentException
281
-     * @throws InvalidInterfaceException
282
-     * @throws InvalidDataTypeException
283
-     * @throws EE_Error
284
-     * @throws ReflectionException
285
-     * @throws ReflectionException
286
-     * @throws ReflectionException
287
-     */
288
-    public function set($field_name, $field_value, $use_default = false)
289
-    {
290
-        // if not using default and nothing has changed, and object has already been setup (has ID),
291
-        // then don't do anything
292
-        if (
293
-            ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
295
-            && $this->ID()
296
-        ) {
297
-            return;
298
-        }
299
-        $model              = $this->get_model();
300
-        $this->_has_changes = true;
301
-        $field_obj          = $model->field_settings_for($field_name);
302
-        if ($field_obj instanceof EE_Model_Field_Base) {
303
-            //			if ( method_exists( $field_obj, 'set_timezone' )) {
304
-            if ($field_obj instanceof EE_Datetime_Field) {
305
-                $field_obj->set_timezone($this->_timezone);
306
-                $field_obj->set_date_format($this->_dt_frmt);
307
-                $field_obj->set_time_format($this->_tm_frmt);
308
-            }
309
-            $holder_of_value = $field_obj->prepare_for_set($field_value);
310
-            //should the value be null?
311
-            if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
313
-                /**
314
-                 * To save having to refactor all the models, if a default value is used for a
315
-                 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
-                 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
-                 * object.
318
-                 *
319
-                 * @since 4.6.10+
320
-                 */
321
-                if (
322
-                    $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
325
-                ) {
326
-                    empty($this->_fields[ $field_name ])
327
-                        ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
329
-                }
330
-            } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
332
-            }
333
-            //if we're not in the constructor...
334
-            //now check if what we set was a primary key
335
-            if (
336
-                //note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
-                $this->_props_n_values_provided_in_constructor
338
-                && $field_value
339
-                && $field_name === $model->primary_key_name()
340
-            ) {
341
-                //if so, we want all this object's fields to be filled either with
342
-                //what we've explicitly set on this model
343
-                //or what we have in the db
344
-                // echo "setting primary key!";
345
-                $fields_on_model = self::_get_model(get_class($this))->field_settings();
346
-                $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
-                foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
-                        && $field_obj->get_name() !== $field_name
350
-                    ) {
351
-                        $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
-                    }
353
-                }
354
-                //oh this model object has an ID? well make sure its in the entity mapper
355
-                $model->add_to_entity_map($this);
356
-            }
357
-            //let's unset any cache for this field_name from the $_cached_properties property.
358
-            $this->_clear_cached_property($field_name);
359
-        } else {
360
-            throw new EE_Error(
361
-                sprintf(
362
-                    esc_html__(
363
-                        'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
-                        'event_espresso'
365
-                    ),
366
-                    $field_name
367
-                )
368
-            );
369
-        }
370
-    }
371
-
372
-
373
-    /**
374
-     * Set custom select values for model.
375
-     *
376
-     * @param array $custom_select_values
377
-     */
378
-    public function setCustomSelectsValues(array $custom_select_values)
379
-    {
380
-        $this->custom_selection_results = $custom_select_values;
381
-    }
382
-
383
-
384
-    /**
385
-     * Returns the custom select value for the provided alias if its set.
386
-     * If not set, returns null.
387
-     *
388
-     * @param string $alias
389
-     * @return string|int|float|null
390
-     */
391
-    public function getCustomSelect($alias)
392
-    {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
395
-            : null;
396
-    }
397
-
398
-
399
-    /**
400
-     * This sets the field value on the db column if it exists for the given $column_name or
401
-     * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
-     *
403
-     * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
-     * @param string $field_name  Must be the exact column name.
405
-     * @param mixed  $field_value The value to set.
406
-     * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
-     * @throws InvalidArgumentException
408
-     * @throws InvalidInterfaceException
409
-     * @throws InvalidDataTypeException
410
-     * @throws EE_Error
411
-     * @throws ReflectionException
412
-     */
413
-    public function set_field_or_extra_meta($field_name, $field_value)
414
-    {
415
-        if ($this->get_model()->has_field($field_name)) {
416
-            $this->set($field_name, $field_value);
417
-            return true;
418
-        }
419
-        //ensure this object is saved first so that extra meta can be properly related.
420
-        $this->save();
421
-        return $this->update_extra_meta($field_name, $field_value);
422
-    }
423
-
424
-
425
-    /**
426
-     * This retrieves the value of the db column set on this class or if that's not present
427
-     * it will attempt to retrieve from extra_meta if found.
428
-     * Example Usage:
429
-     * Via EE_Message child class:
430
-     * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
-     * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
-     * also have additional main fields specific to the messenger.  The system accommodates those extra
433
-     * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
-     * value for those extra fields dynamically via the EE_message object.
435
-     *
436
-     * @param  string $field_name expecting the fully qualified field name.
437
-     * @return mixed|null  value for the field if found.  null if not found.
438
-     * @throws ReflectionException
439
-     * @throws InvalidArgumentException
440
-     * @throws InvalidInterfaceException
441
-     * @throws InvalidDataTypeException
442
-     * @throws EE_Error
443
-     */
444
-    public function get_field_or_extra_meta($field_name)
445
-    {
446
-        if ($this->get_model()->has_field($field_name)) {
447
-            $column_value = $this->get($field_name);
448
-        } else {
449
-            //This isn't a column in the main table, let's see if it is in the extra meta.
450
-            $column_value = $this->get_extra_meta($field_name, true, null);
451
-        }
452
-        return $column_value;
453
-    }
454
-
455
-
456
-    /**
457
-     * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
-     * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
-     * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
-     * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
-     *
462
-     * @access public
463
-     * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
-     * @return void
465
-     * @throws InvalidArgumentException
466
-     * @throws InvalidInterfaceException
467
-     * @throws InvalidDataTypeException
468
-     * @throws EE_Error
469
-     * @throws ReflectionException
470
-     */
471
-    public function set_timezone($timezone = '')
472
-    {
473
-        $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
-        //make sure we clear all cached properties because they won't be relevant now
475
-        $this->_clear_cached_properties();
476
-        //make sure we update field settings and the date for all EE_Datetime_Fields
477
-        $model_fields = $this->get_model()->field_settings(false);
478
-        foreach ($model_fields as $field_name => $field_obj) {
479
-            if ($field_obj instanceof EE_Datetime_Field) {
480
-                $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
-                    $this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
483
-                }
484
-            }
485
-        }
486
-    }
487
-
488
-
489
-    /**
490
-     * This just returns whatever is set for the current timezone.
491
-     *
492
-     * @access public
493
-     * @return string timezone string
494
-     */
495
-    public function get_timezone()
496
-    {
497
-        return $this->_timezone;
498
-    }
499
-
500
-
501
-    /**
502
-     * This sets the internal date format to what is sent in to be used as the new default for the class
503
-     * internally instead of wp set date format options
504
-     *
505
-     * @since 4.6
506
-     * @param string $format should be a format recognizable by PHP date() functions.
507
-     */
508
-    public function set_date_format($format)
509
-    {
510
-        $this->_dt_frmt = $format;
511
-        //clear cached_properties because they won't be relevant now.
512
-        $this->_clear_cached_properties();
513
-    }
514
-
515
-
516
-    /**
517
-     * This sets the internal time format string to what is sent in to be used as the new default for the
518
-     * class internally instead of wp set time format options.
519
-     *
520
-     * @since 4.6
521
-     * @param string $format should be a format recognizable by PHP date() functions.
522
-     */
523
-    public function set_time_format($format)
524
-    {
525
-        $this->_tm_frmt = $format;
526
-        //clear cached_properties because they won't be relevant now.
527
-        $this->_clear_cached_properties();
528
-    }
529
-
530
-
531
-    /**
532
-     * This returns the current internal set format for the date and time formats.
533
-     *
534
-     * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
-     *                             where the first value is the date format and the second value is the time format.
536
-     * @return mixed string|array
537
-     */
538
-    public function get_format($full = true)
539
-    {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
-    }
542
-
543
-
544
-    /**
545
-     * cache
546
-     * stores the passed model object on the current model object.
547
-     * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
-     *
549
-     * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
-     *                                       'Registration' associated with this model object
551
-     * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
-     *                                       that could be a payment or a registration)
553
-     * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
-     *                                       items which will be stored in an array on this object
555
-     * @throws ReflectionException
556
-     * @throws InvalidArgumentException
557
-     * @throws InvalidInterfaceException
558
-     * @throws InvalidDataTypeException
559
-     * @throws EE_Error
560
-     * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
-     *                                       related thing, no array)
562
-     */
563
-    public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
-    {
565
-        // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
567
-            return false;
568
-        }
569
-        // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
-            throw new EE_Error(
572
-                sprintf(
573
-                    esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
-                    $relationName,
575
-                    get_class($this)
576
-                )
577
-            );
578
-        }
579
-        // how many things are related ?
580
-        if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
-            // if it's a "belongs to" relationship, then there's only one related model object
582
-            // eg, if this is a registration, there's only 1 attendee for it
583
-            // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
585
-            $return                                  = true;
586
-        } else {
587
-            // otherwise, this is the "many" side of a one to many relationship,
588
-            // so we'll add the object to the array of related objects for that type.
589
-            // eg: if this is an event, there are many registrations for that event,
590
-            // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
592
-                // if for some reason, the cached item is a model object,
593
-                // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
-                                                           instanceof
596
-                                                           EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
598
-            }
599
-            // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
601
-                // if the cache_id exists, then it means we are purposely trying to cache this
602
-                // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
-                $return                                               = $cache_id;
605
-            } elseif ($object_to_cache->ID()) {
606
-                // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
-                $return                                                            = $object_to_cache->ID();
609
-            } else {
610
-                // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
612
-                // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
614
-                // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
616
-            }
617
-        }
618
-        return $return;
619
-    }
620
-
621
-
622
-    /**
623
-     * For adding an item to the cached_properties property.
624
-     *
625
-     * @access protected
626
-     * @param string      $fieldname the property item the corresponding value is for.
627
-     * @param mixed       $value     The value we are caching.
628
-     * @param string|null $cache_type
629
-     * @return void
630
-     * @throws ReflectionException
631
-     * @throws InvalidArgumentException
632
-     * @throws InvalidInterfaceException
633
-     * @throws InvalidDataTypeException
634
-     * @throws EE_Error
635
-     */
636
-    protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
-    {
638
-        //first make sure this property exists
639
-        $this->get_model()->field_settings_for($fieldname);
640
-        $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
-    }
643
-
644
-
645
-    /**
646
-     * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
-     * This also SETS the cache if we return the actual property!
648
-     *
649
-     * @param string $fieldname        the name of the property we're trying to retrieve
650
-     * @param bool   $pretty
651
-     * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
-     *                                 (in cases where the same property may be used for different outputs
653
-     *                                 - i.e. datetime, money etc.)
654
-     *                                 It can also accept certain pre-defined "schema" strings
655
-     *                                 to define how to output the property.
656
-     *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
-     * @return mixed                   whatever the value for the property is we're retrieving
658
-     * @throws ReflectionException
659
-     * @throws InvalidArgumentException
660
-     * @throws InvalidInterfaceException
661
-     * @throws InvalidDataTypeException
662
-     * @throws EE_Error
663
-     */
664
-    protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
-    {
666
-        //verify the field exists
667
-        $model = $this->get_model();
668
-        $model->field_settings_for($fieldname);
669
-        $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
-        }
674
-        $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
-        $this->_set_cached_property($fieldname, $value, $cache_type);
676
-        return $value;
677
-    }
678
-
679
-
680
-    /**
681
-     * If the cache didn't fetch the needed item, this fetches it.
682
-     *
683
-     * @param string $fieldname
684
-     * @param bool   $pretty
685
-     * @param string $extra_cache_ref
686
-     * @return mixed
687
-     * @throws InvalidArgumentException
688
-     * @throws InvalidInterfaceException
689
-     * @throws InvalidDataTypeException
690
-     * @throws EE_Error
691
-     * @throws ReflectionException
692
-     */
693
-    protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
-    {
695
-        $field_obj = $this->get_model()->field_settings_for($fieldname);
696
-        // If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
-        if ($field_obj instanceof EE_Datetime_Field) {
698
-            $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
-        }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
702
-        }
703
-        $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
-        return $value;
707
-    }
708
-
709
-
710
-    /**
711
-     * set timezone, formats, and output for EE_Datetime_Field objects
712
-     *
713
-     * @param \EE_Datetime_Field $datetime_field
714
-     * @param bool               $pretty
715
-     * @param null               $date_or_time
716
-     * @return void
717
-     * @throws InvalidArgumentException
718
-     * @throws InvalidInterfaceException
719
-     * @throws InvalidDataTypeException
720
-     * @throws EE_Error
721
-     */
722
-    protected function _prepare_datetime_field(
723
-        EE_Datetime_Field $datetime_field,
724
-        $pretty = false,
725
-        $date_or_time = null
726
-    ) {
727
-        $datetime_field->set_timezone($this->_timezone);
728
-        $datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
-        $datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
-        //set the output returned
731
-        switch ($date_or_time) {
732
-            case 'D' :
733
-                $datetime_field->set_date_time_output('date');
734
-                break;
735
-            case 'T' :
736
-                $datetime_field->set_date_time_output('time');
737
-                break;
738
-            default :
739
-                $datetime_field->set_date_time_output();
740
-        }
741
-    }
742
-
743
-
744
-    /**
745
-     * This just takes care of clearing out the cached_properties
746
-     *
747
-     * @return void
748
-     */
749
-    protected function _clear_cached_properties()
750
-    {
751
-        $this->_cached_properties = array();
752
-    }
753
-
754
-
755
-    /**
756
-     * This just clears out ONE property if it exists in the cache
757
-     *
758
-     * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
-     * @return void
760
-     */
761
-    protected function _clear_cached_property($property_name)
762
-    {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
765
-        }
766
-    }
767
-
768
-
769
-    /**
770
-     * Ensures that this related thing is a model object.
771
-     *
772
-     * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
-     * @param string $model_name   name of the related thing, eg 'Attendee',
774
-     * @return EE_Base_Class
775
-     * @throws ReflectionException
776
-     * @throws InvalidArgumentException
777
-     * @throws InvalidInterfaceException
778
-     * @throws InvalidDataTypeException
779
-     * @throws EE_Error
780
-     */
781
-    protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
-    {
783
-        $other_model_instance = self::_get_model_instance_with_name(
784
-            self::_get_model_classname($model_name),
785
-            $this->_timezone
786
-        );
787
-        return $other_model_instance->ensure_is_obj($object_or_id);
788
-    }
789
-
790
-
791
-    /**
792
-     * Forgets the cached model of the given relation Name. So the next time we request it,
793
-     * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
-     * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
-     * then only remove that one object from our cached array. Otherwise, clear the entire list
796
-     *
797
-     * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
-     *                                                     Eg 'Registration'
799
-     * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
-     *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
-     *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
-     * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
-     *                                                     this is HasMany or HABTM.
804
-     * @throws ReflectionException
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidInterfaceException
807
-     * @throws InvalidDataTypeException
808
-     * @throws EE_Error
809
-     * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
-     *                                                     relation from all
811
-     */
812
-    public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
-    {
814
-        $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
-        $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
817
-            throw new EE_Error(
818
-                sprintf(
819
-                    esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
-                    $relationName,
821
-                    get_class($this)
822
-                )
823
-            );
824
-        }
825
-        if ($clear_all) {
826
-            $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
828
-        } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
831
-        } else {
832
-            if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
-                && $object_to_remove_or_index_into_array->ID()
834
-            ) {
835
-                $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
-                ) {
839
-                    $index_found_at = null;
840
-                    //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
-                        /** @noinspection TypeUnsafeComparisonInspection */
843
-                        if (
844
-                            $obj instanceof EE_Base_Class
845
-                            && (
846
-                                $obj == $object_to_remove_or_index_into_array
847
-                                || $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
-                            )
849
-                        ) {
850
-                            $index_found_at = $index;
851
-                            break;
852
-                        }
853
-                    }
854
-                    if ($index_found_at) {
855
-                        $index_in_cache = $index_found_at;
856
-                    } else {
857
-                        //it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
-                        //if it wasn't in it to begin with. So we're done
859
-                        return $object_to_remove_or_index_into_array;
860
-                    }
861
-                }
862
-            } elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
-                //so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
-                foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
-                    /** @noinspection TypeUnsafeComparisonInspection */
866
-                    if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
-                        $index_in_cache = $index;
868
-                    }
869
-                }
870
-            } else {
871
-                $index_in_cache = $object_to_remove_or_index_into_array;
872
-            }
873
-            //supposedly we've found it. But it could just be that the client code
874
-            //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
-            } else {
879
-                //that thing was never cached anyways.
880
-                $obj_removed = null;
881
-            }
882
-        }
883
-        return $obj_removed;
884
-    }
885
-
886
-
887
-    /**
888
-     * update_cache_after_object_save
889
-     * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
-     * obtained after being saved to the db
891
-     *
892
-     * @param string        $relationName       - the type of object that is cached
893
-     * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
-     * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
-     * @return boolean TRUE on success, FALSE on fail
896
-     * @throws ReflectionException
897
-     * @throws InvalidArgumentException
898
-     * @throws InvalidInterfaceException
899
-     * @throws InvalidDataTypeException
900
-     * @throws EE_Error
901
-     */
902
-    public function update_cache_after_object_save(
903
-        $relationName,
904
-        EE_Base_Class $newly_saved_object,
905
-        $current_cache_id = ''
906
-    ) {
907
-        // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
909
-        if ($newly_saved_object instanceof $obj_class) {
910
-            /* @type EE_Base_Class $newly_saved_object */
911
-            // now get the type of relation
912
-            $relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
-            // if this is a 1:1 relationship
914
-            if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
-                // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
917
-                return true;
918
-                // or if it's some kind of sordid feral polyamorous relationship...
919
-            }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
-            ) {
923
-                // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
-                // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
-                return true;
928
-            }
929
-        }
930
-        return false;
931
-    }
932
-
933
-
934
-    /**
935
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
-     *
938
-     * @param string $relationName
939
-     * @return EE_Base_Class
940
-     */
941
-    public function get_one_from_cache($relationName)
942
-    {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
945
-            : null;
946
-        if (is_array($cached_array_or_object)) {
947
-            return array_shift($cached_array_or_object);
948
-        }
949
-        return $cached_array_or_object;
950
-    }
951
-
952
-
953
-    /**
954
-     * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
-     * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
-     *
957
-     * @param string $relationName
958
-     * @throws ReflectionException
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidInterfaceException
961
-     * @throws InvalidDataTypeException
962
-     * @throws EE_Error
963
-     * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
-     */
965
-    public function get_all_from_cache($relationName)
966
-    {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
-        // if the result is not an array, but exists, make it an array
969
-        $objects = is_array($objects) ? $objects : array($objects);
970
-        //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
-        //basically, if this model object was stored in the session, and these cached model objects
972
-        //already have IDs, let's make sure they're in their model's entity mapper
973
-        //otherwise we will have duplicates next time we call
974
-        // EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
-        $model = EE_Registry::instance()->load_model($relationName);
976
-        foreach ($objects as $model_object) {
977
-            if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
-                //ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
-                if ($model_object->ID()) {
980
-                    $model->add_to_entity_map($model_object);
981
-                }
982
-            } else {
983
-                throw new EE_Error(
984
-                    sprintf(
985
-                        esc_html__(
986
-                            'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
-                            'event_espresso'
988
-                        ),
989
-                        $relationName,
990
-                        gettype($model_object)
991
-                    )
992
-                );
993
-            }
994
-        }
995
-        return $objects;
996
-    }
997
-
998
-
999
-    /**
1000
-     * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
-     * matching the given query conditions.
1002
-     *
1003
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1004
-     * @param int   $limit              How many objects to return.
1005
-     * @param array $query_params       Any additional conditions on the query.
1006
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
-     *                                  you can indicate just the columns you want returned
1008
-     * @return array|EE_Base_Class[]
1009
-     * @throws ReflectionException
1010
-     * @throws InvalidArgumentException
1011
-     * @throws InvalidInterfaceException
1012
-     * @throws InvalidDataTypeException
1013
-     * @throws EE_Error
1014
-     */
1015
-    public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
-    {
1017
-        $model         = $this->get_model();
1018
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
-            ? $model->get_primary_key_field()->get_name()
1020
-            : $field_to_order_by;
1021
-        $current_value = ! empty($field) ? $this->get($field) : null;
1022
-        if (empty($field) || empty($current_value)) {
1023
-            return array();
1024
-        }
1025
-        return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
-    }
1027
-
1028
-
1029
-    /**
1030
-     * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
-     * matching the given query conditions.
1032
-     *
1033
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1034
-     * @param int   $limit              How many objects to return.
1035
-     * @param array $query_params       Any additional conditions on the query.
1036
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
-     *                                  you can indicate just the columns you want returned
1038
-     * @return array|EE_Base_Class[]
1039
-     * @throws ReflectionException
1040
-     * @throws InvalidArgumentException
1041
-     * @throws InvalidInterfaceException
1042
-     * @throws InvalidDataTypeException
1043
-     * @throws EE_Error
1044
-     */
1045
-    public function previous_x(
1046
-        $field_to_order_by = null,
1047
-        $limit = 1,
1048
-        $query_params = array(),
1049
-        $columns_to_select = null
1050
-    ) {
1051
-        $model         = $this->get_model();
1052
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
-            ? $model->get_primary_key_field()->get_name()
1054
-            : $field_to_order_by;
1055
-        $current_value = ! empty($field) ? $this->get($field) : null;
1056
-        if (empty($field) || empty($current_value)) {
1057
-            return array();
1058
-        }
1059
-        return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
-     * matching the given query conditions.
1066
-     *
1067
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1068
-     * @param array $query_params       Any additional conditions on the query.
1069
-     * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
-     *                                  you can indicate just the columns you want returned
1071
-     * @return array|EE_Base_Class
1072
-     * @throws ReflectionException
1073
-     * @throws InvalidArgumentException
1074
-     * @throws InvalidInterfaceException
1075
-     * @throws InvalidDataTypeException
1076
-     * @throws EE_Error
1077
-     */
1078
-    public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
-    {
1080
-        $model         = $this->get_model();
1081
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
-            ? $model->get_primary_key_field()->get_name()
1083
-            : $field_to_order_by;
1084
-        $current_value = ! empty($field) ? $this->get($field) : null;
1085
-        if (empty($field) || empty($current_value)) {
1086
-            return array();
1087
-        }
1088
-        return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
-    }
1090
-
1091
-
1092
-    /**
1093
-     * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
-     * matching the given query conditions.
1095
-     *
1096
-     * @param null  $field_to_order_by  What field is being used as the reference point.
1097
-     * @param array $query_params       Any additional conditions on the query.
1098
-     * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
-     *                                  you can indicate just the column you want returned
1100
-     * @return array|EE_Base_Class
1101
-     * @throws ReflectionException
1102
-     * @throws InvalidArgumentException
1103
-     * @throws InvalidInterfaceException
1104
-     * @throws InvalidDataTypeException
1105
-     * @throws EE_Error
1106
-     */
1107
-    public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
-    {
1109
-        $model         = $this->get_model();
1110
-        $field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
-            ? $model->get_primary_key_field()->get_name()
1112
-            : $field_to_order_by;
1113
-        $current_value = ! empty($field) ? $this->get($field) : null;
1114
-        if (empty($field) || empty($current_value)) {
1115
-            return array();
1116
-        }
1117
-        return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * Overrides parent because parent expects old models.
1123
-     * This also doesn't do any validation, and won't work for serialized arrays
1124
-     *
1125
-     * @param string $field_name
1126
-     * @param mixed  $field_value_from_db
1127
-     * @throws ReflectionException
1128
-     * @throws InvalidArgumentException
1129
-     * @throws InvalidInterfaceException
1130
-     * @throws InvalidDataTypeException
1131
-     * @throws EE_Error
1132
-     */
1133
-    public function set_from_db($field_name, $field_value_from_db)
1134
-    {
1135
-        $field_obj = $this->get_model()->field_settings_for($field_name);
1136
-        if ($field_obj instanceof EE_Model_Field_Base) {
1137
-            //you would think the DB has no NULLs for non-null label fields right? wrong!
1138
-            //eg, a CPT model object could have an entry in the posts table, but no
1139
-            //entry in the meta table. Meaning that all its columns in the meta table
1140
-            //are null! yikes! so when we find one like that, use defaults for its meta columns
1141
-            if ($field_value_from_db === null) {
1142
-                if ($field_obj->is_nullable()) {
1143
-                    //if the field allows nulls, then let it be null
1144
-                    $field_value = null;
1145
-                } else {
1146
-                    $field_value = $field_obj->get_default_value();
1147
-                }
1148
-            } else {
1149
-                $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
-            }
1151
-            $this->_fields[ $field_name ] = $field_value;
1152
-            $this->_clear_cached_property($field_name);
1153
-        }
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * verifies that the specified field is of the correct type
1159
-     *
1160
-     * @param string $field_name
1161
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
-     *                                (in cases where the same property may be used for different outputs
1163
-     *                                - i.e. datetime, money etc.)
1164
-     * @return mixed
1165
-     * @throws ReflectionException
1166
-     * @throws InvalidArgumentException
1167
-     * @throws InvalidInterfaceException
1168
-     * @throws InvalidDataTypeException
1169
-     * @throws EE_Error
1170
-     */
1171
-    public function get($field_name, $extra_cache_ref = null)
1172
-    {
1173
-        return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * This method simply returns the RAW unprocessed value for the given property in this class
1179
-     *
1180
-     * @param  string $field_name A valid fieldname
1181
-     * @return mixed              Whatever the raw value stored on the property is.
1182
-     * @throws ReflectionException
1183
-     * @throws InvalidArgumentException
1184
-     * @throws InvalidInterfaceException
1185
-     * @throws InvalidDataTypeException
1186
-     * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
-     */
1188
-    public function get_raw($field_name)
1189
-    {
1190
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * This is used to return the internal DateTime object used for a field that is a
1199
-     * EE_Datetime_Field.
1200
-     *
1201
-     * @param string $field_name               The field name retrieving the DateTime object.
1202
-     * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
-     * @throws EE_Error an error is set and false returned.  If the field IS an
1204
-     *                                         EE_Datetime_Field and but the field value is null, then
1205
-     *                                         just null is returned (because that indicates that likely
1206
-     *                                         this field is nullable).
1207
-     * @throws InvalidArgumentException
1208
-     * @throws InvalidDataTypeException
1209
-     * @throws InvalidInterfaceException
1210
-     * @throws ReflectionException
1211
-     */
1212
-    public function get_DateTime_object($field_name)
1213
-    {
1214
-        $field_settings = $this->get_model()->field_settings_for($field_name);
1215
-        if (! $field_settings instanceof EE_Datetime_Field) {
1216
-            EE_Error::add_error(
1217
-                sprintf(
1218
-                    esc_html__(
1219
-                        'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1220
-                        'event_espresso'
1221
-                    ),
1222
-                    $field_name
1223
-                ),
1224
-                __FILE__,
1225
-                __FUNCTION__,
1226
-                __LINE__
1227
-            );
1228
-            return false;
1229
-        }
1230
-        return isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime
1231
-            ? clone $this->_fields[$field_name]
1232
-            : null;
1233
-    }
1234
-
1235
-
1236
-    /**
1237
-     * To be used in template to immediately echo out the value, and format it for output.
1238
-     * Eg, should call stripslashes and whatnot before echoing
1239
-     *
1240
-     * @param string $field_name      the name of the field as it appears in the DB
1241
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1242
-     *                                (in cases where the same property may be used for different outputs
1243
-     *                                - i.e. datetime, money etc.)
1244
-     * @return void
1245
-     * @throws ReflectionException
1246
-     * @throws InvalidArgumentException
1247
-     * @throws InvalidInterfaceException
1248
-     * @throws InvalidDataTypeException
1249
-     * @throws EE_Error
1250
-     */
1251
-    public function e($field_name, $extra_cache_ref = null)
1252
-    {
1253
-        echo $this->get_pretty($field_name, $extra_cache_ref);
1254
-    }
1255
-
1256
-
1257
-    /**
1258
-     * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1259
-     * can be easily used as the value of form input.
1260
-     *
1261
-     * @param string $field_name
1262
-     * @return void
1263
-     * @throws ReflectionException
1264
-     * @throws InvalidArgumentException
1265
-     * @throws InvalidInterfaceException
1266
-     * @throws InvalidDataTypeException
1267
-     * @throws EE_Error
1268
-     */
1269
-    public function f($field_name)
1270
-    {
1271
-        $this->e($field_name, 'form_input');
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * Same as `f()` but just returns the value instead of echoing it
1277
-     *
1278
-     * @param string $field_name
1279
-     * @return string
1280
-     * @throws ReflectionException
1281
-     * @throws InvalidArgumentException
1282
-     * @throws InvalidInterfaceException
1283
-     * @throws InvalidDataTypeException
1284
-     * @throws EE_Error
1285
-     */
1286
-    public function get_f($field_name)
1287
-    {
1288
-        return (string) $this->get_pretty($field_name, 'form_input');
1289
-    }
1290
-
1291
-
1292
-    /**
1293
-     * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1294
-     * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1295
-     * to see what options are available.
1296
-     *
1297
-     * @param string $field_name
1298
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1299
-     *                                (in cases where the same property may be used for different outputs
1300
-     *                                - i.e. datetime, money etc.)
1301
-     * @return mixed
1302
-     * @throws ReflectionException
1303
-     * @throws InvalidArgumentException
1304
-     * @throws InvalidInterfaceException
1305
-     * @throws InvalidDataTypeException
1306
-     * @throws EE_Error
1307
-     */
1308
-    public function get_pretty($field_name, $extra_cache_ref = null)
1309
-    {
1310
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * This simply returns the datetime for the given field name
1316
-     * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1317
-     * (and the equivalent e_date, e_time, e_datetime).
1318
-     *
1319
-     * @access   protected
1320
-     * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1321
-     * @param string   $dt_frmt      valid datetime format used for date
1322
-     *                               (if '' then we just use the default on the field,
1323
-     *                               if NULL we use the last-used format)
1324
-     * @param string   $tm_frmt      Same as above except this is for time format
1325
-     * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1326
-     * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1327
-     * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1328
-     *                               if field is not a valid dtt field, or void if echoing
1329
-     * @throws ReflectionException
1330
-     * @throws InvalidArgumentException
1331
-     * @throws InvalidInterfaceException
1332
-     * @throws InvalidDataTypeException
1333
-     * @throws EE_Error
1334
-     */
1335
-    protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1336
-    {
1337
-        // clear cached property
1338
-        $this->_clear_cached_property($field_name);
1339
-        //reset format properties because they are used in get()
1340
-        $this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1341
-        $this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1342
-        if ($echo) {
1343
-            $this->e($field_name, $date_or_time);
1344
-            return '';
1345
-        }
1346
-        return $this->get($field_name, $date_or_time);
1347
-    }
1348
-
1349
-
1350
-    /**
1351
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1352
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1353
-     * other echoes the pretty value for dtt)
1354
-     *
1355
-     * @param  string $field_name name of model object datetime field holding the value
1356
-     * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1357
-     * @return string            datetime value formatted
1358
-     * @throws ReflectionException
1359
-     * @throws InvalidArgumentException
1360
-     * @throws InvalidInterfaceException
1361
-     * @throws InvalidDataTypeException
1362
-     * @throws EE_Error
1363
-     */
1364
-    public function get_date($field_name, $format = '')
1365
-    {
1366
-        return $this->_get_datetime($field_name, $format, null, 'D');
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * @param        $field_name
1372
-     * @param string $format
1373
-     * @throws ReflectionException
1374
-     * @throws InvalidArgumentException
1375
-     * @throws InvalidInterfaceException
1376
-     * @throws InvalidDataTypeException
1377
-     * @throws EE_Error
1378
-     */
1379
-    public function e_date($field_name, $format = '')
1380
-    {
1381
-        $this->_get_datetime($field_name, $format, null, 'D', true);
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1387
-     * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1388
-     * other echoes the pretty value for dtt)
1389
-     *
1390
-     * @param  string $field_name name of model object datetime field holding the value
1391
-     * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1392
-     * @return string             datetime value formatted
1393
-     * @throws ReflectionException
1394
-     * @throws InvalidArgumentException
1395
-     * @throws InvalidInterfaceException
1396
-     * @throws InvalidDataTypeException
1397
-     * @throws EE_Error
1398
-     */
1399
-    public function get_time($field_name, $format = '')
1400
-    {
1401
-        return $this->_get_datetime($field_name, null, $format, 'T');
1402
-    }
1403
-
1404
-
1405
-    /**
1406
-     * @param        $field_name
1407
-     * @param string $format
1408
-     * @throws ReflectionException
1409
-     * @throws InvalidArgumentException
1410
-     * @throws InvalidInterfaceException
1411
-     * @throws InvalidDataTypeException
1412
-     * @throws EE_Error
1413
-     */
1414
-    public function e_time($field_name, $format = '')
1415
-    {
1416
-        $this->_get_datetime($field_name, null, $format, 'T', true);
1417
-    }
1418
-
1419
-
1420
-    /**
1421
-     * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1422
-     * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1423
-     * other echoes the pretty value for dtt)
1424
-     *
1425
-     * @param  string $field_name name of model object datetime field holding the value
1426
-     * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1427
-     * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1428
-     * @return string             datetime value formatted
1429
-     * @throws ReflectionException
1430
-     * @throws InvalidArgumentException
1431
-     * @throws InvalidInterfaceException
1432
-     * @throws InvalidDataTypeException
1433
-     * @throws EE_Error
1434
-     */
1435
-    public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1436
-    {
1437
-        return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1438
-    }
1439
-
1440
-
1441
-    /**
1442
-     * @param string $field_name
1443
-     * @param string $dt_frmt
1444
-     * @param string $tm_frmt
1445
-     * @throws ReflectionException
1446
-     * @throws InvalidArgumentException
1447
-     * @throws InvalidInterfaceException
1448
-     * @throws InvalidDataTypeException
1449
-     * @throws EE_Error
1450
-     */
1451
-    public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1452
-    {
1453
-        $this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1454
-    }
1455
-
1456
-
1457
-    /**
1458
-     * Get the i8ln value for a date using the WordPress @see date_i18n function.
1459
-     *
1460
-     * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1461
-     * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1462
-     *                           on the object will be used.
1463
-     * @return string Date and time string in set locale or false if no field exists for the given
1464
-     * @throws ReflectionException
1465
-     * @throws InvalidArgumentException
1466
-     * @throws InvalidInterfaceException
1467
-     * @throws InvalidDataTypeException
1468
-     * @throws EE_Error
1469
-     *                           field name.
1470
-     */
1471
-    public function get_i18n_datetime($field_name, $format = '')
1472
-    {
1473
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1474
-        return date_i18n(
1475
-            $format,
1476
-            EEH_DTT_Helper::get_timestamp_with_offset(
1477
-                $this->get_raw($field_name),
1478
-                $this->_timezone
1479
-            )
1480
-        );
1481
-    }
1482
-
1483
-
1484
-    /**
1485
-     * This method validates whether the given field name is a valid field on the model object as well as it is of a
1486
-     * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1487
-     * thrown.
1488
-     *
1489
-     * @param  string $field_name The field name being checked
1490
-     * @throws ReflectionException
1491
-     * @throws InvalidArgumentException
1492
-     * @throws InvalidInterfaceException
1493
-     * @throws InvalidDataTypeException
1494
-     * @throws EE_Error
1495
-     * @return EE_Datetime_Field
1496
-     */
1497
-    protected function _get_dtt_field_settings($field_name)
1498
-    {
1499
-        $field = $this->get_model()->field_settings_for($field_name);
1500
-        //check if field is dtt
1501
-        if ($field instanceof EE_Datetime_Field) {
1502
-            return $field;
1503
-        }
1504
-        throw new EE_Error(
1505
-            sprintf(
1506
-                esc_html__(
1507
-                    'The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1508
-                    'event_espresso'
1509
-                ),
1510
-                $field_name,
1511
-                self::_get_model_classname(get_class($this))
1512
-            )
1513
-        );
1514
-    }
1515
-
1516
-
1517
-
1518
-
1519
-    /**
1520
-     * NOTE ABOUT BELOW:
1521
-     * These convenience date and time setters are for setting date and time independently.  In other words you might
1522
-     * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1523
-     * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1524
-     * method and make sure you send the entire datetime value for setting.
1525
-     */
1526
-    /**
1527
-     * sets the time on a datetime property
1528
-     *
1529
-     * @access protected
1530
-     * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1531
-     * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1532
-     * @throws ReflectionException
1533
-     * @throws InvalidArgumentException
1534
-     * @throws InvalidInterfaceException
1535
-     * @throws InvalidDataTypeException
1536
-     * @throws EE_Error
1537
-     */
1538
-    protected function _set_time_for($time, $fieldname)
1539
-    {
1540
-        $this->_set_date_time('T', $time, $fieldname);
1541
-    }
1542
-
1543
-
1544
-    /**
1545
-     * sets the date on a datetime property
1546
-     *
1547
-     * @access protected
1548
-     * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1549
-     * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1550
-     * @throws ReflectionException
1551
-     * @throws InvalidArgumentException
1552
-     * @throws InvalidInterfaceException
1553
-     * @throws InvalidDataTypeException
1554
-     * @throws EE_Error
1555
-     */
1556
-    protected function _set_date_for($date, $fieldname)
1557
-    {
1558
-        $this->_set_date_time('D', $date, $fieldname);
1559
-    }
1560
-
1561
-
1562
-    /**
1563
-     * This takes care of setting a date or time independently on a given model object property. This method also
1564
-     * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1565
-     *
1566
-     * @access protected
1567
-     * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1568
-     * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1569
-     * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1570
-     *                                        EE_Datetime_Field property)
1571
-     * @throws ReflectionException
1572
-     * @throws InvalidArgumentException
1573
-     * @throws InvalidInterfaceException
1574
-     * @throws InvalidDataTypeException
1575
-     * @throws EE_Error
1576
-     */
1577
-    protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1578
-    {
1579
-        $field = $this->_get_dtt_field_settings($fieldname);
1580
-        $field->set_timezone($this->_timezone);
1581
-        $field->set_date_format($this->_dt_frmt);
1582
-        $field->set_time_format($this->_tm_frmt);
1583
-        switch ($what) {
1584
-            case 'T' :
1585
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1586
-                    $datetime_value,
1587
-                    $this->_fields[ $fieldname ]
1588
-                );
1589
-                break;
1590
-            case 'D' :
1591
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1592
-                    $datetime_value,
1593
-                    $this->_fields[ $fieldname ]
1594
-                );
1595
-                break;
1596
-            case 'B' :
1597
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1598
-                break;
1599
-        }
1600
-        $this->_clear_cached_property($fieldname);
1601
-    }
1602
-
1603
-
1604
-    /**
1605
-     * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1606
-     * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1607
-     * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1608
-     * that could lead to some unexpected results!
1609
-     *
1610
-     * @access public
1611
-     * @param string $field_name               This is the name of the field on the object that contains the date/time
1612
-     *                                         value being returned.
1613
-     * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1614
-     * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1615
-     * @param string $prepend                  You can include something to prepend on the timestamp
1616
-     * @param string $append                   You can include something to append on the timestamp
1617
-     * @throws ReflectionException
1618
-     * @throws InvalidArgumentException
1619
-     * @throws InvalidInterfaceException
1620
-     * @throws InvalidDataTypeException
1621
-     * @throws EE_Error
1622
-     * @return string timestamp
1623
-     */
1624
-    public function display_in_my_timezone(
1625
-        $field_name,
1626
-        $callback = 'get_datetime',
1627
-        $args = null,
1628
-        $prepend = '',
1629
-        $append = ''
1630
-    ) {
1631
-        $timezone = EEH_DTT_Helper::get_timezone();
1632
-        if ($timezone === $this->_timezone) {
1633
-            return '';
1634
-        }
1635
-        $original_timezone = $this->_timezone;
1636
-        $this->set_timezone($timezone);
1637
-        $fn   = (array) $field_name;
1638
-        $args = array_merge($fn, (array) $args);
1639
-        if (! method_exists($this, $callback)) {
1640
-            throw new EE_Error(
1641
-                sprintf(
1642
-                    esc_html__(
1643
-                        'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1644
-                        'event_espresso'
1645
-                    ),
1646
-                    $callback
1647
-                )
1648
-            );
1649
-        }
1650
-        $args   = (array) $args;
1651
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1652
-        $this->set_timezone($original_timezone);
1653
-        return $return;
1654
-    }
1655
-
1656
-
1657
-    /**
1658
-     * Deletes this model object.
1659
-     * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1660
-     * override
1661
-     * `EE_Base_Class::_delete` NOT this class.
1662
-     *
1663
-     * @return boolean | int
1664
-     * @throws ReflectionException
1665
-     * @throws InvalidArgumentException
1666
-     * @throws InvalidInterfaceException
1667
-     * @throws InvalidDataTypeException
1668
-     * @throws EE_Error
1669
-     */
1670
-    public function delete()
1671
-    {
1672
-        /**
1673
-         * Called just before the `EE_Base_Class::_delete` method call.
1674
-         * Note:
1675
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1676
-         * should be aware that `_delete` may not always result in a permanent delete.
1677
-         * For example, `EE_Soft_Delete_Base_Class::_delete`
1678
-         * soft deletes (trash) the object and does not permanently delete it.
1679
-         *
1680
-         * @param EE_Base_Class $model_object about to be 'deleted'
1681
-         */
1682
-        do_action('AHEE__EE_Base_Class__delete__before', $this);
1683
-        $result = $this->_delete();
1684
-        /**
1685
-         * Called just after the `EE_Base_Class::_delete` method call.
1686
-         * Note:
1687
-         * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1688
-         * should be aware that `_delete` may not always result in a permanent delete.
1689
-         * For example `EE_Soft_Base_Class::_delete`
1690
-         * soft deletes (trash) the object and does not permanently delete it.
1691
-         *
1692
-         * @param EE_Base_Class $model_object that was just 'deleted'
1693
-         * @param boolean       $result
1694
-         */
1695
-        do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1696
-        return $result;
1697
-    }
1698
-
1699
-
1700
-    /**
1701
-     * Calls the specific delete method for the instantiated class.
1702
-     * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1703
-     * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1704
-     * `EE_Base_Class::delete`
1705
-     *
1706
-     * @return bool|int
1707
-     * @throws ReflectionException
1708
-     * @throws InvalidArgumentException
1709
-     * @throws InvalidInterfaceException
1710
-     * @throws InvalidDataTypeException
1711
-     * @throws EE_Error
1712
-     */
1713
-    protected function _delete()
1714
-    {
1715
-        return $this->delete_permanently();
1716
-    }
1717
-
1718
-
1719
-    /**
1720
-     * Deletes this model object permanently from db
1721
-     * (but keep in mind related models may block the delete and return an error)
1722
-     *
1723
-     * @return bool | int
1724
-     * @throws ReflectionException
1725
-     * @throws InvalidArgumentException
1726
-     * @throws InvalidInterfaceException
1727
-     * @throws InvalidDataTypeException
1728
-     * @throws EE_Error
1729
-     */
1730
-    public function delete_permanently()
1731
-    {
1732
-        /**
1733
-         * Called just before HARD deleting a model object
1734
-         *
1735
-         * @param EE_Base_Class $model_object about to be 'deleted'
1736
-         */
1737
-        do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1738
-        $model  = $this->get_model();
1739
-        $result = $model->delete_permanently_by_ID($this->ID());
1740
-        $this->refresh_cache_of_related_objects();
1741
-        /**
1742
-         * Called just after HARD deleting a model object
1743
-         *
1744
-         * @param EE_Base_Class $model_object that was just 'deleted'
1745
-         * @param boolean       $result
1746
-         */
1747
-        do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1748
-        return $result;
1749
-    }
1750
-
1751
-
1752
-    /**
1753
-     * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1754
-     * related model objects
1755
-     *
1756
-     * @throws ReflectionException
1757
-     * @throws InvalidArgumentException
1758
-     * @throws InvalidInterfaceException
1759
-     * @throws InvalidDataTypeException
1760
-     * @throws EE_Error
1761
-     */
1762
-    public function refresh_cache_of_related_objects()
1763
-    {
1764
-        $model = $this->get_model();
1765
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
-            if (! empty($this->_model_relations[ $relation_name ])) {
1767
-                $related_objects = $this->_model_relations[ $relation_name ];
1768
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769
-                    //this relation only stores a single model object, not an array
1770
-                    //but let's make it consistent
1771
-                    $related_objects = array($related_objects);
1772
-                }
1773
-                foreach ($related_objects as $related_object) {
1774
-                    //only refresh their cache if they're in memory
1775
-                    if ($related_object instanceof EE_Base_Class) {
1776
-                        $related_object->clear_cache(
1777
-                            $model->get_this_model_name(),
1778
-                            $this
1779
-                        );
1780
-                    }
1781
-                }
1782
-            }
1783
-        }
1784
-    }
1785
-
1786
-
1787
-    /**
1788
-     *        Saves this object to the database. An array may be supplied to set some values on this
1789
-     * object just before saving.
1790
-     *
1791
-     * @access public
1792
-     * @param array $set_cols_n_values keys are field names, values are their new values,
1793
-     *                                 if provided during the save() method (often client code will change the fields'
1794
-     *                                 values before calling save)
1795
-     * @throws InvalidArgumentException
1796
-     * @throws InvalidInterfaceException
1797
-     * @throws InvalidDataTypeException
1798
-     * @throws EE_Error
1799
-     * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1800
-     *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1801
-     * @throws ReflectionException
1802
-     * @throws ReflectionException
1803
-     * @throws ReflectionException
1804
-     */
1805
-    public function save($set_cols_n_values = array())
1806
-    {
1807
-        $model = $this->get_model();
1808
-        /**
1809
-         * Filters the fields we're about to save on the model object
1810
-         *
1811
-         * @param array         $set_cols_n_values
1812
-         * @param EE_Base_Class $model_object
1813
-         */
1814
-        $set_cols_n_values = (array) apply_filters(
1815
-            'FHEE__EE_Base_Class__save__set_cols_n_values',
1816
-            $set_cols_n_values,
1817
-            $this
1818
-        );
1819
-        //set attributes as provided in $set_cols_n_values
1820
-        foreach ($set_cols_n_values as $column => $value) {
1821
-            $this->set($column, $value);
1822
-        }
1823
-        // no changes ? then don't do anything
1824
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825
-            return 0;
1826
-        }
1827
-        /**
1828
-         * Saving a model object.
1829
-         * Before we perform a save, this action is fired.
1830
-         *
1831
-         * @param EE_Base_Class $model_object the model object about to be saved.
1832
-         */
1833
-        do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
-        if (! $this->allow_persist()) {
1835
-            return 0;
1836
-        }
1837
-        // now get current attribute values
1838
-        $save_cols_n_values = $this->_fields;
1839
-        // if the object already has an ID, update it. Otherwise, insert it
1840
-        // also: change the assumption about values passed to the model NOT being prepare dby the model object.
1841
-        // They have been
1842
-        $old_assumption_concerning_value_preparation = $model
1843
-            ->get_assumption_concerning_values_already_prepared_by_model_object();
1844
-        $model->assume_values_already_prepared_by_model_object(true);
1845
-        //does this model have an autoincrement PK?
1846
-        if ($model->has_primary_key_field()) {
1847
-            if ($model->get_primary_key_field()->is_auto_increment()) {
1848
-                //ok check if it's set, if so: update; if not, insert
1849
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1850
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851
-                } else {
1852
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1853
-                    $results = $model->insert($save_cols_n_values);
1854
-                    if ($results) {
1855
-                        //if successful, set the primary key
1856
-                        //but don't use the normal SET method, because it will check if
1857
-                        //an item with the same ID exists in the mapper & db, then
1858
-                        //will find it in the db (because we just added it) and THAT object
1859
-                        //will get added to the mapper before we can add this one!
1860
-                        //but if we just avoid using the SET method, all that headache can be avoided
1861
-                        $pk_field_name                   = $model->primary_key_name();
1862
-                        $this->_fields[ $pk_field_name ] = $results;
1863
-                        $this->_clear_cached_property($pk_field_name);
1864
-                        $model->add_to_entity_map($this);
1865
-                        $this->_update_cached_related_model_objs_fks();
1866
-                    }
1867
-                }
1868
-            } else {//PK is NOT auto-increment
1869
-                //so check if one like it already exists in the db
1870
-                if ($model->exists_by_ID($this->ID())) {
1871
-                    if (WP_DEBUG && ! $this->in_entity_map()) {
1872
-                        throw new EE_Error(
1873
-                            sprintf(
1874
-                                esc_html__(
1875
-                                    'Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1876
-                                    'event_espresso'
1877
-                                ),
1878
-                                get_class($this),
1879
-                                get_class($model) . '::instance()->add_to_entity_map()',
1880
-                                get_class($model) . '::instance()->get_one_by_ID()',
1881
-                                '<br />'
1882
-                            )
1883
-                        );
1884
-                    }
1885
-                    $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1886
-                } else {
1887
-                    $results = $model->insert($save_cols_n_values);
1888
-                    $this->_update_cached_related_model_objs_fks();
1889
-                }
1890
-            }
1891
-        } else {//there is NO primary key
1892
-            $already_in_db = false;
1893
-            foreach ($model->unique_indexes() as $index) {
1894
-                $uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1895
-                if ($model->exists(array($uniqueness_where_params))) {
1896
-                    $already_in_db = true;
1897
-                }
1898
-            }
1899
-            if ($already_in_db) {
1900
-                $combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1901
-                    $model->get_combined_primary_key_fields());
1902
-                $results                     = $model->update(
1903
-                    $save_cols_n_values,
1904
-                    $combined_pk_fields_n_values
1905
-                );
1906
-            } else {
1907
-                $results = $model->insert($save_cols_n_values);
1908
-            }
1909
-        }
1910
-        //restore the old assumption about values being prepared by the model object
1911
-        $model->assume_values_already_prepared_by_model_object(
1912
-                $old_assumption_concerning_value_preparation
1913
-            );
1914
-        /**
1915
-         * After saving the model object this action is called
1916
-         *
1917
-         * @param EE_Base_Class $model_object which was just saved
1918
-         * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1919
-         *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1920
-         */
1921
-        do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1922
-        $this->_has_changes = false;
1923
-        return $results;
1924
-    }
1925
-
1926
-
1927
-    /**
1928
-     * Updates the foreign key on related models objects pointing to this to have this model object's ID
1929
-     * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1930
-     * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1931
-     * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1932
-     * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1933
-     * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1934
-     * or not they exist in the DB (if they do, their DB records will be automatically updated)
1935
-     *
1936
-     * @return void
1937
-     * @throws ReflectionException
1938
-     * @throws InvalidArgumentException
1939
-     * @throws InvalidInterfaceException
1940
-     * @throws InvalidDataTypeException
1941
-     * @throws EE_Error
1942
-     */
1943
-    protected function _update_cached_related_model_objs_fks()
1944
-    {
1945
-        $model = $this->get_model();
1946
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1947
-            if ($relation_obj instanceof EE_Has_Many_Relation) {
1948
-                foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1949
-                    $fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1950
-                        $model->get_this_model_name()
1951
-                    );
1952
-                    $related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1953
-                    if ($related_model_obj_in_cache->ID()) {
1954
-                        $related_model_obj_in_cache->save();
1955
-                    }
1956
-                }
1957
-            }
1958
-        }
1959
-    }
1960
-
1961
-
1962
-    /**
1963
-     * Saves this model object and its NEW cached relations to the database.
1964
-     * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1965
-     * In order for that to work, we would need to mark model objects as dirty/clean...
1966
-     * because otherwise, there's a potential for infinite looping of saving
1967
-     * Saves the cached related model objects, and ensures the relation between them
1968
-     * and this object and properly setup
1969
-     *
1970
-     * @return int ID of new model object on save; 0 on failure+
1971
-     * @throws ReflectionException
1972
-     * @throws InvalidArgumentException
1973
-     * @throws InvalidInterfaceException
1974
-     * @throws InvalidDataTypeException
1975
-     * @throws EE_Error
1976
-     */
1977
-    public function save_new_cached_related_model_objs()
1978
-    {
1979
-        //make sure this has been saved
1980
-        if (! $this->ID()) {
1981
-            $id = $this->save();
1982
-        } else {
1983
-            $id = $this->ID();
1984
-        }
1985
-        //now save all the NEW cached model objects  (ie they don't exist in the DB)
1986
-        foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
-            if ($this->_model_relations[ $relationName ]) {
1988
-                //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989
-                //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990
-                /* @var $related_model_obj EE_Base_Class */
1991
-                if ($relationObj instanceof EE_Belongs_To_Relation) {
1992
-                    //add a relation to that relation type (which saves the appropriate thing in the process)
1993
-                    //but ONLY if it DOES NOT exist in the DB
1994
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1995
-                    //					if( ! $related_model_obj->ID()){
1996
-                    $this->_add_relation_to($related_model_obj, $relationName);
1997
-                    $related_model_obj->save_new_cached_related_model_objs();
1998
-                    //					}
1999
-                } else {
2000
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2001
-                        //add a relation to that relation type (which saves the appropriate thing in the process)
2002
-                        //but ONLY if it DOES NOT exist in the DB
2003
-                        //						if( ! $related_model_obj->ID()){
2004
-                        $this->_add_relation_to($related_model_obj, $relationName);
2005
-                        $related_model_obj->save_new_cached_related_model_objs();
2006
-                        //						}
2007
-                    }
2008
-                }
2009
-            }
2010
-        }
2011
-        return $id;
2012
-    }
2013
-
2014
-
2015
-    /**
2016
-     * for getting a model while instantiated.
2017
-     *
2018
-     * @return EEM_Base | EEM_CPT_Base
2019
-     * @throws ReflectionException
2020
-     * @throws InvalidArgumentException
2021
-     * @throws InvalidInterfaceException
2022
-     * @throws InvalidDataTypeException
2023
-     * @throws EE_Error
2024
-     */
2025
-    public function get_model()
2026
-    {
2027
-        if (! $this->_model) {
2028
-            $modelName    = self::_get_model_classname(get_class($this));
2029
-            $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030
-        } else {
2031
-            $this->_model->set_timezone($this->_timezone);
2032
-        }
2033
-        return $this->_model;
2034
-    }
2035
-
2036
-
2037
-    /**
2038
-     * @param $props_n_values
2039
-     * @param $classname
2040
-     * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2041
-     * @throws ReflectionException
2042
-     * @throws InvalidArgumentException
2043
-     * @throws InvalidInterfaceException
2044
-     * @throws InvalidDataTypeException
2045
-     * @throws EE_Error
2046
-     */
2047
-    protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2048
-    {
2049
-        //TODO: will not work for Term_Relationships because they have no PK!
2050
-        $primary_id_ref = self::_get_primary_key_name($classname);
2051
-        if (
2052
-            array_key_exists($primary_id_ref, $props_n_values)
2053
-            && ! empty($props_n_values[ $primary_id_ref ])
2054
-        ) {
2055
-            $id = $props_n_values[ $primary_id_ref ];
2056
-            return self::_get_model($classname)->get_from_entity_map($id);
2057
-        }
2058
-        return false;
2059
-    }
2060
-
2061
-
2062
-    /**
2063
-     * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2064
-     * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2065
-     * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
2066
-     * we return false.
2067
-     *
2068
-     * @param  array  $props_n_values   incoming array of properties and their values
2069
-     * @param  string $classname        the classname of the child class
2070
-     * @param null    $timezone
2071
-     * @param array   $date_formats     incoming date_formats in an array where the first value is the
2072
-     *                                  date_format and the second value is the time format
2073
-     * @return mixed (EE_Base_Class|bool)
2074
-     * @throws InvalidArgumentException
2075
-     * @throws InvalidInterfaceException
2076
-     * @throws InvalidDataTypeException
2077
-     * @throws EE_Error
2078
-     * @throws ReflectionException
2079
-     * @throws ReflectionException
2080
-     * @throws ReflectionException
2081
-     */
2082
-    protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2083
-    {
2084
-        $existing = null;
2085
-        $model    = self::_get_model($classname, $timezone);
2086
-        if ($model->has_primary_key_field()) {
2087
-            $primary_id_ref = self::_get_primary_key_name($classname);
2088
-            if (array_key_exists($primary_id_ref, $props_n_values)
2089
-                && ! empty($props_n_values[ $primary_id_ref ])
2090
-            ) {
2091
-                $existing = $model->get_one_by_ID(
2092
-                    $props_n_values[ $primary_id_ref ]
2093
-                );
2094
-            }
2095
-        } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2096
-            //no primary key on this model, but there's still a matching item in the DB
2097
-            $existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2098
-                self::_get_model($classname, $timezone)
2099
-                    ->get_index_primary_key_string($props_n_values)
2100
-            );
2101
-        }
2102
-        if ($existing) {
2103
-            //set date formats if present before setting values
2104
-            if (! empty($date_formats) && is_array($date_formats)) {
2105
-                $existing->set_date_format($date_formats[0]);
2106
-                $existing->set_time_format($date_formats[1]);
2107
-            } else {
2108
-                //set default formats for date and time
2109
-                $existing->set_date_format(get_option('date_format'));
2110
-                $existing->set_time_format(get_option('time_format'));
2111
-            }
2112
-            foreach ($props_n_values as $property => $field_value) {
2113
-                $existing->set($property, $field_value);
2114
-            }
2115
-            return $existing;
2116
-        }
2117
-        return false;
2118
-    }
2119
-
2120
-
2121
-    /**
2122
-     * Gets the EEM_*_Model for this class
2123
-     *
2124
-     * @access public now, as this is more convenient
2125
-     * @param      $classname
2126
-     * @param null $timezone
2127
-     * @throws ReflectionException
2128
-     * @throws InvalidArgumentException
2129
-     * @throws InvalidInterfaceException
2130
-     * @throws InvalidDataTypeException
2131
-     * @throws EE_Error
2132
-     * @return EEM_Base
2133
-     */
2134
-    protected static function _get_model($classname, $timezone = null)
2135
-    {
2136
-        //find model for this class
2137
-        if (! $classname) {
2138
-            throw new EE_Error(
2139
-                sprintf(
2140
-                    esc_html__(
2141
-                        'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2142
-                        'event_espresso'
2143
-                    ),
2144
-                    $classname
2145
-                )
2146
-            );
2147
-        }
2148
-        $modelName = self::_get_model_classname($classname);
2149
-        return self::_get_model_instance_with_name($modelName, $timezone);
2150
-    }
2151
-
2152
-
2153
-    /**
2154
-     * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2155
-     *
2156
-     * @param string $model_classname
2157
-     * @param null   $timezone
2158
-     * @return EEM_Base
2159
-     * @throws ReflectionException
2160
-     * @throws InvalidArgumentException
2161
-     * @throws InvalidInterfaceException
2162
-     * @throws InvalidDataTypeException
2163
-     * @throws EE_Error
2164
-     */
2165
-    protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2166
-    {
2167
-        $model_classname = str_replace('EEM_', '', $model_classname);
2168
-        $model           = EE_Registry::instance()->load_model($model_classname);
2169
-        $model->set_timezone($timezone);
2170
-        return $model;
2171
-    }
2172
-
2173
-
2174
-    /**
2175
-     * If a model name is provided (eg Registration), gets the model classname for that model.
2176
-     * Also works if a model class's classname is provided (eg EE_Registration).
2177
-     *
2178
-     * @param null $model_name
2179
-     * @return string like EEM_Attendee
2180
-     */
2181
-    private static function _get_model_classname($model_name = null)
2182
-    {
2183
-        if (strpos($model_name, 'EE_') === 0) {
2184
-            $model_classname = str_replace('EE_', 'EEM_', $model_name);
2185
-        } else {
2186
-            $model_classname = 'EEM_' . $model_name;
2187
-        }
2188
-        return $model_classname;
2189
-    }
2190
-
2191
-
2192
-    /**
2193
-     * returns the name of the primary key attribute
2194
-     *
2195
-     * @param null $classname
2196
-     * @throws ReflectionException
2197
-     * @throws InvalidArgumentException
2198
-     * @throws InvalidInterfaceException
2199
-     * @throws InvalidDataTypeException
2200
-     * @throws EE_Error
2201
-     * @return string
2202
-     */
2203
-    protected static function _get_primary_key_name($classname = null)
2204
-    {
2205
-        if (! $classname) {
2206
-            throw new EE_Error(
2207
-                sprintf(
2208
-                    esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2209
-                    $classname
2210
-                )
2211
-            );
2212
-        }
2213
-        return self::_get_model($classname)->get_primary_key_field()->get_name();
2214
-    }
2215
-
2216
-
2217
-    /**
2218
-     * Gets the value of the primary key.
2219
-     * If the object hasn't yet been saved, it should be whatever the model field's default was
2220
-     * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2221
-     * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2222
-     *
2223
-     * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2224
-     * @throws ReflectionException
2225
-     * @throws InvalidArgumentException
2226
-     * @throws InvalidInterfaceException
2227
-     * @throws InvalidDataTypeException
2228
-     * @throws EE_Error
2229
-     */
2230
-    public function ID()
2231
-    {
2232
-        $model = $this->get_model();
2233
-        //now that we know the name of the variable, use a variable variable to get its value and return its
2234
-        if ($model->has_primary_key_field()) {
2235
-            return $this->_fields[ $model->primary_key_name() ];
2236
-        }
2237
-        return $model->get_index_primary_key_string($this->_fields);
2238
-    }
2239
-
2240
-
2241
-    /**
2242
-     * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2243
-     * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2244
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2245
-     *
2246
-     * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2247
-     * @param string $relationName                     eg 'Events','Question',etc.
2248
-     *                                                 an attendee to a group, you also want to specify which role they
2249
-     *                                                 will have in that group. So you would use this parameter to
2250
-     *                                                 specify array('role-column-name'=>'role-id')
2251
-     * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2252
-     *                                                 allow you to further constrict the relation to being added.
2253
-     *                                                 However, keep in mind that the columns (keys) given must match a
2254
-     *                                                 column on the JOIN table and currently only the HABTM models
2255
-     *                                                 accept these additional conditions.  Also remember that if an
2256
-     *                                                 exact match isn't found for these extra cols/val pairs, then a
2257
-     *                                                 NEW row is created in the join table.
2258
-     * @param null   $cache_id
2259
-     * @throws ReflectionException
2260
-     * @throws InvalidArgumentException
2261
-     * @throws InvalidInterfaceException
2262
-     * @throws InvalidDataTypeException
2263
-     * @throws EE_Error
2264
-     * @return EE_Base_Class the object the relation was added to
2265
-     */
2266
-    public function _add_relation_to(
2267
-        $otherObjectModelObjectOrID,
2268
-        $relationName,
2269
-        $extra_join_model_fields_n_values = array(),
2270
-        $cache_id = null
2271
-    ) {
2272
-        $model = $this->get_model();
2273
-        //if this thing exists in the DB, save the relation to the DB
2274
-        if ($this->ID()) {
2275
-            $otherObject = $model->add_relationship_to(
2276
-                $this,
2277
-                $otherObjectModelObjectOrID,
2278
-                $relationName,
2279
-                $extra_join_model_fields_n_values
2280
-            );
2281
-            //clear cache so future get_many_related and get_first_related() return new results.
2282
-            $this->clear_cache($relationName, $otherObject, true);
2283
-            if ($otherObject instanceof EE_Base_Class) {
2284
-                $otherObject->clear_cache($model->get_this_model_name(), $this);
2285
-            }
2286
-        } else {
2287
-            //this thing doesn't exist in the DB,  so just cache it
2288
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289
-                throw new EE_Error(
2290
-                    sprintf(
2291
-                        esc_html__(
2292
-                            'Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2293
-                            'event_espresso'
2294
-                        ),
2295
-                        $otherObjectModelObjectOrID,
2296
-                        get_class($this)
2297
-                    )
2298
-                );
2299
-            }
2300
-            $otherObject = $otherObjectModelObjectOrID;
2301
-            $this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2302
-        }
2303
-        if ($otherObject instanceof EE_Base_Class) {
2304
-            //fix the reciprocal relation too
2305
-            if ($otherObject->ID()) {
2306
-                //its saved so assumed relations exist in the DB, so we can just
2307
-                //clear the cache so future queries use the updated info in the DB
2308
-                $otherObject->clear_cache(
2309
-                    $model->get_this_model_name(),
2310
-                    null,
2311
-                    true
2312
-                );
2313
-            } else {
2314
-                //it's not saved, so it caches relations like this
2315
-                $otherObject->cache($model->get_this_model_name(), $this);
2316
-            }
2317
-        }
2318
-        return $otherObject;
2319
-    }
2320
-
2321
-
2322
-    /**
2323
-     * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2324
-     * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2325
-     * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2326
-     * from the cache
2327
-     *
2328
-     * @param mixed  $otherObjectModelObjectOrID
2329
-     *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2330
-     *                to the DB yet
2331
-     * @param string $relationName
2332
-     * @param array  $where_query
2333
-     *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2334
-     *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2335
-     *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2336
-     *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2337
-     *                created in the join table.
2338
-     * @return EE_Base_Class the relation was removed from
2339
-     * @throws ReflectionException
2340
-     * @throws InvalidArgumentException
2341
-     * @throws InvalidInterfaceException
2342
-     * @throws InvalidDataTypeException
2343
-     * @throws EE_Error
2344
-     */
2345
-    public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2346
-    {
2347
-        if ($this->ID()) {
2348
-            //if this exists in the DB, save the relation change to the DB too
2349
-            $otherObject = $this->get_model()->remove_relationship_to(
2350
-                $this,
2351
-                $otherObjectModelObjectOrID,
2352
-                $relationName,
2353
-                $where_query
2354
-            );
2355
-            $this->clear_cache(
2356
-                $relationName,
2357
-                $otherObject
2358
-            );
2359
-        } else {
2360
-            //this doesn't exist in the DB, just remove it from the cache
2361
-            $otherObject = $this->clear_cache(
2362
-                $relationName,
2363
-                $otherObjectModelObjectOrID
2364
-            );
2365
-        }
2366
-        if ($otherObject instanceof EE_Base_Class) {
2367
-            $otherObject->clear_cache(
2368
-                $this->get_model()->get_this_model_name(),
2369
-                $this
2370
-            );
2371
-        }
2372
-        return $otherObject;
2373
-    }
2374
-
2375
-
2376
-    /**
2377
-     * Removes ALL the related things for the $relationName.
2378
-     *
2379
-     * @param string $relationName
2380
-     * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2381
-     * @return EE_Base_Class
2382
-     * @throws ReflectionException
2383
-     * @throws InvalidArgumentException
2384
-     * @throws InvalidInterfaceException
2385
-     * @throws InvalidDataTypeException
2386
-     * @throws EE_Error
2387
-     */
2388
-    public function _remove_relations($relationName, $where_query_params = array())
2389
-    {
2390
-        if ($this->ID()) {
2391
-            //if this exists in the DB, save the relation change to the DB too
2392
-            $otherObjects = $this->get_model()->remove_relations(
2393
-                $this,
2394
-                $relationName,
2395
-                $where_query_params
2396
-            );
2397
-            $this->clear_cache(
2398
-                $relationName,
2399
-                null,
2400
-                true
2401
-            );
2402
-        } else {
2403
-            //this doesn't exist in the DB, just remove it from the cache
2404
-            $otherObjects = $this->clear_cache(
2405
-                $relationName,
2406
-                null,
2407
-                true
2408
-            );
2409
-        }
2410
-        if (is_array($otherObjects)) {
2411
-            foreach ($otherObjects as $otherObject) {
2412
-                $otherObject->clear_cache(
2413
-                    $this->get_model()->get_this_model_name(),
2414
-                    $this
2415
-                );
2416
-            }
2417
-        }
2418
-        return $otherObjects;
2419
-    }
2420
-
2421
-
2422
-    /**
2423
-     * Gets all the related model objects of the specified type. Eg, if the current class if
2424
-     * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2425
-     * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2426
-     * because we want to get even deleted items etc.
2427
-     *
2428
-     * @param string $relationName key in the model's _model_relations array
2429
-     * @param array  $query_params like EEM_Base::get_all
2430
-     * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2431
-     *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2432
-     *                             results if you want IDs
2433
-     * @throws ReflectionException
2434
-     * @throws InvalidArgumentException
2435
-     * @throws InvalidInterfaceException
2436
-     * @throws InvalidDataTypeException
2437
-     * @throws EE_Error
2438
-     */
2439
-    public function get_many_related($relationName, $query_params = array())
2440
-    {
2441
-        if ($this->ID()) {
2442
-            //this exists in the DB, so get the related things from either the cache or the DB
2443
-            //if there are query parameters, forget about caching the related model objects.
2444
-            if ($query_params) {
2445
-                $related_model_objects = $this->get_model()->get_all_related(
2446
-                    $this,
2447
-                    $relationName,
2448
-                    $query_params
2449
-                );
2450
-            } else {
2451
-                //did we already cache the result of this query?
2452
-                $cached_results = $this->get_all_from_cache($relationName);
2453
-                if (! $cached_results) {
2454
-                    $related_model_objects = $this->get_model()->get_all_related(
2455
-                        $this,
2456
-                        $relationName,
2457
-                        $query_params
2458
-                    );
2459
-                    //if no query parameters were passed, then we got all the related model objects
2460
-                    //for that relation. We can cache them then.
2461
-                    foreach ($related_model_objects as $related_model_object) {
2462
-                        $this->cache($relationName, $related_model_object);
2463
-                    }
2464
-                } else {
2465
-                    $related_model_objects = $cached_results;
2466
-                }
2467
-            }
2468
-        } else {
2469
-            //this doesn't exist in the DB, so just get the related things from the cache
2470
-            $related_model_objects = $this->get_all_from_cache($relationName);
2471
-        }
2472
-        return $related_model_objects;
2473
-    }
2474
-
2475
-
2476
-    /**
2477
-     * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2478
-     * unless otherwise specified in the $query_params
2479
-     *
2480
-     * @param string $relation_name  model_name like 'Event', or 'Registration'
2481
-     * @param array  $query_params   like EEM_Base::get_all's
2482
-     * @param string $field_to_count name of field to count by. By default, uses primary key
2483
-     * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2484
-     *                               that by the setting $distinct to TRUE;
2485
-     * @return int
2486
-     * @throws ReflectionException
2487
-     * @throws InvalidArgumentException
2488
-     * @throws InvalidInterfaceException
2489
-     * @throws InvalidDataTypeException
2490
-     * @throws EE_Error
2491
-     */
2492
-    public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2493
-    {
2494
-        return $this->get_model()->count_related(
2495
-            $this,
2496
-            $relation_name,
2497
-            $query_params,
2498
-            $field_to_count,
2499
-            $distinct
2500
-        );
2501
-    }
2502
-
2503
-
2504
-    /**
2505
-     * Instead of getting the related model objects, simply sums up the values of the specified field.
2506
-     * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2507
-     *
2508
-     * @param string $relation_name model_name like 'Event', or 'Registration'
2509
-     * @param array  $query_params  like EEM_Base::get_all's
2510
-     * @param string $field_to_sum  name of field to count by.
2511
-     *                              By default, uses primary key
2512
-     *                              (which doesn't make much sense, so you should probably change it)
2513
-     * @return int
2514
-     * @throws ReflectionException
2515
-     * @throws InvalidArgumentException
2516
-     * @throws InvalidInterfaceException
2517
-     * @throws InvalidDataTypeException
2518
-     * @throws EE_Error
2519
-     */
2520
-    public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2521
-    {
2522
-        return $this->get_model()->sum_related(
2523
-            $this,
2524
-            $relation_name,
2525
-            $query_params,
2526
-            $field_to_sum
2527
-        );
2528
-    }
2529
-
2530
-
2531
-    /**
2532
-     * Gets the first (ie, one) related model object of the specified type.
2533
-     *
2534
-     * @param string $relationName key in the model's _model_relations array
2535
-     * @param array  $query_params like EEM_Base::get_all
2536
-     * @return EE_Base_Class (not an array, a single object)
2537
-     * @throws ReflectionException
2538
-     * @throws InvalidArgumentException
2539
-     * @throws InvalidInterfaceException
2540
-     * @throws InvalidDataTypeException
2541
-     * @throws EE_Error
2542
-     */
2543
-    public function get_first_related($relationName, $query_params = array())
2544
-    {
2545
-        $model = $this->get_model();
2546
-        if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2547
-            //if they've provided some query parameters, don't bother trying to cache the result
2548
-            //also make sure we're not caching the result of get_first_related
2549
-            //on a relation which should have an array of objects (because the cache might have an array of objects)
2550
-            if ($query_params
2551
-                || ! $model->related_settings_for($relationName)
2552
-                     instanceof
2553
-                     EE_Belongs_To_Relation
2554
-            ) {
2555
-                $related_model_object = $model->get_first_related(
2556
-                    $this,
2557
-                    $relationName,
2558
-                    $query_params
2559
-                );
2560
-            } else {
2561
-                //first, check if we've already cached the result of this query
2562
-                $cached_result = $this->get_one_from_cache($relationName);
2563
-                if (! $cached_result) {
2564
-                    $related_model_object = $model->get_first_related(
2565
-                        $this,
2566
-                        $relationName,
2567
-                        $query_params
2568
-                    );
2569
-                    $this->cache($relationName, $related_model_object);
2570
-                } else {
2571
-                    $related_model_object = $cached_result;
2572
-                }
2573
-            }
2574
-        } else {
2575
-            $related_model_object = null;
2576
-            // this doesn't exist in the Db,
2577
-            // but maybe the relation is of type belongs to, and so the related thing might
2578
-            if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2579
-                $related_model_object = $model->get_first_related(
2580
-                    $this,
2581
-                    $relationName,
2582
-                    $query_params
2583
-                );
2584
-            }
2585
-            // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586
-            // just get what's cached on this object
2587
-            if (! $related_model_object) {
2588
-                $related_model_object = $this->get_one_from_cache($relationName);
2589
-            }
2590
-        }
2591
-        return $related_model_object;
2592
-    }
2593
-
2594
-
2595
-    /**
2596
-     * Does a delete on all related objects of type $relationName and removes
2597
-     * the current model object's relation to them. If they can't be deleted (because
2598
-     * of blocking related model objects) does nothing. If the related model objects are
2599
-     * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2600
-     * If this model object doesn't exist yet in the DB, just removes its related things
2601
-     *
2602
-     * @param string $relationName
2603
-     * @param array  $query_params like EEM_Base::get_all's
2604
-     * @return int how many deleted
2605
-     * @throws ReflectionException
2606
-     * @throws InvalidArgumentException
2607
-     * @throws InvalidInterfaceException
2608
-     * @throws InvalidDataTypeException
2609
-     * @throws EE_Error
2610
-     */
2611
-    public function delete_related($relationName, $query_params = array())
2612
-    {
2613
-        if ($this->ID()) {
2614
-            $count = $this->get_model()->delete_related(
2615
-                $this,
2616
-                $relationName,
2617
-                $query_params
2618
-            );
2619
-        } else {
2620
-            $count = count($this->get_all_from_cache($relationName));
2621
-            $this->clear_cache($relationName, null, true);
2622
-        }
2623
-        return $count;
2624
-    }
2625
-
2626
-
2627
-    /**
2628
-     * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2629
-     * the current model object's relation to them. If they can't be deleted (because
2630
-     * of blocking related model objects) just does a soft delete on it instead, if possible.
2631
-     * If the related thing isn't a soft-deletable model object, this function is identical
2632
-     * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2633
-     *
2634
-     * @param string $relationName
2635
-     * @param array  $query_params like EEM_Base::get_all's
2636
-     * @return int how many deleted (including those soft deleted)
2637
-     * @throws ReflectionException
2638
-     * @throws InvalidArgumentException
2639
-     * @throws InvalidInterfaceException
2640
-     * @throws InvalidDataTypeException
2641
-     * @throws EE_Error
2642
-     */
2643
-    public function delete_related_permanently($relationName, $query_params = array())
2644
-    {
2645
-        if ($this->ID()) {
2646
-            $count = $this->get_model()->delete_related_permanently(
2647
-                $this,
2648
-                $relationName,
2649
-                $query_params
2650
-            );
2651
-        } else {
2652
-            $count = count($this->get_all_from_cache($relationName));
2653
-        }
2654
-        $this->clear_cache($relationName, null, true);
2655
-        return $count;
2656
-    }
2657
-
2658
-
2659
-    /**
2660
-     * is_set
2661
-     * Just a simple utility function children can use for checking if property exists
2662
-     *
2663
-     * @access  public
2664
-     * @param  string $field_name property to check
2665
-     * @return bool                              TRUE if existing,FALSE if not.
2666
-     */
2667
-    public function is_set($field_name)
2668
-    {
2669
-        return isset($this->_fields[ $field_name ]);
2670
-    }
2671
-
2672
-
2673
-    /**
2674
-     * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2675
-     * EE_Error exception if they don't
2676
-     *
2677
-     * @param  mixed (string|array) $properties properties to check
2678
-     * @throws EE_Error
2679
-     * @return bool                              TRUE if existing, throw EE_Error if not.
2680
-     */
2681
-    protected function _property_exists($properties)
2682
-    {
2683
-        foreach ((array) $properties as $property_name) {
2684
-            //first make sure this property exists
2685
-            if (! $this->_fields[ $property_name ]) {
2686
-                throw new EE_Error(
2687
-                    sprintf(
2688
-                        esc_html__(
2689
-                            'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2690
-                            'event_espresso'
2691
-                        ),
2692
-                        $property_name
2693
-                    )
2694
-                );
2695
-            }
2696
-        }
2697
-        return true;
2698
-    }
2699
-
2700
-
2701
-    /**
2702
-     * This simply returns an array of model fields for this object
2703
-     *
2704
-     * @return array
2705
-     * @throws ReflectionException
2706
-     * @throws InvalidArgumentException
2707
-     * @throws InvalidInterfaceException
2708
-     * @throws InvalidDataTypeException
2709
-     * @throws EE_Error
2710
-     */
2711
-    public function model_field_array()
2712
-    {
2713
-        $fields     = $this->get_model()->field_settings(false);
2714
-        $properties = array();
2715
-        //remove prepended underscore
2716
-        foreach ($fields as $field_name => $settings) {
2717
-            $properties[ $field_name ] = $this->get($field_name);
2718
-        }
2719
-        return $properties;
2720
-    }
2721
-
2722
-
2723
-    /**
2724
-     * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2725
-     * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2726
-     * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2727
-     * Instead of requiring a plugin to extend the EE_Base_Class
2728
-     * (which works fine is there's only 1 plugin, but when will that happen?)
2729
-     * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2730
-     * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2731
-     * and accepts 2 arguments: the object on which the function was called,
2732
-     * and an array of the original arguments passed to the function.
2733
-     * Whatever their callback function returns will be returned by this function.
2734
-     * Example: in functions.php (or in a plugin):
2735
-     *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2736
-     *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2737
-     *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2738
-     *          return $previousReturnValue.$returnString;
2739
-     *      }
2740
-     * require('EE_Answer.class.php');
2741
-     * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2742
-     * echo $answer->my_callback('monkeys',100);
2743
-     * //will output "you called my_callback! and passed args:monkeys,100"
2744
-     *
2745
-     * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2746
-     * @param array  $args       array of original arguments passed to the function
2747
-     * @throws EE_Error
2748
-     * @return mixed whatever the plugin which calls add_filter decides
2749
-     */
2750
-    public function __call($methodName, $args)
2751
-    {
2752
-        $className = get_class($this);
2753
-        $tagName   = "FHEE__{$className}__{$methodName}";
2754
-        if (! has_filter($tagName)) {
2755
-            throw new EE_Error(
2756
-                sprintf(
2757
-                    esc_html__(
2758
-                        "Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2759
-                        'event_espresso'
2760
-                    ),
2761
-                    $methodName,
2762
-                    $className,
2763
-                    $tagName
2764
-                )
2765
-            );
2766
-        }
2767
-        return apply_filters($tagName, null, $this, $args);
2768
-    }
2769
-
2770
-
2771
-    /**
2772
-     * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2773
-     * A $previous_value can be specified in case there are many meta rows with the same key
2774
-     *
2775
-     * @param string $meta_key
2776
-     * @param mixed  $meta_value
2777
-     * @param mixed  $previous_value
2778
-     * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2779
-     *                  NOTE: if the values haven't changed, returns 0
2780
-     * @throws InvalidArgumentException
2781
-     * @throws InvalidInterfaceException
2782
-     * @throws InvalidDataTypeException
2783
-     * @throws EE_Error
2784
-     * @throws ReflectionException
2785
-     */
2786
-    public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2787
-    {
2788
-        $query_params = array(
2789
-            array(
2790
-                'EXM_key'  => $meta_key,
2791
-                'OBJ_ID'   => $this->ID(),
2792
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2793
-            ),
2794
-        );
2795
-        if ($previous_value !== null) {
2796
-            $query_params[0]['EXM_value'] = $meta_value;
2797
-        }
2798
-        $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
-        if (! $existing_rows_like_that) {
2800
-            return $this->add_extra_meta($meta_key, $meta_value);
2801
-        }
2802
-        foreach ($existing_rows_like_that as $existing_row) {
2803
-            $existing_row->save(array('EXM_value' => $meta_value));
2804
-        }
2805
-        return count($existing_rows_like_that);
2806
-    }
2807
-
2808
-
2809
-    /**
2810
-     * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2811
-     * no other extra meta for this model object have the same key. Returns TRUE if the
2812
-     * extra meta row was entered, false if not
2813
-     *
2814
-     * @param string  $meta_key
2815
-     * @param mixed   $meta_value
2816
-     * @param boolean $unique
2817
-     * @return boolean
2818
-     * @throws InvalidArgumentException
2819
-     * @throws InvalidInterfaceException
2820
-     * @throws InvalidDataTypeException
2821
-     * @throws EE_Error
2822
-     * @throws ReflectionException
2823
-     * @throws ReflectionException
2824
-     */
2825
-    public function add_extra_meta($meta_key, $meta_value, $unique = false)
2826
-    {
2827
-        if ($unique) {
2828
-            $existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2829
-                array(
2830
-                    array(
2831
-                        'EXM_key'  => $meta_key,
2832
-                        'OBJ_ID'   => $this->ID(),
2833
-                        'EXM_type' => $this->get_model()->get_this_model_name(),
2834
-                    ),
2835
-                )
2836
-            );
2837
-            if ($existing_extra_meta) {
2838
-                return false;
2839
-            }
2840
-        }
2841
-        $new_extra_meta = EE_Extra_Meta::new_instance(
2842
-            array(
2843
-                'EXM_key'   => $meta_key,
2844
-                'EXM_value' => $meta_value,
2845
-                'OBJ_ID'    => $this->ID(),
2846
-                'EXM_type'  => $this->get_model()->get_this_model_name(),
2847
-            )
2848
-        );
2849
-        $new_extra_meta->save();
2850
-        return true;
2851
-    }
2852
-
2853
-
2854
-    /**
2855
-     * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2856
-     * is specified, only deletes extra meta records with that value.
2857
-     *
2858
-     * @param string $meta_key
2859
-     * @param mixed  $meta_value
2860
-     * @return int number of extra meta rows deleted
2861
-     * @throws InvalidArgumentException
2862
-     * @throws InvalidInterfaceException
2863
-     * @throws InvalidDataTypeException
2864
-     * @throws EE_Error
2865
-     * @throws ReflectionException
2866
-     */
2867
-    public function delete_extra_meta($meta_key, $meta_value = null)
2868
-    {
2869
-        $query_params = array(
2870
-            array(
2871
-                'EXM_key'  => $meta_key,
2872
-                'OBJ_ID'   => $this->ID(),
2873
-                'EXM_type' => $this->get_model()->get_this_model_name(),
2874
-            ),
2875
-        );
2876
-        if ($meta_value !== null) {
2877
-            $query_params[0]['EXM_value'] = $meta_value;
2878
-        }
2879
-        return EEM_Extra_Meta::instance()->delete($query_params);
2880
-    }
2881
-
2882
-
2883
-    /**
2884
-     * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2885
-     * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2886
-     * You can specify $default is case you haven't found the extra meta
2887
-     *
2888
-     * @param string  $meta_key
2889
-     * @param boolean $single
2890
-     * @param mixed   $default if we don't find anything, what should we return?
2891
-     * @return mixed single value if $single; array if ! $single
2892
-     * @throws ReflectionException
2893
-     * @throws InvalidArgumentException
2894
-     * @throws InvalidInterfaceException
2895
-     * @throws InvalidDataTypeException
2896
-     * @throws EE_Error
2897
-     */
2898
-    public function get_extra_meta($meta_key, $single = false, $default = null)
2899
-    {
2900
-        if ($single) {
2901
-            $result = $this->get_first_related(
2902
-                'Extra_Meta',
2903
-                array(array('EXM_key' => $meta_key))
2904
-            );
2905
-            if ($result instanceof EE_Extra_Meta) {
2906
-                return $result->value();
2907
-            }
2908
-        } else {
2909
-            $results = $this->get_many_related(
2910
-                'Extra_Meta',
2911
-                array(array('EXM_key' => $meta_key))
2912
-            );
2913
-            if ($results) {
2914
-                $values = array();
2915
-                foreach ($results as $result) {
2916
-                    if ($result instanceof EE_Extra_Meta) {
2917
-                        $values[ $result->ID() ] = $result->value();
2918
-                    }
2919
-                }
2920
-                return $values;
2921
-            }
2922
-        }
2923
-        //if nothing discovered yet return default.
2924
-        return apply_filters(
2925
-            'FHEE__EE_Base_Class__get_extra_meta__default_value',
2926
-            $default,
2927
-            $meta_key,
2928
-            $single,
2929
-            $this
2930
-        );
2931
-    }
2932
-
2933
-
2934
-    /**
2935
-     * Returns a simple array of all the extra meta associated with this model object.
2936
-     * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2937
-     * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2938
-     * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2939
-     * If $one_of_each_key is false, it will return an array with the top-level keys being
2940
-     * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2941
-     * finally the extra meta's value as each sub-value. (eg
2942
-     * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2943
-     *
2944
-     * @param boolean $one_of_each_key
2945
-     * @return array
2946
-     * @throws ReflectionException
2947
-     * @throws InvalidArgumentException
2948
-     * @throws InvalidInterfaceException
2949
-     * @throws InvalidDataTypeException
2950
-     * @throws EE_Error
2951
-     */
2952
-    public function all_extra_meta_array($one_of_each_key = true)
2953
-    {
2954
-        $return_array = array();
2955
-        if ($one_of_each_key) {
2956
-            $extra_meta_objs = $this->get_many_related(
2957
-                'Extra_Meta',
2958
-                array('group_by' => 'EXM_key')
2959
-            );
2960
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2961
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2963
-                }
2964
-            }
2965
-        } else {
2966
-            $extra_meta_objs = $this->get_many_related('Extra_Meta');
2967
-            foreach ($extra_meta_objs as $extra_meta_obj) {
2968
-                if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
-                        $return_array[ $extra_meta_obj->key() ] = array();
2971
-                    }
2972
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2973
-                }
2974
-            }
2975
-        }
2976
-        return $return_array;
2977
-    }
2978
-
2979
-
2980
-    /**
2981
-     * Gets a pretty nice displayable nice for this model object. Often overridden
2982
-     *
2983
-     * @return string
2984
-     * @throws ReflectionException
2985
-     * @throws InvalidArgumentException
2986
-     * @throws InvalidInterfaceException
2987
-     * @throws InvalidDataTypeException
2988
-     * @throws EE_Error
2989
-     */
2990
-    public function name()
2991
-    {
2992
-        //find a field that's not a text field
2993
-        $field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2994
-        if ($field_we_can_use) {
2995
-            return $this->get($field_we_can_use->get_name());
2996
-        }
2997
-        $first_few_properties = $this->model_field_array();
2998
-        $first_few_properties = array_slice($first_few_properties, 0, 3);
2999
-        $name_parts           = array();
3000
-        foreach ($first_few_properties as $name => $value) {
3001
-            $name_parts[] = "$name:$value";
3002
-        }
3003
-        return implode(',', $name_parts);
3004
-    }
3005
-
3006
-
3007
-    /**
3008
-     * in_entity_map
3009
-     * Checks if this model object has been proven to already be in the entity map
3010
-     *
3011
-     * @return boolean
3012
-     * @throws ReflectionException
3013
-     * @throws InvalidArgumentException
3014
-     * @throws InvalidInterfaceException
3015
-     * @throws InvalidDataTypeException
3016
-     * @throws EE_Error
3017
-     */
3018
-    public function in_entity_map()
3019
-    {
3020
-        // well, if we looked, did we find it in the entity map?
3021
-        return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3022
-    }
3023
-
3024
-
3025
-    /**
3026
-     * refresh_from_db
3027
-     * Makes sure the fields and values on this model object are in-sync with what's in the database.
3028
-     *
3029
-     * @throws ReflectionException
3030
-     * @throws InvalidArgumentException
3031
-     * @throws InvalidInterfaceException
3032
-     * @throws InvalidDataTypeException
3033
-     * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3034
-     * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3035
-     */
3036
-    public function refresh_from_db()
3037
-    {
3038
-        if ($this->ID() && $this->in_entity_map()) {
3039
-            $this->get_model()->refresh_entity_map_from_db($this->ID());
3040
-        } else {
3041
-            //if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3042
-            //if it has an ID but it's not in the map, and you're asking me to refresh it
3043
-            //that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3044
-            //absolutely nothing in it for this ID
3045
-            if (WP_DEBUG) {
3046
-                throw new EE_Error(
3047
-                    sprintf(
3048
-                        esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3049
-                            'event_espresso'),
3050
-                        $this->ID(),
3051
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3053
-                    )
3054
-                );
3055
-            }
3056
-        }
3057
-    }
3058
-
3059
-
3060
-    /**
3061
-     * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3062
-     * (probably a bad assumption they have made, oh well)
3063
-     *
3064
-     * @return string
3065
-     */
3066
-    public function __toString()
3067
-    {
3068
-        try {
3069
-            return sprintf('%s (%s)', $this->name(), $this->ID());
3070
-        } catch (Exception $e) {
3071
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3072
-            return '';
3073
-        }
3074
-    }
3075
-
3076
-
3077
-    /**
3078
-     * Clear related model objects if they're already in the DB, because otherwise when we
3079
-     * UN-serialize this model object we'll need to be careful to add them to the entity map.
3080
-     * This means if we have made changes to those related model objects, and want to unserialize
3081
-     * the this model object on a subsequent request, changes to those related model objects will be lost.
3082
-     * Instead, those related model objects should be directly serialized and stored.
3083
-     * Eg, the following won't work:
3084
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3085
-     * $att = $reg->attendee();
3086
-     * $att->set( 'ATT_fname', 'Dirk' );
3087
-     * update_option( 'my_option', serialize( $reg ) );
3088
-     * //END REQUEST
3089
-     * //START NEXT REQUEST
3090
-     * $reg = get_option( 'my_option' );
3091
-     * $reg->attendee()->save();
3092
-     * And would need to be replace with:
3093
-     * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3094
-     * $att = $reg->attendee();
3095
-     * $att->set( 'ATT_fname', 'Dirk' );
3096
-     * update_option( 'my_option', serialize( $reg ) );
3097
-     * //END REQUEST
3098
-     * //START NEXT REQUEST
3099
-     * $att = get_option( 'my_option' );
3100
-     * $att->save();
3101
-     *
3102
-     * @return array
3103
-     * @throws ReflectionException
3104
-     * @throws InvalidArgumentException
3105
-     * @throws InvalidInterfaceException
3106
-     * @throws InvalidDataTypeException
3107
-     * @throws EE_Error
3108
-     */
3109
-    public function __sleep()
3110
-    {
3111
-        $model = $this->get_model();
3112
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113
-            if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
-                $classname = 'EE_' . $model->get_this_model_name();
3115
-                if (
3116
-                    $this->get_one_from_cache($relation_name) instanceof $classname
3117
-                    && $this->get_one_from_cache($relation_name)->ID()
3118
-                ) {
3119
-                    $this->clear_cache(
3120
-                        $relation_name,
3121
-                        $this->get_one_from_cache($relation_name)->ID()
3122
-                    );
3123
-                }
3124
-            }
3125
-        }
3126
-        $this->_props_n_values_provided_in_constructor = array();
3127
-        $properties_to_serialize                       = get_object_vars($this);
3128
-        //don't serialize the model. It's big and that risks recursion
3129
-        unset($properties_to_serialize['_model']);
3130
-        return array_keys($properties_to_serialize);
3131
-    }
3132
-
3133
-
3134
-    /**
3135
-     * restore _props_n_values_provided_in_constructor
3136
-     * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3137
-     * and therefore should NOT be used to determine if state change has occurred since initial construction.
3138
-     * At best, you would only be able to detect if state change has occurred during THIS request.
3139
-     */
3140
-    public function __wakeup()
3141
-    {
3142
-        $this->_props_n_values_provided_in_constructor = $this->_fields;
3143
-    }
3144
-
3145
-
3146
-    /**
3147
-     * Usage of this magic method is to ensure any internally cached references to object instances that must remain
3148
-     * distinct with the clone host instance are also cloned.
3149
-     */
3150
-    public function __clone()
3151
-    {
3152
-        //handle DateTimes (this is handled in here because there's no one specific child class that uses datetimes).
3153
-        foreach ($this->_fields as $field => $value) {
3154
-            if ($value instanceof DateTime) {
3155
-                $this->_fields[$field] = clone $value;
3156
-            }
3157
-        }
3158
-    }
18
+	/**
19
+	 * This is an array of the original properties and values provided during construction
20
+	 * of this model object. (keys are model field names, values are their values).
21
+	 * This list is important to remember so that when we are merging data from the db, we know
22
+	 * which values to override and which to not override.
23
+	 *
24
+	 * @var array
25
+	 */
26
+	protected $_props_n_values_provided_in_constructor;
27
+
28
+	/**
29
+	 * Timezone
30
+	 * This gets set by the "set_timezone()" method so that we know what timezone incoming strings|timestamps are in.
31
+	 * This can also be used before a get to set what timezone you want strings coming out of the object to be in.  NOT
32
+	 * all EE_Base_Class child classes use this property but any that use a EE_Datetime_Field data type will have
33
+	 * access to it.
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $_timezone;
38
+
39
+	/**
40
+	 * date format
41
+	 * pattern or format for displaying dates
42
+	 *
43
+	 * @var string $_dt_frmt
44
+	 */
45
+	protected $_dt_frmt;
46
+
47
+	/**
48
+	 * time format
49
+	 * pattern or format for displaying time
50
+	 *
51
+	 * @var string $_tm_frmt
52
+	 */
53
+	protected $_tm_frmt;
54
+
55
+	/**
56
+	 * This property is for holding a cached array of object properties indexed by property name as the key.
57
+	 * The purpose of this is for setting a cache on properties that may have calculated values after a
58
+	 * prepare_for_get.  That way the cache can be checked first and the calculated property returned instead of having
59
+	 * to recalculate. Used by _set_cached_property() and _get_cached_property() methods.
60
+	 *
61
+	 * @var array
62
+	 */
63
+	protected $_cached_properties = array();
64
+
65
+	/**
66
+	 * An array containing keys of the related model, and values are either an array of related mode objects or a
67
+	 * single
68
+	 * related model object. see the model's _model_relations. The keys should match those specified. And if the
69
+	 * relation is of type EE_Belongs_To (or one of its children), then there should only be ONE related model object,
70
+	 * all others have an array)
71
+	 *
72
+	 * @var array
73
+	 */
74
+	protected $_model_relations = array();
75
+
76
+	/**
77
+	 * Array where keys are field names (see the model's _fields property) and values are their values. To see what
78
+	 * their types should be, look at what that field object returns on its prepare_for_get and prepare_for_set methods)
79
+	 *
80
+	 * @var array
81
+	 */
82
+	protected $_fields = array();
83
+
84
+	/**
85
+	 * @var boolean indicating whether or not this model object is intended to ever be saved
86
+	 * For example, we might create model objects intended to only be used for the duration
87
+	 * of this request and to be thrown away, and if they were accidentally saved
88
+	 * it would be a bug.
89
+	 */
90
+	protected $_allow_persist = true;
91
+
92
+	/**
93
+	 * @var boolean indicating whether or not this model object's properties have changed since construction
94
+	 */
95
+	protected $_has_changes = false;
96
+
97
+	/**
98
+	 * @var EEM_Base
99
+	 */
100
+	protected $_model;
101
+
102
+	/**
103
+	 * This is a cache of results from custom selections done on a query that constructs this entity. The only purpose
104
+	 * for these values is for retrieval of the results, they are not further queryable and they are not persisted to
105
+	 * the db.  They also do not automatically update if there are any changes to the data that produced their results.
106
+	 * The format is a simple array of field_alias => field_value.  So for instance if a custom select was something
107
+	 * like,  "Select COUNT(Registration.REG_ID) as Registration_Count ...", then the resulting value will be in this
108
+	 * array as:
109
+	 * array(
110
+	 *  'Registration_Count' => 24
111
+	 * );
112
+	 * Note: if the custom select configuration for the query included a data type, the value will be in the data type
113
+	 * provided for the query (@see EventEspresso\core\domain\values\model\CustomSelects::__construct phpdocs for more
114
+	 * info)
115
+	 *
116
+	 * @var array
117
+	 */
118
+	protected $custom_selection_results = array();
119
+
120
+
121
+	/**
122
+	 * basic constructor for Event Espresso classes, performs any necessary initialization, and verifies it's children
123
+	 * play nice
124
+	 *
125
+	 * @param array   $fieldValues                             where each key is a field (ie, array key in the 2nd
126
+	 *                                                         layer of the model's _fields array, (eg, EVT_ID,
127
+	 *                                                         TXN_amount, QST_name, etc) and values are their values
128
+	 * @param boolean $bydb                                    a flag for setting if the class is instantiated by the
129
+	 *                                                         corresponding db model or not.
130
+	 * @param string  $timezone                                indicate what timezone you want any datetime fields to
131
+	 *                                                         be in when instantiating a EE_Base_Class object.
132
+	 * @param array   $date_formats                            An array of date formats to set on construct where first
133
+	 *                                                         value is the date_format and second value is the time
134
+	 *                                                         format.
135
+	 * @throws InvalidArgumentException
136
+	 * @throws InvalidInterfaceException
137
+	 * @throws InvalidDataTypeException
138
+	 * @throws EE_Error
139
+	 * @throws ReflectionException
140
+	 */
141
+	protected function __construct($fieldValues = array(), $bydb = false, $timezone = '', $date_formats = array())
142
+	{
143
+		$className = get_class($this);
144
+		do_action("AHEE__{$className}__construct", $this, $fieldValues);
145
+		$model        = $this->get_model();
146
+		$model_fields = $model->field_settings(false);
147
+		// ensure $fieldValues is an array
148
+		$fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149
+		// verify client code has not passed any invalid field names
150
+		foreach ($fieldValues as $field_name => $field_value) {
151
+			if (! isset($model_fields[ $field_name ])) {
152
+				throw new EE_Error(
153
+					sprintf(
154
+						esc_html__(
155
+							'Invalid field (%s) passed to constructor of %s. Allowed fields are :%s',
156
+							'event_espresso'
157
+						),
158
+						$field_name,
159
+						get_class($this),
160
+						implode(', ', array_keys($model_fields))
161
+					)
162
+				);
163
+			}
164
+		}
165
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
+		if (! empty($date_formats) && is_array($date_formats)) {
167
+			list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168
+		} else {
169
+			//set default formats for date and time
170
+			$this->_dt_frmt = (string) get_option('date_format', 'Y-m-d');
171
+			$this->_tm_frmt = (string) get_option('time_format', 'g:i a');
172
+		}
173
+		//if db model is instantiating
174
+		if ($bydb) {
175
+			//client code has indicated these field values are from the database
176
+			foreach ($model_fields as $fieldName => $field) {
177
+				$this->set_from_db(
178
+					$fieldName,
179
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
180
+				);
181
+			}
182
+		} else {
183
+			//we're constructing a brand
184
+			//new instance of the model object. Generally, this means we'll need to do more field validation
185
+			foreach ($model_fields as $fieldName => $field) {
186
+				$this->set(
187
+					$fieldName,
188
+					isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
189
+				);
190
+			}
191
+		}
192
+		//remember what values were passed to this constructor
193
+		$this->_props_n_values_provided_in_constructor = $fieldValues;
194
+		//remember in entity mapper
195
+		if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
196
+			$model->add_to_entity_map($this);
197
+		}
198
+		//setup all the relations
199
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
+				$this->_model_relations[ $relation_name ] = null;
202
+			} else {
203
+				$this->_model_relations[ $relation_name ] = array();
204
+			}
205
+		}
206
+		/**
207
+		 * Action done at the end of each model object construction
208
+		 *
209
+		 * @param EE_Base_Class $this the model object just created
210
+		 */
211
+		do_action('AHEE__EE_Base_Class__construct__finished', $this);
212
+	}
213
+
214
+
215
+	/**
216
+	 * Gets whether or not this model object is allowed to persist/be saved to the database.
217
+	 *
218
+	 * @return boolean
219
+	 */
220
+	public function allow_persist()
221
+	{
222
+		return $this->_allow_persist;
223
+	}
224
+
225
+
226
+	/**
227
+	 * Sets whether or not this model object should be allowed to be saved to the DB.
228
+	 * Normally once this is set to FALSE you wouldn't set it back to TRUE, unless
229
+	 * you got new information that somehow made you change your mind.
230
+	 *
231
+	 * @param boolean $allow_persist
232
+	 * @return boolean
233
+	 */
234
+	public function set_allow_persist($allow_persist)
235
+	{
236
+		return $this->_allow_persist = $allow_persist;
237
+	}
238
+
239
+
240
+	/**
241
+	 * Gets the field's original value when this object was constructed during this request.
242
+	 * This can be helpful when determining if a model object has changed or not
243
+	 *
244
+	 * @param string $field_name
245
+	 * @return mixed|null
246
+	 * @throws ReflectionException
247
+	 * @throws InvalidArgumentException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws InvalidDataTypeException
250
+	 * @throws EE_Error
251
+	 */
252
+	public function get_original($field_name)
253
+	{
254
+		if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
255
+			&& $field_settings = $this->get_model()->field_settings_for($field_name)
256
+		) {
257
+			return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
258
+		}
259
+		return null;
260
+	}
261
+
262
+
263
+	/**
264
+	 * @param EE_Base_Class $obj
265
+	 * @return string
266
+	 */
267
+	public function get_class($obj)
268
+	{
269
+		return get_class($obj);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Overrides parent because parent expects old models.
275
+	 * This also doesn't do any validation, and won't work for serialized arrays
276
+	 *
277
+	 * @param    string $field_name
278
+	 * @param    mixed  $field_value
279
+	 * @param bool      $use_default
280
+	 * @throws InvalidArgumentException
281
+	 * @throws InvalidInterfaceException
282
+	 * @throws InvalidDataTypeException
283
+	 * @throws EE_Error
284
+	 * @throws ReflectionException
285
+	 * @throws ReflectionException
286
+	 * @throws ReflectionException
287
+	 */
288
+	public function set($field_name, $field_value, $use_default = false)
289
+	{
290
+		// if not using default and nothing has changed, and object has already been setup (has ID),
291
+		// then don't do anything
292
+		if (
293
+			! $use_default
294
+			&& $this->_fields[ $field_name ] === $field_value
295
+			&& $this->ID()
296
+		) {
297
+			return;
298
+		}
299
+		$model              = $this->get_model();
300
+		$this->_has_changes = true;
301
+		$field_obj          = $model->field_settings_for($field_name);
302
+		if ($field_obj instanceof EE_Model_Field_Base) {
303
+			//			if ( method_exists( $field_obj, 'set_timezone' )) {
304
+			if ($field_obj instanceof EE_Datetime_Field) {
305
+				$field_obj->set_timezone($this->_timezone);
306
+				$field_obj->set_date_format($this->_dt_frmt);
307
+				$field_obj->set_time_format($this->_tm_frmt);
308
+			}
309
+			$holder_of_value = $field_obj->prepare_for_set($field_value);
310
+			//should the value be null?
311
+			if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
+				$this->_fields[ $field_name ] = $field_obj->get_default_value();
313
+				/**
314
+				 * To save having to refactor all the models, if a default value is used for a
315
+				 * EE_Datetime_Field, and that value is not null nor is it a DateTime
316
+				 * object.  Then let's do a set again to ensure that it becomes a DateTime
317
+				 * object.
318
+				 *
319
+				 * @since 4.6.10+
320
+				 */
321
+				if (
322
+					$field_obj instanceof EE_Datetime_Field
323
+					&& $this->_fields[ $field_name ] !== null
324
+					&& ! $this->_fields[ $field_name ] instanceof DateTime
325
+				) {
326
+					empty($this->_fields[ $field_name ])
327
+						? $this->set($field_name, time())
328
+						: $this->set($field_name, $this->_fields[ $field_name ]);
329
+				}
330
+			} else {
331
+				$this->_fields[ $field_name ] = $holder_of_value;
332
+			}
333
+			//if we're not in the constructor...
334
+			//now check if what we set was a primary key
335
+			if (
336
+				//note: props_n_values_provided_in_constructor is only set at the END of the constructor
337
+				$this->_props_n_values_provided_in_constructor
338
+				&& $field_value
339
+				&& $field_name === $model->primary_key_name()
340
+			) {
341
+				//if so, we want all this object's fields to be filled either with
342
+				//what we've explicitly set on this model
343
+				//or what we have in the db
344
+				// echo "setting primary key!";
345
+				$fields_on_model = self::_get_model(get_class($this))->field_settings();
346
+				$obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347
+				foreach ($fields_on_model as $field_obj) {
348
+					if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349
+						&& $field_obj->get_name() !== $field_name
350
+					) {
351
+						$this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
352
+					}
353
+				}
354
+				//oh this model object has an ID? well make sure its in the entity mapper
355
+				$model->add_to_entity_map($this);
356
+			}
357
+			//let's unset any cache for this field_name from the $_cached_properties property.
358
+			$this->_clear_cached_property($field_name);
359
+		} else {
360
+			throw new EE_Error(
361
+				sprintf(
362
+					esc_html__(
363
+						'A valid EE_Model_Field_Base could not be found for the given field name: %s',
364
+						'event_espresso'
365
+					),
366
+					$field_name
367
+				)
368
+			);
369
+		}
370
+	}
371
+
372
+
373
+	/**
374
+	 * Set custom select values for model.
375
+	 *
376
+	 * @param array $custom_select_values
377
+	 */
378
+	public function setCustomSelectsValues(array $custom_select_values)
379
+	{
380
+		$this->custom_selection_results = $custom_select_values;
381
+	}
382
+
383
+
384
+	/**
385
+	 * Returns the custom select value for the provided alias if its set.
386
+	 * If not set, returns null.
387
+	 *
388
+	 * @param string $alias
389
+	 * @return string|int|float|null
390
+	 */
391
+	public function getCustomSelect($alias)
392
+	{
393
+		return isset($this->custom_selection_results[ $alias ])
394
+			? $this->custom_selection_results[ $alias ]
395
+			: null;
396
+	}
397
+
398
+
399
+	/**
400
+	 * This sets the field value on the db column if it exists for the given $column_name or
401
+	 * saves it to EE_Extra_Meta if the given $column_name does not match a db column.
402
+	 *
403
+	 * @see EE_message::get_column_value for related documentation on the necessity of this method.
404
+	 * @param string $field_name  Must be the exact column name.
405
+	 * @param mixed  $field_value The value to set.
406
+	 * @return int|bool @see EE_Base_Class::update_extra_meta() for return docs.
407
+	 * @throws InvalidArgumentException
408
+	 * @throws InvalidInterfaceException
409
+	 * @throws InvalidDataTypeException
410
+	 * @throws EE_Error
411
+	 * @throws ReflectionException
412
+	 */
413
+	public function set_field_or_extra_meta($field_name, $field_value)
414
+	{
415
+		if ($this->get_model()->has_field($field_name)) {
416
+			$this->set($field_name, $field_value);
417
+			return true;
418
+		}
419
+		//ensure this object is saved first so that extra meta can be properly related.
420
+		$this->save();
421
+		return $this->update_extra_meta($field_name, $field_value);
422
+	}
423
+
424
+
425
+	/**
426
+	 * This retrieves the value of the db column set on this class or if that's not present
427
+	 * it will attempt to retrieve from extra_meta if found.
428
+	 * Example Usage:
429
+	 * Via EE_Message child class:
430
+	 * Due to the dynamic nature of the EE_messages system, EE_messengers will always have a "to",
431
+	 * "from", "subject", and "content" field (as represented in the EE_Message schema), however they may
432
+	 * also have additional main fields specific to the messenger.  The system accommodates those extra
433
+	 * fields through the EE_Extra_Meta table.  This method allows for EE_messengers to retrieve the
434
+	 * value for those extra fields dynamically via the EE_message object.
435
+	 *
436
+	 * @param  string $field_name expecting the fully qualified field name.
437
+	 * @return mixed|null  value for the field if found.  null if not found.
438
+	 * @throws ReflectionException
439
+	 * @throws InvalidArgumentException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws EE_Error
443
+	 */
444
+	public function get_field_or_extra_meta($field_name)
445
+	{
446
+		if ($this->get_model()->has_field($field_name)) {
447
+			$column_value = $this->get($field_name);
448
+		} else {
449
+			//This isn't a column in the main table, let's see if it is in the extra meta.
450
+			$column_value = $this->get_extra_meta($field_name, true, null);
451
+		}
452
+		return $column_value;
453
+	}
454
+
455
+
456
+	/**
457
+	 * See $_timezone property for description of what the timezone property is for.  This SETS the timezone internally
458
+	 * for being able to reference what timezone we are running conversions on when converting TO the internal timezone
459
+	 * (UTC Unix Timestamp) for the object OR when converting FROM the internal timezone (UTC Unix Timestamp). This is
460
+	 * available to all child classes that may be using the EE_Datetime_Field for a field data type.
461
+	 *
462
+	 * @access public
463
+	 * @param string $timezone A valid timezone string as described by @link http://www.php.net/manual/en/timezones.php
464
+	 * @return void
465
+	 * @throws InvalidArgumentException
466
+	 * @throws InvalidInterfaceException
467
+	 * @throws InvalidDataTypeException
468
+	 * @throws EE_Error
469
+	 * @throws ReflectionException
470
+	 */
471
+	public function set_timezone($timezone = '')
472
+	{
473
+		$this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
474
+		//make sure we clear all cached properties because they won't be relevant now
475
+		$this->_clear_cached_properties();
476
+		//make sure we update field settings and the date for all EE_Datetime_Fields
477
+		$model_fields = $this->get_model()->field_settings(false);
478
+		foreach ($model_fields as $field_name => $field_obj) {
479
+			if ($field_obj instanceof EE_Datetime_Field) {
480
+				$field_obj->set_timezone($this->_timezone);
481
+				if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
+					$this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
483
+				}
484
+			}
485
+		}
486
+	}
487
+
488
+
489
+	/**
490
+	 * This just returns whatever is set for the current timezone.
491
+	 *
492
+	 * @access public
493
+	 * @return string timezone string
494
+	 */
495
+	public function get_timezone()
496
+	{
497
+		return $this->_timezone;
498
+	}
499
+
500
+
501
+	/**
502
+	 * This sets the internal date format to what is sent in to be used as the new default for the class
503
+	 * internally instead of wp set date format options
504
+	 *
505
+	 * @since 4.6
506
+	 * @param string $format should be a format recognizable by PHP date() functions.
507
+	 */
508
+	public function set_date_format($format)
509
+	{
510
+		$this->_dt_frmt = $format;
511
+		//clear cached_properties because they won't be relevant now.
512
+		$this->_clear_cached_properties();
513
+	}
514
+
515
+
516
+	/**
517
+	 * This sets the internal time format string to what is sent in to be used as the new default for the
518
+	 * class internally instead of wp set time format options.
519
+	 *
520
+	 * @since 4.6
521
+	 * @param string $format should be a format recognizable by PHP date() functions.
522
+	 */
523
+	public function set_time_format($format)
524
+	{
525
+		$this->_tm_frmt = $format;
526
+		//clear cached_properties because they won't be relevant now.
527
+		$this->_clear_cached_properties();
528
+	}
529
+
530
+
531
+	/**
532
+	 * This returns the current internal set format for the date and time formats.
533
+	 *
534
+	 * @param bool $full           if true (default), then return the full format.  Otherwise will return an array
535
+	 *                             where the first value is the date format and the second value is the time format.
536
+	 * @return mixed string|array
537
+	 */
538
+	public function get_format($full = true)
539
+	{
540
+		return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541
+	}
542
+
543
+
544
+	/**
545
+	 * cache
546
+	 * stores the passed model object on the current model object.
547
+	 * In certain circumstances, we can use this cached model object instead of querying for another one entirely.
548
+	 *
549
+	 * @param string        $relationName    one of the keys in the _model_relations array on the model. Eg
550
+	 *                                       'Registration' associated with this model object
551
+	 * @param EE_Base_Class $object_to_cache that has a relation to this model object. (Eg, if this is a Transaction,
552
+	 *                                       that could be a payment or a registration)
553
+	 * @param null          $cache_id        a string or number that will be used as the key for any Belongs_To_Many
554
+	 *                                       items which will be stored in an array on this object
555
+	 * @throws ReflectionException
556
+	 * @throws InvalidArgumentException
557
+	 * @throws InvalidInterfaceException
558
+	 * @throws InvalidDataTypeException
559
+	 * @throws EE_Error
560
+	 * @return mixed    index into cache, or just TRUE if the relation is of type Belongs_To (because there's only one
561
+	 *                                       related thing, no array)
562
+	 */
563
+	public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564
+	{
565
+		// its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
+		if (! $object_to_cache instanceof EE_Base_Class) {
567
+			return false;
568
+		}
569
+		// also get "how" the object is related, or throw an error
570
+		if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571
+			throw new EE_Error(
572
+				sprintf(
573
+					esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
574
+					$relationName,
575
+					get_class($this)
576
+				)
577
+			);
578
+		}
579
+		// how many things are related ?
580
+		if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
581
+			// if it's a "belongs to" relationship, then there's only one related model object
582
+			// eg, if this is a registration, there's only 1 attendee for it
583
+			// so for these model objects just set it to be cached
584
+			$this->_model_relations[ $relationName ] = $object_to_cache;
585
+			$return                                  = true;
586
+		} else {
587
+			// otherwise, this is the "many" side of a one to many relationship,
588
+			// so we'll add the object to the array of related objects for that type.
589
+			// eg: if this is an event, there are many registrations for that event,
590
+			// so we cache the registrations in an array
591
+			if (! is_array($this->_model_relations[ $relationName ])) {
592
+				// if for some reason, the cached item is a model object,
593
+				// then stick that in the array, otherwise start with an empty array
594
+				$this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
595
+														   instanceof
596
+														   EE_Base_Class
597
+					? array($this->_model_relations[ $relationName ]) : array();
598
+			}
599
+			// first check for a cache_id which is normally empty
600
+			if (! empty($cache_id)) {
601
+				// if the cache_id exists, then it means we are purposely trying to cache this
602
+				// with a known key that can then be used to retrieve the object later on
603
+				$this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
604
+				$return                                               = $cache_id;
605
+			} elseif ($object_to_cache->ID()) {
606
+				// OR the cached object originally came from the db, so let's just use it's PK for an ID
607
+				$this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
608
+				$return                                                            = $object_to_cache->ID();
609
+			} else {
610
+				// OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
+				$this->_model_relations[ $relationName ][] = $object_to_cache;
612
+				// move the internal pointer to the end of the array
613
+				end($this->_model_relations[ $relationName ]);
614
+				// and grab the key so that we can return it
615
+				$return = key($this->_model_relations[ $relationName ]);
616
+			}
617
+		}
618
+		return $return;
619
+	}
620
+
621
+
622
+	/**
623
+	 * For adding an item to the cached_properties property.
624
+	 *
625
+	 * @access protected
626
+	 * @param string      $fieldname the property item the corresponding value is for.
627
+	 * @param mixed       $value     The value we are caching.
628
+	 * @param string|null $cache_type
629
+	 * @return void
630
+	 * @throws ReflectionException
631
+	 * @throws InvalidArgumentException
632
+	 * @throws InvalidInterfaceException
633
+	 * @throws InvalidDataTypeException
634
+	 * @throws EE_Error
635
+	 */
636
+	protected function _set_cached_property($fieldname, $value, $cache_type = null)
637
+	{
638
+		//first make sure this property exists
639
+		$this->get_model()->field_settings_for($fieldname);
640
+		$cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
+		$this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
642
+	}
643
+
644
+
645
+	/**
646
+	 * This returns the value cached property if it exists OR the actual property value if the cache doesn't exist.
647
+	 * This also SETS the cache if we return the actual property!
648
+	 *
649
+	 * @param string $fieldname        the name of the property we're trying to retrieve
650
+	 * @param bool   $pretty
651
+	 * @param string $extra_cache_ref  This allows the user to specify an extra cache ref for the given property
652
+	 *                                 (in cases where the same property may be used for different outputs
653
+	 *                                 - i.e. datetime, money etc.)
654
+	 *                                 It can also accept certain pre-defined "schema" strings
655
+	 *                                 to define how to output the property.
656
+	 *                                 see the field's prepare_for_pretty_echoing for what strings can be used
657
+	 * @return mixed                   whatever the value for the property is we're retrieving
658
+	 * @throws ReflectionException
659
+	 * @throws InvalidArgumentException
660
+	 * @throws InvalidInterfaceException
661
+	 * @throws InvalidDataTypeException
662
+	 * @throws EE_Error
663
+	 */
664
+	protected function _get_cached_property($fieldname, $pretty = false, $extra_cache_ref = null)
665
+	{
666
+		//verify the field exists
667
+		$model = $this->get_model();
668
+		$model->field_settings_for($fieldname);
669
+		$cache_type = $pretty ? 'pretty' : 'standard';
670
+		$cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
+		if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
+			return $this->_cached_properties[ $fieldname ][ $cache_type ];
673
+		}
674
+		$value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675
+		$this->_set_cached_property($fieldname, $value, $cache_type);
676
+		return $value;
677
+	}
678
+
679
+
680
+	/**
681
+	 * If the cache didn't fetch the needed item, this fetches it.
682
+	 *
683
+	 * @param string $fieldname
684
+	 * @param bool   $pretty
685
+	 * @param string $extra_cache_ref
686
+	 * @return mixed
687
+	 * @throws InvalidArgumentException
688
+	 * @throws InvalidInterfaceException
689
+	 * @throws InvalidDataTypeException
690
+	 * @throws EE_Error
691
+	 * @throws ReflectionException
692
+	 */
693
+	protected function _get_fresh_property($fieldname, $pretty = false, $extra_cache_ref = null)
694
+	{
695
+		$field_obj = $this->get_model()->field_settings_for($fieldname);
696
+		// If this is an EE_Datetime_Field we need to make sure timezone, formats, and output are correct
697
+		if ($field_obj instanceof EE_Datetime_Field) {
698
+			$this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699
+		}
700
+		if (! isset($this->_fields[ $fieldname ])) {
701
+			$this->_fields[ $fieldname ] = null;
702
+		}
703
+		$value = $pretty
704
+			? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
+			: $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
706
+		return $value;
707
+	}
708
+
709
+
710
+	/**
711
+	 * set timezone, formats, and output for EE_Datetime_Field objects
712
+	 *
713
+	 * @param \EE_Datetime_Field $datetime_field
714
+	 * @param bool               $pretty
715
+	 * @param null               $date_or_time
716
+	 * @return void
717
+	 * @throws InvalidArgumentException
718
+	 * @throws InvalidInterfaceException
719
+	 * @throws InvalidDataTypeException
720
+	 * @throws EE_Error
721
+	 */
722
+	protected function _prepare_datetime_field(
723
+		EE_Datetime_Field $datetime_field,
724
+		$pretty = false,
725
+		$date_or_time = null
726
+	) {
727
+		$datetime_field->set_timezone($this->_timezone);
728
+		$datetime_field->set_date_format($this->_dt_frmt, $pretty);
729
+		$datetime_field->set_time_format($this->_tm_frmt, $pretty);
730
+		//set the output returned
731
+		switch ($date_or_time) {
732
+			case 'D' :
733
+				$datetime_field->set_date_time_output('date');
734
+				break;
735
+			case 'T' :
736
+				$datetime_field->set_date_time_output('time');
737
+				break;
738
+			default :
739
+				$datetime_field->set_date_time_output();
740
+		}
741
+	}
742
+
743
+
744
+	/**
745
+	 * This just takes care of clearing out the cached_properties
746
+	 *
747
+	 * @return void
748
+	 */
749
+	protected function _clear_cached_properties()
750
+	{
751
+		$this->_cached_properties = array();
752
+	}
753
+
754
+
755
+	/**
756
+	 * This just clears out ONE property if it exists in the cache
757
+	 *
758
+	 * @param  string $property_name the property to remove if it exists (from the _cached_properties array)
759
+	 * @return void
760
+	 */
761
+	protected function _clear_cached_property($property_name)
762
+	{
763
+		if (isset($this->_cached_properties[ $property_name ])) {
764
+			unset($this->_cached_properties[ $property_name ]);
765
+		}
766
+	}
767
+
768
+
769
+	/**
770
+	 * Ensures that this related thing is a model object.
771
+	 *
772
+	 * @param mixed  $object_or_id EE_base_Class/int/string either a related model object, or its ID
773
+	 * @param string $model_name   name of the related thing, eg 'Attendee',
774
+	 * @return EE_Base_Class
775
+	 * @throws ReflectionException
776
+	 * @throws InvalidArgumentException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws InvalidDataTypeException
779
+	 * @throws EE_Error
780
+	 */
781
+	protected function ensure_related_thing_is_model_obj($object_or_id, $model_name)
782
+	{
783
+		$other_model_instance = self::_get_model_instance_with_name(
784
+			self::_get_model_classname($model_name),
785
+			$this->_timezone
786
+		);
787
+		return $other_model_instance->ensure_is_obj($object_or_id);
788
+	}
789
+
790
+
791
+	/**
792
+	 * Forgets the cached model of the given relation Name. So the next time we request it,
793
+	 * we will fetch it again from the database. (Handy if you know it's changed somehow).
794
+	 * If a specific object is supplied, and the relationship to it is either a HasMany or HABTM,
795
+	 * then only remove that one object from our cached array. Otherwise, clear the entire list
796
+	 *
797
+	 * @param string $relationName                         one of the keys in the _model_relations array on the model.
798
+	 *                                                     Eg 'Registration'
799
+	 * @param mixed  $object_to_remove_or_index_into_array or an index into the array of cached things, or NULL
800
+	 *                                                     if you intend to use $clear_all = TRUE, or the relation only
801
+	 *                                                     has 1 object anyways (ie, it's a BelongsToRelation)
802
+	 * @param bool   $clear_all                            This flags clearing the entire cache relation property if
803
+	 *                                                     this is HasMany or HABTM.
804
+	 * @throws ReflectionException
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws EE_Error
809
+	 * @return EE_Base_Class | boolean from which was cleared from the cache, or true if we requested to remove a
810
+	 *                                                     relation from all
811
+	 */
812
+	public function clear_cache($relationName, $object_to_remove_or_index_into_array = null, $clear_all = false)
813
+	{
814
+		$relationship_to_model = $this->get_model()->related_settings_for($relationName);
815
+		$index_in_cache        = '';
816
+		if (! $relationship_to_model) {
817
+			throw new EE_Error(
818
+				sprintf(
819
+					esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
820
+					$relationName,
821
+					get_class($this)
822
+				)
823
+			);
824
+		}
825
+		if ($clear_all) {
826
+			$obj_removed                             = true;
827
+			$this->_model_relations[ $relationName ] = null;
828
+		} elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
+			$obj_removed                             = $this->_model_relations[ $relationName ];
830
+			$this->_model_relations[ $relationName ] = null;
831
+		} else {
832
+			if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833
+				&& $object_to_remove_or_index_into_array->ID()
834
+			) {
835
+				$index_in_cache = $object_to_remove_or_index_into_array->ID();
836
+				if (is_array($this->_model_relations[ $relationName ])
837
+					&& ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
838
+				) {
839
+					$index_found_at = null;
840
+					//find this object in the array even though it has a different key
841
+					foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
842
+						/** @noinspection TypeUnsafeComparisonInspection */
843
+						if (
844
+							$obj instanceof EE_Base_Class
845
+							&& (
846
+								$obj == $object_to_remove_or_index_into_array
847
+								|| $obj->ID() === $object_to_remove_or_index_into_array->ID()
848
+							)
849
+						) {
850
+							$index_found_at = $index;
851
+							break;
852
+						}
853
+					}
854
+					if ($index_found_at) {
855
+						$index_in_cache = $index_found_at;
856
+					} else {
857
+						//it wasn't found. huh. well obviously it doesn't need to be removed from teh cache
858
+						//if it wasn't in it to begin with. So we're done
859
+						return $object_to_remove_or_index_into_array;
860
+					}
861
+				}
862
+			} elseif ($object_to_remove_or_index_into_array instanceof EE_Base_Class) {
863
+				//so they provided a model object, but it's not yet saved to the DB... so let's go hunting for it!
864
+				foreach ($this->get_all_from_cache($relationName) as $index => $potentially_obj_we_want) {
865
+					/** @noinspection TypeUnsafeComparisonInspection */
866
+					if ($potentially_obj_we_want == $object_to_remove_or_index_into_array) {
867
+						$index_in_cache = $index;
868
+					}
869
+				}
870
+			} else {
871
+				$index_in_cache = $object_to_remove_or_index_into_array;
872
+			}
873
+			//supposedly we've found it. But it could just be that the client code
874
+			//provided a bad index/object
875
+			if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
+				$obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
+				unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
878
+			} else {
879
+				//that thing was never cached anyways.
880
+				$obj_removed = null;
881
+			}
882
+		}
883
+		return $obj_removed;
884
+	}
885
+
886
+
887
+	/**
888
+	 * update_cache_after_object_save
889
+	 * Allows a cached item to have it's cache ID (within the array of cached items) reset using the new ID it has
890
+	 * obtained after being saved to the db
891
+	 *
892
+	 * @param string        $relationName       - the type of object that is cached
893
+	 * @param EE_Base_Class $newly_saved_object - the newly saved object to be re-cached
894
+	 * @param string        $current_cache_id   - the ID that was used when originally caching the object
895
+	 * @return boolean TRUE on success, FALSE on fail
896
+	 * @throws ReflectionException
897
+	 * @throws InvalidArgumentException
898
+	 * @throws InvalidInterfaceException
899
+	 * @throws InvalidDataTypeException
900
+	 * @throws EE_Error
901
+	 */
902
+	public function update_cache_after_object_save(
903
+		$relationName,
904
+		EE_Base_Class $newly_saved_object,
905
+		$current_cache_id = ''
906
+	) {
907
+		// verify that incoming object is of the correct type
908
+		$obj_class = 'EE_' . $relationName;
909
+		if ($newly_saved_object instanceof $obj_class) {
910
+			/* @type EE_Base_Class $newly_saved_object */
911
+			// now get the type of relation
912
+			$relationship_to_model = $this->get_model()->related_settings_for($relationName);
913
+			// if this is a 1:1 relationship
914
+			if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915
+				// then just replace the cached object with the newly saved object
916
+				$this->_model_relations[ $relationName ] = $newly_saved_object;
917
+				return true;
918
+				// or if it's some kind of sordid feral polyamorous relationship...
919
+			}
920
+			if (is_array($this->_model_relations[ $relationName ])
921
+					  && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
922
+			) {
923
+				// then remove the current cached item
924
+				unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
925
+				// and cache the newly saved object using it's new ID
926
+				$this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
927
+				return true;
928
+			}
929
+		}
930
+		return false;
931
+	}
932
+
933
+
934
+	/**
935
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
936
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
937
+	 *
938
+	 * @param string $relationName
939
+	 * @return EE_Base_Class
940
+	 */
941
+	public function get_one_from_cache($relationName)
942
+	{
943
+		$cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
+			? $this->_model_relations[ $relationName ]
945
+			: null;
946
+		if (is_array($cached_array_or_object)) {
947
+			return array_shift($cached_array_or_object);
948
+		}
949
+		return $cached_array_or_object;
950
+	}
951
+
952
+
953
+	/**
954
+	 * Fetches a single EE_Base_Class on that relation. (If the relation is of type
955
+	 * BelongsTo, it will only ever have 1 object. However, other relations could have an array of objects)
956
+	 *
957
+	 * @param string $relationName
958
+	 * @throws ReflectionException
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidInterfaceException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws EE_Error
963
+	 * @return EE_Base_Class[] NOT necessarily indexed by primary keys
964
+	 */
965
+	public function get_all_from_cache($relationName)
966
+	{
967
+		$objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
968
+		// if the result is not an array, but exists, make it an array
969
+		$objects = is_array($objects) ? $objects : array($objects);
970
+		//bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
971
+		//basically, if this model object was stored in the session, and these cached model objects
972
+		//already have IDs, let's make sure they're in their model's entity mapper
973
+		//otherwise we will have duplicates next time we call
974
+		// EE_Registry::instance()->load_model( $relationName )->get_one_by_ID( $result->ID() );
975
+		$model = EE_Registry::instance()->load_model($relationName);
976
+		foreach ($objects as $model_object) {
977
+			if ($model instanceof EEM_Base && $model_object instanceof EE_Base_Class) {
978
+				//ensure its in the map if it has an ID; otherwise it will be added to the map when its saved
979
+				if ($model_object->ID()) {
980
+					$model->add_to_entity_map($model_object);
981
+				}
982
+			} else {
983
+				throw new EE_Error(
984
+					sprintf(
985
+						esc_html__(
986
+							'Error retrieving related model objects. Either $1%s is not a model or $2%s is not a model object',
987
+							'event_espresso'
988
+						),
989
+						$relationName,
990
+						gettype($model_object)
991
+					)
992
+				);
993
+			}
994
+		}
995
+		return $objects;
996
+	}
997
+
998
+
999
+	/**
1000
+	 * Returns the next x number of EE_Base_Class objects in sequence from this object as found in the database
1001
+	 * matching the given query conditions.
1002
+	 *
1003
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1004
+	 * @param int   $limit              How many objects to return.
1005
+	 * @param array $query_params       Any additional conditions on the query.
1006
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1007
+	 *                                  you can indicate just the columns you want returned
1008
+	 * @return array|EE_Base_Class[]
1009
+	 * @throws ReflectionException
1010
+	 * @throws InvalidArgumentException
1011
+	 * @throws InvalidInterfaceException
1012
+	 * @throws InvalidDataTypeException
1013
+	 * @throws EE_Error
1014
+	 */
1015
+	public function next_x($field_to_order_by = null, $limit = 1, $query_params = array(), $columns_to_select = null)
1016
+	{
1017
+		$model         = $this->get_model();
1018
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1019
+			? $model->get_primary_key_field()->get_name()
1020
+			: $field_to_order_by;
1021
+		$current_value = ! empty($field) ? $this->get($field) : null;
1022
+		if (empty($field) || empty($current_value)) {
1023
+			return array();
1024
+		}
1025
+		return $model->next_x($current_value, $field, $limit, $query_params, $columns_to_select);
1026
+	}
1027
+
1028
+
1029
+	/**
1030
+	 * Returns the previous x number of EE_Base_Class objects in sequence from this object as found in the database
1031
+	 * matching the given query conditions.
1032
+	 *
1033
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1034
+	 * @param int   $limit              How many objects to return.
1035
+	 * @param array $query_params       Any additional conditions on the query.
1036
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1037
+	 *                                  you can indicate just the columns you want returned
1038
+	 * @return array|EE_Base_Class[]
1039
+	 * @throws ReflectionException
1040
+	 * @throws InvalidArgumentException
1041
+	 * @throws InvalidInterfaceException
1042
+	 * @throws InvalidDataTypeException
1043
+	 * @throws EE_Error
1044
+	 */
1045
+	public function previous_x(
1046
+		$field_to_order_by = null,
1047
+		$limit = 1,
1048
+		$query_params = array(),
1049
+		$columns_to_select = null
1050
+	) {
1051
+		$model         = $this->get_model();
1052
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1053
+			? $model->get_primary_key_field()->get_name()
1054
+			: $field_to_order_by;
1055
+		$current_value = ! empty($field) ? $this->get($field) : null;
1056
+		if (empty($field) || empty($current_value)) {
1057
+			return array();
1058
+		}
1059
+		return $model->previous_x($current_value, $field, $limit, $query_params, $columns_to_select);
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * Returns the next EE_Base_Class object in sequence from this object as found in the database
1065
+	 * matching the given query conditions.
1066
+	 *
1067
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1068
+	 * @param array $query_params       Any additional conditions on the query.
1069
+	 * @param null  $columns_to_select  If left null, then an array of EE_Base_Class objects is returned, otherwise
1070
+	 *                                  you can indicate just the columns you want returned
1071
+	 * @return array|EE_Base_Class
1072
+	 * @throws ReflectionException
1073
+	 * @throws InvalidArgumentException
1074
+	 * @throws InvalidInterfaceException
1075
+	 * @throws InvalidDataTypeException
1076
+	 * @throws EE_Error
1077
+	 */
1078
+	public function next($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1079
+	{
1080
+		$model         = $this->get_model();
1081
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1082
+			? $model->get_primary_key_field()->get_name()
1083
+			: $field_to_order_by;
1084
+		$current_value = ! empty($field) ? $this->get($field) : null;
1085
+		if (empty($field) || empty($current_value)) {
1086
+			return array();
1087
+		}
1088
+		return $model->next($current_value, $field, $query_params, $columns_to_select);
1089
+	}
1090
+
1091
+
1092
+	/**
1093
+	 * Returns the previous EE_Base_Class object in sequence from this object as found in the database
1094
+	 * matching the given query conditions.
1095
+	 *
1096
+	 * @param null  $field_to_order_by  What field is being used as the reference point.
1097
+	 * @param array $query_params       Any additional conditions on the query.
1098
+	 * @param null  $columns_to_select  If left null, then an EE_Base_Class object is returned, otherwise
1099
+	 *                                  you can indicate just the column you want returned
1100
+	 * @return array|EE_Base_Class
1101
+	 * @throws ReflectionException
1102
+	 * @throws InvalidArgumentException
1103
+	 * @throws InvalidInterfaceException
1104
+	 * @throws InvalidDataTypeException
1105
+	 * @throws EE_Error
1106
+	 */
1107
+	public function previous($field_to_order_by = null, $query_params = array(), $columns_to_select = null)
1108
+	{
1109
+		$model         = $this->get_model();
1110
+		$field         = empty($field_to_order_by) && $model->has_primary_key_field()
1111
+			? $model->get_primary_key_field()->get_name()
1112
+			: $field_to_order_by;
1113
+		$current_value = ! empty($field) ? $this->get($field) : null;
1114
+		if (empty($field) || empty($current_value)) {
1115
+			return array();
1116
+		}
1117
+		return $model->previous($current_value, $field, $query_params, $columns_to_select);
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * Overrides parent because parent expects old models.
1123
+	 * This also doesn't do any validation, and won't work for serialized arrays
1124
+	 *
1125
+	 * @param string $field_name
1126
+	 * @param mixed  $field_value_from_db
1127
+	 * @throws ReflectionException
1128
+	 * @throws InvalidArgumentException
1129
+	 * @throws InvalidInterfaceException
1130
+	 * @throws InvalidDataTypeException
1131
+	 * @throws EE_Error
1132
+	 */
1133
+	public function set_from_db($field_name, $field_value_from_db)
1134
+	{
1135
+		$field_obj = $this->get_model()->field_settings_for($field_name);
1136
+		if ($field_obj instanceof EE_Model_Field_Base) {
1137
+			//you would think the DB has no NULLs for non-null label fields right? wrong!
1138
+			//eg, a CPT model object could have an entry in the posts table, but no
1139
+			//entry in the meta table. Meaning that all its columns in the meta table
1140
+			//are null! yikes! so when we find one like that, use defaults for its meta columns
1141
+			if ($field_value_from_db === null) {
1142
+				if ($field_obj->is_nullable()) {
1143
+					//if the field allows nulls, then let it be null
1144
+					$field_value = null;
1145
+				} else {
1146
+					$field_value = $field_obj->get_default_value();
1147
+				}
1148
+			} else {
1149
+				$field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150
+			}
1151
+			$this->_fields[ $field_name ] = $field_value;
1152
+			$this->_clear_cached_property($field_name);
1153
+		}
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * verifies that the specified field is of the correct type
1159
+	 *
1160
+	 * @param string $field_name
1161
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1162
+	 *                                (in cases where the same property may be used for different outputs
1163
+	 *                                - i.e. datetime, money etc.)
1164
+	 * @return mixed
1165
+	 * @throws ReflectionException
1166
+	 * @throws InvalidArgumentException
1167
+	 * @throws InvalidInterfaceException
1168
+	 * @throws InvalidDataTypeException
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	public function get($field_name, $extra_cache_ref = null)
1172
+	{
1173
+		return $this->_get_cached_property($field_name, false, $extra_cache_ref);
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * This method simply returns the RAW unprocessed value for the given property in this class
1179
+	 *
1180
+	 * @param  string $field_name A valid fieldname
1181
+	 * @return mixed              Whatever the raw value stored on the property is.
1182
+	 * @throws ReflectionException
1183
+	 * @throws InvalidArgumentException
1184
+	 * @throws InvalidInterfaceException
1185
+	 * @throws InvalidDataTypeException
1186
+	 * @throws EE_Error if fieldSettings is misconfigured or the field doesn't exist.
1187
+	 */
1188
+	public function get_raw($field_name)
1189
+	{
1190
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1191
+		return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
+			? $this->_fields[ $field_name ]->format('U')
1193
+			: $this->_fields[ $field_name ];
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * This is used to return the internal DateTime object used for a field that is a
1199
+	 * EE_Datetime_Field.
1200
+	 *
1201
+	 * @param string $field_name               The field name retrieving the DateTime object.
1202
+	 * @return mixed null | false | DateTime  If the requested field is NOT a EE_Datetime_Field then
1203
+	 * @throws EE_Error an error is set and false returned.  If the field IS an
1204
+	 *                                         EE_Datetime_Field and but the field value is null, then
1205
+	 *                                         just null is returned (because that indicates that likely
1206
+	 *                                         this field is nullable).
1207
+	 * @throws InvalidArgumentException
1208
+	 * @throws InvalidDataTypeException
1209
+	 * @throws InvalidInterfaceException
1210
+	 * @throws ReflectionException
1211
+	 */
1212
+	public function get_DateTime_object($field_name)
1213
+	{
1214
+		$field_settings = $this->get_model()->field_settings_for($field_name);
1215
+		if (! $field_settings instanceof EE_Datetime_Field) {
1216
+			EE_Error::add_error(
1217
+				sprintf(
1218
+					esc_html__(
1219
+						'The field %s is not an EE_Datetime_Field field.  There is no DateTime object stored on this field type.',
1220
+						'event_espresso'
1221
+					),
1222
+					$field_name
1223
+				),
1224
+				__FILE__,
1225
+				__FUNCTION__,
1226
+				__LINE__
1227
+			);
1228
+			return false;
1229
+		}
1230
+		return isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime
1231
+			? clone $this->_fields[$field_name]
1232
+			: null;
1233
+	}
1234
+
1235
+
1236
+	/**
1237
+	 * To be used in template to immediately echo out the value, and format it for output.
1238
+	 * Eg, should call stripslashes and whatnot before echoing
1239
+	 *
1240
+	 * @param string $field_name      the name of the field as it appears in the DB
1241
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1242
+	 *                                (in cases where the same property may be used for different outputs
1243
+	 *                                - i.e. datetime, money etc.)
1244
+	 * @return void
1245
+	 * @throws ReflectionException
1246
+	 * @throws InvalidArgumentException
1247
+	 * @throws InvalidInterfaceException
1248
+	 * @throws InvalidDataTypeException
1249
+	 * @throws EE_Error
1250
+	 */
1251
+	public function e($field_name, $extra_cache_ref = null)
1252
+	{
1253
+		echo $this->get_pretty($field_name, $extra_cache_ref);
1254
+	}
1255
+
1256
+
1257
+	/**
1258
+	 * Exactly like e(), echoes out the field, but sets its schema to 'form_input', so that it
1259
+	 * can be easily used as the value of form input.
1260
+	 *
1261
+	 * @param string $field_name
1262
+	 * @return void
1263
+	 * @throws ReflectionException
1264
+	 * @throws InvalidArgumentException
1265
+	 * @throws InvalidInterfaceException
1266
+	 * @throws InvalidDataTypeException
1267
+	 * @throws EE_Error
1268
+	 */
1269
+	public function f($field_name)
1270
+	{
1271
+		$this->e($field_name, 'form_input');
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * Same as `f()` but just returns the value instead of echoing it
1277
+	 *
1278
+	 * @param string $field_name
1279
+	 * @return string
1280
+	 * @throws ReflectionException
1281
+	 * @throws InvalidArgumentException
1282
+	 * @throws InvalidInterfaceException
1283
+	 * @throws InvalidDataTypeException
1284
+	 * @throws EE_Error
1285
+	 */
1286
+	public function get_f($field_name)
1287
+	{
1288
+		return (string) $this->get_pretty($field_name, 'form_input');
1289
+	}
1290
+
1291
+
1292
+	/**
1293
+	 * Gets a pretty view of the field's value. $extra_cache_ref can specify different formats for this.
1294
+	 * The $extra_cache_ref will be passed to the model field's prepare_for_pretty_echoing, so consult the field's class
1295
+	 * to see what options are available.
1296
+	 *
1297
+	 * @param string $field_name
1298
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
1299
+	 *                                (in cases where the same property may be used for different outputs
1300
+	 *                                - i.e. datetime, money etc.)
1301
+	 * @return mixed
1302
+	 * @throws ReflectionException
1303
+	 * @throws InvalidArgumentException
1304
+	 * @throws InvalidInterfaceException
1305
+	 * @throws InvalidDataTypeException
1306
+	 * @throws EE_Error
1307
+	 */
1308
+	public function get_pretty($field_name, $extra_cache_ref = null)
1309
+	{
1310
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * This simply returns the datetime for the given field name
1316
+	 * Note: this protected function is called by the wrapper get_date or get_time or get_datetime functions
1317
+	 * (and the equivalent e_date, e_time, e_datetime).
1318
+	 *
1319
+	 * @access   protected
1320
+	 * @param string   $field_name   Field on the instantiated EE_Base_Class child object
1321
+	 * @param string   $dt_frmt      valid datetime format used for date
1322
+	 *                               (if '' then we just use the default on the field,
1323
+	 *                               if NULL we use the last-used format)
1324
+	 * @param string   $tm_frmt      Same as above except this is for time format
1325
+	 * @param string   $date_or_time if NULL then both are returned, otherwise "D" = only date and "T" = only time.
1326
+	 * @param  boolean $echo         Whether the dtt is echoing using pretty echoing or just returned using vanilla get
1327
+	 * @return string|bool|EE_Error string on success, FALSE on fail, or EE_Error Exception is thrown
1328
+	 *                               if field is not a valid dtt field, or void if echoing
1329
+	 * @throws ReflectionException
1330
+	 * @throws InvalidArgumentException
1331
+	 * @throws InvalidInterfaceException
1332
+	 * @throws InvalidDataTypeException
1333
+	 * @throws EE_Error
1334
+	 */
1335
+	protected function _get_datetime($field_name, $dt_frmt = '', $tm_frmt = '', $date_or_time = '', $echo = false)
1336
+	{
1337
+		// clear cached property
1338
+		$this->_clear_cached_property($field_name);
1339
+		//reset format properties because they are used in get()
1340
+		$this->_dt_frmt = $dt_frmt !== '' ? $dt_frmt : $this->_dt_frmt;
1341
+		$this->_tm_frmt = $tm_frmt !== '' ? $tm_frmt : $this->_tm_frmt;
1342
+		if ($echo) {
1343
+			$this->e($field_name, $date_or_time);
1344
+			return '';
1345
+		}
1346
+		return $this->get($field_name, $date_or_time);
1347
+	}
1348
+
1349
+
1350
+	/**
1351
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the date
1352
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1353
+	 * other echoes the pretty value for dtt)
1354
+	 *
1355
+	 * @param  string $field_name name of model object datetime field holding the value
1356
+	 * @param  string $format     format for the date returned (if NULL we use default in dt_frmt property)
1357
+	 * @return string            datetime value formatted
1358
+	 * @throws ReflectionException
1359
+	 * @throws InvalidArgumentException
1360
+	 * @throws InvalidInterfaceException
1361
+	 * @throws InvalidDataTypeException
1362
+	 * @throws EE_Error
1363
+	 */
1364
+	public function get_date($field_name, $format = '')
1365
+	{
1366
+		return $this->_get_datetime($field_name, $format, null, 'D');
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * @param        $field_name
1372
+	 * @param string $format
1373
+	 * @throws ReflectionException
1374
+	 * @throws InvalidArgumentException
1375
+	 * @throws InvalidInterfaceException
1376
+	 * @throws InvalidDataTypeException
1377
+	 * @throws EE_Error
1378
+	 */
1379
+	public function e_date($field_name, $format = '')
1380
+	{
1381
+		$this->_get_datetime($field_name, $format, null, 'D', true);
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * below are wrapper functions for the various datetime outputs that can be obtained for JUST returning the time
1387
+	 * portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1388
+	 * other echoes the pretty value for dtt)
1389
+	 *
1390
+	 * @param  string $field_name name of model object datetime field holding the value
1391
+	 * @param  string $format     format for the time returned ( if NULL we use default in tm_frmt property)
1392
+	 * @return string             datetime value formatted
1393
+	 * @throws ReflectionException
1394
+	 * @throws InvalidArgumentException
1395
+	 * @throws InvalidInterfaceException
1396
+	 * @throws InvalidDataTypeException
1397
+	 * @throws EE_Error
1398
+	 */
1399
+	public function get_time($field_name, $format = '')
1400
+	{
1401
+		return $this->_get_datetime($field_name, null, $format, 'T');
1402
+	}
1403
+
1404
+
1405
+	/**
1406
+	 * @param        $field_name
1407
+	 * @param string $format
1408
+	 * @throws ReflectionException
1409
+	 * @throws InvalidArgumentException
1410
+	 * @throws InvalidInterfaceException
1411
+	 * @throws InvalidDataTypeException
1412
+	 * @throws EE_Error
1413
+	 */
1414
+	public function e_time($field_name, $format = '')
1415
+	{
1416
+		$this->_get_datetime($field_name, null, $format, 'T', true);
1417
+	}
1418
+
1419
+
1420
+	/**
1421
+	 * below are wrapper functions for the various datetime outputs that can be obtained for returning the date AND
1422
+	 * time portion of a datetime value. (note the only difference between get_ and e_ is one returns the value and the
1423
+	 * other echoes the pretty value for dtt)
1424
+	 *
1425
+	 * @param  string $field_name name of model object datetime field holding the value
1426
+	 * @param  string $dt_frmt    format for the date returned (if NULL we use default in dt_frmt property)
1427
+	 * @param  string $tm_frmt    format for the time returned (if NULL we use default in tm_frmt property)
1428
+	 * @return string             datetime value formatted
1429
+	 * @throws ReflectionException
1430
+	 * @throws InvalidArgumentException
1431
+	 * @throws InvalidInterfaceException
1432
+	 * @throws InvalidDataTypeException
1433
+	 * @throws EE_Error
1434
+	 */
1435
+	public function get_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1436
+	{
1437
+		return $this->_get_datetime($field_name, $dt_frmt, $tm_frmt);
1438
+	}
1439
+
1440
+
1441
+	/**
1442
+	 * @param string $field_name
1443
+	 * @param string $dt_frmt
1444
+	 * @param string $tm_frmt
1445
+	 * @throws ReflectionException
1446
+	 * @throws InvalidArgumentException
1447
+	 * @throws InvalidInterfaceException
1448
+	 * @throws InvalidDataTypeException
1449
+	 * @throws EE_Error
1450
+	 */
1451
+	public function e_datetime($field_name, $dt_frmt = '', $tm_frmt = '')
1452
+	{
1453
+		$this->_get_datetime($field_name, $dt_frmt, $tm_frmt, null, true);
1454
+	}
1455
+
1456
+
1457
+	/**
1458
+	 * Get the i8ln value for a date using the WordPress @see date_i18n function.
1459
+	 *
1460
+	 * @param string $field_name The EE_Datetime_Field reference for the date being retrieved.
1461
+	 * @param string $format     PHP valid date/time string format.  If none is provided then the internal set format
1462
+	 *                           on the object will be used.
1463
+	 * @return string Date and time string in set locale or false if no field exists for the given
1464
+	 * @throws ReflectionException
1465
+	 * @throws InvalidArgumentException
1466
+	 * @throws InvalidInterfaceException
1467
+	 * @throws InvalidDataTypeException
1468
+	 * @throws EE_Error
1469
+	 *                           field name.
1470
+	 */
1471
+	public function get_i18n_datetime($field_name, $format = '')
1472
+	{
1473
+		$format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1474
+		return date_i18n(
1475
+			$format,
1476
+			EEH_DTT_Helper::get_timestamp_with_offset(
1477
+				$this->get_raw($field_name),
1478
+				$this->_timezone
1479
+			)
1480
+		);
1481
+	}
1482
+
1483
+
1484
+	/**
1485
+	 * This method validates whether the given field name is a valid field on the model object as well as it is of a
1486
+	 * type EE_Datetime_Field.  On success there will be returned the field settings.  On fail an EE_Error exception is
1487
+	 * thrown.
1488
+	 *
1489
+	 * @param  string $field_name The field name being checked
1490
+	 * @throws ReflectionException
1491
+	 * @throws InvalidArgumentException
1492
+	 * @throws InvalidInterfaceException
1493
+	 * @throws InvalidDataTypeException
1494
+	 * @throws EE_Error
1495
+	 * @return EE_Datetime_Field
1496
+	 */
1497
+	protected function _get_dtt_field_settings($field_name)
1498
+	{
1499
+		$field = $this->get_model()->field_settings_for($field_name);
1500
+		//check if field is dtt
1501
+		if ($field instanceof EE_Datetime_Field) {
1502
+			return $field;
1503
+		}
1504
+		throw new EE_Error(
1505
+			sprintf(
1506
+				esc_html__(
1507
+					'The field name "%s" has been requested for the EE_Base_Class datetime functions and it is not a valid EE_Datetime_Field.  Please check the spelling of the field and make sure it has been setup as a EE_Datetime_Field in the %s model constructor',
1508
+					'event_espresso'
1509
+				),
1510
+				$field_name,
1511
+				self::_get_model_classname(get_class($this))
1512
+			)
1513
+		);
1514
+	}
1515
+
1516
+
1517
+
1518
+
1519
+	/**
1520
+	 * NOTE ABOUT BELOW:
1521
+	 * These convenience date and time setters are for setting date and time independently.  In other words you might
1522
+	 * want to change the time on a datetime_field but leave the date the same (or vice versa). IF on the other hand
1523
+	 * you want to set both date and time at the same time, you can just use the models default set($fieldname,$value)
1524
+	 * method and make sure you send the entire datetime value for setting.
1525
+	 */
1526
+	/**
1527
+	 * sets the time on a datetime property
1528
+	 *
1529
+	 * @access protected
1530
+	 * @param string|Datetime $time      a valid time string for php datetime functions (or DateTime object)
1531
+	 * @param string          $fieldname the name of the field the time is being set on (must match a EE_Datetime_Field)
1532
+	 * @throws ReflectionException
1533
+	 * @throws InvalidArgumentException
1534
+	 * @throws InvalidInterfaceException
1535
+	 * @throws InvalidDataTypeException
1536
+	 * @throws EE_Error
1537
+	 */
1538
+	protected function _set_time_for($time, $fieldname)
1539
+	{
1540
+		$this->_set_date_time('T', $time, $fieldname);
1541
+	}
1542
+
1543
+
1544
+	/**
1545
+	 * sets the date on a datetime property
1546
+	 *
1547
+	 * @access protected
1548
+	 * @param string|DateTime $date      a valid date string for php datetime functions ( or DateTime object)
1549
+	 * @param string          $fieldname the name of the field the date is being set on (must match a EE_Datetime_Field)
1550
+	 * @throws ReflectionException
1551
+	 * @throws InvalidArgumentException
1552
+	 * @throws InvalidInterfaceException
1553
+	 * @throws InvalidDataTypeException
1554
+	 * @throws EE_Error
1555
+	 */
1556
+	protected function _set_date_for($date, $fieldname)
1557
+	{
1558
+		$this->_set_date_time('D', $date, $fieldname);
1559
+	}
1560
+
1561
+
1562
+	/**
1563
+	 * This takes care of setting a date or time independently on a given model object property. This method also
1564
+	 * verifies that the given fieldname matches a model object property and is for a EE_Datetime_Field field
1565
+	 *
1566
+	 * @access protected
1567
+	 * @param string          $what           "T" for time, 'B' for both, 'D' for Date.
1568
+	 * @param string|DateTime $datetime_value A valid Date or Time string (or DateTime object)
1569
+	 * @param string          $fieldname      the name of the field the date OR time is being set on (must match a
1570
+	 *                                        EE_Datetime_Field property)
1571
+	 * @throws ReflectionException
1572
+	 * @throws InvalidArgumentException
1573
+	 * @throws InvalidInterfaceException
1574
+	 * @throws InvalidDataTypeException
1575
+	 * @throws EE_Error
1576
+	 */
1577
+	protected function _set_date_time($what = 'T', $datetime_value, $fieldname)
1578
+	{
1579
+		$field = $this->_get_dtt_field_settings($fieldname);
1580
+		$field->set_timezone($this->_timezone);
1581
+		$field->set_date_format($this->_dt_frmt);
1582
+		$field->set_time_format($this->_tm_frmt);
1583
+		switch ($what) {
1584
+			case 'T' :
1585
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1586
+					$datetime_value,
1587
+					$this->_fields[ $fieldname ]
1588
+				);
1589
+				break;
1590
+			case 'D' :
1591
+				$this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1592
+					$datetime_value,
1593
+					$this->_fields[ $fieldname ]
1594
+				);
1595
+				break;
1596
+			case 'B' :
1597
+				$this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1598
+				break;
1599
+		}
1600
+		$this->_clear_cached_property($fieldname);
1601
+	}
1602
+
1603
+
1604
+	/**
1605
+	 * This will return a timestamp for the website timezone but ONLY when the current website timezone is different
1606
+	 * than the timezone set for the website. NOTE, this currently only works well with methods that return values.  If
1607
+	 * you use it with methods that echo values the $_timestamp property may not get reset to its original value and
1608
+	 * that could lead to some unexpected results!
1609
+	 *
1610
+	 * @access public
1611
+	 * @param string $field_name               This is the name of the field on the object that contains the date/time
1612
+	 *                                         value being returned.
1613
+	 * @param string $callback                 must match a valid method in this class (defaults to get_datetime)
1614
+	 * @param mixed (array|string) $args       This is the arguments that will be passed to the callback.
1615
+	 * @param string $prepend                  You can include something to prepend on the timestamp
1616
+	 * @param string $append                   You can include something to append on the timestamp
1617
+	 * @throws ReflectionException
1618
+	 * @throws InvalidArgumentException
1619
+	 * @throws InvalidInterfaceException
1620
+	 * @throws InvalidDataTypeException
1621
+	 * @throws EE_Error
1622
+	 * @return string timestamp
1623
+	 */
1624
+	public function display_in_my_timezone(
1625
+		$field_name,
1626
+		$callback = 'get_datetime',
1627
+		$args = null,
1628
+		$prepend = '',
1629
+		$append = ''
1630
+	) {
1631
+		$timezone = EEH_DTT_Helper::get_timezone();
1632
+		if ($timezone === $this->_timezone) {
1633
+			return '';
1634
+		}
1635
+		$original_timezone = $this->_timezone;
1636
+		$this->set_timezone($timezone);
1637
+		$fn   = (array) $field_name;
1638
+		$args = array_merge($fn, (array) $args);
1639
+		if (! method_exists($this, $callback)) {
1640
+			throw new EE_Error(
1641
+				sprintf(
1642
+					esc_html__(
1643
+						'The method named "%s" given as the callback param in "display_in_my_timezone" does not exist.  Please check your spelling',
1644
+						'event_espresso'
1645
+					),
1646
+					$callback
1647
+				)
1648
+			);
1649
+		}
1650
+		$args   = (array) $args;
1651
+		$return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1652
+		$this->set_timezone($original_timezone);
1653
+		return $return;
1654
+	}
1655
+
1656
+
1657
+	/**
1658
+	 * Deletes this model object.
1659
+	 * This calls the `EE_Base_Class::_delete` method.  Child classes wishing to change default behaviour should
1660
+	 * override
1661
+	 * `EE_Base_Class::_delete` NOT this class.
1662
+	 *
1663
+	 * @return boolean | int
1664
+	 * @throws ReflectionException
1665
+	 * @throws InvalidArgumentException
1666
+	 * @throws InvalidInterfaceException
1667
+	 * @throws InvalidDataTypeException
1668
+	 * @throws EE_Error
1669
+	 */
1670
+	public function delete()
1671
+	{
1672
+		/**
1673
+		 * Called just before the `EE_Base_Class::_delete` method call.
1674
+		 * Note:
1675
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1676
+		 * should be aware that `_delete` may not always result in a permanent delete.
1677
+		 * For example, `EE_Soft_Delete_Base_Class::_delete`
1678
+		 * soft deletes (trash) the object and does not permanently delete it.
1679
+		 *
1680
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1681
+		 */
1682
+		do_action('AHEE__EE_Base_Class__delete__before', $this);
1683
+		$result = $this->_delete();
1684
+		/**
1685
+		 * Called just after the `EE_Base_Class::_delete` method call.
1686
+		 * Note:
1687
+		 * `EE_Base_Class::_delete` might be overridden by child classes so any client code hooking into these actions
1688
+		 * should be aware that `_delete` may not always result in a permanent delete.
1689
+		 * For example `EE_Soft_Base_Class::_delete`
1690
+		 * soft deletes (trash) the object and does not permanently delete it.
1691
+		 *
1692
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1693
+		 * @param boolean       $result
1694
+		 */
1695
+		do_action('AHEE__EE_Base_Class__delete__end', $this, $result);
1696
+		return $result;
1697
+	}
1698
+
1699
+
1700
+	/**
1701
+	 * Calls the specific delete method for the instantiated class.
1702
+	 * This method is called by the public `EE_Base_Class::delete` method.  Any child classes desiring to override
1703
+	 * default functionality for "delete" (which is to call `permanently_delete`) should override this method NOT
1704
+	 * `EE_Base_Class::delete`
1705
+	 *
1706
+	 * @return bool|int
1707
+	 * @throws ReflectionException
1708
+	 * @throws InvalidArgumentException
1709
+	 * @throws InvalidInterfaceException
1710
+	 * @throws InvalidDataTypeException
1711
+	 * @throws EE_Error
1712
+	 */
1713
+	protected function _delete()
1714
+	{
1715
+		return $this->delete_permanently();
1716
+	}
1717
+
1718
+
1719
+	/**
1720
+	 * Deletes this model object permanently from db
1721
+	 * (but keep in mind related models may block the delete and return an error)
1722
+	 *
1723
+	 * @return bool | int
1724
+	 * @throws ReflectionException
1725
+	 * @throws InvalidArgumentException
1726
+	 * @throws InvalidInterfaceException
1727
+	 * @throws InvalidDataTypeException
1728
+	 * @throws EE_Error
1729
+	 */
1730
+	public function delete_permanently()
1731
+	{
1732
+		/**
1733
+		 * Called just before HARD deleting a model object
1734
+		 *
1735
+		 * @param EE_Base_Class $model_object about to be 'deleted'
1736
+		 */
1737
+		do_action('AHEE__EE_Base_Class__delete_permanently__before', $this);
1738
+		$model  = $this->get_model();
1739
+		$result = $model->delete_permanently_by_ID($this->ID());
1740
+		$this->refresh_cache_of_related_objects();
1741
+		/**
1742
+		 * Called just after HARD deleting a model object
1743
+		 *
1744
+		 * @param EE_Base_Class $model_object that was just 'deleted'
1745
+		 * @param boolean       $result
1746
+		 */
1747
+		do_action('AHEE__EE_Base_Class__delete_permanently__end', $this, $result);
1748
+		return $result;
1749
+	}
1750
+
1751
+
1752
+	/**
1753
+	 * When this model object is deleted, it may still be cached on related model objects. This clears the cache of
1754
+	 * related model objects
1755
+	 *
1756
+	 * @throws ReflectionException
1757
+	 * @throws InvalidArgumentException
1758
+	 * @throws InvalidInterfaceException
1759
+	 * @throws InvalidDataTypeException
1760
+	 * @throws EE_Error
1761
+	 */
1762
+	public function refresh_cache_of_related_objects()
1763
+	{
1764
+		$model = $this->get_model();
1765
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
+			if (! empty($this->_model_relations[ $relation_name ])) {
1767
+				$related_objects = $this->_model_relations[ $relation_name ];
1768
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769
+					//this relation only stores a single model object, not an array
1770
+					//but let's make it consistent
1771
+					$related_objects = array($related_objects);
1772
+				}
1773
+				foreach ($related_objects as $related_object) {
1774
+					//only refresh their cache if they're in memory
1775
+					if ($related_object instanceof EE_Base_Class) {
1776
+						$related_object->clear_cache(
1777
+							$model->get_this_model_name(),
1778
+							$this
1779
+						);
1780
+					}
1781
+				}
1782
+			}
1783
+		}
1784
+	}
1785
+
1786
+
1787
+	/**
1788
+	 *        Saves this object to the database. An array may be supplied to set some values on this
1789
+	 * object just before saving.
1790
+	 *
1791
+	 * @access public
1792
+	 * @param array $set_cols_n_values keys are field names, values are their new values,
1793
+	 *                                 if provided during the save() method (often client code will change the fields'
1794
+	 *                                 values before calling save)
1795
+	 * @throws InvalidArgumentException
1796
+	 * @throws InvalidInterfaceException
1797
+	 * @throws InvalidDataTypeException
1798
+	 * @throws EE_Error
1799
+	 * @return int , 1 on a successful update, the ID of the new entry on insert; 0 on failure or if the model object
1800
+	 *                                 isn't allowed to persist (as determined by EE_Base_Class::allow_persist())
1801
+	 * @throws ReflectionException
1802
+	 * @throws ReflectionException
1803
+	 * @throws ReflectionException
1804
+	 */
1805
+	public function save($set_cols_n_values = array())
1806
+	{
1807
+		$model = $this->get_model();
1808
+		/**
1809
+		 * Filters the fields we're about to save on the model object
1810
+		 *
1811
+		 * @param array         $set_cols_n_values
1812
+		 * @param EE_Base_Class $model_object
1813
+		 */
1814
+		$set_cols_n_values = (array) apply_filters(
1815
+			'FHEE__EE_Base_Class__save__set_cols_n_values',
1816
+			$set_cols_n_values,
1817
+			$this
1818
+		);
1819
+		//set attributes as provided in $set_cols_n_values
1820
+		foreach ($set_cols_n_values as $column => $value) {
1821
+			$this->set($column, $value);
1822
+		}
1823
+		// no changes ? then don't do anything
1824
+		if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825
+			return 0;
1826
+		}
1827
+		/**
1828
+		 * Saving a model object.
1829
+		 * Before we perform a save, this action is fired.
1830
+		 *
1831
+		 * @param EE_Base_Class $model_object the model object about to be saved.
1832
+		 */
1833
+		do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
+		if (! $this->allow_persist()) {
1835
+			return 0;
1836
+		}
1837
+		// now get current attribute values
1838
+		$save_cols_n_values = $this->_fields;
1839
+		// if the object already has an ID, update it. Otherwise, insert it
1840
+		// also: change the assumption about values passed to the model NOT being prepare dby the model object.
1841
+		// They have been
1842
+		$old_assumption_concerning_value_preparation = $model
1843
+			->get_assumption_concerning_values_already_prepared_by_model_object();
1844
+		$model->assume_values_already_prepared_by_model_object(true);
1845
+		//does this model have an autoincrement PK?
1846
+		if ($model->has_primary_key_field()) {
1847
+			if ($model->get_primary_key_field()->is_auto_increment()) {
1848
+				//ok check if it's set, if so: update; if not, insert
1849
+				if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1850
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851
+				} else {
1852
+					unset($save_cols_n_values[ $model->primary_key_name() ]);
1853
+					$results = $model->insert($save_cols_n_values);
1854
+					if ($results) {
1855
+						//if successful, set the primary key
1856
+						//but don't use the normal SET method, because it will check if
1857
+						//an item with the same ID exists in the mapper & db, then
1858
+						//will find it in the db (because we just added it) and THAT object
1859
+						//will get added to the mapper before we can add this one!
1860
+						//but if we just avoid using the SET method, all that headache can be avoided
1861
+						$pk_field_name                   = $model->primary_key_name();
1862
+						$this->_fields[ $pk_field_name ] = $results;
1863
+						$this->_clear_cached_property($pk_field_name);
1864
+						$model->add_to_entity_map($this);
1865
+						$this->_update_cached_related_model_objs_fks();
1866
+					}
1867
+				}
1868
+			} else {//PK is NOT auto-increment
1869
+				//so check if one like it already exists in the db
1870
+				if ($model->exists_by_ID($this->ID())) {
1871
+					if (WP_DEBUG && ! $this->in_entity_map()) {
1872
+						throw new EE_Error(
1873
+							sprintf(
1874
+								esc_html__(
1875
+									'Using a model object %1$s that is NOT in the entity map, can lead to unexpected errors. You should either: %4$s 1. Put it in the entity mapper by calling %2$s %4$s 2. Discard this model object and use what is in the entity mapper %4$s 3. Fetch from the database using %3$s',
1876
+									'event_espresso'
1877
+								),
1878
+								get_class($this),
1879
+								get_class($model) . '::instance()->add_to_entity_map()',
1880
+								get_class($model) . '::instance()->get_one_by_ID()',
1881
+								'<br />'
1882
+							)
1883
+						);
1884
+					}
1885
+					$results = $model->update_by_ID($save_cols_n_values, $this->ID());
1886
+				} else {
1887
+					$results = $model->insert($save_cols_n_values);
1888
+					$this->_update_cached_related_model_objs_fks();
1889
+				}
1890
+			}
1891
+		} else {//there is NO primary key
1892
+			$already_in_db = false;
1893
+			foreach ($model->unique_indexes() as $index) {
1894
+				$uniqueness_where_params = array_intersect_key($save_cols_n_values, $index->fields());
1895
+				if ($model->exists(array($uniqueness_where_params))) {
1896
+					$already_in_db = true;
1897
+				}
1898
+			}
1899
+			if ($already_in_db) {
1900
+				$combined_pk_fields_n_values = array_intersect_key($save_cols_n_values,
1901
+					$model->get_combined_primary_key_fields());
1902
+				$results                     = $model->update(
1903
+					$save_cols_n_values,
1904
+					$combined_pk_fields_n_values
1905
+				);
1906
+			} else {
1907
+				$results = $model->insert($save_cols_n_values);
1908
+			}
1909
+		}
1910
+		//restore the old assumption about values being prepared by the model object
1911
+		$model->assume_values_already_prepared_by_model_object(
1912
+				$old_assumption_concerning_value_preparation
1913
+			);
1914
+		/**
1915
+		 * After saving the model object this action is called
1916
+		 *
1917
+		 * @param EE_Base_Class $model_object which was just saved
1918
+		 * @param boolean|int   $results      if it were updated, TRUE or FALSE; if it were newly inserted
1919
+		 *                                    the new ID (or 0 if an error occurred and it wasn't updated)
1920
+		 */
1921
+		do_action('AHEE__EE_Base_Class__save__end', $this, $results);
1922
+		$this->_has_changes = false;
1923
+		return $results;
1924
+	}
1925
+
1926
+
1927
+	/**
1928
+	 * Updates the foreign key on related models objects pointing to this to have this model object's ID
1929
+	 * as their foreign key.  If the cached related model objects already exist in the db, saves them (so that the DB
1930
+	 * is consistent) Especially useful in case we JUST added this model object ot the database and we want to let its
1931
+	 * cached relations with foreign keys to it know about that change. Eg: we've created a transaction but haven't
1932
+	 * saved it to the db. We also create a registration and don't save it to the DB, but we DO cache it on the
1933
+	 * transaction. Now, when we save the transaction, the registration's TXN_ID will be automatically updated, whether
1934
+	 * or not they exist in the DB (if they do, their DB records will be automatically updated)
1935
+	 *
1936
+	 * @return void
1937
+	 * @throws ReflectionException
1938
+	 * @throws InvalidArgumentException
1939
+	 * @throws InvalidInterfaceException
1940
+	 * @throws InvalidDataTypeException
1941
+	 * @throws EE_Error
1942
+	 */
1943
+	protected function _update_cached_related_model_objs_fks()
1944
+	{
1945
+		$model = $this->get_model();
1946
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1947
+			if ($relation_obj instanceof EE_Has_Many_Relation) {
1948
+				foreach ($this->get_all_from_cache($relation_name) as $related_model_obj_in_cache) {
1949
+					$fk_to_this = $related_model_obj_in_cache->get_model()->get_foreign_key_to(
1950
+						$model->get_this_model_name()
1951
+					);
1952
+					$related_model_obj_in_cache->set($fk_to_this->get_name(), $this->ID());
1953
+					if ($related_model_obj_in_cache->ID()) {
1954
+						$related_model_obj_in_cache->save();
1955
+					}
1956
+				}
1957
+			}
1958
+		}
1959
+	}
1960
+
1961
+
1962
+	/**
1963
+	 * Saves this model object and its NEW cached relations to the database.
1964
+	 * (Meaning, for now, IT DOES NOT WORK if the cached items already exist in the DB.
1965
+	 * In order for that to work, we would need to mark model objects as dirty/clean...
1966
+	 * because otherwise, there's a potential for infinite looping of saving
1967
+	 * Saves the cached related model objects, and ensures the relation between them
1968
+	 * and this object and properly setup
1969
+	 *
1970
+	 * @return int ID of new model object on save; 0 on failure+
1971
+	 * @throws ReflectionException
1972
+	 * @throws InvalidArgumentException
1973
+	 * @throws InvalidInterfaceException
1974
+	 * @throws InvalidDataTypeException
1975
+	 * @throws EE_Error
1976
+	 */
1977
+	public function save_new_cached_related_model_objs()
1978
+	{
1979
+		//make sure this has been saved
1980
+		if (! $this->ID()) {
1981
+			$id = $this->save();
1982
+		} else {
1983
+			$id = $this->ID();
1984
+		}
1985
+		//now save all the NEW cached model objects  (ie they don't exist in the DB)
1986
+		foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
+			if ($this->_model_relations[ $relationName ]) {
1988
+				//is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989
+				//or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990
+				/* @var $related_model_obj EE_Base_Class */
1991
+				if ($relationObj instanceof EE_Belongs_To_Relation) {
1992
+					//add a relation to that relation type (which saves the appropriate thing in the process)
1993
+					//but ONLY if it DOES NOT exist in the DB
1994
+					$related_model_obj = $this->_model_relations[ $relationName ];
1995
+					//					if( ! $related_model_obj->ID()){
1996
+					$this->_add_relation_to($related_model_obj, $relationName);
1997
+					$related_model_obj->save_new_cached_related_model_objs();
1998
+					//					}
1999
+				} else {
2000
+					foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2001
+						//add a relation to that relation type (which saves the appropriate thing in the process)
2002
+						//but ONLY if it DOES NOT exist in the DB
2003
+						//						if( ! $related_model_obj->ID()){
2004
+						$this->_add_relation_to($related_model_obj, $relationName);
2005
+						$related_model_obj->save_new_cached_related_model_objs();
2006
+						//						}
2007
+					}
2008
+				}
2009
+			}
2010
+		}
2011
+		return $id;
2012
+	}
2013
+
2014
+
2015
+	/**
2016
+	 * for getting a model while instantiated.
2017
+	 *
2018
+	 * @return EEM_Base | EEM_CPT_Base
2019
+	 * @throws ReflectionException
2020
+	 * @throws InvalidArgumentException
2021
+	 * @throws InvalidInterfaceException
2022
+	 * @throws InvalidDataTypeException
2023
+	 * @throws EE_Error
2024
+	 */
2025
+	public function get_model()
2026
+	{
2027
+		if (! $this->_model) {
2028
+			$modelName    = self::_get_model_classname(get_class($this));
2029
+			$this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030
+		} else {
2031
+			$this->_model->set_timezone($this->_timezone);
2032
+		}
2033
+		return $this->_model;
2034
+	}
2035
+
2036
+
2037
+	/**
2038
+	 * @param $props_n_values
2039
+	 * @param $classname
2040
+	 * @return mixed bool|EE_Base_Class|EEM_CPT_Base
2041
+	 * @throws ReflectionException
2042
+	 * @throws InvalidArgumentException
2043
+	 * @throws InvalidInterfaceException
2044
+	 * @throws InvalidDataTypeException
2045
+	 * @throws EE_Error
2046
+	 */
2047
+	protected static function _get_object_from_entity_mapper($props_n_values, $classname)
2048
+	{
2049
+		//TODO: will not work for Term_Relationships because they have no PK!
2050
+		$primary_id_ref = self::_get_primary_key_name($classname);
2051
+		if (
2052
+			array_key_exists($primary_id_ref, $props_n_values)
2053
+			&& ! empty($props_n_values[ $primary_id_ref ])
2054
+		) {
2055
+			$id = $props_n_values[ $primary_id_ref ];
2056
+			return self::_get_model($classname)->get_from_entity_map($id);
2057
+		}
2058
+		return false;
2059
+	}
2060
+
2061
+
2062
+	/**
2063
+	 * This is called by child static "new_instance" method and we'll check to see if there is an existing db entry for
2064
+	 * the primary key (if present in incoming values). If there is a key in the incoming array that matches the
2065
+	 * primary key for the model AND it is not null, then we check the db. If there's a an object we return it.  If not
2066
+	 * we return false.
2067
+	 *
2068
+	 * @param  array  $props_n_values   incoming array of properties and their values
2069
+	 * @param  string $classname        the classname of the child class
2070
+	 * @param null    $timezone
2071
+	 * @param array   $date_formats     incoming date_formats in an array where the first value is the
2072
+	 *                                  date_format and the second value is the time format
2073
+	 * @return mixed (EE_Base_Class|bool)
2074
+	 * @throws InvalidArgumentException
2075
+	 * @throws InvalidInterfaceException
2076
+	 * @throws InvalidDataTypeException
2077
+	 * @throws EE_Error
2078
+	 * @throws ReflectionException
2079
+	 * @throws ReflectionException
2080
+	 * @throws ReflectionException
2081
+	 */
2082
+	protected static function _check_for_object($props_n_values, $classname, $timezone = null, $date_formats = array())
2083
+	{
2084
+		$existing = null;
2085
+		$model    = self::_get_model($classname, $timezone);
2086
+		if ($model->has_primary_key_field()) {
2087
+			$primary_id_ref = self::_get_primary_key_name($classname);
2088
+			if (array_key_exists($primary_id_ref, $props_n_values)
2089
+				&& ! empty($props_n_values[ $primary_id_ref ])
2090
+			) {
2091
+				$existing = $model->get_one_by_ID(
2092
+					$props_n_values[ $primary_id_ref ]
2093
+				);
2094
+			}
2095
+		} elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
2096
+			//no primary key on this model, but there's still a matching item in the DB
2097
+			$existing = self::_get_model($classname, $timezone)->get_one_by_ID(
2098
+				self::_get_model($classname, $timezone)
2099
+					->get_index_primary_key_string($props_n_values)
2100
+			);
2101
+		}
2102
+		if ($existing) {
2103
+			//set date formats if present before setting values
2104
+			if (! empty($date_formats) && is_array($date_formats)) {
2105
+				$existing->set_date_format($date_formats[0]);
2106
+				$existing->set_time_format($date_formats[1]);
2107
+			} else {
2108
+				//set default formats for date and time
2109
+				$existing->set_date_format(get_option('date_format'));
2110
+				$existing->set_time_format(get_option('time_format'));
2111
+			}
2112
+			foreach ($props_n_values as $property => $field_value) {
2113
+				$existing->set($property, $field_value);
2114
+			}
2115
+			return $existing;
2116
+		}
2117
+		return false;
2118
+	}
2119
+
2120
+
2121
+	/**
2122
+	 * Gets the EEM_*_Model for this class
2123
+	 *
2124
+	 * @access public now, as this is more convenient
2125
+	 * @param      $classname
2126
+	 * @param null $timezone
2127
+	 * @throws ReflectionException
2128
+	 * @throws InvalidArgumentException
2129
+	 * @throws InvalidInterfaceException
2130
+	 * @throws InvalidDataTypeException
2131
+	 * @throws EE_Error
2132
+	 * @return EEM_Base
2133
+	 */
2134
+	protected static function _get_model($classname, $timezone = null)
2135
+	{
2136
+		//find model for this class
2137
+		if (! $classname) {
2138
+			throw new EE_Error(
2139
+				sprintf(
2140
+					esc_html__(
2141
+						'What were you thinking calling _get_model(%s)?? You need to specify the class name',
2142
+						'event_espresso'
2143
+					),
2144
+					$classname
2145
+				)
2146
+			);
2147
+		}
2148
+		$modelName = self::_get_model_classname($classname);
2149
+		return self::_get_model_instance_with_name($modelName, $timezone);
2150
+	}
2151
+
2152
+
2153
+	/**
2154
+	 * Gets the model instance (eg instance of EEM_Attendee) given its classname (eg EE_Attendee)
2155
+	 *
2156
+	 * @param string $model_classname
2157
+	 * @param null   $timezone
2158
+	 * @return EEM_Base
2159
+	 * @throws ReflectionException
2160
+	 * @throws InvalidArgumentException
2161
+	 * @throws InvalidInterfaceException
2162
+	 * @throws InvalidDataTypeException
2163
+	 * @throws EE_Error
2164
+	 */
2165
+	protected static function _get_model_instance_with_name($model_classname, $timezone = null)
2166
+	{
2167
+		$model_classname = str_replace('EEM_', '', $model_classname);
2168
+		$model           = EE_Registry::instance()->load_model($model_classname);
2169
+		$model->set_timezone($timezone);
2170
+		return $model;
2171
+	}
2172
+
2173
+
2174
+	/**
2175
+	 * If a model name is provided (eg Registration), gets the model classname for that model.
2176
+	 * Also works if a model class's classname is provided (eg EE_Registration).
2177
+	 *
2178
+	 * @param null $model_name
2179
+	 * @return string like EEM_Attendee
2180
+	 */
2181
+	private static function _get_model_classname($model_name = null)
2182
+	{
2183
+		if (strpos($model_name, 'EE_') === 0) {
2184
+			$model_classname = str_replace('EE_', 'EEM_', $model_name);
2185
+		} else {
2186
+			$model_classname = 'EEM_' . $model_name;
2187
+		}
2188
+		return $model_classname;
2189
+	}
2190
+
2191
+
2192
+	/**
2193
+	 * returns the name of the primary key attribute
2194
+	 *
2195
+	 * @param null $classname
2196
+	 * @throws ReflectionException
2197
+	 * @throws InvalidArgumentException
2198
+	 * @throws InvalidInterfaceException
2199
+	 * @throws InvalidDataTypeException
2200
+	 * @throws EE_Error
2201
+	 * @return string
2202
+	 */
2203
+	protected static function _get_primary_key_name($classname = null)
2204
+	{
2205
+		if (! $classname) {
2206
+			throw new EE_Error(
2207
+				sprintf(
2208
+					esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
2209
+					$classname
2210
+				)
2211
+			);
2212
+		}
2213
+		return self::_get_model($classname)->get_primary_key_field()->get_name();
2214
+	}
2215
+
2216
+
2217
+	/**
2218
+	 * Gets the value of the primary key.
2219
+	 * If the object hasn't yet been saved, it should be whatever the model field's default was
2220
+	 * (eg, if this were the EE_Event class, look at the primary key field on EEM_Event and see what its default value
2221
+	 * is. Usually defaults for integer primary keys are 0; string primary keys are usually NULL).
2222
+	 *
2223
+	 * @return mixed, if the primary key is of type INT it'll be an int. Otherwise it could be a string
2224
+	 * @throws ReflectionException
2225
+	 * @throws InvalidArgumentException
2226
+	 * @throws InvalidInterfaceException
2227
+	 * @throws InvalidDataTypeException
2228
+	 * @throws EE_Error
2229
+	 */
2230
+	public function ID()
2231
+	{
2232
+		$model = $this->get_model();
2233
+		//now that we know the name of the variable, use a variable variable to get its value and return its
2234
+		if ($model->has_primary_key_field()) {
2235
+			return $this->_fields[ $model->primary_key_name() ];
2236
+		}
2237
+		return $model->get_index_primary_key_string($this->_fields);
2238
+	}
2239
+
2240
+
2241
+	/**
2242
+	 * Adds a relationship to the specified EE_Base_Class object, given the relationship's name. Eg, if the current
2243
+	 * model is related to a group of events, the $relationName should be 'Event', and should be a key in the EE
2244
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just caches the related thing
2245
+	 *
2246
+	 * @param mixed  $otherObjectModelObjectOrID       EE_Base_Class or the ID of the other object
2247
+	 * @param string $relationName                     eg 'Events','Question',etc.
2248
+	 *                                                 an attendee to a group, you also want to specify which role they
2249
+	 *                                                 will have in that group. So you would use this parameter to
2250
+	 *                                                 specify array('role-column-name'=>'role-id')
2251
+	 * @param array  $extra_join_model_fields_n_values You can optionally include an array of key=>value pairs that
2252
+	 *                                                 allow you to further constrict the relation to being added.
2253
+	 *                                                 However, keep in mind that the columns (keys) given must match a
2254
+	 *                                                 column on the JOIN table and currently only the HABTM models
2255
+	 *                                                 accept these additional conditions.  Also remember that if an
2256
+	 *                                                 exact match isn't found for these extra cols/val pairs, then a
2257
+	 *                                                 NEW row is created in the join table.
2258
+	 * @param null   $cache_id
2259
+	 * @throws ReflectionException
2260
+	 * @throws InvalidArgumentException
2261
+	 * @throws InvalidInterfaceException
2262
+	 * @throws InvalidDataTypeException
2263
+	 * @throws EE_Error
2264
+	 * @return EE_Base_Class the object the relation was added to
2265
+	 */
2266
+	public function _add_relation_to(
2267
+		$otherObjectModelObjectOrID,
2268
+		$relationName,
2269
+		$extra_join_model_fields_n_values = array(),
2270
+		$cache_id = null
2271
+	) {
2272
+		$model = $this->get_model();
2273
+		//if this thing exists in the DB, save the relation to the DB
2274
+		if ($this->ID()) {
2275
+			$otherObject = $model->add_relationship_to(
2276
+				$this,
2277
+				$otherObjectModelObjectOrID,
2278
+				$relationName,
2279
+				$extra_join_model_fields_n_values
2280
+			);
2281
+			//clear cache so future get_many_related and get_first_related() return new results.
2282
+			$this->clear_cache($relationName, $otherObject, true);
2283
+			if ($otherObject instanceof EE_Base_Class) {
2284
+				$otherObject->clear_cache($model->get_this_model_name(), $this);
2285
+			}
2286
+		} else {
2287
+			//this thing doesn't exist in the DB,  so just cache it
2288
+			if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289
+				throw new EE_Error(
2290
+					sprintf(
2291
+						esc_html__(
2292
+							'Before a model object is saved to the database, calls to _add_relation_to must be passed an actual object, not just an ID. You provided %s as the model object to a %s',
2293
+							'event_espresso'
2294
+						),
2295
+						$otherObjectModelObjectOrID,
2296
+						get_class($this)
2297
+					)
2298
+				);
2299
+			}
2300
+			$otherObject = $otherObjectModelObjectOrID;
2301
+			$this->cache($relationName, $otherObjectModelObjectOrID, $cache_id);
2302
+		}
2303
+		if ($otherObject instanceof EE_Base_Class) {
2304
+			//fix the reciprocal relation too
2305
+			if ($otherObject->ID()) {
2306
+				//its saved so assumed relations exist in the DB, so we can just
2307
+				//clear the cache so future queries use the updated info in the DB
2308
+				$otherObject->clear_cache(
2309
+					$model->get_this_model_name(),
2310
+					null,
2311
+					true
2312
+				);
2313
+			} else {
2314
+				//it's not saved, so it caches relations like this
2315
+				$otherObject->cache($model->get_this_model_name(), $this);
2316
+			}
2317
+		}
2318
+		return $otherObject;
2319
+	}
2320
+
2321
+
2322
+	/**
2323
+	 * Removes a relationship to the specified EE_Base_Class object, given the relationships' name. Eg, if the current
2324
+	 * model is related to a group of events, the $relationName should be 'Events', and should be a key in the EE
2325
+	 * Model's $_model_relations array. If this model object doesn't exist in the DB, just removes the related thing
2326
+	 * from the cache
2327
+	 *
2328
+	 * @param mixed  $otherObjectModelObjectOrID
2329
+	 *                EE_Base_Class or the ID of the other object, OR an array key into the cache if this isn't saved
2330
+	 *                to the DB yet
2331
+	 * @param string $relationName
2332
+	 * @param array  $where_query
2333
+	 *                You can optionally include an array of key=>value pairs that allow you to further constrict the
2334
+	 *                relation to being added. However, keep in mind that the columns (keys) given must match a column
2335
+	 *                on the JOIN table and currently only the HABTM models accept these additional conditions. Also
2336
+	 *                remember that if an exact match isn't found for these extra cols/val pairs, then a NEW row is
2337
+	 *                created in the join table.
2338
+	 * @return EE_Base_Class the relation was removed from
2339
+	 * @throws ReflectionException
2340
+	 * @throws InvalidArgumentException
2341
+	 * @throws InvalidInterfaceException
2342
+	 * @throws InvalidDataTypeException
2343
+	 * @throws EE_Error
2344
+	 */
2345
+	public function _remove_relation_to($otherObjectModelObjectOrID, $relationName, $where_query = array())
2346
+	{
2347
+		if ($this->ID()) {
2348
+			//if this exists in the DB, save the relation change to the DB too
2349
+			$otherObject = $this->get_model()->remove_relationship_to(
2350
+				$this,
2351
+				$otherObjectModelObjectOrID,
2352
+				$relationName,
2353
+				$where_query
2354
+			);
2355
+			$this->clear_cache(
2356
+				$relationName,
2357
+				$otherObject
2358
+			);
2359
+		} else {
2360
+			//this doesn't exist in the DB, just remove it from the cache
2361
+			$otherObject = $this->clear_cache(
2362
+				$relationName,
2363
+				$otherObjectModelObjectOrID
2364
+			);
2365
+		}
2366
+		if ($otherObject instanceof EE_Base_Class) {
2367
+			$otherObject->clear_cache(
2368
+				$this->get_model()->get_this_model_name(),
2369
+				$this
2370
+			);
2371
+		}
2372
+		return $otherObject;
2373
+	}
2374
+
2375
+
2376
+	/**
2377
+	 * Removes ALL the related things for the $relationName.
2378
+	 *
2379
+	 * @param string $relationName
2380
+	 * @param array  $where_query_params like EEM_Base::get_all's $query_params[0] (where conditions)
2381
+	 * @return EE_Base_Class
2382
+	 * @throws ReflectionException
2383
+	 * @throws InvalidArgumentException
2384
+	 * @throws InvalidInterfaceException
2385
+	 * @throws InvalidDataTypeException
2386
+	 * @throws EE_Error
2387
+	 */
2388
+	public function _remove_relations($relationName, $where_query_params = array())
2389
+	{
2390
+		if ($this->ID()) {
2391
+			//if this exists in the DB, save the relation change to the DB too
2392
+			$otherObjects = $this->get_model()->remove_relations(
2393
+				$this,
2394
+				$relationName,
2395
+				$where_query_params
2396
+			);
2397
+			$this->clear_cache(
2398
+				$relationName,
2399
+				null,
2400
+				true
2401
+			);
2402
+		} else {
2403
+			//this doesn't exist in the DB, just remove it from the cache
2404
+			$otherObjects = $this->clear_cache(
2405
+				$relationName,
2406
+				null,
2407
+				true
2408
+			);
2409
+		}
2410
+		if (is_array($otherObjects)) {
2411
+			foreach ($otherObjects as $otherObject) {
2412
+				$otherObject->clear_cache(
2413
+					$this->get_model()->get_this_model_name(),
2414
+					$this
2415
+				);
2416
+			}
2417
+		}
2418
+		return $otherObjects;
2419
+	}
2420
+
2421
+
2422
+	/**
2423
+	 * Gets all the related model objects of the specified type. Eg, if the current class if
2424
+	 * EE_Event, you could call $this->get_many_related('Registration') to get an array of all the
2425
+	 * EE_Registration objects which related to this event. Note: by default, we remove the "default query params"
2426
+	 * because we want to get even deleted items etc.
2427
+	 *
2428
+	 * @param string $relationName key in the model's _model_relations array
2429
+	 * @param array  $query_params like EEM_Base::get_all
2430
+	 * @return EE_Base_Class[]     Results not necessarily indexed by IDs, because some results might not have primary
2431
+	 *                             keys or might not be saved yet. Consider using EEM_Base::get_IDs() on these
2432
+	 *                             results if you want IDs
2433
+	 * @throws ReflectionException
2434
+	 * @throws InvalidArgumentException
2435
+	 * @throws InvalidInterfaceException
2436
+	 * @throws InvalidDataTypeException
2437
+	 * @throws EE_Error
2438
+	 */
2439
+	public function get_many_related($relationName, $query_params = array())
2440
+	{
2441
+		if ($this->ID()) {
2442
+			//this exists in the DB, so get the related things from either the cache or the DB
2443
+			//if there are query parameters, forget about caching the related model objects.
2444
+			if ($query_params) {
2445
+				$related_model_objects = $this->get_model()->get_all_related(
2446
+					$this,
2447
+					$relationName,
2448
+					$query_params
2449
+				);
2450
+			} else {
2451
+				//did we already cache the result of this query?
2452
+				$cached_results = $this->get_all_from_cache($relationName);
2453
+				if (! $cached_results) {
2454
+					$related_model_objects = $this->get_model()->get_all_related(
2455
+						$this,
2456
+						$relationName,
2457
+						$query_params
2458
+					);
2459
+					//if no query parameters were passed, then we got all the related model objects
2460
+					//for that relation. We can cache them then.
2461
+					foreach ($related_model_objects as $related_model_object) {
2462
+						$this->cache($relationName, $related_model_object);
2463
+					}
2464
+				} else {
2465
+					$related_model_objects = $cached_results;
2466
+				}
2467
+			}
2468
+		} else {
2469
+			//this doesn't exist in the DB, so just get the related things from the cache
2470
+			$related_model_objects = $this->get_all_from_cache($relationName);
2471
+		}
2472
+		return $related_model_objects;
2473
+	}
2474
+
2475
+
2476
+	/**
2477
+	 * Instead of getting the related model objects, simply counts them. Ignores default_where_conditions by default,
2478
+	 * unless otherwise specified in the $query_params
2479
+	 *
2480
+	 * @param string $relation_name  model_name like 'Event', or 'Registration'
2481
+	 * @param array  $query_params   like EEM_Base::get_all's
2482
+	 * @param string $field_to_count name of field to count by. By default, uses primary key
2483
+	 * @param bool   $distinct       if we want to only count the distinct values for the column then you can trigger
2484
+	 *                               that by the setting $distinct to TRUE;
2485
+	 * @return int
2486
+	 * @throws ReflectionException
2487
+	 * @throws InvalidArgumentException
2488
+	 * @throws InvalidInterfaceException
2489
+	 * @throws InvalidDataTypeException
2490
+	 * @throws EE_Error
2491
+	 */
2492
+	public function count_related($relation_name, $query_params = array(), $field_to_count = null, $distinct = false)
2493
+	{
2494
+		return $this->get_model()->count_related(
2495
+			$this,
2496
+			$relation_name,
2497
+			$query_params,
2498
+			$field_to_count,
2499
+			$distinct
2500
+		);
2501
+	}
2502
+
2503
+
2504
+	/**
2505
+	 * Instead of getting the related model objects, simply sums up the values of the specified field.
2506
+	 * Note: ignores default_where_conditions by default, unless otherwise specified in the $query_params
2507
+	 *
2508
+	 * @param string $relation_name model_name like 'Event', or 'Registration'
2509
+	 * @param array  $query_params  like EEM_Base::get_all's
2510
+	 * @param string $field_to_sum  name of field to count by.
2511
+	 *                              By default, uses primary key
2512
+	 *                              (which doesn't make much sense, so you should probably change it)
2513
+	 * @return int
2514
+	 * @throws ReflectionException
2515
+	 * @throws InvalidArgumentException
2516
+	 * @throws InvalidInterfaceException
2517
+	 * @throws InvalidDataTypeException
2518
+	 * @throws EE_Error
2519
+	 */
2520
+	public function sum_related($relation_name, $query_params = array(), $field_to_sum = null)
2521
+	{
2522
+		return $this->get_model()->sum_related(
2523
+			$this,
2524
+			$relation_name,
2525
+			$query_params,
2526
+			$field_to_sum
2527
+		);
2528
+	}
2529
+
2530
+
2531
+	/**
2532
+	 * Gets the first (ie, one) related model object of the specified type.
2533
+	 *
2534
+	 * @param string $relationName key in the model's _model_relations array
2535
+	 * @param array  $query_params like EEM_Base::get_all
2536
+	 * @return EE_Base_Class (not an array, a single object)
2537
+	 * @throws ReflectionException
2538
+	 * @throws InvalidArgumentException
2539
+	 * @throws InvalidInterfaceException
2540
+	 * @throws InvalidDataTypeException
2541
+	 * @throws EE_Error
2542
+	 */
2543
+	public function get_first_related($relationName, $query_params = array())
2544
+	{
2545
+		$model = $this->get_model();
2546
+		if ($this->ID()) {//this exists in the DB, get from the cache OR the DB
2547
+			//if they've provided some query parameters, don't bother trying to cache the result
2548
+			//also make sure we're not caching the result of get_first_related
2549
+			//on a relation which should have an array of objects (because the cache might have an array of objects)
2550
+			if ($query_params
2551
+				|| ! $model->related_settings_for($relationName)
2552
+					 instanceof
2553
+					 EE_Belongs_To_Relation
2554
+			) {
2555
+				$related_model_object = $model->get_first_related(
2556
+					$this,
2557
+					$relationName,
2558
+					$query_params
2559
+				);
2560
+			} else {
2561
+				//first, check if we've already cached the result of this query
2562
+				$cached_result = $this->get_one_from_cache($relationName);
2563
+				if (! $cached_result) {
2564
+					$related_model_object = $model->get_first_related(
2565
+						$this,
2566
+						$relationName,
2567
+						$query_params
2568
+					);
2569
+					$this->cache($relationName, $related_model_object);
2570
+				} else {
2571
+					$related_model_object = $cached_result;
2572
+				}
2573
+			}
2574
+		} else {
2575
+			$related_model_object = null;
2576
+			// this doesn't exist in the Db,
2577
+			// but maybe the relation is of type belongs to, and so the related thing might
2578
+			if ($model->related_settings_for($relationName) instanceof EE_Belongs_To_Relation) {
2579
+				$related_model_object = $model->get_first_related(
2580
+					$this,
2581
+					$relationName,
2582
+					$query_params
2583
+				);
2584
+			}
2585
+			// this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586
+			// just get what's cached on this object
2587
+			if (! $related_model_object) {
2588
+				$related_model_object = $this->get_one_from_cache($relationName);
2589
+			}
2590
+		}
2591
+		return $related_model_object;
2592
+	}
2593
+
2594
+
2595
+	/**
2596
+	 * Does a delete on all related objects of type $relationName and removes
2597
+	 * the current model object's relation to them. If they can't be deleted (because
2598
+	 * of blocking related model objects) does nothing. If the related model objects are
2599
+	 * soft-deletable, they will be soft-deleted regardless of related blocking model objects.
2600
+	 * If this model object doesn't exist yet in the DB, just removes its related things
2601
+	 *
2602
+	 * @param string $relationName
2603
+	 * @param array  $query_params like EEM_Base::get_all's
2604
+	 * @return int how many deleted
2605
+	 * @throws ReflectionException
2606
+	 * @throws InvalidArgumentException
2607
+	 * @throws InvalidInterfaceException
2608
+	 * @throws InvalidDataTypeException
2609
+	 * @throws EE_Error
2610
+	 */
2611
+	public function delete_related($relationName, $query_params = array())
2612
+	{
2613
+		if ($this->ID()) {
2614
+			$count = $this->get_model()->delete_related(
2615
+				$this,
2616
+				$relationName,
2617
+				$query_params
2618
+			);
2619
+		} else {
2620
+			$count = count($this->get_all_from_cache($relationName));
2621
+			$this->clear_cache($relationName, null, true);
2622
+		}
2623
+		return $count;
2624
+	}
2625
+
2626
+
2627
+	/**
2628
+	 * Does a hard delete (ie, removes the DB row) on all related objects of type $relationName and removes
2629
+	 * the current model object's relation to them. If they can't be deleted (because
2630
+	 * of blocking related model objects) just does a soft delete on it instead, if possible.
2631
+	 * If the related thing isn't a soft-deletable model object, this function is identical
2632
+	 * to delete_related(). If this model object doesn't exist in the DB, just remove its related things
2633
+	 *
2634
+	 * @param string $relationName
2635
+	 * @param array  $query_params like EEM_Base::get_all's
2636
+	 * @return int how many deleted (including those soft deleted)
2637
+	 * @throws ReflectionException
2638
+	 * @throws InvalidArgumentException
2639
+	 * @throws InvalidInterfaceException
2640
+	 * @throws InvalidDataTypeException
2641
+	 * @throws EE_Error
2642
+	 */
2643
+	public function delete_related_permanently($relationName, $query_params = array())
2644
+	{
2645
+		if ($this->ID()) {
2646
+			$count = $this->get_model()->delete_related_permanently(
2647
+				$this,
2648
+				$relationName,
2649
+				$query_params
2650
+			);
2651
+		} else {
2652
+			$count = count($this->get_all_from_cache($relationName));
2653
+		}
2654
+		$this->clear_cache($relationName, null, true);
2655
+		return $count;
2656
+	}
2657
+
2658
+
2659
+	/**
2660
+	 * is_set
2661
+	 * Just a simple utility function children can use for checking if property exists
2662
+	 *
2663
+	 * @access  public
2664
+	 * @param  string $field_name property to check
2665
+	 * @return bool                              TRUE if existing,FALSE if not.
2666
+	 */
2667
+	public function is_set($field_name)
2668
+	{
2669
+		return isset($this->_fields[ $field_name ]);
2670
+	}
2671
+
2672
+
2673
+	/**
2674
+	 * Just a simple utility function children can use for checking if property (or properties) exists and throwing an
2675
+	 * EE_Error exception if they don't
2676
+	 *
2677
+	 * @param  mixed (string|array) $properties properties to check
2678
+	 * @throws EE_Error
2679
+	 * @return bool                              TRUE if existing, throw EE_Error if not.
2680
+	 */
2681
+	protected function _property_exists($properties)
2682
+	{
2683
+		foreach ((array) $properties as $property_name) {
2684
+			//first make sure this property exists
2685
+			if (! $this->_fields[ $property_name ]) {
2686
+				throw new EE_Error(
2687
+					sprintf(
2688
+						esc_html__(
2689
+							'Trying to retrieve a non-existent property (%s).  Double check the spelling please',
2690
+							'event_espresso'
2691
+						),
2692
+						$property_name
2693
+					)
2694
+				);
2695
+			}
2696
+		}
2697
+		return true;
2698
+	}
2699
+
2700
+
2701
+	/**
2702
+	 * This simply returns an array of model fields for this object
2703
+	 *
2704
+	 * @return array
2705
+	 * @throws ReflectionException
2706
+	 * @throws InvalidArgumentException
2707
+	 * @throws InvalidInterfaceException
2708
+	 * @throws InvalidDataTypeException
2709
+	 * @throws EE_Error
2710
+	 */
2711
+	public function model_field_array()
2712
+	{
2713
+		$fields     = $this->get_model()->field_settings(false);
2714
+		$properties = array();
2715
+		//remove prepended underscore
2716
+		foreach ($fields as $field_name => $settings) {
2717
+			$properties[ $field_name ] = $this->get($field_name);
2718
+		}
2719
+		return $properties;
2720
+	}
2721
+
2722
+
2723
+	/**
2724
+	 * Very handy general function to allow for plugins to extend any child of EE_Base_Class.
2725
+	 * If a method is called on a child of EE_Base_Class that doesn't exist, this function is called
2726
+	 * (http://www.garfieldtech.com/blog/php-magic-call) and passed the method's name and arguments.
2727
+	 * Instead of requiring a plugin to extend the EE_Base_Class
2728
+	 * (which works fine is there's only 1 plugin, but when will that happen?)
2729
+	 * they can add a hook onto 'filters_hook_espresso__{className}__{methodName}'
2730
+	 * (eg, filters_hook_espresso__EE_Answer__my_great_function)
2731
+	 * and accepts 2 arguments: the object on which the function was called,
2732
+	 * and an array of the original arguments passed to the function.
2733
+	 * Whatever their callback function returns will be returned by this function.
2734
+	 * Example: in functions.php (or in a plugin):
2735
+	 *      add_filter('FHEE__EE_Answer__my_callback','my_callback',10,3);
2736
+	 *      function my_callback($previousReturnValue,EE_Base_Class $object,$argsArray){
2737
+	 *          $returnString= "you called my_callback! and passed args:".implode(",",$argsArray);
2738
+	 *          return $previousReturnValue.$returnString;
2739
+	 *      }
2740
+	 * require('EE_Answer.class.php');
2741
+	 * $answer= EE_Answer::new_instance(array('REG_ID' => 2,'QST_ID' => 3,'ANS_value' => The answer is 42'));
2742
+	 * echo $answer->my_callback('monkeys',100);
2743
+	 * //will output "you called my_callback! and passed args:monkeys,100"
2744
+	 *
2745
+	 * @param string $methodName name of method which was called on a child of EE_Base_Class, but which
2746
+	 * @param array  $args       array of original arguments passed to the function
2747
+	 * @throws EE_Error
2748
+	 * @return mixed whatever the plugin which calls add_filter decides
2749
+	 */
2750
+	public function __call($methodName, $args)
2751
+	{
2752
+		$className = get_class($this);
2753
+		$tagName   = "FHEE__{$className}__{$methodName}";
2754
+		if (! has_filter($tagName)) {
2755
+			throw new EE_Error(
2756
+				sprintf(
2757
+					esc_html__(
2758
+						"Method %s on class %s does not exist! You can create one with the following code in functions.php or in a plugin: add_filter('%s','my_callback',10,3);function my_callback(\$previousReturnValue,EE_Base_Class \$object, \$argsArray){/*function body*/return \$whatever;}",
2759
+						'event_espresso'
2760
+					),
2761
+					$methodName,
2762
+					$className,
2763
+					$tagName
2764
+				)
2765
+			);
2766
+		}
2767
+		return apply_filters($tagName, null, $this, $args);
2768
+	}
2769
+
2770
+
2771
+	/**
2772
+	 * Similar to insert_post_meta, adds a record in the Extra_Meta model's table with the given key and value.
2773
+	 * A $previous_value can be specified in case there are many meta rows with the same key
2774
+	 *
2775
+	 * @param string $meta_key
2776
+	 * @param mixed  $meta_value
2777
+	 * @param mixed  $previous_value
2778
+	 * @return bool|int # of records updated (or BOOLEAN if we actually ended up inserting the extra meta row)
2779
+	 *                  NOTE: if the values haven't changed, returns 0
2780
+	 * @throws InvalidArgumentException
2781
+	 * @throws InvalidInterfaceException
2782
+	 * @throws InvalidDataTypeException
2783
+	 * @throws EE_Error
2784
+	 * @throws ReflectionException
2785
+	 */
2786
+	public function update_extra_meta($meta_key, $meta_value, $previous_value = null)
2787
+	{
2788
+		$query_params = array(
2789
+			array(
2790
+				'EXM_key'  => $meta_key,
2791
+				'OBJ_ID'   => $this->ID(),
2792
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2793
+			),
2794
+		);
2795
+		if ($previous_value !== null) {
2796
+			$query_params[0]['EXM_value'] = $meta_value;
2797
+		}
2798
+		$existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
+		if (! $existing_rows_like_that) {
2800
+			return $this->add_extra_meta($meta_key, $meta_value);
2801
+		}
2802
+		foreach ($existing_rows_like_that as $existing_row) {
2803
+			$existing_row->save(array('EXM_value' => $meta_value));
2804
+		}
2805
+		return count($existing_rows_like_that);
2806
+	}
2807
+
2808
+
2809
+	/**
2810
+	 * Adds a new extra meta record. If $unique is set to TRUE, we'll first double-check
2811
+	 * no other extra meta for this model object have the same key. Returns TRUE if the
2812
+	 * extra meta row was entered, false if not
2813
+	 *
2814
+	 * @param string  $meta_key
2815
+	 * @param mixed   $meta_value
2816
+	 * @param boolean $unique
2817
+	 * @return boolean
2818
+	 * @throws InvalidArgumentException
2819
+	 * @throws InvalidInterfaceException
2820
+	 * @throws InvalidDataTypeException
2821
+	 * @throws EE_Error
2822
+	 * @throws ReflectionException
2823
+	 * @throws ReflectionException
2824
+	 */
2825
+	public function add_extra_meta($meta_key, $meta_value, $unique = false)
2826
+	{
2827
+		if ($unique) {
2828
+			$existing_extra_meta = EEM_Extra_Meta::instance()->get_one(
2829
+				array(
2830
+					array(
2831
+						'EXM_key'  => $meta_key,
2832
+						'OBJ_ID'   => $this->ID(),
2833
+						'EXM_type' => $this->get_model()->get_this_model_name(),
2834
+					),
2835
+				)
2836
+			);
2837
+			if ($existing_extra_meta) {
2838
+				return false;
2839
+			}
2840
+		}
2841
+		$new_extra_meta = EE_Extra_Meta::new_instance(
2842
+			array(
2843
+				'EXM_key'   => $meta_key,
2844
+				'EXM_value' => $meta_value,
2845
+				'OBJ_ID'    => $this->ID(),
2846
+				'EXM_type'  => $this->get_model()->get_this_model_name(),
2847
+			)
2848
+		);
2849
+		$new_extra_meta->save();
2850
+		return true;
2851
+	}
2852
+
2853
+
2854
+	/**
2855
+	 * Deletes all the extra meta rows for this record as specified by key. If $meta_value
2856
+	 * is specified, only deletes extra meta records with that value.
2857
+	 *
2858
+	 * @param string $meta_key
2859
+	 * @param mixed  $meta_value
2860
+	 * @return int number of extra meta rows deleted
2861
+	 * @throws InvalidArgumentException
2862
+	 * @throws InvalidInterfaceException
2863
+	 * @throws InvalidDataTypeException
2864
+	 * @throws EE_Error
2865
+	 * @throws ReflectionException
2866
+	 */
2867
+	public function delete_extra_meta($meta_key, $meta_value = null)
2868
+	{
2869
+		$query_params = array(
2870
+			array(
2871
+				'EXM_key'  => $meta_key,
2872
+				'OBJ_ID'   => $this->ID(),
2873
+				'EXM_type' => $this->get_model()->get_this_model_name(),
2874
+			),
2875
+		);
2876
+		if ($meta_value !== null) {
2877
+			$query_params[0]['EXM_value'] = $meta_value;
2878
+		}
2879
+		return EEM_Extra_Meta::instance()->delete($query_params);
2880
+	}
2881
+
2882
+
2883
+	/**
2884
+	 * Gets the extra meta with the given meta key. If you specify "single" we just return 1, otherwise
2885
+	 * an array of everything found. Requires that this model actually have a relation of type EE_Has_Many_Any_Relation.
2886
+	 * You can specify $default is case you haven't found the extra meta
2887
+	 *
2888
+	 * @param string  $meta_key
2889
+	 * @param boolean $single
2890
+	 * @param mixed   $default if we don't find anything, what should we return?
2891
+	 * @return mixed single value if $single; array if ! $single
2892
+	 * @throws ReflectionException
2893
+	 * @throws InvalidArgumentException
2894
+	 * @throws InvalidInterfaceException
2895
+	 * @throws InvalidDataTypeException
2896
+	 * @throws EE_Error
2897
+	 */
2898
+	public function get_extra_meta($meta_key, $single = false, $default = null)
2899
+	{
2900
+		if ($single) {
2901
+			$result = $this->get_first_related(
2902
+				'Extra_Meta',
2903
+				array(array('EXM_key' => $meta_key))
2904
+			);
2905
+			if ($result instanceof EE_Extra_Meta) {
2906
+				return $result->value();
2907
+			}
2908
+		} else {
2909
+			$results = $this->get_many_related(
2910
+				'Extra_Meta',
2911
+				array(array('EXM_key' => $meta_key))
2912
+			);
2913
+			if ($results) {
2914
+				$values = array();
2915
+				foreach ($results as $result) {
2916
+					if ($result instanceof EE_Extra_Meta) {
2917
+						$values[ $result->ID() ] = $result->value();
2918
+					}
2919
+				}
2920
+				return $values;
2921
+			}
2922
+		}
2923
+		//if nothing discovered yet return default.
2924
+		return apply_filters(
2925
+			'FHEE__EE_Base_Class__get_extra_meta__default_value',
2926
+			$default,
2927
+			$meta_key,
2928
+			$single,
2929
+			$this
2930
+		);
2931
+	}
2932
+
2933
+
2934
+	/**
2935
+	 * Returns a simple array of all the extra meta associated with this model object.
2936
+	 * If $one_of_each_key is true (Default), it will be an array of simple key-value pairs, keys being the
2937
+	 * extra meta's key, and teh value being its value. However, if there are duplicate extra meta rows with
2938
+	 * the same key, only one will be used. (eg array('foo'=>'bar','monkey'=>123))
2939
+	 * If $one_of_each_key is false, it will return an array with the top-level keys being
2940
+	 * the extra meta keys, but their values are also arrays, which have the extra-meta's ID as their sub-key, and
2941
+	 * finally the extra meta's value as each sub-value. (eg
2942
+	 * array('foo'=>array(1=>'bar',2=>'bill'),'monkey'=>array(3=>123)))
2943
+	 *
2944
+	 * @param boolean $one_of_each_key
2945
+	 * @return array
2946
+	 * @throws ReflectionException
2947
+	 * @throws InvalidArgumentException
2948
+	 * @throws InvalidInterfaceException
2949
+	 * @throws InvalidDataTypeException
2950
+	 * @throws EE_Error
2951
+	 */
2952
+	public function all_extra_meta_array($one_of_each_key = true)
2953
+	{
2954
+		$return_array = array();
2955
+		if ($one_of_each_key) {
2956
+			$extra_meta_objs = $this->get_many_related(
2957
+				'Extra_Meta',
2958
+				array('group_by' => 'EXM_key')
2959
+			);
2960
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2961
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
+					$return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2963
+				}
2964
+			}
2965
+		} else {
2966
+			$extra_meta_objs = $this->get_many_related('Extra_Meta');
2967
+			foreach ($extra_meta_objs as $extra_meta_obj) {
2968
+				if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
+					if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
+						$return_array[ $extra_meta_obj->key() ] = array();
2971
+					}
2972
+					$return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2973
+				}
2974
+			}
2975
+		}
2976
+		return $return_array;
2977
+	}
2978
+
2979
+
2980
+	/**
2981
+	 * Gets a pretty nice displayable nice for this model object. Often overridden
2982
+	 *
2983
+	 * @return string
2984
+	 * @throws ReflectionException
2985
+	 * @throws InvalidArgumentException
2986
+	 * @throws InvalidInterfaceException
2987
+	 * @throws InvalidDataTypeException
2988
+	 * @throws EE_Error
2989
+	 */
2990
+	public function name()
2991
+	{
2992
+		//find a field that's not a text field
2993
+		$field_we_can_use = $this->get_model()->get_a_field_of_type('EE_Text_Field_Base');
2994
+		if ($field_we_can_use) {
2995
+			return $this->get($field_we_can_use->get_name());
2996
+		}
2997
+		$first_few_properties = $this->model_field_array();
2998
+		$first_few_properties = array_slice($first_few_properties, 0, 3);
2999
+		$name_parts           = array();
3000
+		foreach ($first_few_properties as $name => $value) {
3001
+			$name_parts[] = "$name:$value";
3002
+		}
3003
+		return implode(',', $name_parts);
3004
+	}
3005
+
3006
+
3007
+	/**
3008
+	 * in_entity_map
3009
+	 * Checks if this model object has been proven to already be in the entity map
3010
+	 *
3011
+	 * @return boolean
3012
+	 * @throws ReflectionException
3013
+	 * @throws InvalidArgumentException
3014
+	 * @throws InvalidInterfaceException
3015
+	 * @throws InvalidDataTypeException
3016
+	 * @throws EE_Error
3017
+	 */
3018
+	public function in_entity_map()
3019
+	{
3020
+		// well, if we looked, did we find it in the entity map?
3021
+		return $this->ID() && $this->get_model()->get_from_entity_map($this->ID()) === $this;
3022
+	}
3023
+
3024
+
3025
+	/**
3026
+	 * refresh_from_db
3027
+	 * Makes sure the fields and values on this model object are in-sync with what's in the database.
3028
+	 *
3029
+	 * @throws ReflectionException
3030
+	 * @throws InvalidArgumentException
3031
+	 * @throws InvalidInterfaceException
3032
+	 * @throws InvalidDataTypeException
3033
+	 * @throws EE_Error if this model object isn't in the entity mapper (because then you should
3034
+	 * just use what's in the entity mapper and refresh it) and WP_DEBUG is TRUE
3035
+	 */
3036
+	public function refresh_from_db()
3037
+	{
3038
+		if ($this->ID() && $this->in_entity_map()) {
3039
+			$this->get_model()->refresh_entity_map_from_db($this->ID());
3040
+		} else {
3041
+			//if it doesn't have ID, you shouldn't be asking to refresh it from teh database (because its not in the database)
3042
+			//if it has an ID but it's not in the map, and you're asking me to refresh it
3043
+			//that's kinda dangerous. You should just use what's in the entity map, or add this to the entity map if there's
3044
+			//absolutely nothing in it for this ID
3045
+			if (WP_DEBUG) {
3046
+				throw new EE_Error(
3047
+					sprintf(
3048
+						esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3049
+							'event_espresso'),
3050
+						$this->ID(),
3051
+						get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
+						get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3053
+					)
3054
+				);
3055
+			}
3056
+		}
3057
+	}
3058
+
3059
+
3060
+	/**
3061
+	 * Because some other plugins, like Advanced Cron Manager, expect all objects to have this method
3062
+	 * (probably a bad assumption they have made, oh well)
3063
+	 *
3064
+	 * @return string
3065
+	 */
3066
+	public function __toString()
3067
+	{
3068
+		try {
3069
+			return sprintf('%s (%s)', $this->name(), $this->ID());
3070
+		} catch (Exception $e) {
3071
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
3072
+			return '';
3073
+		}
3074
+	}
3075
+
3076
+
3077
+	/**
3078
+	 * Clear related model objects if they're already in the DB, because otherwise when we
3079
+	 * UN-serialize this model object we'll need to be careful to add them to the entity map.
3080
+	 * This means if we have made changes to those related model objects, and want to unserialize
3081
+	 * the this model object on a subsequent request, changes to those related model objects will be lost.
3082
+	 * Instead, those related model objects should be directly serialized and stored.
3083
+	 * Eg, the following won't work:
3084
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3085
+	 * $att = $reg->attendee();
3086
+	 * $att->set( 'ATT_fname', 'Dirk' );
3087
+	 * update_option( 'my_option', serialize( $reg ) );
3088
+	 * //END REQUEST
3089
+	 * //START NEXT REQUEST
3090
+	 * $reg = get_option( 'my_option' );
3091
+	 * $reg->attendee()->save();
3092
+	 * And would need to be replace with:
3093
+	 * $reg = EEM_Registration::instance()->get_one_by_ID( 123 );
3094
+	 * $att = $reg->attendee();
3095
+	 * $att->set( 'ATT_fname', 'Dirk' );
3096
+	 * update_option( 'my_option', serialize( $reg ) );
3097
+	 * //END REQUEST
3098
+	 * //START NEXT REQUEST
3099
+	 * $att = get_option( 'my_option' );
3100
+	 * $att->save();
3101
+	 *
3102
+	 * @return array
3103
+	 * @throws ReflectionException
3104
+	 * @throws InvalidArgumentException
3105
+	 * @throws InvalidInterfaceException
3106
+	 * @throws InvalidDataTypeException
3107
+	 * @throws EE_Error
3108
+	 */
3109
+	public function __sleep()
3110
+	{
3111
+		$model = $this->get_model();
3112
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113
+			if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
+				$classname = 'EE_' . $model->get_this_model_name();
3115
+				if (
3116
+					$this->get_one_from_cache($relation_name) instanceof $classname
3117
+					&& $this->get_one_from_cache($relation_name)->ID()
3118
+				) {
3119
+					$this->clear_cache(
3120
+						$relation_name,
3121
+						$this->get_one_from_cache($relation_name)->ID()
3122
+					);
3123
+				}
3124
+			}
3125
+		}
3126
+		$this->_props_n_values_provided_in_constructor = array();
3127
+		$properties_to_serialize                       = get_object_vars($this);
3128
+		//don't serialize the model. It's big and that risks recursion
3129
+		unset($properties_to_serialize['_model']);
3130
+		return array_keys($properties_to_serialize);
3131
+	}
3132
+
3133
+
3134
+	/**
3135
+	 * restore _props_n_values_provided_in_constructor
3136
+	 * PLZ NOTE: this will reset the array to whatever fields values were present prior to serialization,
3137
+	 * and therefore should NOT be used to determine if state change has occurred since initial construction.
3138
+	 * At best, you would only be able to detect if state change has occurred during THIS request.
3139
+	 */
3140
+	public function __wakeup()
3141
+	{
3142
+		$this->_props_n_values_provided_in_constructor = $this->_fields;
3143
+	}
3144
+
3145
+
3146
+	/**
3147
+	 * Usage of this magic method is to ensure any internally cached references to object instances that must remain
3148
+	 * distinct with the clone host instance are also cloned.
3149
+	 */
3150
+	public function __clone()
3151
+	{
3152
+		//handle DateTimes (this is handled in here because there's no one specific child class that uses datetimes).
3153
+		foreach ($this->_fields as $field => $value) {
3154
+			if ($value instanceof DateTime) {
3155
+				$this->_fields[$field] = clone $value;
3156
+			}
3157
+		}
3158
+	}
3159 3159
 }
3160 3160
 
3161 3161
 
Please login to merge, or discard this patch.
Spacing   +116 added lines, -116 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
         $fieldValues = is_array($fieldValues) ? $fieldValues : array($fieldValues);
149 149
         // verify client code has not passed any invalid field names
150 150
         foreach ($fieldValues as $field_name => $field_value) {
151
-            if (! isset($model_fields[ $field_name ])) {
151
+            if ( ! isset($model_fields[$field_name])) {
152 152
                 throw new EE_Error(
153 153
                     sprintf(
154 154
                         esc_html__(
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
             }
164 164
         }
165 165
         $this->_timezone = EEH_DTT_Helper::get_valid_timezone_string($timezone);
166
-        if (! empty($date_formats) && is_array($date_formats)) {
166
+        if ( ! empty($date_formats) && is_array($date_formats)) {
167 167
             list($this->_dt_frmt, $this->_tm_frmt) = $date_formats;
168 168
         } else {
169 169
             //set default formats for date and time
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
             foreach ($model_fields as $fieldName => $field) {
177 177
                 $this->set_from_db(
178 178
                     $fieldName,
179
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null
179
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null
180 180
                 );
181 181
             }
182 182
         } else {
@@ -185,22 +185,22 @@  discard block
 block discarded – undo
185 185
             foreach ($model_fields as $fieldName => $field) {
186 186
                 $this->set(
187 187
                     $fieldName,
188
-                    isset($fieldValues[ $fieldName ]) ? $fieldValues[ $fieldName ] : null, true
188
+                    isset($fieldValues[$fieldName]) ? $fieldValues[$fieldName] : null, true
189 189
                 );
190 190
             }
191 191
         }
192 192
         //remember what values were passed to this constructor
193 193
         $this->_props_n_values_provided_in_constructor = $fieldValues;
194 194
         //remember in entity mapper
195
-        if (! $bydb && $model->has_primary_key_field() && $this->ID()) {
195
+        if ( ! $bydb && $model->has_primary_key_field() && $this->ID()) {
196 196
             $model->add_to_entity_map($this);
197 197
         }
198 198
         //setup all the relations
199 199
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
200 200
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
201
-                $this->_model_relations[ $relation_name ] = null;
201
+                $this->_model_relations[$relation_name] = null;
202 202
             } else {
203
-                $this->_model_relations[ $relation_name ] = array();
203
+                $this->_model_relations[$relation_name] = array();
204 204
             }
205 205
         }
206 206
         /**
@@ -251,10 +251,10 @@  discard block
 block discarded – undo
251 251
      */
252 252
     public function get_original($field_name)
253 253
     {
254
-        if (isset($this->_props_n_values_provided_in_constructor[ $field_name ])
254
+        if (isset($this->_props_n_values_provided_in_constructor[$field_name])
255 255
             && $field_settings = $this->get_model()->field_settings_for($field_name)
256 256
         ) {
257
-            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[ $field_name ]);
257
+            return $field_settings->prepare_for_get($this->_props_n_values_provided_in_constructor[$field_name]);
258 258
         }
259 259
         return null;
260 260
     }
@@ -291,7 +291,7 @@  discard block
 block discarded – undo
291 291
         // then don't do anything
292 292
         if (
293 293
             ! $use_default
294
-            && $this->_fields[ $field_name ] === $field_value
294
+            && $this->_fields[$field_name] === $field_value
295 295
             && $this->ID()
296 296
         ) {
297 297
             return;
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
             $holder_of_value = $field_obj->prepare_for_set($field_value);
310 310
             //should the value be null?
311 311
             if (($field_value === null || $holder_of_value === null || $holder_of_value === '') && $use_default) {
312
-                $this->_fields[ $field_name ] = $field_obj->get_default_value();
312
+                $this->_fields[$field_name] = $field_obj->get_default_value();
313 313
                 /**
314 314
                  * To save having to refactor all the models, if a default value is used for a
315 315
                  * EE_Datetime_Field, and that value is not null nor is it a DateTime
@@ -320,15 +320,15 @@  discard block
 block discarded – undo
320 320
                  */
321 321
                 if (
322 322
                     $field_obj instanceof EE_Datetime_Field
323
-                    && $this->_fields[ $field_name ] !== null
324
-                    && ! $this->_fields[ $field_name ] instanceof DateTime
323
+                    && $this->_fields[$field_name] !== null
324
+                    && ! $this->_fields[$field_name] instanceof DateTime
325 325
                 ) {
326
-                    empty($this->_fields[ $field_name ])
326
+                    empty($this->_fields[$field_name])
327 327
                         ? $this->set($field_name, time())
328
-                        : $this->set($field_name, $this->_fields[ $field_name ]);
328
+                        : $this->set($field_name, $this->_fields[$field_name]);
329 329
                 }
330 330
             } else {
331
-                $this->_fields[ $field_name ] = $holder_of_value;
331
+                $this->_fields[$field_name] = $holder_of_value;
332 332
             }
333 333
             //if we're not in the constructor...
334 334
             //now check if what we set was a primary key
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
                 $fields_on_model = self::_get_model(get_class($this))->field_settings();
346 346
                 $obj_in_db       = self::_get_model(get_class($this))->get_one_by_ID($field_value);
347 347
                 foreach ($fields_on_model as $field_obj) {
348
-                    if (! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
348
+                    if ( ! array_key_exists($field_obj->get_name(), $this->_props_n_values_provided_in_constructor)
349 349
                         && $field_obj->get_name() !== $field_name
350 350
                     ) {
351 351
                         $this->set($field_obj->get_name(), $obj_in_db->get($field_obj->get_name()));
@@ -390,8 +390,8 @@  discard block
 block discarded – undo
390 390
      */
391 391
     public function getCustomSelect($alias)
392 392
     {
393
-        return isset($this->custom_selection_results[ $alias ])
394
-            ? $this->custom_selection_results[ $alias ]
393
+        return isset($this->custom_selection_results[$alias])
394
+            ? $this->custom_selection_results[$alias]
395 395
             : null;
396 396
     }
397 397
 
@@ -478,8 +478,8 @@  discard block
 block discarded – undo
478 478
         foreach ($model_fields as $field_name => $field_obj) {
479 479
             if ($field_obj instanceof EE_Datetime_Field) {
480 480
                 $field_obj->set_timezone($this->_timezone);
481
-                if (isset($this->_fields[ $field_name ]) && $this->_fields[ $field_name ] instanceof DateTime) {
482
-                    $this->_fields[ $field_name ]->setTimezone(new DateTimeZone($this->_timezone));
481
+                if (isset($this->_fields[$field_name]) && $this->_fields[$field_name] instanceof DateTime) {
482
+                    $this->_fields[$field_name]->setTimezone(new DateTimeZone($this->_timezone));
483 483
                 }
484 484
             }
485 485
         }
@@ -537,7 +537,7 @@  discard block
 block discarded – undo
537 537
      */
538 538
     public function get_format($full = true)
539 539
     {
540
-        return $full ? $this->_dt_frmt . ' ' . $this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
540
+        return $full ? $this->_dt_frmt.' '.$this->_tm_frmt : array($this->_dt_frmt, $this->_tm_frmt);
541 541
     }
542 542
 
543 543
 
@@ -563,11 +563,11 @@  discard block
 block discarded – undo
563 563
     public function cache($relationName = '', $object_to_cache = null, $cache_id = null)
564 564
     {
565 565
         // its entirely possible that there IS no related object yet in which case there is nothing to cache.
566
-        if (! $object_to_cache instanceof EE_Base_Class) {
566
+        if ( ! $object_to_cache instanceof EE_Base_Class) {
567 567
             return false;
568 568
         }
569 569
         // also get "how" the object is related, or throw an error
570
-        if (! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
570
+        if ( ! $relationship_to_model = $this->get_model()->related_settings_for($relationName)) {
571 571
             throw new EE_Error(
572 572
                 sprintf(
573 573
                     esc_html__('There is no relationship to %s on a %s. Cannot cache it', 'event_espresso'),
@@ -581,38 +581,38 @@  discard block
 block discarded – undo
581 581
             // if it's a "belongs to" relationship, then there's only one related model object
582 582
             // eg, if this is a registration, there's only 1 attendee for it
583 583
             // so for these model objects just set it to be cached
584
-            $this->_model_relations[ $relationName ] = $object_to_cache;
584
+            $this->_model_relations[$relationName] = $object_to_cache;
585 585
             $return                                  = true;
586 586
         } else {
587 587
             // otherwise, this is the "many" side of a one to many relationship,
588 588
             // so we'll add the object to the array of related objects for that type.
589 589
             // eg: if this is an event, there are many registrations for that event,
590 590
             // so we cache the registrations in an array
591
-            if (! is_array($this->_model_relations[ $relationName ])) {
591
+            if ( ! is_array($this->_model_relations[$relationName])) {
592 592
                 // if for some reason, the cached item is a model object,
593 593
                 // then stick that in the array, otherwise start with an empty array
594
-                $this->_model_relations[ $relationName ] = $this->_model_relations[ $relationName ]
594
+                $this->_model_relations[$relationName] = $this->_model_relations[$relationName]
595 595
                                                            instanceof
596 596
                                                            EE_Base_Class
597
-                    ? array($this->_model_relations[ $relationName ]) : array();
597
+                    ? array($this->_model_relations[$relationName]) : array();
598 598
             }
599 599
             // first check for a cache_id which is normally empty
600
-            if (! empty($cache_id)) {
600
+            if ( ! empty($cache_id)) {
601 601
                 // if the cache_id exists, then it means we are purposely trying to cache this
602 602
                 // with a known key that can then be used to retrieve the object later on
603
-                $this->_model_relations[ $relationName ][ $cache_id ] = $object_to_cache;
603
+                $this->_model_relations[$relationName][$cache_id] = $object_to_cache;
604 604
                 $return                                               = $cache_id;
605 605
             } elseif ($object_to_cache->ID()) {
606 606
                 // OR the cached object originally came from the db, so let's just use it's PK for an ID
607
-                $this->_model_relations[ $relationName ][ $object_to_cache->ID() ] = $object_to_cache;
607
+                $this->_model_relations[$relationName][$object_to_cache->ID()] = $object_to_cache;
608 608
                 $return                                                            = $object_to_cache->ID();
609 609
             } else {
610 610
                 // OR it's a new object with no ID, so just throw it in the array with an auto-incremented ID
611
-                $this->_model_relations[ $relationName ][] = $object_to_cache;
611
+                $this->_model_relations[$relationName][] = $object_to_cache;
612 612
                 // move the internal pointer to the end of the array
613
-                end($this->_model_relations[ $relationName ]);
613
+                end($this->_model_relations[$relationName]);
614 614
                 // and grab the key so that we can return it
615
-                $return = key($this->_model_relations[ $relationName ]);
615
+                $return = key($this->_model_relations[$relationName]);
616 616
             }
617 617
         }
618 618
         return $return;
@@ -638,7 +638,7 @@  discard block
 block discarded – undo
638 638
         //first make sure this property exists
639 639
         $this->get_model()->field_settings_for($fieldname);
640 640
         $cache_type                                            = empty($cache_type) ? 'standard' : $cache_type;
641
-        $this->_cached_properties[ $fieldname ][ $cache_type ] = $value;
641
+        $this->_cached_properties[$fieldname][$cache_type] = $value;
642 642
     }
643 643
 
644 644
 
@@ -667,9 +667,9 @@  discard block
 block discarded – undo
667 667
         $model = $this->get_model();
668 668
         $model->field_settings_for($fieldname);
669 669
         $cache_type = $pretty ? 'pretty' : 'standard';
670
-        $cache_type .= ! empty($extra_cache_ref) ? '_' . $extra_cache_ref : '';
671
-        if (isset($this->_cached_properties[ $fieldname ][ $cache_type ])) {
672
-            return $this->_cached_properties[ $fieldname ][ $cache_type ];
670
+        $cache_type .= ! empty($extra_cache_ref) ? '_'.$extra_cache_ref : '';
671
+        if (isset($this->_cached_properties[$fieldname][$cache_type])) {
672
+            return $this->_cached_properties[$fieldname][$cache_type];
673 673
         }
674 674
         $value = $this->_get_fresh_property($fieldname, $pretty, $extra_cache_ref);
675 675
         $this->_set_cached_property($fieldname, $value, $cache_type);
@@ -697,12 +697,12 @@  discard block
 block discarded – undo
697 697
         if ($field_obj instanceof EE_Datetime_Field) {
698 698
             $this->_prepare_datetime_field($field_obj, $pretty, $extra_cache_ref);
699 699
         }
700
-        if (! isset($this->_fields[ $fieldname ])) {
701
-            $this->_fields[ $fieldname ] = null;
700
+        if ( ! isset($this->_fields[$fieldname])) {
701
+            $this->_fields[$fieldname] = null;
702 702
         }
703 703
         $value = $pretty
704
-            ? $field_obj->prepare_for_pretty_echoing($this->_fields[ $fieldname ], $extra_cache_ref)
705
-            : $field_obj->prepare_for_get($this->_fields[ $fieldname ]);
704
+            ? $field_obj->prepare_for_pretty_echoing($this->_fields[$fieldname], $extra_cache_ref)
705
+            : $field_obj->prepare_for_get($this->_fields[$fieldname]);
706 706
         return $value;
707 707
     }
708 708
 
@@ -760,8 +760,8 @@  discard block
 block discarded – undo
760 760
      */
761 761
     protected function _clear_cached_property($property_name)
762 762
     {
763
-        if (isset($this->_cached_properties[ $property_name ])) {
764
-            unset($this->_cached_properties[ $property_name ]);
763
+        if (isset($this->_cached_properties[$property_name])) {
764
+            unset($this->_cached_properties[$property_name]);
765 765
         }
766 766
     }
767 767
 
@@ -813,7 +813,7 @@  discard block
 block discarded – undo
813 813
     {
814 814
         $relationship_to_model = $this->get_model()->related_settings_for($relationName);
815 815
         $index_in_cache        = '';
816
-        if (! $relationship_to_model) {
816
+        if ( ! $relationship_to_model) {
817 817
             throw new EE_Error(
818 818
                 sprintf(
819 819
                     esc_html__('There is no relationship to %s on a %s. Cannot clear that cache', 'event_espresso'),
@@ -824,21 +824,21 @@  discard block
 block discarded – undo
824 824
         }
825 825
         if ($clear_all) {
826 826
             $obj_removed                             = true;
827
-            $this->_model_relations[ $relationName ] = null;
827
+            $this->_model_relations[$relationName] = null;
828 828
         } elseif ($relationship_to_model instanceof EE_Belongs_To_Relation) {
829
-            $obj_removed                             = $this->_model_relations[ $relationName ];
830
-            $this->_model_relations[ $relationName ] = null;
829
+            $obj_removed                             = $this->_model_relations[$relationName];
830
+            $this->_model_relations[$relationName] = null;
831 831
         } else {
832 832
             if ($object_to_remove_or_index_into_array instanceof EE_Base_Class
833 833
                 && $object_to_remove_or_index_into_array->ID()
834 834
             ) {
835 835
                 $index_in_cache = $object_to_remove_or_index_into_array->ID();
836
-                if (is_array($this->_model_relations[ $relationName ])
837
-                    && ! isset($this->_model_relations[ $relationName ][ $index_in_cache ])
836
+                if (is_array($this->_model_relations[$relationName])
837
+                    && ! isset($this->_model_relations[$relationName][$index_in_cache])
838 838
                 ) {
839 839
                     $index_found_at = null;
840 840
                     //find this object in the array even though it has a different key
841
-                    foreach ($this->_model_relations[ $relationName ] as $index => $obj) {
841
+                    foreach ($this->_model_relations[$relationName] as $index => $obj) {
842 842
                         /** @noinspection TypeUnsafeComparisonInspection */
843 843
                         if (
844 844
                             $obj instanceof EE_Base_Class
@@ -872,9 +872,9 @@  discard block
 block discarded – undo
872 872
             }
873 873
             //supposedly we've found it. But it could just be that the client code
874 874
             //provided a bad index/object
875
-            if (isset($this->_model_relations[ $relationName ][ $index_in_cache ])) {
876
-                $obj_removed = $this->_model_relations[ $relationName ][ $index_in_cache ];
877
-                unset($this->_model_relations[ $relationName ][ $index_in_cache ]);
875
+            if (isset($this->_model_relations[$relationName][$index_in_cache])) {
876
+                $obj_removed = $this->_model_relations[$relationName][$index_in_cache];
877
+                unset($this->_model_relations[$relationName][$index_in_cache]);
878 878
             } else {
879 879
                 //that thing was never cached anyways.
880 880
                 $obj_removed = null;
@@ -905,7 +905,7 @@  discard block
 block discarded – undo
905 905
         $current_cache_id = ''
906 906
     ) {
907 907
         // verify that incoming object is of the correct type
908
-        $obj_class = 'EE_' . $relationName;
908
+        $obj_class = 'EE_'.$relationName;
909 909
         if ($newly_saved_object instanceof $obj_class) {
910 910
             /* @type EE_Base_Class $newly_saved_object */
911 911
             // now get the type of relation
@@ -913,17 +913,17 @@  discard block
 block discarded – undo
913 913
             // if this is a 1:1 relationship
914 914
             if ($relationship_to_model instanceof EE_Belongs_To_Relation) {
915 915
                 // then just replace the cached object with the newly saved object
916
-                $this->_model_relations[ $relationName ] = $newly_saved_object;
916
+                $this->_model_relations[$relationName] = $newly_saved_object;
917 917
                 return true;
918 918
                 // or if it's some kind of sordid feral polyamorous relationship...
919 919
             }
920
-            if (is_array($this->_model_relations[ $relationName ])
921
-                      && isset($this->_model_relations[ $relationName ][ $current_cache_id ])
920
+            if (is_array($this->_model_relations[$relationName])
921
+                      && isset($this->_model_relations[$relationName][$current_cache_id])
922 922
             ) {
923 923
                 // then remove the current cached item
924
-                unset($this->_model_relations[ $relationName ][ $current_cache_id ]);
924
+                unset($this->_model_relations[$relationName][$current_cache_id]);
925 925
                 // and cache the newly saved object using it's new ID
926
-                $this->_model_relations[ $relationName ][ $newly_saved_object->ID() ] = $newly_saved_object;
926
+                $this->_model_relations[$relationName][$newly_saved_object->ID()] = $newly_saved_object;
927 927
                 return true;
928 928
             }
929 929
         }
@@ -940,8 +940,8 @@  discard block
 block discarded – undo
940 940
      */
941 941
     public function get_one_from_cache($relationName)
942 942
     {
943
-        $cached_array_or_object = isset($this->_model_relations[ $relationName ])
944
-            ? $this->_model_relations[ $relationName ]
943
+        $cached_array_or_object = isset($this->_model_relations[$relationName])
944
+            ? $this->_model_relations[$relationName]
945 945
             : null;
946 946
         if (is_array($cached_array_or_object)) {
947 947
             return array_shift($cached_array_or_object);
@@ -964,7 +964,7 @@  discard block
 block discarded – undo
964 964
      */
965 965
     public function get_all_from_cache($relationName)
966 966
     {
967
-        $objects = isset($this->_model_relations[ $relationName ]) ? $this->_model_relations[ $relationName ] : array();
967
+        $objects = isset($this->_model_relations[$relationName]) ? $this->_model_relations[$relationName] : array();
968 968
         // if the result is not an array, but exists, make it an array
969 969
         $objects = is_array($objects) ? $objects : array($objects);
970 970
         //bugfix for https://events.codebasehq.com/projects/event-espresso/tickets/7143
@@ -1148,7 +1148,7 @@  discard block
 block discarded – undo
1148 1148
             } else {
1149 1149
                 $field_value = $field_obj->prepare_for_set_from_db($field_value_from_db);
1150 1150
             }
1151
-            $this->_fields[ $field_name ] = $field_value;
1151
+            $this->_fields[$field_name] = $field_value;
1152 1152
             $this->_clear_cached_property($field_name);
1153 1153
         }
1154 1154
     }
@@ -1188,9 +1188,9 @@  discard block
 block discarded – undo
1188 1188
     public function get_raw($field_name)
1189 1189
     {
1190 1190
         $field_settings = $this->get_model()->field_settings_for($field_name);
1191
-        return $field_settings instanceof EE_Datetime_Field && $this->_fields[ $field_name ] instanceof DateTime
1192
-            ? $this->_fields[ $field_name ]->format('U')
1193
-            : $this->_fields[ $field_name ];
1191
+        return $field_settings instanceof EE_Datetime_Field && $this->_fields[$field_name] instanceof DateTime
1192
+            ? $this->_fields[$field_name]->format('U')
1193
+            : $this->_fields[$field_name];
1194 1194
     }
1195 1195
 
1196 1196
 
@@ -1212,7 +1212,7 @@  discard block
 block discarded – undo
1212 1212
     public function get_DateTime_object($field_name)
1213 1213
     {
1214 1214
         $field_settings = $this->get_model()->field_settings_for($field_name);
1215
-        if (! $field_settings instanceof EE_Datetime_Field) {
1215
+        if ( ! $field_settings instanceof EE_Datetime_Field) {
1216 1216
             EE_Error::add_error(
1217 1217
                 sprintf(
1218 1218
                     esc_html__(
@@ -1470,7 +1470,7 @@  discard block
 block discarded – undo
1470 1470
      */
1471 1471
     public function get_i18n_datetime($field_name, $format = '')
1472 1472
     {
1473
-        $format = empty($format) ? $this->_dt_frmt . ' ' . $this->_tm_frmt : $format;
1473
+        $format = empty($format) ? $this->_dt_frmt.' '.$this->_tm_frmt : $format;
1474 1474
         return date_i18n(
1475 1475
             $format,
1476 1476
             EEH_DTT_Helper::get_timestamp_with_offset(
@@ -1582,19 +1582,19 @@  discard block
 block discarded – undo
1582 1582
         $field->set_time_format($this->_tm_frmt);
1583 1583
         switch ($what) {
1584 1584
             case 'T' :
1585
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_time(
1585
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_time(
1586 1586
                     $datetime_value,
1587
-                    $this->_fields[ $fieldname ]
1587
+                    $this->_fields[$fieldname]
1588 1588
                 );
1589 1589
                 break;
1590 1590
             case 'D' :
1591
-                $this->_fields[ $fieldname ] = $field->prepare_for_set_with_new_date(
1591
+                $this->_fields[$fieldname] = $field->prepare_for_set_with_new_date(
1592 1592
                     $datetime_value,
1593
-                    $this->_fields[ $fieldname ]
1593
+                    $this->_fields[$fieldname]
1594 1594
                 );
1595 1595
                 break;
1596 1596
             case 'B' :
1597
-                $this->_fields[ $fieldname ] = $field->prepare_for_set($datetime_value);
1597
+                $this->_fields[$fieldname] = $field->prepare_for_set($datetime_value);
1598 1598
                 break;
1599 1599
         }
1600 1600
         $this->_clear_cached_property($fieldname);
@@ -1636,7 +1636,7 @@  discard block
 block discarded – undo
1636 1636
         $this->set_timezone($timezone);
1637 1637
         $fn   = (array) $field_name;
1638 1638
         $args = array_merge($fn, (array) $args);
1639
-        if (! method_exists($this, $callback)) {
1639
+        if ( ! method_exists($this, $callback)) {
1640 1640
             throw new EE_Error(
1641 1641
                 sprintf(
1642 1642
                     esc_html__(
@@ -1648,7 +1648,7 @@  discard block
 block discarded – undo
1648 1648
             );
1649 1649
         }
1650 1650
         $args   = (array) $args;
1651
-        $return = $prepend . call_user_func_array(array($this, $callback), $args) . $append;
1651
+        $return = $prepend.call_user_func_array(array($this, $callback), $args).$append;
1652 1652
         $this->set_timezone($original_timezone);
1653 1653
         return $return;
1654 1654
     }
@@ -1763,8 +1763,8 @@  discard block
 block discarded – undo
1763 1763
     {
1764 1764
         $model = $this->get_model();
1765 1765
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
1766
-            if (! empty($this->_model_relations[ $relation_name ])) {
1767
-                $related_objects = $this->_model_relations[ $relation_name ];
1766
+            if ( ! empty($this->_model_relations[$relation_name])) {
1767
+                $related_objects = $this->_model_relations[$relation_name];
1768 1768
                 if ($relation_obj instanceof EE_Belongs_To_Relation) {
1769 1769
                     //this relation only stores a single model object, not an array
1770 1770
                     //but let's make it consistent
@@ -1821,7 +1821,7 @@  discard block
 block discarded – undo
1821 1821
             $this->set($column, $value);
1822 1822
         }
1823 1823
         // no changes ? then don't do anything
1824
-        if (! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1824
+        if ( ! $this->_has_changes && $this->ID() && $model->get_primary_key_field()->is_auto_increment()) {
1825 1825
             return 0;
1826 1826
         }
1827 1827
         /**
@@ -1831,7 +1831,7 @@  discard block
 block discarded – undo
1831 1831
          * @param EE_Base_Class $model_object the model object about to be saved.
1832 1832
          */
1833 1833
         do_action('AHEE__EE_Base_Class__save__begin', $this);
1834
-        if (! $this->allow_persist()) {
1834
+        if ( ! $this->allow_persist()) {
1835 1835
             return 0;
1836 1836
         }
1837 1837
         // now get current attribute values
@@ -1846,10 +1846,10 @@  discard block
 block discarded – undo
1846 1846
         if ($model->has_primary_key_field()) {
1847 1847
             if ($model->get_primary_key_field()->is_auto_increment()) {
1848 1848
                 //ok check if it's set, if so: update; if not, insert
1849
-                if (! empty($save_cols_n_values[ $model->primary_key_name() ])) {
1849
+                if ( ! empty($save_cols_n_values[$model->primary_key_name()])) {
1850 1850
                     $results = $model->update_by_ID($save_cols_n_values, $this->ID());
1851 1851
                 } else {
1852
-                    unset($save_cols_n_values[ $model->primary_key_name() ]);
1852
+                    unset($save_cols_n_values[$model->primary_key_name()]);
1853 1853
                     $results = $model->insert($save_cols_n_values);
1854 1854
                     if ($results) {
1855 1855
                         //if successful, set the primary key
@@ -1859,7 +1859,7 @@  discard block
 block discarded – undo
1859 1859
                         //will get added to the mapper before we can add this one!
1860 1860
                         //but if we just avoid using the SET method, all that headache can be avoided
1861 1861
                         $pk_field_name                   = $model->primary_key_name();
1862
-                        $this->_fields[ $pk_field_name ] = $results;
1862
+                        $this->_fields[$pk_field_name] = $results;
1863 1863
                         $this->_clear_cached_property($pk_field_name);
1864 1864
                         $model->add_to_entity_map($this);
1865 1865
                         $this->_update_cached_related_model_objs_fks();
@@ -1876,8 +1876,8 @@  discard block
 block discarded – undo
1876 1876
                                     'event_espresso'
1877 1877
                                 ),
1878 1878
                                 get_class($this),
1879
-                                get_class($model) . '::instance()->add_to_entity_map()',
1880
-                                get_class($model) . '::instance()->get_one_by_ID()',
1879
+                                get_class($model).'::instance()->add_to_entity_map()',
1880
+                                get_class($model).'::instance()->get_one_by_ID()',
1881 1881
                                 '<br />'
1882 1882
                             )
1883 1883
                         );
@@ -1977,27 +1977,27 @@  discard block
 block discarded – undo
1977 1977
     public function save_new_cached_related_model_objs()
1978 1978
     {
1979 1979
         //make sure this has been saved
1980
-        if (! $this->ID()) {
1980
+        if ( ! $this->ID()) {
1981 1981
             $id = $this->save();
1982 1982
         } else {
1983 1983
             $id = $this->ID();
1984 1984
         }
1985 1985
         //now save all the NEW cached model objects  (ie they don't exist in the DB)
1986 1986
         foreach ($this->get_model()->relation_settings() as $relationName => $relationObj) {
1987
-            if ($this->_model_relations[ $relationName ]) {
1987
+            if ($this->_model_relations[$relationName]) {
1988 1988
                 //is this a relation where we should expect just ONE related object (ie, EE_Belongs_To_relation)
1989 1989
                 //or MANY related objects (ie, EE_HABTM_Relation or EE_Has_Many_Relation)?
1990 1990
                 /* @var $related_model_obj EE_Base_Class */
1991 1991
                 if ($relationObj instanceof EE_Belongs_To_Relation) {
1992 1992
                     //add a relation to that relation type (which saves the appropriate thing in the process)
1993 1993
                     //but ONLY if it DOES NOT exist in the DB
1994
-                    $related_model_obj = $this->_model_relations[ $relationName ];
1994
+                    $related_model_obj = $this->_model_relations[$relationName];
1995 1995
                     //					if( ! $related_model_obj->ID()){
1996 1996
                     $this->_add_relation_to($related_model_obj, $relationName);
1997 1997
                     $related_model_obj->save_new_cached_related_model_objs();
1998 1998
                     //					}
1999 1999
                 } else {
2000
-                    foreach ($this->_model_relations[ $relationName ] as $related_model_obj) {
2000
+                    foreach ($this->_model_relations[$relationName] as $related_model_obj) {
2001 2001
                         //add a relation to that relation type (which saves the appropriate thing in the process)
2002 2002
                         //but ONLY if it DOES NOT exist in the DB
2003 2003
                         //						if( ! $related_model_obj->ID()){
@@ -2024,7 +2024,7 @@  discard block
 block discarded – undo
2024 2024
      */
2025 2025
     public function get_model()
2026 2026
     {
2027
-        if (! $this->_model) {
2027
+        if ( ! $this->_model) {
2028 2028
             $modelName    = self::_get_model_classname(get_class($this));
2029 2029
             $this->_model = self::_get_model_instance_with_name($modelName, $this->_timezone);
2030 2030
         } else {
@@ -2050,9 +2050,9 @@  discard block
 block discarded – undo
2050 2050
         $primary_id_ref = self::_get_primary_key_name($classname);
2051 2051
         if (
2052 2052
             array_key_exists($primary_id_ref, $props_n_values)
2053
-            && ! empty($props_n_values[ $primary_id_ref ])
2053
+            && ! empty($props_n_values[$primary_id_ref])
2054 2054
         ) {
2055
-            $id = $props_n_values[ $primary_id_ref ];
2055
+            $id = $props_n_values[$primary_id_ref];
2056 2056
             return self::_get_model($classname)->get_from_entity_map($id);
2057 2057
         }
2058 2058
         return false;
@@ -2086,10 +2086,10 @@  discard block
 block discarded – undo
2086 2086
         if ($model->has_primary_key_field()) {
2087 2087
             $primary_id_ref = self::_get_primary_key_name($classname);
2088 2088
             if (array_key_exists($primary_id_ref, $props_n_values)
2089
-                && ! empty($props_n_values[ $primary_id_ref ])
2089
+                && ! empty($props_n_values[$primary_id_ref])
2090 2090
             ) {
2091 2091
                 $existing = $model->get_one_by_ID(
2092
-                    $props_n_values[ $primary_id_ref ]
2092
+                    $props_n_values[$primary_id_ref]
2093 2093
                 );
2094 2094
             }
2095 2095
         } elseif ($model->has_all_combined_primary_key_fields($props_n_values)) {
@@ -2101,7 +2101,7 @@  discard block
 block discarded – undo
2101 2101
         }
2102 2102
         if ($existing) {
2103 2103
             //set date formats if present before setting values
2104
-            if (! empty($date_formats) && is_array($date_formats)) {
2104
+            if ( ! empty($date_formats) && is_array($date_formats)) {
2105 2105
                 $existing->set_date_format($date_formats[0]);
2106 2106
                 $existing->set_time_format($date_formats[1]);
2107 2107
             } else {
@@ -2134,7 +2134,7 @@  discard block
 block discarded – undo
2134 2134
     protected static function _get_model($classname, $timezone = null)
2135 2135
     {
2136 2136
         //find model for this class
2137
-        if (! $classname) {
2137
+        if ( ! $classname) {
2138 2138
             throw new EE_Error(
2139 2139
                 sprintf(
2140 2140
                     esc_html__(
@@ -2183,7 +2183,7 @@  discard block
 block discarded – undo
2183 2183
         if (strpos($model_name, 'EE_') === 0) {
2184 2184
             $model_classname = str_replace('EE_', 'EEM_', $model_name);
2185 2185
         } else {
2186
-            $model_classname = 'EEM_' . $model_name;
2186
+            $model_classname = 'EEM_'.$model_name;
2187 2187
         }
2188 2188
         return $model_classname;
2189 2189
     }
@@ -2202,7 +2202,7 @@  discard block
 block discarded – undo
2202 2202
      */
2203 2203
     protected static function _get_primary_key_name($classname = null)
2204 2204
     {
2205
-        if (! $classname) {
2205
+        if ( ! $classname) {
2206 2206
             throw new EE_Error(
2207 2207
                 sprintf(
2208 2208
                     esc_html__('What were you thinking calling _get_primary_key_name(%s)', 'event_espresso'),
@@ -2232,7 +2232,7 @@  discard block
 block discarded – undo
2232 2232
         $model = $this->get_model();
2233 2233
         //now that we know the name of the variable, use a variable variable to get its value and return its
2234 2234
         if ($model->has_primary_key_field()) {
2235
-            return $this->_fields[ $model->primary_key_name() ];
2235
+            return $this->_fields[$model->primary_key_name()];
2236 2236
         }
2237 2237
         return $model->get_index_primary_key_string($this->_fields);
2238 2238
     }
@@ -2285,7 +2285,7 @@  discard block
 block discarded – undo
2285 2285
             }
2286 2286
         } else {
2287 2287
             //this thing doesn't exist in the DB,  so just cache it
2288
-            if (! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2288
+            if ( ! $otherObjectModelObjectOrID instanceof EE_Base_Class) {
2289 2289
                 throw new EE_Error(
2290 2290
                     sprintf(
2291 2291
                         esc_html__(
@@ -2450,7 +2450,7 @@  discard block
 block discarded – undo
2450 2450
             } else {
2451 2451
                 //did we already cache the result of this query?
2452 2452
                 $cached_results = $this->get_all_from_cache($relationName);
2453
-                if (! $cached_results) {
2453
+                if ( ! $cached_results) {
2454 2454
                     $related_model_objects = $this->get_model()->get_all_related(
2455 2455
                         $this,
2456 2456
                         $relationName,
@@ -2560,7 +2560,7 @@  discard block
 block discarded – undo
2560 2560
             } else {
2561 2561
                 //first, check if we've already cached the result of this query
2562 2562
                 $cached_result = $this->get_one_from_cache($relationName);
2563
-                if (! $cached_result) {
2563
+                if ( ! $cached_result) {
2564 2564
                     $related_model_object = $model->get_first_related(
2565 2565
                         $this,
2566 2566
                         $relationName,
@@ -2584,7 +2584,7 @@  discard block
 block discarded – undo
2584 2584
             }
2585 2585
             // this doesn't exist in the DB and apparently the thing it belongs to doesn't either,
2586 2586
             // just get what's cached on this object
2587
-            if (! $related_model_object) {
2587
+            if ( ! $related_model_object) {
2588 2588
                 $related_model_object = $this->get_one_from_cache($relationName);
2589 2589
             }
2590 2590
         }
@@ -2666,7 +2666,7 @@  discard block
 block discarded – undo
2666 2666
      */
2667 2667
     public function is_set($field_name)
2668 2668
     {
2669
-        return isset($this->_fields[ $field_name ]);
2669
+        return isset($this->_fields[$field_name]);
2670 2670
     }
2671 2671
 
2672 2672
 
@@ -2682,7 +2682,7 @@  discard block
 block discarded – undo
2682 2682
     {
2683 2683
         foreach ((array) $properties as $property_name) {
2684 2684
             //first make sure this property exists
2685
-            if (! $this->_fields[ $property_name ]) {
2685
+            if ( ! $this->_fields[$property_name]) {
2686 2686
                 throw new EE_Error(
2687 2687
                     sprintf(
2688 2688
                         esc_html__(
@@ -2714,7 +2714,7 @@  discard block
 block discarded – undo
2714 2714
         $properties = array();
2715 2715
         //remove prepended underscore
2716 2716
         foreach ($fields as $field_name => $settings) {
2717
-            $properties[ $field_name ] = $this->get($field_name);
2717
+            $properties[$field_name] = $this->get($field_name);
2718 2718
         }
2719 2719
         return $properties;
2720 2720
     }
@@ -2751,7 +2751,7 @@  discard block
 block discarded – undo
2751 2751
     {
2752 2752
         $className = get_class($this);
2753 2753
         $tagName   = "FHEE__{$className}__{$methodName}";
2754
-        if (! has_filter($tagName)) {
2754
+        if ( ! has_filter($tagName)) {
2755 2755
             throw new EE_Error(
2756 2756
                 sprintf(
2757 2757
                     esc_html__(
@@ -2796,7 +2796,7 @@  discard block
 block discarded – undo
2796 2796
             $query_params[0]['EXM_value'] = $meta_value;
2797 2797
         }
2798 2798
         $existing_rows_like_that = EEM_Extra_Meta::instance()->get_all($query_params);
2799
-        if (! $existing_rows_like_that) {
2799
+        if ( ! $existing_rows_like_that) {
2800 2800
             return $this->add_extra_meta($meta_key, $meta_value);
2801 2801
         }
2802 2802
         foreach ($existing_rows_like_that as $existing_row) {
@@ -2914,7 +2914,7 @@  discard block
 block discarded – undo
2914 2914
                 $values = array();
2915 2915
                 foreach ($results as $result) {
2916 2916
                     if ($result instanceof EE_Extra_Meta) {
2917
-                        $values[ $result->ID() ] = $result->value();
2917
+                        $values[$result->ID()] = $result->value();
2918 2918
                     }
2919 2919
                 }
2920 2920
                 return $values;
@@ -2959,17 +2959,17 @@  discard block
 block discarded – undo
2959 2959
             );
2960 2960
             foreach ($extra_meta_objs as $extra_meta_obj) {
2961 2961
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2962
-                    $return_array[ $extra_meta_obj->key() ] = $extra_meta_obj->value();
2962
+                    $return_array[$extra_meta_obj->key()] = $extra_meta_obj->value();
2963 2963
                 }
2964 2964
             }
2965 2965
         } else {
2966 2966
             $extra_meta_objs = $this->get_many_related('Extra_Meta');
2967 2967
             foreach ($extra_meta_objs as $extra_meta_obj) {
2968 2968
                 if ($extra_meta_obj instanceof EE_Extra_Meta) {
2969
-                    if (! isset($return_array[ $extra_meta_obj->key() ])) {
2970
-                        $return_array[ $extra_meta_obj->key() ] = array();
2969
+                    if ( ! isset($return_array[$extra_meta_obj->key()])) {
2970
+                        $return_array[$extra_meta_obj->key()] = array();
2971 2971
                     }
2972
-                    $return_array[ $extra_meta_obj->key() ][ $extra_meta_obj->ID() ] = $extra_meta_obj->value();
2972
+                    $return_array[$extra_meta_obj->key()][$extra_meta_obj->ID()] = $extra_meta_obj->value();
2973 2973
                 }
2974 2974
             }
2975 2975
         }
@@ -3048,8 +3048,8 @@  discard block
 block discarded – undo
3048 3048
                         esc_html__('Trying to refresh a model object with ID "%1$s" that\'s not in the entity map? First off: you should put it in the entity map by calling %2$s. Second off, if you want what\'s in the database right now, you should just call %3$s yourself and discard this model object.',
3049 3049
                             'event_espresso'),
3050 3050
                         $this->ID(),
3051
-                        get_class($this->get_model()) . '::instance()->add_to_entity_map()',
3052
-                        get_class($this->get_model()) . '::instance()->refresh_entity_map()'
3051
+                        get_class($this->get_model()).'::instance()->add_to_entity_map()',
3052
+                        get_class($this->get_model()).'::instance()->refresh_entity_map()'
3053 3053
                     )
3054 3054
                 );
3055 3055
             }
@@ -3111,7 +3111,7 @@  discard block
 block discarded – undo
3111 3111
         $model = $this->get_model();
3112 3112
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
3113 3113
             if ($relation_obj instanceof EE_Belongs_To_Relation) {
3114
-                $classname = 'EE_' . $model->get_this_model_name();
3114
+                $classname = 'EE_'.$model->get_this_model_name();
3115 3115
                 if (
3116 3116
                     $this->get_one_from_cache($relation_name) instanceof $classname
3117 3117
                     && $this->get_one_from_cache($relation_name)->ID()
Please login to merge, or discard this patch.
core/middleware/EE_Recommended_Versions.core.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
         //$this->_response->add_output( "\n\t IN >>  " . __CLASS__ );
37 37
         //$this->_response->set_notice( 1, 'hey look at this' );
38 38
         // check required WP version
39
-        if (! $this->_minimum_wp_version_required()) {
39
+        if ( ! $this->_minimum_wp_version_required()) {
40 40
             $this->_request->un_set('activate', true);
41 41
             add_action('admin_notices', array($this, 'minimum_wp_version_error'), 1);
42 42
             //$this->_response->add_output( "\n<br />" . 'minimum_wp_version_error' );
@@ -44,12 +44,12 @@  discard block
 block discarded – undo
44 44
             $this->_response->deactivate_plugin();
45 45
         }
46 46
         // check recommended PHP version
47
-        if (! $this->_minimum_php_version_recommended()) {
47
+        if ( ! $this->_minimum_php_version_recommended()) {
48 48
             $this->_display_minimum_recommended_php_version_notice();
49 49
         }
50 50
 
51 51
         //upcoming required version
52
-        if (! $this->upcomingRequiredPhpVersion()) {
52
+        if ( ! $this->upcomingRequiredPhpVersion()) {
53 53
             $this->displayUpcomingRequiredVersion();
54 54
         }
55 55
         $this->_response = $this->process_request_stack($this->_request, $this->_response);
@@ -172,9 +172,9 @@  discard block
 block discarded – undo
172 172
      */
173 173
     private function _display_minimum_recommended_php_version_notice()
174 174
     {
175
-        if($this->_request->isAdmin()){
175
+        if ($this->_request->isAdmin()) {
176 176
             new PersistentAdminNotice(
177
-                'php_version_' . str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED) . '_recommended',
177
+                'php_version_'.str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED).'_recommended',
178 178
                 sprintf(
179 179
                     __(
180 180
                         'Event Espresso recommends PHP version %1$s or greater for optimal performance. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
             && apply_filters('FHEE__EE_Recommended_Versions__displayUpcomingRequiredVersion', true, $this->_request)
200 200
             && current_user_can('update_plugins')
201 201
         ) {
202
-            add_action('admin_notices', function () {
202
+            add_action('admin_notices', function() {
203 203
                 echo '<div class="notice event-espresso-admin-notice notice-warning"><p>'
204 204
                      . sprintf(
205 205
                          esc_html__(
Please login to merge, or discard this patch.
Indentation   +189 added lines, -189 removed lines patch added patch discarded remove patch
@@ -21,199 +21,199 @@
 block discarded – undo
21 21
 {
22 22
 
23 23
 
24
-    /**
25
-     * converts a Request to a Response
26
-     *
27
-     * @param EE_Request  $request
28
-     * @param EE_Response $response
29
-     * @return EE_Response
30
-     * @throws InvalidDataTypeException
31
-     */
32
-    public function handle_request(EE_Request $request, EE_Response $response)
33
-    {
34
-        $this->_request  = $request;
35
-        $this->_response = $response;
36
-        //$this->_response->add_output( "\n\t IN >>  " . __CLASS__ );
37
-        //$this->_response->set_notice( 1, 'hey look at this' );
38
-        // check required WP version
39
-        if (! $this->_minimum_wp_version_required()) {
40
-            $this->_request->un_set('activate', true);
41
-            add_action('admin_notices', array($this, 'minimum_wp_version_error'), 1);
42
-            //$this->_response->add_output( "\n<br />" . 'minimum_wp_version_error' );
43
-            $this->_response->terminate_request();
44
-            $this->_response->deactivate_plugin();
45
-        }
46
-        // check recommended PHP version
47
-        if (! $this->_minimum_php_version_recommended()) {
48
-            $this->_display_minimum_recommended_php_version_notice();
49
-        }
50
-
51
-        //upcoming required version
52
-        if (! $this->upcomingRequiredPhpVersion()) {
53
-            $this->displayUpcomingRequiredVersion();
54
-        }
55
-        $this->_response = $this->process_request_stack($this->_request, $this->_response);
56
-        //$this->_response->add_output( "\n\t OUT << " . __CLASS__ );
57
-        return $this->_response;
58
-    }
59
-
60
-
61
-    /**
62
-     * Helper method to assess installed wp version against given values.
63
-     * By default this compares the required minimum version of WP for EE against the installed version of WP
64
-     * Note, $wp_version is the first parameter sent into the PHP version_compare function (what is being checked
65
-     * against) so consider that when sending in your values.
66
-     *
67
-     * @param string $version_to_check
68
-     * @param string $operator
69
-     * @return bool
70
-     */
71
-    public static function check_wp_version($version_to_check = EE_MIN_WP_VER_REQUIRED, $operator = '>=')
72
-    {
73
-        global $wp_version;
74
-        return version_compare(
75
-            // first account for wp_version being pre-release
76
-            // (like RC, beta etc) which are usually in the format like 4.7-RC3-39519
77
-            strpos($wp_version, '-') > 0
78
-                ? substr($wp_version, 0, strpos($wp_version, '-'))
79
-                : $wp_version,
80
-            $version_to_check,
81
-            $operator
82
-        );
83
-    }
84
-
85
-
86
-
87
-    /**
88
-     *    _minimum_wp_version_required
89
-     *
90
-     * @access private
91
-     * @return boolean
92
-     */
93
-    private function _minimum_wp_version_required()
94
-    {
95
-        return EE_Recommended_Versions::check_wp_version();
96
-    }
97
-
98
-
99
-
100
-    /**
101
-     *    _check_php_version
102
-     *
103
-     * @access private
104
-     * @param string $min_version
105
-     * @return boolean
106
-     */
107
-    private function _check_php_version($min_version = EE_MIN_PHP_VER_RECOMMENDED)
108
-    {
109
-        return version_compare(PHP_VERSION, $min_version, '>=');
110
-    }
111
-
112
-
113
-
114
-    /**
115
-     *    _minimum_php_version_recommended
116
-     *
117
-     * @access private
118
-     * @return boolean
119
-     */
120
-    private function _minimum_php_version_recommended()
121
-    {
122
-        return $this->_check_php_version();
123
-    }
124
-
125
-
126
-    /**
127
-     * Returns whether the provided php version number is greater than the current version of php installed on the server.
128
-     * @param string $version_required
129
-     * @return bool
130
-     */
131
-    private function upcomingRequiredPhpVersion($version_required = '5.5')
132
-    {
133
-        return $this->_check_php_version($version_required);
134
-    }
135
-
136
-
137
-
138
-    /**
139
-     *    minimum_wp_version_error
140
-     *
141
-     * @return void
142
-     */
143
-    public function minimum_wp_version_error()
144
-    {
145
-        global $wp_version;
146
-        ?>
24
+	/**
25
+	 * converts a Request to a Response
26
+	 *
27
+	 * @param EE_Request  $request
28
+	 * @param EE_Response $response
29
+	 * @return EE_Response
30
+	 * @throws InvalidDataTypeException
31
+	 */
32
+	public function handle_request(EE_Request $request, EE_Response $response)
33
+	{
34
+		$this->_request  = $request;
35
+		$this->_response = $response;
36
+		//$this->_response->add_output( "\n\t IN >>  " . __CLASS__ );
37
+		//$this->_response->set_notice( 1, 'hey look at this' );
38
+		// check required WP version
39
+		if (! $this->_minimum_wp_version_required()) {
40
+			$this->_request->un_set('activate', true);
41
+			add_action('admin_notices', array($this, 'minimum_wp_version_error'), 1);
42
+			//$this->_response->add_output( "\n<br />" . 'minimum_wp_version_error' );
43
+			$this->_response->terminate_request();
44
+			$this->_response->deactivate_plugin();
45
+		}
46
+		// check recommended PHP version
47
+		if (! $this->_minimum_php_version_recommended()) {
48
+			$this->_display_minimum_recommended_php_version_notice();
49
+		}
50
+
51
+		//upcoming required version
52
+		if (! $this->upcomingRequiredPhpVersion()) {
53
+			$this->displayUpcomingRequiredVersion();
54
+		}
55
+		$this->_response = $this->process_request_stack($this->_request, $this->_response);
56
+		//$this->_response->add_output( "\n\t OUT << " . __CLASS__ );
57
+		return $this->_response;
58
+	}
59
+
60
+
61
+	/**
62
+	 * Helper method to assess installed wp version against given values.
63
+	 * By default this compares the required minimum version of WP for EE against the installed version of WP
64
+	 * Note, $wp_version is the first parameter sent into the PHP version_compare function (what is being checked
65
+	 * against) so consider that when sending in your values.
66
+	 *
67
+	 * @param string $version_to_check
68
+	 * @param string $operator
69
+	 * @return bool
70
+	 */
71
+	public static function check_wp_version($version_to_check = EE_MIN_WP_VER_REQUIRED, $operator = '>=')
72
+	{
73
+		global $wp_version;
74
+		return version_compare(
75
+			// first account for wp_version being pre-release
76
+			// (like RC, beta etc) which are usually in the format like 4.7-RC3-39519
77
+			strpos($wp_version, '-') > 0
78
+				? substr($wp_version, 0, strpos($wp_version, '-'))
79
+				: $wp_version,
80
+			$version_to_check,
81
+			$operator
82
+		);
83
+	}
84
+
85
+
86
+
87
+	/**
88
+	 *    _minimum_wp_version_required
89
+	 *
90
+	 * @access private
91
+	 * @return boolean
92
+	 */
93
+	private function _minimum_wp_version_required()
94
+	{
95
+		return EE_Recommended_Versions::check_wp_version();
96
+	}
97
+
98
+
99
+
100
+	/**
101
+	 *    _check_php_version
102
+	 *
103
+	 * @access private
104
+	 * @param string $min_version
105
+	 * @return boolean
106
+	 */
107
+	private function _check_php_version($min_version = EE_MIN_PHP_VER_RECOMMENDED)
108
+	{
109
+		return version_compare(PHP_VERSION, $min_version, '>=');
110
+	}
111
+
112
+
113
+
114
+	/**
115
+	 *    _minimum_php_version_recommended
116
+	 *
117
+	 * @access private
118
+	 * @return boolean
119
+	 */
120
+	private function _minimum_php_version_recommended()
121
+	{
122
+		return $this->_check_php_version();
123
+	}
124
+
125
+
126
+	/**
127
+	 * Returns whether the provided php version number is greater than the current version of php installed on the server.
128
+	 * @param string $version_required
129
+	 * @return bool
130
+	 */
131
+	private function upcomingRequiredPhpVersion($version_required = '5.5')
132
+	{
133
+		return $this->_check_php_version($version_required);
134
+	}
135
+
136
+
137
+
138
+	/**
139
+	 *    minimum_wp_version_error
140
+	 *
141
+	 * @return void
142
+	 */
143
+	public function minimum_wp_version_error()
144
+	{
145
+		global $wp_version;
146
+		?>
147 147
         <div class="error">
148 148
             <p>
149 149
                 <?php
150
-                printf(
151
-                    __('We\'re sorry, but Event Espresso requires WordPress version %1$s or greater in order to operate. You are currently running version %2$s.%3$sFor information on how to update your version of WordPress, please go to %4$s.',
152
-                        'event_espresso'),
153
-                    EE_MIN_WP_VER_REQUIRED,
154
-                    $wp_version,
155
-                    '<br/>',
156
-                    '<a href="http://codex.wordpress.org/Updating_WordPress">http://codex.wordpress.org/Updating_WordPress</a>'
157
-                );
158
-                ?>
150
+				printf(
151
+					__('We\'re sorry, but Event Espresso requires WordPress version %1$s or greater in order to operate. You are currently running version %2$s.%3$sFor information on how to update your version of WordPress, please go to %4$s.',
152
+						'event_espresso'),
153
+					EE_MIN_WP_VER_REQUIRED,
154
+					$wp_version,
155
+					'<br/>',
156
+					'<a href="http://codex.wordpress.org/Updating_WordPress">http://codex.wordpress.org/Updating_WordPress</a>'
157
+				);
158
+				?>
159 159
             </p>
160 160
         </div>
161 161
         <?php
162
-    }
163
-
164
-
165
-
166
-    /**
167
-     *    _display_minimum_recommended_php_version_notice
168
-     *
169
-     * @access private
170
-     * @return void
171
-     * @throws InvalidDataTypeException
172
-     */
173
-    private function _display_minimum_recommended_php_version_notice()
174
-    {
175
-        if($this->_request->isAdmin()){
176
-            new PersistentAdminNotice(
177
-                'php_version_' . str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED) . '_recommended',
178
-                sprintf(
179
-                    __(
180
-                        'Event Espresso recommends PHP version %1$s or greater for optimal performance. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
181
-                        'event_espresso'
182
-                    ),
183
-                    EE_MIN_PHP_VER_RECOMMENDED,
184
-                    PHP_VERSION,
185
-                    '<br/>',
186
-                    '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
187
-                )
188
-            );
189
-        }
190
-    }
191
-
192
-
193
-    /**
194
-     *  Sets a notice for an upcoming required version of PHP in the next update of EE core.
195
-     */
196
-    private function displayUpcomingRequiredVersion()
197
-    {
198
-        if ($this->_request->isAdmin()
199
-            && apply_filters('FHEE__EE_Recommended_Versions__displayUpcomingRequiredVersion', true, $this->_request)
200
-            && current_user_can('update_plugins')
201
-        ) {
202
-            add_action('admin_notices', function () {
203
-                echo '<div class="notice event-espresso-admin-notice notice-warning"><p>'
204
-                     . sprintf(
205
-                         esc_html__(
206
-                             'Please note: The next update of Event Espresso 4 will %1$srequire%2$s PHP 5.4.45 or greater.  Your web server\'s PHP version is %3$s.  You can contact your host and ask them to update your PHP version to at least PHP 5.6.  Please do not update to the new version of Event Espresso 4 until the PHP update is completed. Read about why keeping your server on the latest version of PHP is a good idea %4$shere%5$s',
207
-                             'event_espresso'
208
-                         ),
209
-                         '<strong>',
210
-                         '</strong>',
211
-                         PHP_VERSION,
212
-                         '<a href="https://wordpress.org/support/upgrade-php/">',
213
-                         '</a>'
214
-                     )
215
-                     . '</p></div>';
216
-            });
217
-        }
218
-    }
162
+	}
163
+
164
+
165
+
166
+	/**
167
+	 *    _display_minimum_recommended_php_version_notice
168
+	 *
169
+	 * @access private
170
+	 * @return void
171
+	 * @throws InvalidDataTypeException
172
+	 */
173
+	private function _display_minimum_recommended_php_version_notice()
174
+	{
175
+		if($this->_request->isAdmin()){
176
+			new PersistentAdminNotice(
177
+				'php_version_' . str_replace('.', '-', EE_MIN_PHP_VER_RECOMMENDED) . '_recommended',
178
+				sprintf(
179
+					__(
180
+						'Event Espresso recommends PHP version %1$s or greater for optimal performance. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
181
+						'event_espresso'
182
+					),
183
+					EE_MIN_PHP_VER_RECOMMENDED,
184
+					PHP_VERSION,
185
+					'<br/>',
186
+					'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
187
+				)
188
+			);
189
+		}
190
+	}
191
+
192
+
193
+	/**
194
+	 *  Sets a notice for an upcoming required version of PHP in the next update of EE core.
195
+	 */
196
+	private function displayUpcomingRequiredVersion()
197
+	{
198
+		if ($this->_request->isAdmin()
199
+			&& apply_filters('FHEE__EE_Recommended_Versions__displayUpcomingRequiredVersion', true, $this->_request)
200
+			&& current_user_can('update_plugins')
201
+		) {
202
+			add_action('admin_notices', function () {
203
+				echo '<div class="notice event-espresso-admin-notice notice-warning"><p>'
204
+					 . sprintf(
205
+						 esc_html__(
206
+							 'Please note: The next update of Event Espresso 4 will %1$srequire%2$s PHP 5.4.45 or greater.  Your web server\'s PHP version is %3$s.  You can contact your host and ask them to update your PHP version to at least PHP 5.6.  Please do not update to the new version of Event Espresso 4 until the PHP update is completed. Read about why keeping your server on the latest version of PHP is a good idea %4$shere%5$s',
207
+							 'event_espresso'
208
+						 ),
209
+						 '<strong>',
210
+						 '</strong>',
211
+						 PHP_VERSION,
212
+						 '<a href="https://wordpress.org/support/upgrade-php/">',
213
+						 '</a>'
214
+					 )
215
+					 . '</p></div>';
216
+			});
217
+		}
218
+	}
219 219
 }
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_List_Table.class.php 1 patch
Indentation   +526 added lines, -526 removed lines patch added patch discarded remove patch
@@ -18,530 +18,530 @@
 block discarded – undo
18 18
 class Events_Admin_List_Table extends EE_Admin_List_Table
19 19
 {
20 20
 
21
-    /**
22
-     * @var EE_Datetime
23
-     */
24
-    private $_dtt;
25
-
26
-
27
-
28
-    /**
29
-     * Initial setup of data properties for the list table.
30
-     */
31
-    protected function _setup_data()
32
-    {
33
-        $this->_data = $this->_admin_page->get_events($this->_per_page, $this->_current_page);
34
-        $this->_all_data_count = $this->_admin_page->get_events(0, 0, true);
35
-    }
36
-
37
-
38
-
39
-    /**
40
-     * Set up of additional properties for the list table.
41
-     */
42
-    protected function _set_properties()
43
-    {
44
-        $this->_wp_list_args = array(
45
-            'singular' => esc_html__('event', 'event_espresso'),
46
-            'plural'   => esc_html__('events', 'event_espresso'),
47
-            'ajax'     => true, //for now
48
-            'screen'   => $this->_admin_page->get_current_screen()->id,
49
-        );
50
-        $this->_columns = array(
51
-            'cb'              => '<input type="checkbox" />',
52
-            'id'              => esc_html__('ID', 'event_espresso'),
53
-            'name'            => esc_html__('Name', 'event_espresso'),
54
-            'author'          => esc_html__('Author', 'event_espresso'),
55
-            'venue'           => esc_html__('Venue', 'event_espresso'),
56
-            'start_date_time' => esc_html__('Event Start', 'event_espresso'),
57
-            'reg_begins'      => esc_html__('On Sale', 'event_espresso'),
58
-            'attendees'       => '<span class="dashicons dashicons-groups ee-icon-color-ee-green ee-icon-size-20">'
59
-                                 . '<span class="screen-reader-text">'
60
-                                 . esc_html__('Approved Registrations', 'event_espresso')
61
-                                 . '</span>'
62
-                                 . '</span>',
63
-            //'tkts_sold' => esc_html__('Tickets Sold', 'event_espresso'),
64
-            'actions'         => esc_html__('Actions', 'event_espresso'),
65
-        );
66
-        $this->_sortable_columns = array(
67
-            'id'              => array('EVT_ID' => true),
68
-            'name'            => array('EVT_name' => false),
69
-            'author'          => array('EVT_wp_user' => false),
70
-            'venue'           => array('Venue.VNU_name' => false),
71
-            'start_date_time' => array('Datetime.DTT_EVT_start' => false),
72
-            'reg_begins'      => array('Datetime.Ticket.TKT_start_date' => false),
73
-        );
74
-        $this->_primary_column = 'id';
75
-        $this->_hidden_columns = array('author');
76
-    }
77
-
78
-
79
-
80
-    /**
81
-     * @return array
82
-     */
83
-    protected function _get_table_filters()
84
-    {
85
-        return array(); //no filters with decaf
86
-    }
87
-
88
-
89
-
90
-    /**
91
-     * Setup of views properties.
92
-     *
93
-     * @throws InvalidDataTypeException
94
-     * @throws InvalidInterfaceException
95
-     * @throws InvalidArgumentException
96
-     */
97
-    protected function _add_view_counts()
98
-    {
99
-        $this->_views['all']['count'] = $this->_admin_page->total_events();
100
-        $this->_views['draft']['count'] = $this->_admin_page->total_events_draft();
101
-        if (EE_Registry::instance()->CAP->current_user_can(
102
-            'ee_delete_events',
103
-            'espresso_events_trash_events'
104
-        )) {
105
-            $this->_views['trash']['count'] = $this->_admin_page->total_trashed_events();
106
-        }
107
-    }
108
-
109
-
110
-
111
-    /**
112
-     * @param EE_Event $item
113
-     * @return string
114
-     * @throws EE_Error
115
-     */
116
-    protected function _get_row_class($item)
117
-    {
118
-        $class = parent::_get_row_class($item);
119
-        //add status class
120
-        $class .= $item instanceof EE_Event
121
-            ? ' ee-status-strip event-status-' . $item->get_active_status()
122
-            : '';
123
-        if ($this->_has_checkbox_column) {
124
-            $class .= ' has-checkbox-column';
125
-        }
126
-        return $class;
127
-    }
128
-
129
-
130
-
131
-    /**
132
-     * @param EE_Event $item
133
-     * @return string
134
-     * @throws EE_Error
135
-     */
136
-    public function column_status(EE_Event $item)
137
-    {
138
-        return '<span class="ee-status-strip ee-status-strip-td event-status-'
139
-               . $item->get_active_status()
140
-               . '"></span>';
141
-    }
142
-
143
-
144
-
145
-    /**
146
-     * @param  EE_Event $item
147
-     * @return string
148
-     * @throws EE_Error
149
-     */
150
-    public function column_cb($item)
151
-    {
152
-        if (! $item instanceof EE_Event) {
153
-            return '';
154
-        }
155
-        $this->_dtt = $item->primary_datetime(); //set this for use in other columns
156
-        //does event have any attached registrations?
157
-        $regs = $item->count_related('Registration');
158
-        return $regs > 0 && $this->_view === 'trash'
159
-            ? '<span class="ee-lock-icon"></span>'
160
-            : sprintf(
161
-                '<input type="checkbox" name="EVT_IDs[]" value="%s" />',
162
-                $item->ID()
163
-            );
164
-    }
165
-
166
-
167
-
168
-    /**
169
-     * @param EE_Event $item
170
-     * @return mixed|string
171
-     * @throws EE_Error
172
-     */
173
-    public function column_id(EE_Event $item)
174
-    {
175
-        $content = $item->ID();
176
-        $content .= '  <span class="show-on-mobile-view-only">' . $item->name() . '</span>';
177
-        return $content;
178
-    }
179
-
180
-
181
-
182
-    /**
183
-     * @param EE_Event $item
184
-     * @return string
185
-     * @throws EE_Error
186
-     * @throws InvalidArgumentException
187
-     * @throws InvalidDataTypeException
188
-     * @throws InvalidInterfaceException
189
-     */
190
-    public function column_name(EE_Event $item)
191
-    {
192
-        $edit_query_args = array(
193
-            'action' => 'edit',
194
-            'post'   => $item->ID(),
195
-        );
196
-        $edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
197
-        $actions = $this->_column_name_action_setup($item);
198
-        $status = ''; //$item->status() !== 'publish' ? ' (' . $item->status() . ')' : '';
199
-        $content = '<strong><a class="row-title" href="'
200
-                   . $edit_link . '">'
201
-                   . $item->name()
202
-                   . '</a></strong>'
203
-                   . $status;
204
-        $content .= '<br><span class="ee-status-text-small">'
205
-                    . EEH_Template::pretty_status(
206
-                $item->get_active_status(),
207
-                false,
208
-                'sentence'
209
-            )
210
-                    . '</span>';
211
-        $content .= $this->row_actions($actions);
212
-        return $content;
213
-    }
214
-
215
-
216
-
217
-    /**
218
-     * Just a method for setting up the actions for the name column
219
-     *
220
-     * @param EE_Event $item
221
-     * @return array array of actions
222
-     * @throws EE_Error
223
-     * @throws InvalidArgumentException
224
-     * @throws InvalidDataTypeException
225
-     * @throws InvalidInterfaceException
226
-     */
227
-    protected function _column_name_action_setup(EE_Event $item)
228
-    {
229
-        //todo: remove when attendees is active
230
-        if (! defined('REG_ADMIN_URL')) {
231
-            define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
232
-        }
233
-        $actions = array();
234
-        $restore_event_link = '';
235
-        $delete_event_link = '';
236
-        $trash_event_link = '';
237
-        if (EE_Registry::instance()->CAP->current_user_can(
238
-            'ee_edit_event',
239
-            'espresso_events_edit',
240
-            $item->ID()
241
-        )) {
242
-            $edit_query_args = array(
243
-                'action' => 'edit',
244
-                'post'   => $item->ID(),
245
-            );
246
-            $edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
247
-            $actions['edit'] = '<a href="' . $edit_link . '"'
248
-                               . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
249
-                               . esc_html__('Edit', 'event_espresso')
250
-                               . '</a>';
251
-        }
252
-        if (
253
-            EE_Registry::instance()->CAP->current_user_can(
254
-                'ee_read_registrations',
255
-                'espresso_registrations_view_registration'
256
-            )
257
-            && EE_Registry::instance()->CAP->current_user_can(
258
-                'ee_read_event',
259
-                'espresso_registrations_view_registration',
260
-                $item->ID()
261
-            )
262
-        ) {
263
-            $attendees_query_args = array(
264
-                'action'   => 'default',
265
-                'event_id' => $item->ID(),
266
-            );
267
-            $attendees_link = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
268
-            $actions['attendees'] = '<a href="' . $attendees_link . '"'
269
-                                    . ' title="' . esc_attr__('View Registrations', 'event_espresso') . '">'
270
-                                    . esc_html__('Registrations', 'event_espresso')
271
-                                    . '</a>';
272
-        }
273
-        if (
274
-        EE_Registry::instance()->CAP->current_user_can(
275
-            'ee_delete_event',
276
-            'espresso_events_trash_event',
277
-            $item->ID()
278
-        )
279
-        ) {
280
-            $trash_event_query_args = array(
281
-                'action' => 'trash_event',
282
-                'EVT_ID' => $item->ID(),
283
-            );
284
-            $trash_event_link = EE_Admin_Page::add_query_args_and_nonce(
285
-                $trash_event_query_args,
286
-                EVENTS_ADMIN_URL
287
-            );
288
-        }
289
-        if (
290
-        EE_Registry::instance()->CAP->current_user_can(
291
-            'ee_delete_event',
292
-            'espresso_events_restore_event',
293
-            $item->ID()
294
-        )
295
-        ) {
296
-            $restore_event_query_args = array(
297
-                'action' => 'restore_event',
298
-                'EVT_ID' => $item->ID(),
299
-            );
300
-            $restore_event_link = EE_Admin_Page::add_query_args_and_nonce(
301
-                $restore_event_query_args,
302
-                EVENTS_ADMIN_URL
303
-            );
304
-        }
305
-        if (
306
-        EE_Registry::instance()->CAP->current_user_can(
307
-            'ee_delete_event',
308
-            'espresso_events_delete_event',
309
-            $item->ID()
310
-        )
311
-        ) {
312
-            $delete_event_query_args = array(
313
-                'action' => 'delete_event',
314
-                'EVT_ID' => $item->ID(),
315
-            );
316
-            $delete_event_link = EE_Admin_Page::add_query_args_and_nonce(
317
-                $delete_event_query_args,
318
-                EVENTS_ADMIN_URL
319
-            );
320
-        }
321
-        $view_link = get_permalink($item->ID());
322
-        $actions['view'] = '<a href="' . $view_link . '"'
323
-                           . ' title="' . esc_attr__('View Event', 'event_espresso') . '">'
324
-                           . esc_html__('View', 'event_espresso')
325
-                           . '</a>';
326
-        if ($item->get('status') === 'trash') {
327
-            if (EE_Registry::instance()->CAP->current_user_can(
328
-                'ee_delete_event',
329
-                'espresso_events_restore_event',
330
-                $item->ID()
331
-            )) {
332
-                $actions['restore_from_trash'] = '<a href="' . $restore_event_link . '"'
333
-                                                 . ' title="' . esc_attr__('Restore from Trash', 'event_espresso')
334
-                                                 . '">'
335
-                                                 . esc_html__('Restore from Trash', 'event_espresso')
336
-                                                 . '</a>';
337
-            }
338
-            if (
339
-                $item->count_related('Registration') === 0
340
-                && EE_Registry::instance()->CAP->current_user_can(
341
-                    'ee_delete_event',
342
-                    'espresso_events_delete_event',
343
-                    $item->ID()
344
-                )
345
-            ) {
346
-                $actions['delete'] = '<a href="' . $delete_event_link . '"'
347
-                                     . ' title="' . esc_attr__('Delete Permanently', 'event_espresso') . '">'
348
-                                     . esc_html__('Delete Permanently', 'event_espresso')
349
-                                     . '</a>';
350
-            }
351
-        } else {
352
-            if (
353
-                EE_Registry::instance()->CAP->current_user_can(
354
-                    'ee_delete_event',
355
-                    'espresso_events_trash_event',
356
-                    $item->ID()
357
-                )
358
-            ) {
359
-                $actions['move to trash'] = '<a href="' . $trash_event_link . '"'
360
-                                            . ' title="' . esc_attr__('Trash Event', 'event_espresso') . '">'
361
-                                            . esc_html__('Trash', 'event_espresso')
362
-                                            . '</a>';
363
-            }
364
-        }
365
-        return $actions;
366
-    }
367
-
368
-
369
-
370
-    /**
371
-     * @param EE_Event $item
372
-     * @return string
373
-     * @throws EE_Error
374
-     */
375
-    public function column_author(EE_Event $item)
376
-    {
377
-        //user author info
378
-        $event_author = get_userdata($item->wp_user());
379
-        $gravatar = get_avatar($item->wp_user(), '15');
380
-        //filter link
381
-        $query_args = array(
382
-            'action'      => 'default',
383
-            'EVT_wp_user' => $item->wp_user(),
384
-        );
385
-        $filter_url = EE_Admin_Page::add_query_args_and_nonce($query_args, EVENTS_ADMIN_URL);
386
-        return $gravatar . '  <a href="' . $filter_url . '"'
387
-               . ' title="' . esc_attr__('Click to filter events by this author.', 'event_espresso') . '">'
388
-               . $event_author->display_name
389
-               . '</a>';
390
-    }
391
-
392
-
393
-
394
-    /**
395
-     * @param EE_Event $item
396
-     * @return string
397
-     * @throws EE_Error
398
-     */
399
-    public function column_venue(EE_Event $item)
400
-    {
401
-        $venue = $item->get_first_related('Venue');
402
-        return ! empty($venue)
403
-            ? $venue->name()
404
-            : '';
405
-    }
406
-
407
-
408
-    /**
409
-     * @param EE_Event $item
410
-     * @return string
411
-     * @throws EE_Error
412
-     */
413
-    public function column_start_date_time(EE_Event $item)
414
-    {
415
-        return $this->_dtt instanceof EE_Datetime
416
-            ? $this->_dtt->get_i18n_datetime('DTT_EVT_start')
417
-            : esc_html__('No Date was saved for this Event', 'event_espresso');
418
-    }
419
-
420
-
421
-    /**
422
-     * @param EE_Event $item
423
-     * @return string
424
-     * @throws EE_Error
425
-     */
426
-    public function column_reg_begins(EE_Event $item)
427
-    {
428
-        $reg_start = $item->get_ticket_with_earliest_start_time();
429
-        return $reg_start instanceof EE_Ticket
430
-            ? $reg_start->get_i18n_datetime('TKT_start_date')
431
-            : esc_html__('No Tickets have been setup for this Event', 'event_espresso');
432
-    }
433
-
434
-
435
-
436
-    /**
437
-     * @param EE_Event $item
438
-     * @return int|string
439
-     * @throws EE_Error
440
-     * @throws InvalidArgumentException
441
-     * @throws InvalidDataTypeException
442
-     * @throws InvalidInterfaceException
443
-     */
444
-    public function column_attendees(EE_Event $item)
445
-    {
446
-        $attendees_query_args = array(
447
-            'action'   => 'default',
448
-            'event_id' => $item->ID(),
449
-        );
450
-        $attendees_link = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
451
-        $registered_attendees = EEM_Registration::instance()->get_event_registration_count($item->ID());
452
-        return EE_Registry::instance()->CAP->current_user_can(
453
-            'ee_read_event',
454
-            'espresso_registrations_view_registration',
455
-            $item->ID()
456
-        )
457
-               && EE_Registry::instance()->CAP->current_user_can(
458
-            'ee_read_registrations',
459
-            'espresso_registrations_view_registration'
460
-        )
461
-            ? '<a href="' . $attendees_link . '">' . $registered_attendees . '</a>'
462
-            : $registered_attendees;
463
-    }
464
-
465
-
466
-
467
-    /**
468
-     * @param EE_Event $item
469
-     * @return float
470
-     * @throws EE_Error
471
-     * @throws InvalidArgumentException
472
-     * @throws InvalidDataTypeException
473
-     * @throws InvalidInterfaceException
474
-     */
475
-    public function column_tkts_sold(EE_Event $item)
476
-    {
477
-        return EEM_Ticket::instance()->sum(array(array('Datetime.EVT_ID' => $item->ID())), 'TKT_sold');
478
-    }
479
-
480
-
481
-
482
-    /**
483
-     * @param EE_Event $item
484
-     * @return string
485
-     * @throws EE_Error
486
-     * @throws InvalidArgumentException
487
-     * @throws InvalidDataTypeException
488
-     * @throws InvalidInterfaceException
489
-     */
490
-    public function column_actions(EE_Event $item)
491
-    {
492
-        //todo: remove when attendees is active
493
-        if (! defined('REG_ADMIN_URL')) {
494
-            define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
495
-        }
496
-        $action_links = array();
497
-        $view_link = get_permalink($item->ID());
498
-        $action_links[] = '<a href="' . $view_link . '"'
499
-                         . ' title="' . esc_attr__('View Event', 'event_espresso') . '" target="_blank">';
500
-        $action_links[] = '<div class="dashicons dashicons-search"></div></a>';
501
-        if (EE_Registry::instance()->CAP->current_user_can(
502
-            'ee_edit_event',
503
-            'espresso_events_edit',
504
-            $item->ID()
505
-        )) {
506
-            $edit_query_args = array(
507
-                'action' => 'edit',
508
-                'post'   => $item->ID(),
509
-            );
510
-            $edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
511
-            $action_links[] = '<a href="' . $edit_link . '"'
512
-                             . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
513
-                             . '<div class="ee-icon ee-icon-calendar-edit"></div>'
514
-                             . '</a>';
515
-        }
516
-        if (
517
-            EE_Registry::instance()->CAP->current_user_can(
518
-                'ee_read_registrations',
519
-                'espresso_registrations_view_registration'
520
-            ) && EE_Registry::instance()->CAP->current_user_can(
521
-                'ee_read_event',
522
-                'espresso_registrations_view_registration',
523
-                $item->ID()
524
-            )
525
-        ) {
526
-            $attendees_query_args = array(
527
-                'action'   => 'default',
528
-                'event_id' => $item->ID(),
529
-            );
530
-            $attendees_link = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
531
-            $action_links[] = '<a href="' . $attendees_link . '"'
532
-                             . ' title="' . esc_attr__('View Registrants', 'event_espresso') . '">'
533
-                             . '<div class="dashicons dashicons-groups"></div>'
534
-                             . '</a>';
535
-        }
536
-        $action_links = apply_filters(
537
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
538
-            $action_links,
539
-            $item
540
-        );
541
-        return $this->_action_string(
542
-            implode("\n\t", $action_links),
543
-            $item,
544
-            'div'
545
-        );
546
-    }
21
+	/**
22
+	 * @var EE_Datetime
23
+	 */
24
+	private $_dtt;
25
+
26
+
27
+
28
+	/**
29
+	 * Initial setup of data properties for the list table.
30
+	 */
31
+	protected function _setup_data()
32
+	{
33
+		$this->_data = $this->_admin_page->get_events($this->_per_page, $this->_current_page);
34
+		$this->_all_data_count = $this->_admin_page->get_events(0, 0, true);
35
+	}
36
+
37
+
38
+
39
+	/**
40
+	 * Set up of additional properties for the list table.
41
+	 */
42
+	protected function _set_properties()
43
+	{
44
+		$this->_wp_list_args = array(
45
+			'singular' => esc_html__('event', 'event_espresso'),
46
+			'plural'   => esc_html__('events', 'event_espresso'),
47
+			'ajax'     => true, //for now
48
+			'screen'   => $this->_admin_page->get_current_screen()->id,
49
+		);
50
+		$this->_columns = array(
51
+			'cb'              => '<input type="checkbox" />',
52
+			'id'              => esc_html__('ID', 'event_espresso'),
53
+			'name'            => esc_html__('Name', 'event_espresso'),
54
+			'author'          => esc_html__('Author', 'event_espresso'),
55
+			'venue'           => esc_html__('Venue', 'event_espresso'),
56
+			'start_date_time' => esc_html__('Event Start', 'event_espresso'),
57
+			'reg_begins'      => esc_html__('On Sale', 'event_espresso'),
58
+			'attendees'       => '<span class="dashicons dashicons-groups ee-icon-color-ee-green ee-icon-size-20">'
59
+								 . '<span class="screen-reader-text">'
60
+								 . esc_html__('Approved Registrations', 'event_espresso')
61
+								 . '</span>'
62
+								 . '</span>',
63
+			//'tkts_sold' => esc_html__('Tickets Sold', 'event_espresso'),
64
+			'actions'         => esc_html__('Actions', 'event_espresso'),
65
+		);
66
+		$this->_sortable_columns = array(
67
+			'id'              => array('EVT_ID' => true),
68
+			'name'            => array('EVT_name' => false),
69
+			'author'          => array('EVT_wp_user' => false),
70
+			'venue'           => array('Venue.VNU_name' => false),
71
+			'start_date_time' => array('Datetime.DTT_EVT_start' => false),
72
+			'reg_begins'      => array('Datetime.Ticket.TKT_start_date' => false),
73
+		);
74
+		$this->_primary_column = 'id';
75
+		$this->_hidden_columns = array('author');
76
+	}
77
+
78
+
79
+
80
+	/**
81
+	 * @return array
82
+	 */
83
+	protected function _get_table_filters()
84
+	{
85
+		return array(); //no filters with decaf
86
+	}
87
+
88
+
89
+
90
+	/**
91
+	 * Setup of views properties.
92
+	 *
93
+	 * @throws InvalidDataTypeException
94
+	 * @throws InvalidInterfaceException
95
+	 * @throws InvalidArgumentException
96
+	 */
97
+	protected function _add_view_counts()
98
+	{
99
+		$this->_views['all']['count'] = $this->_admin_page->total_events();
100
+		$this->_views['draft']['count'] = $this->_admin_page->total_events_draft();
101
+		if (EE_Registry::instance()->CAP->current_user_can(
102
+			'ee_delete_events',
103
+			'espresso_events_trash_events'
104
+		)) {
105
+			$this->_views['trash']['count'] = $this->_admin_page->total_trashed_events();
106
+		}
107
+	}
108
+
109
+
110
+
111
+	/**
112
+	 * @param EE_Event $item
113
+	 * @return string
114
+	 * @throws EE_Error
115
+	 */
116
+	protected function _get_row_class($item)
117
+	{
118
+		$class = parent::_get_row_class($item);
119
+		//add status class
120
+		$class .= $item instanceof EE_Event
121
+			? ' ee-status-strip event-status-' . $item->get_active_status()
122
+			: '';
123
+		if ($this->_has_checkbox_column) {
124
+			$class .= ' has-checkbox-column';
125
+		}
126
+		return $class;
127
+	}
128
+
129
+
130
+
131
+	/**
132
+	 * @param EE_Event $item
133
+	 * @return string
134
+	 * @throws EE_Error
135
+	 */
136
+	public function column_status(EE_Event $item)
137
+	{
138
+		return '<span class="ee-status-strip ee-status-strip-td event-status-'
139
+			   . $item->get_active_status()
140
+			   . '"></span>';
141
+	}
142
+
143
+
144
+
145
+	/**
146
+	 * @param  EE_Event $item
147
+	 * @return string
148
+	 * @throws EE_Error
149
+	 */
150
+	public function column_cb($item)
151
+	{
152
+		if (! $item instanceof EE_Event) {
153
+			return '';
154
+		}
155
+		$this->_dtt = $item->primary_datetime(); //set this for use in other columns
156
+		//does event have any attached registrations?
157
+		$regs = $item->count_related('Registration');
158
+		return $regs > 0 && $this->_view === 'trash'
159
+			? '<span class="ee-lock-icon"></span>'
160
+			: sprintf(
161
+				'<input type="checkbox" name="EVT_IDs[]" value="%s" />',
162
+				$item->ID()
163
+			);
164
+	}
165
+
166
+
167
+
168
+	/**
169
+	 * @param EE_Event $item
170
+	 * @return mixed|string
171
+	 * @throws EE_Error
172
+	 */
173
+	public function column_id(EE_Event $item)
174
+	{
175
+		$content = $item->ID();
176
+		$content .= '  <span class="show-on-mobile-view-only">' . $item->name() . '</span>';
177
+		return $content;
178
+	}
179
+
180
+
181
+
182
+	/**
183
+	 * @param EE_Event $item
184
+	 * @return string
185
+	 * @throws EE_Error
186
+	 * @throws InvalidArgumentException
187
+	 * @throws InvalidDataTypeException
188
+	 * @throws InvalidInterfaceException
189
+	 */
190
+	public function column_name(EE_Event $item)
191
+	{
192
+		$edit_query_args = array(
193
+			'action' => 'edit',
194
+			'post'   => $item->ID(),
195
+		);
196
+		$edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
197
+		$actions = $this->_column_name_action_setup($item);
198
+		$status = ''; //$item->status() !== 'publish' ? ' (' . $item->status() . ')' : '';
199
+		$content = '<strong><a class="row-title" href="'
200
+				   . $edit_link . '">'
201
+				   . $item->name()
202
+				   . '</a></strong>'
203
+				   . $status;
204
+		$content .= '<br><span class="ee-status-text-small">'
205
+					. EEH_Template::pretty_status(
206
+				$item->get_active_status(),
207
+				false,
208
+				'sentence'
209
+			)
210
+					. '</span>';
211
+		$content .= $this->row_actions($actions);
212
+		return $content;
213
+	}
214
+
215
+
216
+
217
+	/**
218
+	 * Just a method for setting up the actions for the name column
219
+	 *
220
+	 * @param EE_Event $item
221
+	 * @return array array of actions
222
+	 * @throws EE_Error
223
+	 * @throws InvalidArgumentException
224
+	 * @throws InvalidDataTypeException
225
+	 * @throws InvalidInterfaceException
226
+	 */
227
+	protected function _column_name_action_setup(EE_Event $item)
228
+	{
229
+		//todo: remove when attendees is active
230
+		if (! defined('REG_ADMIN_URL')) {
231
+			define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
232
+		}
233
+		$actions = array();
234
+		$restore_event_link = '';
235
+		$delete_event_link = '';
236
+		$trash_event_link = '';
237
+		if (EE_Registry::instance()->CAP->current_user_can(
238
+			'ee_edit_event',
239
+			'espresso_events_edit',
240
+			$item->ID()
241
+		)) {
242
+			$edit_query_args = array(
243
+				'action' => 'edit',
244
+				'post'   => $item->ID(),
245
+			);
246
+			$edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
247
+			$actions['edit'] = '<a href="' . $edit_link . '"'
248
+							   . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
249
+							   . esc_html__('Edit', 'event_espresso')
250
+							   . '</a>';
251
+		}
252
+		if (
253
+			EE_Registry::instance()->CAP->current_user_can(
254
+				'ee_read_registrations',
255
+				'espresso_registrations_view_registration'
256
+			)
257
+			&& EE_Registry::instance()->CAP->current_user_can(
258
+				'ee_read_event',
259
+				'espresso_registrations_view_registration',
260
+				$item->ID()
261
+			)
262
+		) {
263
+			$attendees_query_args = array(
264
+				'action'   => 'default',
265
+				'event_id' => $item->ID(),
266
+			);
267
+			$attendees_link = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
268
+			$actions['attendees'] = '<a href="' . $attendees_link . '"'
269
+									. ' title="' . esc_attr__('View Registrations', 'event_espresso') . '">'
270
+									. esc_html__('Registrations', 'event_espresso')
271
+									. '</a>';
272
+		}
273
+		if (
274
+		EE_Registry::instance()->CAP->current_user_can(
275
+			'ee_delete_event',
276
+			'espresso_events_trash_event',
277
+			$item->ID()
278
+		)
279
+		) {
280
+			$trash_event_query_args = array(
281
+				'action' => 'trash_event',
282
+				'EVT_ID' => $item->ID(),
283
+			);
284
+			$trash_event_link = EE_Admin_Page::add_query_args_and_nonce(
285
+				$trash_event_query_args,
286
+				EVENTS_ADMIN_URL
287
+			);
288
+		}
289
+		if (
290
+		EE_Registry::instance()->CAP->current_user_can(
291
+			'ee_delete_event',
292
+			'espresso_events_restore_event',
293
+			$item->ID()
294
+		)
295
+		) {
296
+			$restore_event_query_args = array(
297
+				'action' => 'restore_event',
298
+				'EVT_ID' => $item->ID(),
299
+			);
300
+			$restore_event_link = EE_Admin_Page::add_query_args_and_nonce(
301
+				$restore_event_query_args,
302
+				EVENTS_ADMIN_URL
303
+			);
304
+		}
305
+		if (
306
+		EE_Registry::instance()->CAP->current_user_can(
307
+			'ee_delete_event',
308
+			'espresso_events_delete_event',
309
+			$item->ID()
310
+		)
311
+		) {
312
+			$delete_event_query_args = array(
313
+				'action' => 'delete_event',
314
+				'EVT_ID' => $item->ID(),
315
+			);
316
+			$delete_event_link = EE_Admin_Page::add_query_args_and_nonce(
317
+				$delete_event_query_args,
318
+				EVENTS_ADMIN_URL
319
+			);
320
+		}
321
+		$view_link = get_permalink($item->ID());
322
+		$actions['view'] = '<a href="' . $view_link . '"'
323
+						   . ' title="' . esc_attr__('View Event', 'event_espresso') . '">'
324
+						   . esc_html__('View', 'event_espresso')
325
+						   . '</a>';
326
+		if ($item->get('status') === 'trash') {
327
+			if (EE_Registry::instance()->CAP->current_user_can(
328
+				'ee_delete_event',
329
+				'espresso_events_restore_event',
330
+				$item->ID()
331
+			)) {
332
+				$actions['restore_from_trash'] = '<a href="' . $restore_event_link . '"'
333
+												 . ' title="' . esc_attr__('Restore from Trash', 'event_espresso')
334
+												 . '">'
335
+												 . esc_html__('Restore from Trash', 'event_espresso')
336
+												 . '</a>';
337
+			}
338
+			if (
339
+				$item->count_related('Registration') === 0
340
+				&& EE_Registry::instance()->CAP->current_user_can(
341
+					'ee_delete_event',
342
+					'espresso_events_delete_event',
343
+					$item->ID()
344
+				)
345
+			) {
346
+				$actions['delete'] = '<a href="' . $delete_event_link . '"'
347
+									 . ' title="' . esc_attr__('Delete Permanently', 'event_espresso') . '">'
348
+									 . esc_html__('Delete Permanently', 'event_espresso')
349
+									 . '</a>';
350
+			}
351
+		} else {
352
+			if (
353
+				EE_Registry::instance()->CAP->current_user_can(
354
+					'ee_delete_event',
355
+					'espresso_events_trash_event',
356
+					$item->ID()
357
+				)
358
+			) {
359
+				$actions['move to trash'] = '<a href="' . $trash_event_link . '"'
360
+											. ' title="' . esc_attr__('Trash Event', 'event_espresso') . '">'
361
+											. esc_html__('Trash', 'event_espresso')
362
+											. '</a>';
363
+			}
364
+		}
365
+		return $actions;
366
+	}
367
+
368
+
369
+
370
+	/**
371
+	 * @param EE_Event $item
372
+	 * @return string
373
+	 * @throws EE_Error
374
+	 */
375
+	public function column_author(EE_Event $item)
376
+	{
377
+		//user author info
378
+		$event_author = get_userdata($item->wp_user());
379
+		$gravatar = get_avatar($item->wp_user(), '15');
380
+		//filter link
381
+		$query_args = array(
382
+			'action'      => 'default',
383
+			'EVT_wp_user' => $item->wp_user(),
384
+		);
385
+		$filter_url = EE_Admin_Page::add_query_args_and_nonce($query_args, EVENTS_ADMIN_URL);
386
+		return $gravatar . '  <a href="' . $filter_url . '"'
387
+			   . ' title="' . esc_attr__('Click to filter events by this author.', 'event_espresso') . '">'
388
+			   . $event_author->display_name
389
+			   . '</a>';
390
+	}
391
+
392
+
393
+
394
+	/**
395
+	 * @param EE_Event $item
396
+	 * @return string
397
+	 * @throws EE_Error
398
+	 */
399
+	public function column_venue(EE_Event $item)
400
+	{
401
+		$venue = $item->get_first_related('Venue');
402
+		return ! empty($venue)
403
+			? $venue->name()
404
+			: '';
405
+	}
406
+
407
+
408
+	/**
409
+	 * @param EE_Event $item
410
+	 * @return string
411
+	 * @throws EE_Error
412
+	 */
413
+	public function column_start_date_time(EE_Event $item)
414
+	{
415
+		return $this->_dtt instanceof EE_Datetime
416
+			? $this->_dtt->get_i18n_datetime('DTT_EVT_start')
417
+			: esc_html__('No Date was saved for this Event', 'event_espresso');
418
+	}
419
+
420
+
421
+	/**
422
+	 * @param EE_Event $item
423
+	 * @return string
424
+	 * @throws EE_Error
425
+	 */
426
+	public function column_reg_begins(EE_Event $item)
427
+	{
428
+		$reg_start = $item->get_ticket_with_earliest_start_time();
429
+		return $reg_start instanceof EE_Ticket
430
+			? $reg_start->get_i18n_datetime('TKT_start_date')
431
+			: esc_html__('No Tickets have been setup for this Event', 'event_espresso');
432
+	}
433
+
434
+
435
+
436
+	/**
437
+	 * @param EE_Event $item
438
+	 * @return int|string
439
+	 * @throws EE_Error
440
+	 * @throws InvalidArgumentException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws InvalidInterfaceException
443
+	 */
444
+	public function column_attendees(EE_Event $item)
445
+	{
446
+		$attendees_query_args = array(
447
+			'action'   => 'default',
448
+			'event_id' => $item->ID(),
449
+		);
450
+		$attendees_link = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
451
+		$registered_attendees = EEM_Registration::instance()->get_event_registration_count($item->ID());
452
+		return EE_Registry::instance()->CAP->current_user_can(
453
+			'ee_read_event',
454
+			'espresso_registrations_view_registration',
455
+			$item->ID()
456
+		)
457
+			   && EE_Registry::instance()->CAP->current_user_can(
458
+			'ee_read_registrations',
459
+			'espresso_registrations_view_registration'
460
+		)
461
+			? '<a href="' . $attendees_link . '">' . $registered_attendees . '</a>'
462
+			: $registered_attendees;
463
+	}
464
+
465
+
466
+
467
+	/**
468
+	 * @param EE_Event $item
469
+	 * @return float
470
+	 * @throws EE_Error
471
+	 * @throws InvalidArgumentException
472
+	 * @throws InvalidDataTypeException
473
+	 * @throws InvalidInterfaceException
474
+	 */
475
+	public function column_tkts_sold(EE_Event $item)
476
+	{
477
+		return EEM_Ticket::instance()->sum(array(array('Datetime.EVT_ID' => $item->ID())), 'TKT_sold');
478
+	}
479
+
480
+
481
+
482
+	/**
483
+	 * @param EE_Event $item
484
+	 * @return string
485
+	 * @throws EE_Error
486
+	 * @throws InvalidArgumentException
487
+	 * @throws InvalidDataTypeException
488
+	 * @throws InvalidInterfaceException
489
+	 */
490
+	public function column_actions(EE_Event $item)
491
+	{
492
+		//todo: remove when attendees is active
493
+		if (! defined('REG_ADMIN_URL')) {
494
+			define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
495
+		}
496
+		$action_links = array();
497
+		$view_link = get_permalink($item->ID());
498
+		$action_links[] = '<a href="' . $view_link . '"'
499
+						 . ' title="' . esc_attr__('View Event', 'event_espresso') . '" target="_blank">';
500
+		$action_links[] = '<div class="dashicons dashicons-search"></div></a>';
501
+		if (EE_Registry::instance()->CAP->current_user_can(
502
+			'ee_edit_event',
503
+			'espresso_events_edit',
504
+			$item->ID()
505
+		)) {
506
+			$edit_query_args = array(
507
+				'action' => 'edit',
508
+				'post'   => $item->ID(),
509
+			);
510
+			$edit_link = EE_Admin_Page::add_query_args_and_nonce($edit_query_args, EVENTS_ADMIN_URL);
511
+			$action_links[] = '<a href="' . $edit_link . '"'
512
+							 . ' title="' . esc_attr__('Edit Event', 'event_espresso') . '">'
513
+							 . '<div class="ee-icon ee-icon-calendar-edit"></div>'
514
+							 . '</a>';
515
+		}
516
+		if (
517
+			EE_Registry::instance()->CAP->current_user_can(
518
+				'ee_read_registrations',
519
+				'espresso_registrations_view_registration'
520
+			) && EE_Registry::instance()->CAP->current_user_can(
521
+				'ee_read_event',
522
+				'espresso_registrations_view_registration',
523
+				$item->ID()
524
+			)
525
+		) {
526
+			$attendees_query_args = array(
527
+				'action'   => 'default',
528
+				'event_id' => $item->ID(),
529
+			);
530
+			$attendees_link = EE_Admin_Page::add_query_args_and_nonce($attendees_query_args, REG_ADMIN_URL);
531
+			$action_links[] = '<a href="' . $attendees_link . '"'
532
+							 . ' title="' . esc_attr__('View Registrants', 'event_espresso') . '">'
533
+							 . '<div class="dashicons dashicons-groups"></div>'
534
+							 . '</a>';
535
+		}
536
+		$action_links = apply_filters(
537
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
538
+			$action_links,
539
+			$item
540
+		);
541
+		return $this->_action_string(
542
+			implode("\n\t", $action_links),
543
+			$item,
544
+			'div'
545
+		);
546
+	}
547 547
 }
Please login to merge, or discard this patch.
core/libraries/form_sections/form_handlers/FormHandler.php 1 patch
Indentation   +643 added lines, -643 removed lines patch added patch discarded remove patch
@@ -15,7 +15,7 @@  discard block
 block discarded – undo
15 15
 use EventEspresso\core\exceptions\InvalidFormSubmissionException;
16 16
 
17 17
 if (! defined('EVENT_ESPRESSO_VERSION')) {
18
-    exit('No direct script access allowed');
18
+	exit('No direct script access allowed');
19 19
 }
20 20
 
21 21
 
@@ -34,648 +34,648 @@  discard block
 block discarded – undo
34 34
 abstract class FormHandler implements FormHandlerInterface
35 35
 {
36 36
 
37
-    /**
38
-     * will add opening and closing HTML form tags as well as a submit button
39
-     */
40
-    const ADD_FORM_TAGS_AND_SUBMIT = 'add_form_tags_and_submit';
41
-
42
-    /**
43
-     * will add opening and closing HTML form tags but NOT a submit button
44
-     */
45
-    const ADD_FORM_TAGS_ONLY = 'add_form_tags_only';
46
-
47
-    /**
48
-     * will NOT add opening and closing HTML form tags but will add a submit button
49
-     */
50
-    const ADD_FORM_SUBMIT_ONLY = 'add_form_submit_only';
51
-
52
-    /**
53
-     * will NOT add opening and closing HTML form tags NOR a submit button
54
-     */
55
-    const DO_NOT_SETUP_FORM = 'do_not_setup_form';
56
-
57
-    /**
58
-     * if set to false, then this form has no displayable content,
59
-     * and will only be used for processing data sent passed via GET or POST
60
-     * defaults to true ( ie: form has displayable content )
61
-     *
62
-     * @var boolean $displayable
63
-     */
64
-    private $displayable = true;
65
-
66
-    /**
67
-     * @var string $form_name
68
-     */
69
-    private $form_name;
70
-
71
-    /**
72
-     * @var string $admin_name
73
-     */
74
-    private $admin_name;
75
-
76
-    /**
77
-     * @var string $slug
78
-     */
79
-    private $slug;
80
-
81
-    /**
82
-     * @var string $submit_btn_text
83
-     */
84
-    private $submit_btn_text;
85
-
86
-    /**
87
-     * @var string $form_action
88
-     */
89
-    private $form_action;
90
-
91
-    /**
92
-     * form params in key value pairs
93
-     * can be added to form action URL or as hidden inputs
94
-     *
95
-     * @var array $form_args
96
-     */
97
-    private $form_args = array();
98
-
99
-    /**
100
-     * value of one of the string constant above
101
-     *
102
-     * @var string $form_config
103
-     */
104
-    private $form_config;
105
-
106
-    /**
107
-     * whether or not the form was determined to be invalid
108
-     *
109
-     * @var boolean $form_has_errors
110
-     */
111
-    private $form_has_errors;
112
-
113
-    /**
114
-     * the absolute top level form section being used on the page
115
-     *
116
-     * @var EE_Form_Section_Proper $form
117
-     */
118
-    private $form;
119
-
120
-    /**
121
-     * @var EE_Registry $registry
122
-     */
123
-    protected $registry;
124
-
125
-
126
-
127
-    /**
128
-     * Form constructor.
129
-     *
130
-     * @param string      $form_name
131
-     * @param string      $admin_name
132
-     * @param string      $slug
133
-     * @param string      $form_action
134
-     * @param string      $form_config
135
-     * @param EE_Registry $registry
136
-     * @throws InvalidDataTypeException
137
-     * @throws DomainException
138
-     * @throws InvalidArgumentException
139
-     */
140
-    public function __construct(
141
-        $form_name,
142
-        $admin_name,
143
-        $slug,
144
-        $form_action = '',
145
-        $form_config = FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
146
-        EE_Registry $registry
147
-    ) {
148
-        $this->setFormName($form_name);
149
-        $this->setAdminName($admin_name);
150
-        $this->setSlug($slug);
151
-        $this->setFormAction($form_action);
152
-        $this->setFormConfig($form_config);
153
-        $this->setSubmitBtnText(esc_html__('Submit', 'event_espresso'));
154
-        $this->registry = $registry;
155
-    }
156
-
157
-
158
-
159
-    /**
160
-     * @return array
161
-     */
162
-    public static function getFormConfigConstants()
163
-    {
164
-        return array(
165
-            FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
166
-            FormHandler::ADD_FORM_TAGS_ONLY,
167
-            FormHandler::ADD_FORM_SUBMIT_ONLY,
168
-            FormHandler::DO_NOT_SETUP_FORM,
169
-        );
170
-    }
171
-
172
-
173
-
174
-    /**
175
-     * @param bool $for_display
176
-     * @return EE_Form_Section_Proper
177
-     * @throws EE_Error
178
-     * @throws LogicException
179
-     */
180
-    public function form($for_display = false)
181
-    {
182
-        if (! $this->formIsValid()) {
183
-            return null;
184
-        }
185
-        if ($for_display) {
186
-            $form_config = $this->formConfig();
187
-            if (
188
-                $form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
189
-                || $form_config === FormHandler::ADD_FORM_SUBMIT_ONLY
190
-            ) {
191
-                $this->appendSubmitButton();
192
-                $this->clearFormButtonFloats();
193
-            }
194
-        }
195
-        return $this->form;
196
-    }
197
-
198
-
199
-
200
-    /**
201
-     * @return boolean
202
-     * @throws LogicException
203
-     */
204
-    public function formIsValid()
205
-    {
206
-        if ($this->form instanceof EE_Form_Section_Proper) {
207
-            return true;
208
-        }
209
-        $form = apply_filters(
210
-            'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__formIsValid__generated_form_object',
211
-            $this->generate(),
212
-            $this
213
-        );
214
-        if ($this->verifyForm($form)) {
215
-            $this->setForm($form);
216
-        }
217
-        return true;
218
-    }
219
-
220
-
221
-
222
-    /**
223
-     * @param EE_Form_Section_Proper|null $form
224
-     * @return bool
225
-     * @throws LogicException
226
-     */
227
-    public function verifyForm(EE_Form_Section_Proper $form = null)
228
-    {
229
-        $form = $form !== null ? $form : $this->form;
230
-        if ($form instanceof EE_Form_Section_Proper) {
231
-            return true;
232
-        }
233
-        throw new LogicException(
234
-            sprintf(
235
-                esc_html__('The "%1$s" form is invalid or missing. %2$s', 'event_espresso'),
236
-                $this->form_name,
237
-                var_export($form, true)
238
-            )
239
-        );
240
-    }
241
-
242
-
243
-
244
-    /**
245
-     * @param EE_Form_Section_Proper $form
246
-     */
247
-    public function setForm(EE_Form_Section_Proper $form)
248
-    {
249
-        $this->form = $form;
250
-    }
251
-
252
-
253
-
254
-    /**
255
-     * @return boolean
256
-     */
257
-    public function displayable()
258
-    {
259
-        return $this->displayable;
260
-    }
261
-
262
-
263
-
264
-    /**
265
-     * @param boolean $displayable
266
-     */
267
-    public function setDisplayable($displayable = false)
268
-    {
269
-        $this->displayable = filter_var($displayable, FILTER_VALIDATE_BOOLEAN);
270
-    }
271
-
272
-
273
-
274
-    /**
275
-     * a public name for the form that can be displayed on the frontend of a site
276
-     *
277
-     * @return string
278
-     */
279
-    public function formName()
280
-    {
281
-        return $this->form_name;
282
-    }
283
-
284
-
285
-
286
-    /**
287
-     * @param string $form_name
288
-     * @throws InvalidDataTypeException
289
-     */
290
-    public function setFormName($form_name)
291
-    {
292
-        if (! is_string($form_name)) {
293
-            throw new InvalidDataTypeException('$form_name', $form_name, 'string');
294
-        }
295
-        $this->form_name = $form_name;
296
-    }
297
-
298
-
299
-
300
-    /**
301
-     * a public name for the form that can be displayed, but only in the admin
302
-     *
303
-     * @return string
304
-     */
305
-    public function adminName()
306
-    {
307
-        return $this->admin_name;
308
-    }
309
-
310
-
311
-
312
-    /**
313
-     * @param string $admin_name
314
-     * @throws InvalidDataTypeException
315
-     */
316
-    public function setAdminName($admin_name)
317
-    {
318
-        if (! is_string($admin_name)) {
319
-            throw new InvalidDataTypeException('$admin_name', $admin_name, 'string');
320
-        }
321
-        $this->admin_name = $admin_name;
322
-    }
323
-
324
-
325
-
326
-    /**
327
-     * a URL friendly string that can be used for identifying the form
328
-     *
329
-     * @return string
330
-     */
331
-    public function slug()
332
-    {
333
-        return $this->slug;
334
-    }
335
-
336
-
337
-
338
-    /**
339
-     * @param string $slug
340
-     * @throws InvalidDataTypeException
341
-     */
342
-    public function setSlug($slug)
343
-    {
344
-        if (! is_string($slug)) {
345
-            throw new InvalidDataTypeException('$slug', $slug, 'string');
346
-        }
347
-        $this->slug = $slug;
348
-    }
349
-
350
-
351
-
352
-    /**
353
-     * @return string
354
-     */
355
-    public function submitBtnText()
356
-    {
357
-        return $this->submit_btn_text;
358
-    }
359
-
360
-
361
-
362
-    /**
363
-     * @param string $submit_btn_text
364
-     * @throws InvalidDataTypeException
365
-     * @throws InvalidArgumentException
366
-     */
367
-    public function setSubmitBtnText($submit_btn_text)
368
-    {
369
-        if (! is_string($submit_btn_text)) {
370
-            throw new InvalidDataTypeException('$submit_btn_text', $submit_btn_text, 'string');
371
-        }
372
-        if (empty($submit_btn_text)) {
373
-            throw new InvalidArgumentException(
374
-                esc_html__('Can not set Submit button text because an empty string was provided.', 'event_espresso')
375
-            );
376
-        }
377
-        $this->submit_btn_text = $submit_btn_text;
378
-    }
379
-
380
-
381
-
382
-    /**
383
-     * @return string
384
-     */
385
-    public function formAction()
386
-    {
387
-        return ! empty($this->form_args)
388
-            ? add_query_arg($this->form_args, $this->form_action)
389
-            : $this->form_action;
390
-    }
391
-
392
-
393
-
394
-    /**
395
-     * @param string $form_action
396
-     * @throws InvalidDataTypeException
397
-     */
398
-    public function setFormAction($form_action)
399
-    {
400
-        if (! is_string($form_action)) {
401
-            throw new InvalidDataTypeException('$form_action', $form_action, 'string');
402
-        }
403
-        $this->form_action = $form_action;
404
-    }
405
-
406
-
407
-
408
-    /**
409
-     * @param array $form_args
410
-     * @throws InvalidDataTypeException
411
-     * @throws InvalidArgumentException
412
-     */
413
-    public function addFormActionArgs($form_args = array())
414
-    {
415
-        if (is_object($form_args)) {
416
-            throw new InvalidDataTypeException(
417
-                '$form_args',
418
-                $form_args,
419
-                'anything other than an object was expected.'
420
-            );
421
-        }
422
-        if (empty($form_args)) {
423
-            throw new InvalidArgumentException(
424
-                esc_html__('The redirect arguments can not be an empty array.', 'event_espresso')
425
-            );
426
-        }
427
-        $this->form_args = array_merge($this->form_args, $form_args);
428
-    }
429
-
430
-
431
-
432
-    /**
433
-     * @return string
434
-     */
435
-    public function formConfig()
436
-    {
437
-        return $this->form_config;
438
-    }
439
-
440
-
441
-
442
-    /**
443
-     * @param string $form_config
444
-     * @throws DomainException
445
-     */
446
-    public function setFormConfig($form_config)
447
-    {
448
-        if (
449
-        ! in_array(
450
-            $form_config,
451
-            array(
452
-                FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
453
-                FormHandler::ADD_FORM_TAGS_ONLY,
454
-                FormHandler::ADD_FORM_SUBMIT_ONLY,
455
-                FormHandler::DO_NOT_SETUP_FORM,
456
-            ),
457
-            true
458
-        )
459
-        ) {
460
-            throw new DomainException(
461
-                sprintf(
462
-                    esc_html__('"%1$s" is not a valid value for the form config. Please use one of the class constants on \EventEspresso\core\libraries\form_sections\form_handlers\Form',
463
-                        'event_espresso'),
464
-                    $form_config
465
-                )
466
-            );
467
-        }
468
-        $this->form_config = $form_config;
469
-    }
470
-
471
-
472
-
473
-    /**
474
-     * called after the form is instantiated
475
-     * and used for performing any logic that needs to occur early
476
-     * before any of the other methods are called.
477
-     * returns true if everything is ok to proceed,
478
-     * and false if no further form logic should be implemented
479
-     *
480
-     * @return boolean
481
-     */
482
-    public function initialize()
483
-    {
484
-        $this->form_has_errors = EE_Error::has_error(true);
485
-        return true;
486
-    }
487
-
488
-
489
-
490
-    /**
491
-     * used for setting up css and js
492
-     *
493
-     * @return void
494
-     * @throws LogicException
495
-     * @throws EE_Error
496
-     */
497
-    public function enqueueStylesAndScripts()
498
-    {
499
-        $this->form()->enqueue_js();
500
-    }
501
-
502
-
503
-
504
-    /**
505
-     * creates and returns the actual form
506
-     *
507
-     * @return EE_Form_Section_Proper
508
-     */
509
-    abstract public function generate();
510
-
511
-
512
-
513
-    /**
514
-     * creates and returns an EE_Submit_Input labeled "Submit"
515
-     *
516
-     * @param string $text
517
-     * @return EE_Submit_Input
518
-     */
519
-    public function generateSubmitButton($text = '')
520
-    {
521
-        $text = ! empty($text) ? $text : $this->submitBtnText();
522
-        return new EE_Submit_Input(
523
-            array(
524
-                'html_name'             => 'ee-form-submit-' . $this->slug(),
525
-                'html_id'               => 'ee-form-submit-' . $this->slug(),
526
-                'html_class'            => 'ee-form-submit',
527
-                'html_label'            => '&nbsp;',
528
-                'other_html_attributes' => ' rel="' . $this->slug() . '"',
529
-                'default'               => $text,
530
-            )
531
-        );
532
-    }
533
-
534
-
535
-
536
-    /**
537
-     * calls generateSubmitButton() and appends it onto the form along with a float clearing div
538
-     *
539
-     * @param string $text
540
-     * @return void
541
-     * @throws EE_Error
542
-     */
543
-    public function appendSubmitButton($text = '')
544
-    {
545
-        if ($this->form->subsection_exists($this->slug() . '-submit-btn')) {
546
-            return;
547
-        }
548
-        $this->form->add_subsections(
549
-            array($this->slug() . '-submit-btn' => $this->generateSubmitButton($text)),
550
-            null,
551
-            false
552
-        );
553
-    }
554
-
555
-
556
-
557
-    /**
558
-     * creates and returns an EE_Submit_Input labeled "Cancel"
559
-     *
560
-     * @param string $text
561
-     * @return EE_Submit_Input
562
-     */
563
-    public function generateCancelButton($text = '')
564
-    {
565
-        $cancel_button = new EE_Submit_Input(
566
-            array(
567
-                'html_name'             => 'ee-form-submit-' . $this->slug(), // YES! Same name as submit !!!
568
-                'html_id'               => 'ee-cancel-form-' . $this->slug(),
569
-                'html_class'            => 'ee-cancel-form',
570
-                'html_label'            => '&nbsp;',
571
-                'other_html_attributes' => ' rel="' . $this->slug() . '"',
572
-                'default'               => ! empty($text) ? $text : esc_html__('Cancel', 'event_espresso'),
573
-            )
574
-        );
575
-        $cancel_button->set_button_css_attributes(false);
576
-        return $cancel_button;
577
-    }
578
-
579
-
580
-
581
-    /**
582
-     * appends a float clearing div onto end of form
583
-     *
584
-     * @return void
585
-     * @throws EE_Error
586
-     */
587
-    public function clearFormButtonFloats()
588
-    {
589
-        $this->form->add_subsections(
590
-            array(
591
-                'clear-submit-btn-float' => new EE_Form_Section_HTML(
592
-                    EEH_HTML::div('', '', 'clear-float') . EEH_HTML::divx()
593
-                ),
594
-            ),
595
-            null,
596
-            false
597
-        );
598
-    }
599
-
600
-
601
-    /**
602
-     * takes the generated form and displays it along with ony other non-form HTML that may be required
603
-     * returns a string of HTML that can be directly echoed in a template
604
-     *
605
-     * @return string
606
-     * @throws \InvalidArgumentException
607
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
608
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
609
-     * @throws LogicException
610
-     * @throws EE_Error
611
-     */
612
-    public function display()
613
-    {
614
-        $form_html = apply_filters(
615
-            'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__before_form',
616
-            ''
617
-        );
618
-        $form_config = $this->formConfig();
619
-        if (
620
-            $form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
621
-            || $form_config === FormHandler::ADD_FORM_TAGS_ONLY
622
-        ) {
623
-            $form_html .= $this->form()->form_open($this->formAction());
624
-        }
625
-        $form_html .= $this->form(true)->get_html($this->form_has_errors);
626
-        if (
627
-            $form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
628
-            || $form_config === FormHandler::ADD_FORM_TAGS_ONLY
629
-        ) {
630
-            $form_html .= $this->form()->form_close();
631
-        }
632
-        $form_html .= apply_filters(
633
-            'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__after_form',
634
-            ''
635
-        );
636
-        return $form_html;
637
-    }
638
-
639
-
640
-    /**
641
-     * handles processing the form submission
642
-     * returns true or false depending on whether the form was processed successfully or not
643
-     *
644
-     * @param array $submitted_form_data
645
-     * @return array
646
-     * @throws \InvalidArgumentException
647
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
648
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
649
-     * @throws EE_Error
650
-     * @throws LogicException
651
-     * @throws InvalidFormSubmissionException
652
-     */
653
-    public function process($submitted_form_data = array())
654
-    {
655
-        if (! $this->form()->was_submitted($submitted_form_data)) {
656
-            throw new InvalidFormSubmissionException($this->form_name);
657
-        }
658
-        $this->form(true)->receive_form_submission($submitted_form_data);
659
-        if (! $this->form()->is_valid()) {
660
-            throw new InvalidFormSubmissionException(
661
-                $this->form_name,
662
-                sprintf(
663
-                    esc_html__(
664
-                        'The "%1$s" form is invalid. Please correct the following errors and resubmit: %2$s %3$s',
665
-                        'event_espresso'
666
-                    ),
667
-                    $this->form_name,
668
-                    '<br />',
669
-                    implode('<br />', $this->form()->get_validation_errors_accumulated())
670
-                )
671
-            );
672
-        }
673
-        return apply_filters(
674
-            'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__process__valid_data',
675
-            $this->form()->valid_data(),
676
-            $this
677
-        );
678
-    }
37
+	/**
38
+	 * will add opening and closing HTML form tags as well as a submit button
39
+	 */
40
+	const ADD_FORM_TAGS_AND_SUBMIT = 'add_form_tags_and_submit';
41
+
42
+	/**
43
+	 * will add opening and closing HTML form tags but NOT a submit button
44
+	 */
45
+	const ADD_FORM_TAGS_ONLY = 'add_form_tags_only';
46
+
47
+	/**
48
+	 * will NOT add opening and closing HTML form tags but will add a submit button
49
+	 */
50
+	const ADD_FORM_SUBMIT_ONLY = 'add_form_submit_only';
51
+
52
+	/**
53
+	 * will NOT add opening and closing HTML form tags NOR a submit button
54
+	 */
55
+	const DO_NOT_SETUP_FORM = 'do_not_setup_form';
56
+
57
+	/**
58
+	 * if set to false, then this form has no displayable content,
59
+	 * and will only be used for processing data sent passed via GET or POST
60
+	 * defaults to true ( ie: form has displayable content )
61
+	 *
62
+	 * @var boolean $displayable
63
+	 */
64
+	private $displayable = true;
65
+
66
+	/**
67
+	 * @var string $form_name
68
+	 */
69
+	private $form_name;
70
+
71
+	/**
72
+	 * @var string $admin_name
73
+	 */
74
+	private $admin_name;
75
+
76
+	/**
77
+	 * @var string $slug
78
+	 */
79
+	private $slug;
80
+
81
+	/**
82
+	 * @var string $submit_btn_text
83
+	 */
84
+	private $submit_btn_text;
85
+
86
+	/**
87
+	 * @var string $form_action
88
+	 */
89
+	private $form_action;
90
+
91
+	/**
92
+	 * form params in key value pairs
93
+	 * can be added to form action URL or as hidden inputs
94
+	 *
95
+	 * @var array $form_args
96
+	 */
97
+	private $form_args = array();
98
+
99
+	/**
100
+	 * value of one of the string constant above
101
+	 *
102
+	 * @var string $form_config
103
+	 */
104
+	private $form_config;
105
+
106
+	/**
107
+	 * whether or not the form was determined to be invalid
108
+	 *
109
+	 * @var boolean $form_has_errors
110
+	 */
111
+	private $form_has_errors;
112
+
113
+	/**
114
+	 * the absolute top level form section being used on the page
115
+	 *
116
+	 * @var EE_Form_Section_Proper $form
117
+	 */
118
+	private $form;
119
+
120
+	/**
121
+	 * @var EE_Registry $registry
122
+	 */
123
+	protected $registry;
124
+
125
+
126
+
127
+	/**
128
+	 * Form constructor.
129
+	 *
130
+	 * @param string      $form_name
131
+	 * @param string      $admin_name
132
+	 * @param string      $slug
133
+	 * @param string      $form_action
134
+	 * @param string      $form_config
135
+	 * @param EE_Registry $registry
136
+	 * @throws InvalidDataTypeException
137
+	 * @throws DomainException
138
+	 * @throws InvalidArgumentException
139
+	 */
140
+	public function __construct(
141
+		$form_name,
142
+		$admin_name,
143
+		$slug,
144
+		$form_action = '',
145
+		$form_config = FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
146
+		EE_Registry $registry
147
+	) {
148
+		$this->setFormName($form_name);
149
+		$this->setAdminName($admin_name);
150
+		$this->setSlug($slug);
151
+		$this->setFormAction($form_action);
152
+		$this->setFormConfig($form_config);
153
+		$this->setSubmitBtnText(esc_html__('Submit', 'event_espresso'));
154
+		$this->registry = $registry;
155
+	}
156
+
157
+
158
+
159
+	/**
160
+	 * @return array
161
+	 */
162
+	public static function getFormConfigConstants()
163
+	{
164
+		return array(
165
+			FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
166
+			FormHandler::ADD_FORM_TAGS_ONLY,
167
+			FormHandler::ADD_FORM_SUBMIT_ONLY,
168
+			FormHandler::DO_NOT_SETUP_FORM,
169
+		);
170
+	}
171
+
172
+
173
+
174
+	/**
175
+	 * @param bool $for_display
176
+	 * @return EE_Form_Section_Proper
177
+	 * @throws EE_Error
178
+	 * @throws LogicException
179
+	 */
180
+	public function form($for_display = false)
181
+	{
182
+		if (! $this->formIsValid()) {
183
+			return null;
184
+		}
185
+		if ($for_display) {
186
+			$form_config = $this->formConfig();
187
+			if (
188
+				$form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
189
+				|| $form_config === FormHandler::ADD_FORM_SUBMIT_ONLY
190
+			) {
191
+				$this->appendSubmitButton();
192
+				$this->clearFormButtonFloats();
193
+			}
194
+		}
195
+		return $this->form;
196
+	}
197
+
198
+
199
+
200
+	/**
201
+	 * @return boolean
202
+	 * @throws LogicException
203
+	 */
204
+	public function formIsValid()
205
+	{
206
+		if ($this->form instanceof EE_Form_Section_Proper) {
207
+			return true;
208
+		}
209
+		$form = apply_filters(
210
+			'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__formIsValid__generated_form_object',
211
+			$this->generate(),
212
+			$this
213
+		);
214
+		if ($this->verifyForm($form)) {
215
+			$this->setForm($form);
216
+		}
217
+		return true;
218
+	}
219
+
220
+
221
+
222
+	/**
223
+	 * @param EE_Form_Section_Proper|null $form
224
+	 * @return bool
225
+	 * @throws LogicException
226
+	 */
227
+	public function verifyForm(EE_Form_Section_Proper $form = null)
228
+	{
229
+		$form = $form !== null ? $form : $this->form;
230
+		if ($form instanceof EE_Form_Section_Proper) {
231
+			return true;
232
+		}
233
+		throw new LogicException(
234
+			sprintf(
235
+				esc_html__('The "%1$s" form is invalid or missing. %2$s', 'event_espresso'),
236
+				$this->form_name,
237
+				var_export($form, true)
238
+			)
239
+		);
240
+	}
241
+
242
+
243
+
244
+	/**
245
+	 * @param EE_Form_Section_Proper $form
246
+	 */
247
+	public function setForm(EE_Form_Section_Proper $form)
248
+	{
249
+		$this->form = $form;
250
+	}
251
+
252
+
253
+
254
+	/**
255
+	 * @return boolean
256
+	 */
257
+	public function displayable()
258
+	{
259
+		return $this->displayable;
260
+	}
261
+
262
+
263
+
264
+	/**
265
+	 * @param boolean $displayable
266
+	 */
267
+	public function setDisplayable($displayable = false)
268
+	{
269
+		$this->displayable = filter_var($displayable, FILTER_VALIDATE_BOOLEAN);
270
+	}
271
+
272
+
273
+
274
+	/**
275
+	 * a public name for the form that can be displayed on the frontend of a site
276
+	 *
277
+	 * @return string
278
+	 */
279
+	public function formName()
280
+	{
281
+		return $this->form_name;
282
+	}
283
+
284
+
285
+
286
+	/**
287
+	 * @param string $form_name
288
+	 * @throws InvalidDataTypeException
289
+	 */
290
+	public function setFormName($form_name)
291
+	{
292
+		if (! is_string($form_name)) {
293
+			throw new InvalidDataTypeException('$form_name', $form_name, 'string');
294
+		}
295
+		$this->form_name = $form_name;
296
+	}
297
+
298
+
299
+
300
+	/**
301
+	 * a public name for the form that can be displayed, but only in the admin
302
+	 *
303
+	 * @return string
304
+	 */
305
+	public function adminName()
306
+	{
307
+		return $this->admin_name;
308
+	}
309
+
310
+
311
+
312
+	/**
313
+	 * @param string $admin_name
314
+	 * @throws InvalidDataTypeException
315
+	 */
316
+	public function setAdminName($admin_name)
317
+	{
318
+		if (! is_string($admin_name)) {
319
+			throw new InvalidDataTypeException('$admin_name', $admin_name, 'string');
320
+		}
321
+		$this->admin_name = $admin_name;
322
+	}
323
+
324
+
325
+
326
+	/**
327
+	 * a URL friendly string that can be used for identifying the form
328
+	 *
329
+	 * @return string
330
+	 */
331
+	public function slug()
332
+	{
333
+		return $this->slug;
334
+	}
335
+
336
+
337
+
338
+	/**
339
+	 * @param string $slug
340
+	 * @throws InvalidDataTypeException
341
+	 */
342
+	public function setSlug($slug)
343
+	{
344
+		if (! is_string($slug)) {
345
+			throw new InvalidDataTypeException('$slug', $slug, 'string');
346
+		}
347
+		$this->slug = $slug;
348
+	}
349
+
350
+
351
+
352
+	/**
353
+	 * @return string
354
+	 */
355
+	public function submitBtnText()
356
+	{
357
+		return $this->submit_btn_text;
358
+	}
359
+
360
+
361
+
362
+	/**
363
+	 * @param string $submit_btn_text
364
+	 * @throws InvalidDataTypeException
365
+	 * @throws InvalidArgumentException
366
+	 */
367
+	public function setSubmitBtnText($submit_btn_text)
368
+	{
369
+		if (! is_string($submit_btn_text)) {
370
+			throw new InvalidDataTypeException('$submit_btn_text', $submit_btn_text, 'string');
371
+		}
372
+		if (empty($submit_btn_text)) {
373
+			throw new InvalidArgumentException(
374
+				esc_html__('Can not set Submit button text because an empty string was provided.', 'event_espresso')
375
+			);
376
+		}
377
+		$this->submit_btn_text = $submit_btn_text;
378
+	}
379
+
380
+
381
+
382
+	/**
383
+	 * @return string
384
+	 */
385
+	public function formAction()
386
+	{
387
+		return ! empty($this->form_args)
388
+			? add_query_arg($this->form_args, $this->form_action)
389
+			: $this->form_action;
390
+	}
391
+
392
+
393
+
394
+	/**
395
+	 * @param string $form_action
396
+	 * @throws InvalidDataTypeException
397
+	 */
398
+	public function setFormAction($form_action)
399
+	{
400
+		if (! is_string($form_action)) {
401
+			throw new InvalidDataTypeException('$form_action', $form_action, 'string');
402
+		}
403
+		$this->form_action = $form_action;
404
+	}
405
+
406
+
407
+
408
+	/**
409
+	 * @param array $form_args
410
+	 * @throws InvalidDataTypeException
411
+	 * @throws InvalidArgumentException
412
+	 */
413
+	public function addFormActionArgs($form_args = array())
414
+	{
415
+		if (is_object($form_args)) {
416
+			throw new InvalidDataTypeException(
417
+				'$form_args',
418
+				$form_args,
419
+				'anything other than an object was expected.'
420
+			);
421
+		}
422
+		if (empty($form_args)) {
423
+			throw new InvalidArgumentException(
424
+				esc_html__('The redirect arguments can not be an empty array.', 'event_espresso')
425
+			);
426
+		}
427
+		$this->form_args = array_merge($this->form_args, $form_args);
428
+	}
429
+
430
+
431
+
432
+	/**
433
+	 * @return string
434
+	 */
435
+	public function formConfig()
436
+	{
437
+		return $this->form_config;
438
+	}
439
+
440
+
441
+
442
+	/**
443
+	 * @param string $form_config
444
+	 * @throws DomainException
445
+	 */
446
+	public function setFormConfig($form_config)
447
+	{
448
+		if (
449
+		! in_array(
450
+			$form_config,
451
+			array(
452
+				FormHandler::ADD_FORM_TAGS_AND_SUBMIT,
453
+				FormHandler::ADD_FORM_TAGS_ONLY,
454
+				FormHandler::ADD_FORM_SUBMIT_ONLY,
455
+				FormHandler::DO_NOT_SETUP_FORM,
456
+			),
457
+			true
458
+		)
459
+		) {
460
+			throw new DomainException(
461
+				sprintf(
462
+					esc_html__('"%1$s" is not a valid value for the form config. Please use one of the class constants on \EventEspresso\core\libraries\form_sections\form_handlers\Form',
463
+						'event_espresso'),
464
+					$form_config
465
+				)
466
+			);
467
+		}
468
+		$this->form_config = $form_config;
469
+	}
470
+
471
+
472
+
473
+	/**
474
+	 * called after the form is instantiated
475
+	 * and used for performing any logic that needs to occur early
476
+	 * before any of the other methods are called.
477
+	 * returns true if everything is ok to proceed,
478
+	 * and false if no further form logic should be implemented
479
+	 *
480
+	 * @return boolean
481
+	 */
482
+	public function initialize()
483
+	{
484
+		$this->form_has_errors = EE_Error::has_error(true);
485
+		return true;
486
+	}
487
+
488
+
489
+
490
+	/**
491
+	 * used for setting up css and js
492
+	 *
493
+	 * @return void
494
+	 * @throws LogicException
495
+	 * @throws EE_Error
496
+	 */
497
+	public function enqueueStylesAndScripts()
498
+	{
499
+		$this->form()->enqueue_js();
500
+	}
501
+
502
+
503
+
504
+	/**
505
+	 * creates and returns the actual form
506
+	 *
507
+	 * @return EE_Form_Section_Proper
508
+	 */
509
+	abstract public function generate();
510
+
511
+
512
+
513
+	/**
514
+	 * creates and returns an EE_Submit_Input labeled "Submit"
515
+	 *
516
+	 * @param string $text
517
+	 * @return EE_Submit_Input
518
+	 */
519
+	public function generateSubmitButton($text = '')
520
+	{
521
+		$text = ! empty($text) ? $text : $this->submitBtnText();
522
+		return new EE_Submit_Input(
523
+			array(
524
+				'html_name'             => 'ee-form-submit-' . $this->slug(),
525
+				'html_id'               => 'ee-form-submit-' . $this->slug(),
526
+				'html_class'            => 'ee-form-submit',
527
+				'html_label'            => '&nbsp;',
528
+				'other_html_attributes' => ' rel="' . $this->slug() . '"',
529
+				'default'               => $text,
530
+			)
531
+		);
532
+	}
533
+
534
+
535
+
536
+	/**
537
+	 * calls generateSubmitButton() and appends it onto the form along with a float clearing div
538
+	 *
539
+	 * @param string $text
540
+	 * @return void
541
+	 * @throws EE_Error
542
+	 */
543
+	public function appendSubmitButton($text = '')
544
+	{
545
+		if ($this->form->subsection_exists($this->slug() . '-submit-btn')) {
546
+			return;
547
+		}
548
+		$this->form->add_subsections(
549
+			array($this->slug() . '-submit-btn' => $this->generateSubmitButton($text)),
550
+			null,
551
+			false
552
+		);
553
+	}
554
+
555
+
556
+
557
+	/**
558
+	 * creates and returns an EE_Submit_Input labeled "Cancel"
559
+	 *
560
+	 * @param string $text
561
+	 * @return EE_Submit_Input
562
+	 */
563
+	public function generateCancelButton($text = '')
564
+	{
565
+		$cancel_button = new EE_Submit_Input(
566
+			array(
567
+				'html_name'             => 'ee-form-submit-' . $this->slug(), // YES! Same name as submit !!!
568
+				'html_id'               => 'ee-cancel-form-' . $this->slug(),
569
+				'html_class'            => 'ee-cancel-form',
570
+				'html_label'            => '&nbsp;',
571
+				'other_html_attributes' => ' rel="' . $this->slug() . '"',
572
+				'default'               => ! empty($text) ? $text : esc_html__('Cancel', 'event_espresso'),
573
+			)
574
+		);
575
+		$cancel_button->set_button_css_attributes(false);
576
+		return $cancel_button;
577
+	}
578
+
579
+
580
+
581
+	/**
582
+	 * appends a float clearing div onto end of form
583
+	 *
584
+	 * @return void
585
+	 * @throws EE_Error
586
+	 */
587
+	public function clearFormButtonFloats()
588
+	{
589
+		$this->form->add_subsections(
590
+			array(
591
+				'clear-submit-btn-float' => new EE_Form_Section_HTML(
592
+					EEH_HTML::div('', '', 'clear-float') . EEH_HTML::divx()
593
+				),
594
+			),
595
+			null,
596
+			false
597
+		);
598
+	}
599
+
600
+
601
+	/**
602
+	 * takes the generated form and displays it along with ony other non-form HTML that may be required
603
+	 * returns a string of HTML that can be directly echoed in a template
604
+	 *
605
+	 * @return string
606
+	 * @throws \InvalidArgumentException
607
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
608
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
609
+	 * @throws LogicException
610
+	 * @throws EE_Error
611
+	 */
612
+	public function display()
613
+	{
614
+		$form_html = apply_filters(
615
+			'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__before_form',
616
+			''
617
+		);
618
+		$form_config = $this->formConfig();
619
+		if (
620
+			$form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
621
+			|| $form_config === FormHandler::ADD_FORM_TAGS_ONLY
622
+		) {
623
+			$form_html .= $this->form()->form_open($this->formAction());
624
+		}
625
+		$form_html .= $this->form(true)->get_html($this->form_has_errors);
626
+		if (
627
+			$form_config === FormHandler::ADD_FORM_TAGS_AND_SUBMIT
628
+			|| $form_config === FormHandler::ADD_FORM_TAGS_ONLY
629
+		) {
630
+			$form_html .= $this->form()->form_close();
631
+		}
632
+		$form_html .= apply_filters(
633
+			'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__display__after_form',
634
+			''
635
+		);
636
+		return $form_html;
637
+	}
638
+
639
+
640
+	/**
641
+	 * handles processing the form submission
642
+	 * returns true or false depending on whether the form was processed successfully or not
643
+	 *
644
+	 * @param array $submitted_form_data
645
+	 * @return array
646
+	 * @throws \InvalidArgumentException
647
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
648
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
649
+	 * @throws EE_Error
650
+	 * @throws LogicException
651
+	 * @throws InvalidFormSubmissionException
652
+	 */
653
+	public function process($submitted_form_data = array())
654
+	{
655
+		if (! $this->form()->was_submitted($submitted_form_data)) {
656
+			throw new InvalidFormSubmissionException($this->form_name);
657
+		}
658
+		$this->form(true)->receive_form_submission($submitted_form_data);
659
+		if (! $this->form()->is_valid()) {
660
+			throw new InvalidFormSubmissionException(
661
+				$this->form_name,
662
+				sprintf(
663
+					esc_html__(
664
+						'The "%1$s" form is invalid. Please correct the following errors and resubmit: %2$s %3$s',
665
+						'event_espresso'
666
+					),
667
+					$this->form_name,
668
+					'<br />',
669
+					implode('<br />', $this->form()->get_validation_errors_accumulated())
670
+				)
671
+			);
672
+		}
673
+		return apply_filters(
674
+			'FHEE__EventEspresso_core_libraries_form_sections_form_handlers_FormHandler__process__valid_data',
675
+			$this->form()->valid_data(),
676
+			$this
677
+		);
678
+	}
679 679
 
680 680
 
681 681
 
Please login to merge, or discard this patch.
form_sections/strategies/normalization/EE_Null_Normalization.strategy.php 2 patches
Indentation   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if (! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 
5 5
 
@@ -15,26 +15,26 @@  discard block
 block discarded – undo
15 15
 class EE_Null_Normalization extends EE_Normalization_Strategy_Base
16 16
 {
17 17
 
18
-    /**
19
-     * @param string $value_to_normalize
20
-     * @return null
21
-     */
22
-    public function normalize($value_to_normalize)
23
-    {
24
-        return null;
25
-    }
26
-
27
-
28
-
29
-    /**
30
-     * In the form input we need some string, so use a blank one.
31
-     *
32
-     * @param string $normalized_value
33
-     * @return string
34
-     */
35
-    public function unnormalize($normalized_value)
36
-    {
37
-        return '';
38
-    }
18
+	/**
19
+	 * @param string $value_to_normalize
20
+	 * @return null
21
+	 */
22
+	public function normalize($value_to_normalize)
23
+	{
24
+		return null;
25
+	}
26
+
27
+
28
+
29
+	/**
30
+	 * In the form input we need some string, so use a blank one.
31
+	 *
32
+	 * @param string $normalized_value
33
+	 * @return string
34
+	 */
35
+	public function unnormalize($normalized_value)
36
+	{
37
+		return '';
38
+	}
39 39
 
40 40
 }
41 41
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1,4 +1,4 @@
 block discarded – undo
1
-<?php if (! defined('EVENT_ESPRESSO_VERSION')) {
1
+<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2 2
     exit('No direct script access allowed');
3 3
 }
4 4
 
Please login to merge, or discard this patch.