Completed
Branch decaf-fixes/sanitize-all-reque... (b7fe86)
by
unknown
06:39 queued 04:47
created
core/libraries/shortcodes/EE_Messenger_Shortcodes.lib.php 2 patches
Indentation   +149 added lines, -149 removed lines patch added patch discarded remove patch
@@ -24,157 +24,157 @@
 block discarded – undo
24 24
 {
25 25
 
26 26
 
27
-    /**
28
-     * Hold array of active messengers indexed by messenger name.
29
-     *
30
-     * @since 4.5.0
31
-     *
32
-     * @var EE_messenger[]
33
-     */
34
-    protected $_active_messengers = array();
35
-
36
-
37
-    protected function _init_props()
38
-    {
39
-        $this->label = __('Messenger Shortcodes', 'event_espresso');
40
-        $this->description = __('All shortcodes that are messenger specific.', 'event_espresso');
41
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
42
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
43
-        // add messages about what happens  when the messenger is active.
44
-        $this->_active_messengers = $message_resource_manager->active_messengers();
45
-
46
-        $this->_shortcodes['[DISPLAY_HTML_URL]'] = __(
47
-            'This will return a link to view the template in a browser if the html messenger is active.',
48
-            'event_espresso'
49
-        );
50
-        $this->_shortcodes['[DISPLAY_PDF_URL]'] = __(
51
-            'This will return a link to generate a pdf for the template if the pdf messenger is active.',
52
-            'event_espresso'
53
-        );
54
-        $this->_shortcodes['[DISPLAY_PDF_BUTTON]'] = __(
55
-            'This will return html for a download pdf button trigger if the pdf messenger is active.',
56
-            'event_espresso'
57
-        );
58
-
59
-        /** @var RequestInterface $request */
60
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
61
-        $action = $request->getRequestParam('action');
62
-        // show error message about buttons/urls not working as expected if messenger deactivated.
63
-        if ($action === 'update_message_template' && is_admin()) {
64
-            if (! isset($this->_active_messengers['pdf'])) {
65
-                EE_Error::add_attention(
66
-                    __(
67
-                        'Be aware that the pdf messenger is inactive.  This means that any pdf related shortcodes will parse to an empty string.',
68
-                        'event_espresso'
69
-                    )
70
-                );
71
-            }
72
-
73
-            if (! isset($this->_active_messengers['html'])) {
74
-                EE_Error::add_attention(
75
-                    __(
76
-                        'Be aware that the html messenger is inactive. This means that any html related shortcodes will parse to an empty string.',
77
-                        'event_espresso'
78
-                    )
79
-                );
80
-            }
81
-        }
82
-    }
83
-
84
-
85
-    protected function _parser($shortcode)
86
-    {
87
-        // make sure we end up with a copy of the EE_Messages_Addressee object
88
-        $recipient = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
89
-        $recipient = ! $recipient instanceof EE_Messages_Addressee && is_array(
90
-            $this->_data
91
-        ) && isset($this->_data['data']) && $this->_data['data'] instanceof EE_Messages_Addressee ? $this->_data['data']
92
-            : $recipient;
93
-        $recipient = ! $recipient instanceof EE_Messages_Addressee && ! empty($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee
94
-            ? $this->_extra_data['data'] : $recipient;
95
-
96
-        if (! $recipient instanceof EE_Messages_Addressee) {
97
-            return '';
98
-        }
99
-
100
-        switch ($shortcode) {
101
-            case '[DISPLAY_HTML_URL]':
102
-                return isset($this->_active_messengers['html']) ? $this->_get_url($recipient, 'html') : '';
103
-                break;
104
-            case '[DISPLAY_PDF_URL]':
105
-                return isset($this->_active_messengers['pdf']) ? $this->_get_url($recipient, 'pdf') : '';
106
-                break;
107
-            case '[DISPLAY_PDF_BUTTON]':
108
-                return isset($this->_active_messengers['pdf']) ? $this->_get_button($recipient, 'pdf') : '';
109
-                break;
110
-        }
111
-        return '';
112
-    }
113
-
114
-
115
-    /**
116
-     * This method takes the incoming data and figures out from it what the message type is and evt_id/grp_id and uses
117
-     * that to generate the html for a button in the template.
118
-     *
119
-     * @since 4.5.0
120
-     *
121
-     * @param EE_Messages_Addressee $recipient
122
-     * @param string                $sending_messenger 'html' or 'pdf'
123
-     *
124
-     * @return string                Generated html
125
-     */
126
-    private function _get_button(EE_Messages_Addressee $recipient, $sending_messenger)
127
-    {
128
-        $download_text = $sending_messenger == 'pdf'
129
-            ? __('Download PDF', 'event_espresso')
130
-            : __(
131
-                'Show HTML',
132
-                'event_espresso'
133
-            );
134
-        $content = '
27
+	/**
28
+	 * Hold array of active messengers indexed by messenger name.
29
+	 *
30
+	 * @since 4.5.0
31
+	 *
32
+	 * @var EE_messenger[]
33
+	 */
34
+	protected $_active_messengers = array();
35
+
36
+
37
+	protected function _init_props()
38
+	{
39
+		$this->label = __('Messenger Shortcodes', 'event_espresso');
40
+		$this->description = __('All shortcodes that are messenger specific.', 'event_espresso');
41
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
42
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
43
+		// add messages about what happens  when the messenger is active.
44
+		$this->_active_messengers = $message_resource_manager->active_messengers();
45
+
46
+		$this->_shortcodes['[DISPLAY_HTML_URL]'] = __(
47
+			'This will return a link to view the template in a browser if the html messenger is active.',
48
+			'event_espresso'
49
+		);
50
+		$this->_shortcodes['[DISPLAY_PDF_URL]'] = __(
51
+			'This will return a link to generate a pdf for the template if the pdf messenger is active.',
52
+			'event_espresso'
53
+		);
54
+		$this->_shortcodes['[DISPLAY_PDF_BUTTON]'] = __(
55
+			'This will return html for a download pdf button trigger if the pdf messenger is active.',
56
+			'event_espresso'
57
+		);
58
+
59
+		/** @var RequestInterface $request */
60
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
61
+		$action = $request->getRequestParam('action');
62
+		// show error message about buttons/urls not working as expected if messenger deactivated.
63
+		if ($action === 'update_message_template' && is_admin()) {
64
+			if (! isset($this->_active_messengers['pdf'])) {
65
+				EE_Error::add_attention(
66
+					__(
67
+						'Be aware that the pdf messenger is inactive.  This means that any pdf related shortcodes will parse to an empty string.',
68
+						'event_espresso'
69
+					)
70
+				);
71
+			}
72
+
73
+			if (! isset($this->_active_messengers['html'])) {
74
+				EE_Error::add_attention(
75
+					__(
76
+						'Be aware that the html messenger is inactive. This means that any html related shortcodes will parse to an empty string.',
77
+						'event_espresso'
78
+					)
79
+				);
80
+			}
81
+		}
82
+	}
83
+
84
+
85
+	protected function _parser($shortcode)
86
+	{
87
+		// make sure we end up with a copy of the EE_Messages_Addressee object
88
+		$recipient = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
89
+		$recipient = ! $recipient instanceof EE_Messages_Addressee && is_array(
90
+			$this->_data
91
+		) && isset($this->_data['data']) && $this->_data['data'] instanceof EE_Messages_Addressee ? $this->_data['data']
92
+			: $recipient;
93
+		$recipient = ! $recipient instanceof EE_Messages_Addressee && ! empty($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee
94
+			? $this->_extra_data['data'] : $recipient;
95
+
96
+		if (! $recipient instanceof EE_Messages_Addressee) {
97
+			return '';
98
+		}
99
+
100
+		switch ($shortcode) {
101
+			case '[DISPLAY_HTML_URL]':
102
+				return isset($this->_active_messengers['html']) ? $this->_get_url($recipient, 'html') : '';
103
+				break;
104
+			case '[DISPLAY_PDF_URL]':
105
+				return isset($this->_active_messengers['pdf']) ? $this->_get_url($recipient, 'pdf') : '';
106
+				break;
107
+			case '[DISPLAY_PDF_BUTTON]':
108
+				return isset($this->_active_messengers['pdf']) ? $this->_get_button($recipient, 'pdf') : '';
109
+				break;
110
+		}
111
+		return '';
112
+	}
113
+
114
+
115
+	/**
116
+	 * This method takes the incoming data and figures out from it what the message type is and evt_id/grp_id and uses
117
+	 * that to generate the html for a button in the template.
118
+	 *
119
+	 * @since 4.5.0
120
+	 *
121
+	 * @param EE_Messages_Addressee $recipient
122
+	 * @param string                $sending_messenger 'html' or 'pdf'
123
+	 *
124
+	 * @return string                Generated html
125
+	 */
126
+	private function _get_button(EE_Messages_Addressee $recipient, $sending_messenger)
127
+	{
128
+		$download_text = $sending_messenger == 'pdf'
129
+			? __('Download PDF', 'event_espresso')
130
+			: __(
131
+				'Show HTML',
132
+				'event_espresso'
133
+			);
134
+		$content = '
135 135
 <form method="post" action="' . $this->_get_url($recipient, $sending_messenger) . '" >
136 136
 	<input class="print_button" type="submit" value="' . $download_text . '" />
137 137
 </form>
138 138
 		';
139
-        return $content;
140
-    }
141
-
142
-
143
-    /**
144
-     * This method takes the incoming data and figures out from it what the message type is and
145
-     * evt_id/grp_id and uses that to generate the url for displaying the template in a browser.
146
-     *
147
-     * @since 4.5.0
148
-     *
149
-     * @param EE_Messages_Addressee $recipient
150
-     * @param string                $sending_messenger
151
-     *
152
-     * @return string The generated url for displaying the link.
153
-     * @throws EE_Error
154
-     */
155
-    private function _get_url(EE_Messages_Addressee $recipient, $sending_messenger)
156
-    {
157
-
158
-        $reg = $recipient->reg_obj;
159
-        $reg = ! $reg instanceof EE_Registration ? $recipient->primary_reg_obj : $reg;
160
-
161
-
162
-        if ($this->_message_type instanceof EE_message_type && $this->_message instanceof EE_Message) {
163
-            EE_Registry::instance()->load_helper('MSG_Template');
164
-            try {
165
-                return EEH_MSG_Template::get_url_trigger(
166
-                    $this->_message_type,
167
-                    $this->_message,
168
-                    $reg,
169
-                    $sending_messenger
170
-                );
171
-            } catch (EE_Error $e) {
172
-                if (WP_DEBUG) {
173
-                    $e->get_error();
174
-                }
175
-            }
176
-        }
177
-
178
-        return '';
179
-    }
139
+		return $content;
140
+	}
141
+
142
+
143
+	/**
144
+	 * This method takes the incoming data and figures out from it what the message type is and
145
+	 * evt_id/grp_id and uses that to generate the url for displaying the template in a browser.
146
+	 *
147
+	 * @since 4.5.0
148
+	 *
149
+	 * @param EE_Messages_Addressee $recipient
150
+	 * @param string                $sending_messenger
151
+	 *
152
+	 * @return string The generated url for displaying the link.
153
+	 * @throws EE_Error
154
+	 */
155
+	private function _get_url(EE_Messages_Addressee $recipient, $sending_messenger)
156
+	{
157
+
158
+		$reg = $recipient->reg_obj;
159
+		$reg = ! $reg instanceof EE_Registration ? $recipient->primary_reg_obj : $reg;
160
+
161
+
162
+		if ($this->_message_type instanceof EE_message_type && $this->_message instanceof EE_Message) {
163
+			EE_Registry::instance()->load_helper('MSG_Template');
164
+			try {
165
+				return EEH_MSG_Template::get_url_trigger(
166
+					$this->_message_type,
167
+					$this->_message,
168
+					$reg,
169
+					$sending_messenger
170
+				);
171
+			} catch (EE_Error $e) {
172
+				if (WP_DEBUG) {
173
+					$e->get_error();
174
+				}
175
+			}
176
+		}
177
+
178
+		return '';
179
+	}
180 180
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
61 61
         $action = $request->getRequestParam('action');
62 62
         // show error message about buttons/urls not working as expected if messenger deactivated.
63 63
         if ($action === 'update_message_template' && is_admin()) {
64
-            if (! isset($this->_active_messengers['pdf'])) {
64
+            if ( ! isset($this->_active_messengers['pdf'])) {
65 65
                 EE_Error::add_attention(
66 66
                     __(
67 67
                         'Be aware that the pdf messenger is inactive.  This means that any pdf related shortcodes will parse to an empty string.',
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
                 );
71 71
             }
72 72
 
73
-            if (! isset($this->_active_messengers['html'])) {
73
+            if ( ! isset($this->_active_messengers['html'])) {
74 74
                 EE_Error::add_attention(
75 75
                     __(
76 76
                         'Be aware that the html messenger is inactive. This means that any html related shortcodes will parse to an empty string.',
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
         $recipient = ! $recipient instanceof EE_Messages_Addressee && ! empty($this->_extra_data['data']) && $this->_extra_data['data'] instanceof EE_Messages_Addressee
94 94
             ? $this->_extra_data['data'] : $recipient;
95 95
 
96
-        if (! $recipient instanceof EE_Messages_Addressee) {
96
+        if ( ! $recipient instanceof EE_Messages_Addressee) {
97 97
             return '';
98 98
         }
99 99
 
@@ -132,8 +132,8 @@  discard block
 block discarded – undo
132 132
                 'event_espresso'
133 133
             );
134 134
         $content = '
135
-<form method="post" action="' . $this->_get_url($recipient, $sending_messenger) . '" >
136
-	<input class="print_button" type="submit" value="' . $download_text . '" />
135
+<form method="post" action="' . $this->_get_url($recipient, $sending_messenger).'" >
136
+	<input class="print_button" type="submit" value="' . $download_text.'" />
137 137
 </form>
138 138
 		';
139 139
         return $content;
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Form_Input_Base.input.php 1 patch
Indentation   +1255 added lines, -1255 removed lines patch added patch discarded remove patch
@@ -15,1259 +15,1259 @@
 block discarded – undo
15 15
 abstract class EE_Form_Input_Base extends EE_Form_Section_Validatable
16 16
 {
17 17
 
18
-    /**
19
-     * the input's name attribute
20
-     *
21
-     * @var string
22
-     */
23
-    protected $_html_name;
24
-
25
-    /**
26
-     * id for the html label tag
27
-     *
28
-     * @var string
29
-     */
30
-    protected $_html_label_id;
31
-
32
-    /**
33
-     * class for teh html label tag
34
-     *
35
-     * @var string
36
-     */
37
-    protected $_html_label_class;
38
-
39
-    /**
40
-     * style for teh html label tag
41
-     *
42
-     * @var string
43
-     */
44
-    protected $_html_label_style;
45
-
46
-    /**
47
-     * text to be placed in the html label
48
-     *
49
-     * @var string
50
-     */
51
-    protected $_html_label_text;
52
-
53
-    /**
54
-     * the full html label. If used, all other html_label_* properties are invalid
55
-     *
56
-     * @var string
57
-     */
58
-    protected $_html_label;
59
-
60
-    /**
61
-     * HTML to use for help text (normally placed below form input), in a span which normally
62
-     * has a class of 'description'
63
-     *
64
-     * @var string
65
-     */
66
-    protected $_html_help_text;
67
-
68
-    /**
69
-     * CSS classes for displaying the help span
70
-     *
71
-     * @var string
72
-     */
73
-    protected $_html_help_class = 'description';
74
-
75
-    /**
76
-     * CSS to put in the style attribute on the help span
77
-     *
78
-     * @var string
79
-     */
80
-    protected $_html_help_style;
81
-
82
-    /**
83
-     * Stores whether or not this input's response is required.
84
-     * Because certain styling elements may also want to know that this
85
-     * input is required etc.
86
-     *
87
-     * @var boolean
88
-     */
89
-    protected $_required;
90
-
91
-    /**
92
-     * css class added to required inputs
93
-     *
94
-     * @var string
95
-     */
96
-    protected $_required_css_class = 'ee-required';
97
-
98
-    /**
99
-     * css styles applied to button type inputs
100
-     *
101
-     * @var string
102
-     */
103
-    protected $_button_css_attributes;
104
-
105
-    /**
106
-     * The raw post data submitted for this
107
-     * Generally unsafe for usage in client code
108
-     *
109
-     * @var mixed string or array
110
-     */
111
-    protected $_raw_value;
112
-
113
-    /**
114
-     * Value normalized according to the input's normalization strategy.
115
-     * The normalization strategy dictates whether this is a string, int, float,
116
-     * boolean, or array of any of those.
117
-     *
118
-     * @var mixed
119
-     */
120
-    protected $_normalized_value;
121
-
122
-
123
-    /**
124
-     * Normalized default value either initially set on the input, or provided by calling
125
-     * set_default().
126
-     * @var mixed
127
-     */
128
-    protected $_default;
129
-
130
-    /**
131
-     * Strategy used for displaying this field.
132
-     * Child classes must use _get_display_strategy to access it.
133
-     *
134
-     * @var EE_Display_Strategy_Base
135
-     */
136
-    private $_display_strategy;
137
-
138
-    /**
139
-     * Gets all the validation strategies used on this field
140
-     *
141
-     * @var EE_Validation_Strategy_Base[]
142
-     */
143
-    private $_validation_strategies = array();
144
-
145
-    /**
146
-     * The normalization strategy for this field
147
-     *
148
-     * @var EE_Normalization_Strategy_Base
149
-     */
150
-    private $_normalization_strategy;
151
-
152
-    /**
153
-     * Strategy for removing sensitive data after we're done with the form input
154
-     *
155
-     * @var EE_Sensitive_Data_Removal_Base
156
-     */
157
-    protected $_sensitive_data_removal_strategy;
158
-
159
-    /**
160
-     * Whether this input has been disabled or not.
161
-     * If it's disabled while rendering, an extra hidden input is added that indicates it has been knowingly disabled.
162
-     * (Client-side code that wants to dynamically disable it must also add this hidden input).
163
-     * When the form is submitted, if the input is disabled in the PHP form section, then input is ignored.
164
-     * If the input is missing from the request data but the hidden input indicating the input is disabled, then the input is again ignored.
165
-     *
166
-     * @var boolean
167
-     */
168
-    protected $disabled = false;
169
-
170
-
171
-
172
-    /**
173
-     * @param array                         $input_args       {
174
-     * @type string                         $html_name        the html name for the input
175
-     * @type string                         $html_label_id    the id attribute to give to the html label tag
176
-     * @type string                         $html_label_class the class attribute to give to the html label tag
177
-     * @type string                         $html_label_style the style attribute to give ot teh label tag
178
-     * @type string                         $html_label_text  the text to put in the label tag
179
-     * @type string                         $html_label       the full html label. If used,
180
-     *                                                        all other html_label_* args are invalid
181
-     * @type string                         $html_help_text   text to put in help element
182
-     * @type string                         $html_help_style  style attribute to give to teh help element
183
-     * @type string                         $html_help_class  class attribute to give to the help element
184
-     * @type string                         $default          default value NORMALIZED (eg, if providing the default
185
-     *       for a Yes_No_Input, you should provide TRUE or FALSE, not '1' or '0')
186
-     * @type EE_Display_Strategy_Base       $display          strategy
187
-     * @type EE_Normalization_Strategy_Base $normalization_strategy
188
-     * @type EE_Validation_Strategy_Base[]  $validation_strategies
189
-     * @type boolean                        $ignore_input special argument which can be used to avoid adding any validation strategies,
190
-     *                                                    and sets the normalization strategy to the Null normalization. This is good
191
-     *                                                    when you want the input to be totally ignored server-side (like when using
192
-     *                                                    React.js form inputs)
193
-     *                                                        }
194
-     */
195
-    public function __construct($input_args = array())
196
-    {
197
-        $input_args = (array) apply_filters('FHEE__EE_Form_Input_Base___construct__input_args', $input_args, $this);
198
-        // the following properties must be cast as arrays
199
-        if (isset($input_args['validation_strategies'])) {
200
-            foreach ((array) $input_args['validation_strategies'] as $validation_strategy) {
201
-                if ($validation_strategy instanceof EE_Validation_Strategy_Base && empty($input_args['ignore_input'])) {
202
-                    $this->_validation_strategies[ get_class($validation_strategy) ] = $validation_strategy;
203
-                }
204
-            }
205
-            unset($input_args['validation_strategies']);
206
-        }
207
-        if (isset($input_args['ignore_input'])) {
208
-            $this->_validation_strategies = array();
209
-        }
210
-        // loop thru incoming options
211
-        foreach ($input_args as $key => $value) {
212
-            // add underscore to $key to match property names
213
-            $_key = '_' . $key;
214
-            if (property_exists($this, $_key)) {
215
-                $this->{$_key} = $value;
216
-            }
217
-        }
218
-        // ensure that "required" is set correctly
219
-        $this->set_required(
220
-            $this->_required,
221
-            isset($input_args['required_validation_error_message'])
222
-            ? $input_args['required_validation_error_message']
223
-            : null
224
-        );
225
-        // $this->_html_name_specified = isset( $input_args['html_name'] ) ? TRUE : FALSE;
226
-        $this->_display_strategy->_construct_finalize($this);
227
-        foreach ($this->_validation_strategies as $validation_strategy) {
228
-            $validation_strategy->_construct_finalize($this);
229
-        }
230
-        if (isset($input_args['ignore_input'])) {
231
-            $this->_normalization_strategy = new EE_Null_Normalization();
232
-        }
233
-        if (! $this->_normalization_strategy) {
234
-                $this->_normalization_strategy = new EE_Text_Normalization();
235
-        }
236
-        $this->_normalization_strategy->_construct_finalize($this);
237
-        // at least we can use the normalization strategy to populate the default
238
-        if (isset($input_args['default'])) {
239
-            $this->set_default($input_args['default']);
240
-            unset($input_args['default']);
241
-        }
242
-        if (! $this->_sensitive_data_removal_strategy) {
243
-            $this->_sensitive_data_removal_strategy = new EE_No_Sensitive_Data_Removal();
244
-        }
245
-        $this->_sensitive_data_removal_strategy->_construct_finalize($this);
246
-        parent::__construct($input_args);
247
-    }
248
-
249
-
250
-
251
-    /**
252
-     * Sets the html_name to its default value, if none was specified in teh constructor.
253
-     * Calculation involves using the name and the parent's html_name
254
-     *
255
-     * @throws EE_Error
256
-     */
257
-    protected function _set_default_html_name_if_empty()
258
-    {
259
-        if (! $this->_html_name) {
260
-            $this->_html_name = $this->name();
261
-            if ($this->_parent_section && $this->_parent_section instanceof EE_Form_Section_Proper) {
262
-                $this->_html_name = $this->_parent_section->html_name_prefix() . "[{$this->name()}]";
263
-            }
264
-        }
265
-    }
266
-
267
-
268
-
269
-    /**
270
-     * @param $parent_form_section
271
-     * @param $name
272
-     * @throws EE_Error
273
-     */
274
-    public function _construct_finalize($parent_form_section, $name)
275
-    {
276
-        parent::_construct_finalize($parent_form_section, $name);
277
-        if ($this->_html_label === null && $this->_html_label_text === null) {
278
-            $this->_html_label_text = ucwords(str_replace("_", " ", $name));
279
-        }
280
-        do_action('AHEE__EE_Form_Input_Base___construct_finalize__end', $this, $parent_form_section, $name);
281
-    }
282
-
283
-
284
-
285
-    /**
286
-     * Returns the strategy for displaying this form input. If none is set, throws an exception.
287
-     *
288
-     * @return EE_Display_Strategy_Base
289
-     * @throws EE_Error
290
-     */
291
-    protected function _get_display_strategy()
292
-    {
293
-        $this->ensure_construct_finalized_called();
294
-        if (! $this->_display_strategy || ! $this->_display_strategy instanceof EE_Display_Strategy_Base) {
295
-            throw new EE_Error(
296
-                sprintf(
297
-                    __(
298
-                        "Cannot get display strategy for form input with name %s and id %s, because it has not been set in the constructor",
299
-                        "event_espresso"
300
-                    ),
301
-                    $this->html_name(),
302
-                    $this->html_id()
303
-                )
304
-            );
305
-        } else {
306
-            return $this->_display_strategy;
307
-        }
308
-    }
309
-
310
-
311
-
312
-    /**
313
-     * Sets the display strategy.
314
-     *
315
-     * @param EE_Display_Strategy_Base $strategy
316
-     */
317
-    protected function _set_display_strategy(EE_Display_Strategy_Base $strategy)
318
-    {
319
-        $this->_display_strategy = $strategy;
320
-    }
321
-
322
-
323
-
324
-    /**
325
-     * Sets the sanitization strategy
326
-     *
327
-     * @param EE_Normalization_Strategy_Base $strategy
328
-     */
329
-    protected function _set_normalization_strategy(EE_Normalization_Strategy_Base $strategy)
330
-    {
331
-        $this->_normalization_strategy = $strategy;
332
-    }
333
-
334
-
335
-
336
-    /**
337
-     * Gets sensitive_data_removal_strategy
338
-     *
339
-     * @return EE_Sensitive_Data_Removal_Base
340
-     */
341
-    public function get_sensitive_data_removal_strategy()
342
-    {
343
-        return $this->_sensitive_data_removal_strategy;
344
-    }
345
-
346
-
347
-
348
-    /**
349
-     * Sets sensitive_data_removal_strategy
350
-     *
351
-     * @param EE_Sensitive_Data_Removal_Base $sensitive_data_removal_strategy
352
-     * @return void
353
-     */
354
-    public function set_sensitive_data_removal_strategy($sensitive_data_removal_strategy)
355
-    {
356
-        $this->_sensitive_data_removal_strategy = $sensitive_data_removal_strategy;
357
-    }
358
-
359
-
360
-
361
-    /**
362
-     * Gets the display strategy for this input
363
-     *
364
-     * @return EE_Display_Strategy_Base
365
-     */
366
-    public function get_display_strategy()
367
-    {
368
-        return $this->_display_strategy;
369
-    }
370
-
371
-
372
-
373
-    /**
374
-     * Overwrites the display strategy
375
-     *
376
-     * @param EE_Display_Strategy_Base $display_strategy
377
-     */
378
-    public function set_display_strategy($display_strategy)
379
-    {
380
-        $this->_display_strategy = $display_strategy;
381
-        $this->_display_strategy->_construct_finalize($this);
382
-    }
383
-
384
-
385
-
386
-    /**
387
-     * Gets the normalization strategy set on this input
388
-     *
389
-     * @return EE_Normalization_Strategy_Base
390
-     */
391
-    public function get_normalization_strategy()
392
-    {
393
-        return $this->_normalization_strategy;
394
-    }
395
-
396
-
397
-
398
-    /**
399
-     * Overwrites the normalization strategy
400
-     *
401
-     * @param EE_Normalization_Strategy_Base $normalization_strategy
402
-     */
403
-    public function set_normalization_strategy($normalization_strategy)
404
-    {
405
-        $this->_normalization_strategy = $normalization_strategy;
406
-        $this->_normalization_strategy->_construct_finalize($this);
407
-    }
408
-
409
-
410
-
411
-    /**
412
-     * Returns all teh validation strategies which apply to this field, numerically indexed
413
-     *
414
-     * @return EE_Validation_Strategy_Base[]
415
-     */
416
-    public function get_validation_strategies()
417
-    {
418
-        return $this->_validation_strategies;
419
-    }
420
-
421
-
422
-
423
-    /**
424
-     * Adds this strategy to the field so it will be used in both JS validation and server-side validation
425
-     *
426
-     * @param EE_Validation_Strategy_Base $validation_strategy
427
-     * @return void
428
-     */
429
-    protected function _add_validation_strategy(EE_Validation_Strategy_Base $validation_strategy)
430
-    {
431
-        $validation_strategy->_construct_finalize($this);
432
-        $this->_validation_strategies[] = $validation_strategy;
433
-    }
434
-
435
-
436
-
437
-    /**
438
-     * Adds a new validation strategy onto the form input
439
-     *
440
-     * @param EE_Validation_Strategy_Base $validation_strategy
441
-     * @return void
442
-     */
443
-    public function add_validation_strategy(EE_Validation_Strategy_Base $validation_strategy)
444
-    {
445
-        $this->_add_validation_strategy($validation_strategy);
446
-    }
447
-
448
-
449
-
450
-    /**
451
-     * The classname of the validation strategy to remove
452
-     *
453
-     * @param string $validation_strategy_classname
454
-     */
455
-    public function remove_validation_strategy($validation_strategy_classname)
456
-    {
457
-        foreach ($this->_validation_strategies as $key => $validation_strategy) {
458
-            if ($validation_strategy instanceof $validation_strategy_classname
459
-                || is_subclass_of($validation_strategy, $validation_strategy_classname)
460
-            ) {
461
-                unset($this->_validation_strategies[ $key ]);
462
-            }
463
-        }
464
-    }
465
-
466
-
467
-
468
-    /**
469
-     * returns true if input employs any of the validation strategy defined by the supplied array of classnames
470
-     *
471
-     * @param array $validation_strategy_classnames
472
-     * @return bool
473
-     */
474
-    public function has_validation_strategy($validation_strategy_classnames)
475
-    {
476
-        $validation_strategy_classnames = is_array($validation_strategy_classnames)
477
-            ? $validation_strategy_classnames
478
-            : array($validation_strategy_classnames);
479
-        foreach ($this->_validation_strategies as $key => $validation_strategy) {
480
-            if (in_array($key, $validation_strategy_classnames)) {
481
-                return true;
482
-            }
483
-        }
484
-        return false;
485
-    }
486
-
487
-
488
-
489
-    /**
490
-     * Gets the HTML
491
-     *
492
-     * @return string
493
-     */
494
-    public function get_html()
495
-    {
496
-        return $this->_parent_section->get_html_for_input($this);
497
-    }
498
-
499
-
500
-
501
-    /**
502
-     * Gets the HTML for the input itself (no label or errors) according to the
503
-     * input's display strategy
504
-     * Makes sure the JS and CSS are enqueued for it
505
-     *
506
-     * @return string
507
-     * @throws EE_Error
508
-     */
509
-    public function get_html_for_input()
510
-    {
511
-        return $this->_form_html_filter
512
-            ? $this->_form_html_filter->filterHtml(
513
-                $this->_get_display_strategy()->display(),
514
-                $this
515
-            )
516
-            : $this->_get_display_strategy()->display();
517
-    }
518
-
519
-
520
-
521
-    /**
522
-     * @return string
523
-     */
524
-    public function html_other_attributes()
525
-    {
526
-        EE_Error::doing_it_wrong(
527
-            __METHOD__,
528
-            sprintf(
529
-                esc_html__(
530
-                    'This method is no longer in use. You should replace it by %s',
531
-                    'event_espresso'
532
-                ),
533
-                'EE_Form_Section_Base::other_html_attributes()'
534
-            ),
535
-            '4.10.2.p'
536
-        );
537
-
538
-        return $this->other_html_attributes();
539
-    }
540
-
541
-
542
-
543
-    /**
544
-     * @param string $html_other_attributes
545
-     */
546
-    public function set_html_other_attributes($html_other_attributes)
547
-    {
548
-        EE_Error::doing_it_wrong(
549
-            __METHOD__,
550
-            sprintf(
551
-                esc_html__(
552
-                    'This method is no longer in use. You should replace it by %s',
553
-                    'event_espresso'
554
-                ),
555
-                'EE_Form_Section_Base::set_other_html_attributes()'
556
-            ),
557
-            '4.10.2.p'
558
-        );
559
-
560
-        $this->set_other_html_attributes($html_other_attributes);
561
-    }
562
-
563
-
564
-
565
-    /**
566
-     * Gets the HTML for displaying the label for this form input
567
-     * according to the form section's layout strategy
568
-     *
569
-     * @return string
570
-     */
571
-    public function get_html_for_label()
572
-    {
573
-        return $this->_parent_section->get_layout_strategy()->display_label($this);
574
-    }
575
-
576
-
577
-
578
-    /**
579
-     * Gets the HTML for displaying the errors section for this form input
580
-     * according to the form section's layout strategy
581
-     *
582
-     * @return string
583
-     */
584
-    public function get_html_for_errors()
585
-    {
586
-        return $this->_parent_section->get_layout_strategy()->display_errors($this);
587
-    }
588
-
589
-
590
-
591
-    /**
592
-     * Gets the HTML for displaying the help text for this form input
593
-     * according to the form section's layout strategy
594
-     *
595
-     * @return string
596
-     */
597
-    public function get_html_for_help()
598
-    {
599
-        return $this->_parent_section->get_layout_strategy()->display_help_text($this);
600
-    }
601
-
602
-
603
-
604
-    /**
605
-     * Validates the input's sanitized value (assumes _sanitize() has already been called)
606
-     * and returns whether or not the form input's submitted value is value
607
-     *
608
-     * @return boolean
609
-     */
610
-    protected function _validate()
611
-    {
612
-        if ($this->isDisabled()) {
613
-            return true;
614
-        }
615
-        foreach ($this->_validation_strategies as $validation_strategy) {
616
-            if ($validation_strategy instanceof EE_Validation_Strategy_Base) {
617
-                try {
618
-                    $validation_strategy->validate($this->normalized_value());
619
-                } catch (EE_Validation_Error $e) {
620
-                    $this->add_validation_error($e);
621
-                }
622
-            }
623
-        }
624
-        if ($this->get_validation_errors()) {
625
-            return false;
626
-        } else {
627
-            return true;
628
-        }
629
-    }
630
-
631
-
632
-
633
-    /**
634
-     * Performs basic sanitization on this value. But what sanitization can be performed anyways?
635
-     * This value MIGHT be allowed to have tags, so we can't really remove them.
636
-     *
637
-     * @param string $value
638
-     * @return null|string
639
-     */
640
-    protected function _sanitize($value)
641
-    {
642
-        return $value !== null ? stripslashes(html_entity_decode(trim($value))) : null;
643
-    }
644
-
645
-
646
-
647
-    /**
648
-     * Picks out the form value that relates to this form input,
649
-     * and stores it as the sanitized value on the form input, and sets the normalized value.
650
-     * Returns whether or not any validation errors occurred
651
-     *
652
-     * @param array $req_data
653
-     * @return boolean whether or not there was an error
654
-     * @throws EE_Error
655
-     */
656
-    protected function _normalize($req_data)
657
-    {
658
-        // any existing validation errors don't apply so clear them
659
-        $this->_validation_errors = array();
660
-        // if the input is disabled, ignore whatever input was sent in
661
-        if ($this->isDisabled()) {
662
-            $this->_set_raw_value(null);
663
-            $this->_set_normalized_value($this->get_default());
664
-            return false;
665
-        }
666
-        try {
667
-            $raw_input = $this->find_form_data_for_this_section($req_data);
668
-            // super simple sanitization for now
669
-            if (is_array($raw_input)) {
670
-                $raw_value = array();
671
-                foreach ($raw_input as $key => $value) {
672
-                    $raw_value[ $key ] = $this->_sanitize($value);
673
-                }
674
-                $this->_set_raw_value($raw_value);
675
-            } else {
676
-                $this->_set_raw_value($this->_sanitize($raw_input));
677
-            }
678
-            // we want to mostly leave the input alone in case we need to re-display it to the user
679
-            $this->_set_normalized_value($this->_normalization_strategy->normalize($this->raw_value()));
680
-            return false;
681
-        } catch (EE_Validation_Error $e) {
682
-            $this->add_validation_error($e);
683
-            return true;
684
-        }
685
-    }
686
-
687
-
688
-    /**
689
-     * @return string
690
-     * @throws EE_Error
691
-     */
692
-    public function html_name()
693
-    {
694
-        $this->_set_default_html_name_if_empty();
695
-        return $this->_html_name;
696
-    }
697
-
698
-
699
-    /**
700
-     * @return string
701
-     * @throws EE_Error
702
-     */
703
-    public function html_label_id()
704
-    {
705
-        return ! empty($this->_html_label_id) ? $this->_html_label_id : $this->html_id() . '-lbl';
706
-    }
707
-
708
-
709
-
710
-    /**
711
-     * @return string
712
-     */
713
-    public function html_label_class()
714
-    {
715
-        return $this->_html_label_class;
716
-    }
717
-
718
-
719
-
720
-    /**
721
-     * @return string
722
-     */
723
-    public function html_label_style()
724
-    {
725
-        return $this->_html_label_style;
726
-    }
727
-
728
-
729
-
730
-    /**
731
-     * @return string
732
-     */
733
-    public function html_label_text()
734
-    {
735
-        return $this->_html_label_text;
736
-    }
737
-
738
-
739
-
740
-    /**
741
-     * @return string
742
-     */
743
-    public function html_help_text()
744
-    {
745
-        return $this->_html_help_text;
746
-    }
747
-
748
-
749
-
750
-    /**
751
-     * @return string
752
-     */
753
-    public function html_help_class()
754
-    {
755
-        return $this->_html_help_class;
756
-    }
757
-
758
-
759
-
760
-    /**
761
-     * @return string
762
-     */
763
-    public function html_help_style()
764
-    {
765
-        return $this->_html_style;
766
-    }
767
-
768
-
769
-
770
-    /**
771
-     * returns the raw, UNSAFE, input, almost exactly as the user submitted it.
772
-     * Please note that almost all client code should instead use the normalized_value;
773
-     * or possibly raw_value_in_form (which prepares the string for displaying in an HTML attribute on a tag,
774
-     * mostly by escaping quotes)
775
-     * Note, we do not store the exact original value sent in the user's request because
776
-     * it may have malicious content, and we MIGHT want to store the form input in a transient or something...
777
-     * in which case, we would have stored the malicious content to our database.
778
-     *
779
-     * @return string
780
-     */
781
-    public function raw_value()
782
-    {
783
-        return $this->_raw_value;
784
-    }
785
-
786
-
787
-
788
-    /**
789
-     * Returns a string safe to usage in form inputs when displaying, because
790
-     * it escapes all html entities
791
-     *
792
-     * @return string
793
-     */
794
-    public function raw_value_in_form()
795
-    {
796
-        return htmlentities($this->raw_value(), ENT_QUOTES, 'UTF-8');
797
-    }
798
-
799
-
800
-
801
-    /**
802
-     * returns the value after it's been sanitized, and then converted into it's proper type
803
-     * in PHP. Eg, a string, an int, an array,
804
-     *
805
-     * @return mixed
806
-     */
807
-    public function normalized_value()
808
-    {
809
-        return $this->_normalized_value;
810
-    }
811
-
812
-
813
-
814
-    /**
815
-     * Returns the normalized value is a presentable way. By default this is just
816
-     * the normalized value by itself, but it can be overridden for when that's not
817
-     * the best thing to display
818
-     *
819
-     * @return string
820
-     */
821
-    public function pretty_value()
822
-    {
823
-        return $this->_normalized_value;
824
-    }
825
-
826
-
827
-
828
-    /**
829
-     * When generating the JS for the jquery validation rules like<br>
830
-     * <code>$( "#myform" ).validate({
831
-     * rules: {
832
-     * password: "required",
833
-     * password_again: {
834
-     * equalTo: "#password"
835
-     * }
836
-     * }
837
-     * });</code>
838
-     * if this field had the name 'password_again', it should return
839
-     * <br><code>password_again: {
840
-     * equalTo: "#password"
841
-     * }</code>
842
-     *
843
-     * @return array
844
-     */
845
-    public function get_jquery_validation_rules()
846
-    {
847
-        $jquery_validation_js = array();
848
-        $jquery_validation_rules = array();
849
-        foreach ($this->get_validation_strategies() as $validation_strategy) {
850
-            $jquery_validation_rules = array_replace_recursive(
851
-                $jquery_validation_rules,
852
-                $validation_strategy->get_jquery_validation_rule_array()
853
-            );
854
-        }
855
-        if (! empty($jquery_validation_rules)) {
856
-            foreach ($this->get_display_strategy()->get_html_input_ids(true) as $html_id_with_pound_sign) {
857
-                $jquery_validation_js[ $html_id_with_pound_sign ] = $jquery_validation_rules;
858
-            }
859
-        }
860
-        return $jquery_validation_js;
861
-    }
862
-
863
-
864
-
865
-    /**
866
-     * Sets the input's default value for use in displaying in the form. Note: value should be
867
-     * normalized (Eg, if providing a default of ra Yes_NO_Input you would provide TRUE or FALSE, not '1' or '0')
868
-     *
869
-     * @param mixed $value
870
-     * @return void
871
-     */
872
-    public function set_default($value)
873
-    {
874
-        $this->_default = $value;
875
-        $this->_set_normalized_value($value);
876
-        $this->_set_raw_value($value);
877
-    }
878
-
879
-
880
-
881
-    /**
882
-     * Sets the normalized value on this input
883
-     *
884
-     * @param mixed $value
885
-     */
886
-    protected function _set_normalized_value($value)
887
-    {
888
-        $this->_normalized_value = $value;
889
-    }
890
-
891
-
892
-
893
-    /**
894
-     * Sets the raw value on this input (ie, exactly as the user submitted it)
895
-     *
896
-     * @param mixed $value
897
-     */
898
-    protected function _set_raw_value($value)
899
-    {
900
-        $this->_raw_value = $this->_normalization_strategy->unnormalize($value);
901
-    }
902
-
903
-
904
-
905
-    /**
906
-     * Sets the HTML label text after it has already been defined
907
-     *
908
-     * @param string $label
909
-     * @return void
910
-     */
911
-    public function set_html_label_text($label)
912
-    {
913
-        $this->_html_label_text = $label;
914
-    }
915
-
916
-
917
-
918
-    /**
919
-     * Sets whether or not this field is required, and adjusts the validation strategy.
920
-     * If you want to use the EE_Conditionally_Required_Validation_Strategy,
921
-     * please add it as a validation strategy using add_validation_strategy as normal
922
-     *
923
-     * @param boolean $required boolean
924
-     * @param null    $required_text
925
-     */
926
-    public function set_required($required = true, $required_text = null)
927
-    {
928
-        $required = filter_var($required, FILTER_VALIDATE_BOOLEAN);
929
-        // whether $required is a string or a boolean, we want to add a required validation strategy
930
-        if ($required) {
931
-            $this->_add_validation_strategy(new EE_Required_Validation_Strategy($required_text));
932
-        } else {
933
-            $this->remove_validation_strategy('EE_Required_Validation_Strategy');
934
-        }
935
-        $this->_required = $required;
936
-    }
937
-
938
-
939
-
940
-    /**
941
-     * Returns whether or not this field is required
942
-     *
943
-     * @return boolean
944
-     */
945
-    public function required()
946
-    {
947
-        return $this->_required;
948
-    }
949
-
950
-
951
-
952
-    /**
953
-     * @param string $required_css_class
954
-     */
955
-    public function set_required_css_class($required_css_class)
956
-    {
957
-        $this->_required_css_class = $required_css_class;
958
-    }
959
-
960
-
961
-
962
-    /**
963
-     * @return string
964
-     */
965
-    public function required_css_class()
966
-    {
967
-        return $this->_required_css_class;
968
-    }
969
-
970
-
971
-
972
-    /**
973
-     * @param bool $add_required
974
-     * @return string
975
-     */
976
-    public function html_class($add_required = false)
977
-    {
978
-        return $add_required && $this->required()
979
-            ? $this->required_css_class() . ' ' . $this->_html_class
980
-            : $this->_html_class;
981
-    }
982
-
983
-
984
-    /**
985
-     * Sets the help text, in case
986
-     *
987
-     * @param string $text
988
-     */
989
-    public function set_html_help_text($text)
990
-    {
991
-        $this->_html_help_text = $text;
992
-    }
993
-
994
-
995
-
996
-    /**
997
-     * Uses the sensitive data removal strategy to remove the sensitive data from this
998
-     * input. If there is any kind of sensitive data removal on this input, we clear
999
-     * out the raw value completely
1000
-     *
1001
-     * @return void
1002
-     */
1003
-    public function clean_sensitive_data()
1004
-    {
1005
-        // if we do ANY kind of sensitive data removal on this, then just clear out the raw value
1006
-        // if we need more logic than this we'll make a strategy for it
1007
-        if ($this->_sensitive_data_removal_strategy
1008
-            && ! $this->_sensitive_data_removal_strategy instanceof EE_No_Sensitive_Data_Removal
1009
-        ) {
1010
-            $this->_set_raw_value(null);
1011
-        }
1012
-        // and clean the normalized value according to the appropriate strategy
1013
-        $this->_set_normalized_value(
1014
-            $this->get_sensitive_data_removal_strategy()->remove_sensitive_data(
1015
-                $this->_normalized_value
1016
-            )
1017
-        );
1018
-    }
1019
-
1020
-
1021
-
1022
-    /**
1023
-     * @param bool   $primary
1024
-     * @param string $button_size
1025
-     * @param string $other_attributes
1026
-     */
1027
-    public function set_button_css_attributes($primary = true, $button_size = '', $other_attributes = '')
1028
-    {
1029
-        $button_css_attributes = 'button';
1030
-        $button_css_attributes .= $primary === true ? ' button-primary' : ' button-secondary';
1031
-        switch ($button_size) {
1032
-            case 'xs':
1033
-            case 'extra-small':
1034
-                $button_css_attributes .= ' button-xs';
1035
-                break;
1036
-            case 'sm':
1037
-            case 'small':
1038
-                $button_css_attributes .= ' button-sm';
1039
-                break;
1040
-            case 'lg':
1041
-            case 'large':
1042
-                $button_css_attributes .= ' button-lg';
1043
-                break;
1044
-            case 'block':
1045
-                $button_css_attributes .= ' button-block';
1046
-                break;
1047
-            case 'md':
1048
-            case 'medium':
1049
-            default:
1050
-                $button_css_attributes .= '';
1051
-        }
1052
-        $this->_button_css_attributes .= ! empty($other_attributes)
1053
-            ? $button_css_attributes . ' ' . $other_attributes
1054
-            : $button_css_attributes;
1055
-    }
1056
-
1057
-
1058
-
1059
-    /**
1060
-     * @return string
1061
-     */
1062
-    public function button_css_attributes()
1063
-    {
1064
-        if (empty($this->_button_css_attributes)) {
1065
-            $this->set_button_css_attributes();
1066
-        }
1067
-        return $this->_button_css_attributes;
1068
-    }
1069
-
1070
-
1071
-
1072
-    /**
1073
-     * find_form_data_for_this_section
1074
-     * using this section's name and its parents, finds the value of the form data that corresponds to it.
1075
-     * For example, if this form section's HTML name is my_form[subform][form_input_1],
1076
-     * then it's value should be in request at request['my_form']['subform']['form_input_1'].
1077
-     * (If that doesn't exist, we also check for this subsection's name
1078
-     * at the TOP LEVEL of the request data. Eg request['form_input_1'].)
1079
-     * This function finds its value in the form.
1080
-     *
1081
-     * @param array $req_data
1082
-     * @return mixed whatever the raw value of this form section is in the request data
1083
-     * @throws EE_Error
1084
-     */
1085
-    public function find_form_data_for_this_section($req_data)
1086
-    {
1087
-        $name_parts = $this->getInputNameParts();
1088
-        // now get the value for the input
1089
-        $value = $this->findRequestForSectionUsingNameParts($name_parts, $req_data);
1090
-        // check if this thing's name is at the TOP level of the request data
1091
-        if ($value === null && isset($req_data[ $this->name() ])) {
1092
-            $value = $req_data[ $this->name() ];
1093
-        }
1094
-        return $value;
1095
-    }
1096
-
1097
-
1098
-    /**
1099
-     * If this input's name is something like "foo[bar][baz]"
1100
-     * returns an array like `array('foo','bar',baz')`
1101
-     *
1102
-     * @return array
1103
-     * @throws EE_Error
1104
-     */
1105
-    protected function getInputNameParts()
1106
-    {
1107
-        // break up the html name by "[]"
1108
-        if (strpos($this->html_name(), '[') !== false) {
1109
-            $before_any_brackets = substr($this->html_name(), 0, strpos($this->html_name(), '['));
1110
-        } else {
1111
-            $before_any_brackets = $this->html_name();
1112
-        }
1113
-        // grab all of the segments
1114
-        preg_match_all('~\[([^]]*)\]~', $this->html_name(), $matches);
1115
-        if (isset($matches[1]) && is_array($matches[1])) {
1116
-            $name_parts = $matches[1];
1117
-            array_unshift($name_parts, $before_any_brackets);
1118
-        } else {
1119
-            $name_parts = array($before_any_brackets);
1120
-        }
1121
-        return $name_parts;
1122
-    }
1123
-
1124
-
1125
-
1126
-    /**
1127
-     * @param array $html_name_parts
1128
-     * @param array $req_data
1129
-     * @return array | NULL
1130
-     */
1131
-    public function findRequestForSectionUsingNameParts($html_name_parts, $req_data)
1132
-    {
1133
-        $first_part_to_consider = array_shift($html_name_parts);
1134
-        if (isset($req_data[ $first_part_to_consider ])) {
1135
-            if (empty($html_name_parts)) {
1136
-                return $req_data[ $first_part_to_consider ];
1137
-            } else {
1138
-                return $this->findRequestForSectionUsingNameParts(
1139
-                    $html_name_parts,
1140
-                    $req_data[ $first_part_to_consider ]
1141
-                );
1142
-            }
1143
-        } else {
1144
-            return null;
1145
-        }
1146
-    }
1147
-
1148
-
1149
-
1150
-    /**
1151
-     * Checks if this form input's data is in the request data
1152
-     *
1153
-     * @param array $req_data
1154
-     * @return boolean
1155
-     * @throws EE_Error
1156
-     */
1157
-    public function form_data_present_in($req_data = null)
1158
-    {
1159
-        if ($req_data === null) {
1160
-            /** @var RequestInterface $request */
1161
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1162
-            $req_data = $request->postParams();
1163
-        }
1164
-        $checked_value = $this->find_form_data_for_this_section($req_data);
1165
-        if ($checked_value !== null) {
1166
-            return true;
1167
-        } else {
1168
-            return false;
1169
-        }
1170
-    }
1171
-
1172
-
1173
-
1174
-    /**
1175
-     * Overrides parent to add js data from validation and display strategies
1176
-     *
1177
-     * @param array $form_other_js_data
1178
-     * @return array
1179
-     */
1180
-    public function get_other_js_data($form_other_js_data = array())
1181
-    {
1182
-        return $this->get_other_js_data_from_strategies($form_other_js_data);
1183
-    }
1184
-
1185
-
1186
-
1187
-    /**
1188
-     * Gets other JS data for localization from this input's strategies, like
1189
-     * the validation strategies and the display strategy
1190
-     *
1191
-     * @param array $form_other_js_data
1192
-     * @return array
1193
-     */
1194
-    public function get_other_js_data_from_strategies($form_other_js_data = array())
1195
-    {
1196
-        $form_other_js_data = $this->get_display_strategy()->get_other_js_data($form_other_js_data);
1197
-        foreach ($this->get_validation_strategies() as $validation_strategy) {
1198
-            $form_other_js_data = $validation_strategy->get_other_js_data($form_other_js_data);
1199
-        }
1200
-        return $form_other_js_data;
1201
-    }
1202
-
1203
-
1204
-
1205
-    /**
1206
-     * Override parent because we want to give our strategies an opportunity to enqueue some js and css
1207
-     *
1208
-     * @return void
1209
-     */
1210
-    public function enqueue_js()
1211
-    {
1212
-        // ask our display strategy and validation strategies if they have js to enqueue
1213
-        $this->enqueue_js_from_strategies();
1214
-    }
1215
-
1216
-
1217
-
1218
-    /**
1219
-     * Tells strategies when its ok to enqueue their js and css
1220
-     *
1221
-     * @return void
1222
-     */
1223
-    public function enqueue_js_from_strategies()
1224
-    {
1225
-        $this->get_display_strategy()->enqueue_js();
1226
-        foreach ($this->get_validation_strategies() as $validation_strategy) {
1227
-            $validation_strategy->enqueue_js();
1228
-        }
1229
-    }
1230
-
1231
-
1232
-
1233
-    /**
1234
-     * Gets the default value set on the input (not the current value, which may have been
1235
-     * changed because of a form submission). If no default was set, this us null.
1236
-     * @return mixed
1237
-     */
1238
-    public function get_default()
1239
-    {
1240
-        return $this->_default;
1241
-    }
1242
-
1243
-
1244
-
1245
-    /**
1246
-     * Makes this input disabled. That means it will have the HTML attribute 'disabled="disabled"',
1247
-     * and server-side if any input was received it will be ignored
1248
-     */
1249
-    public function disable($disable = true)
1250
-    {
1251
-        $disabled_attribute = ' disabled="disabled"';
1252
-        $this->disabled = filter_var($disable, FILTER_VALIDATE_BOOLEAN);
1253
-        if ($this->disabled) {
1254
-            if (strpos($this->_other_html_attributes, $disabled_attribute) === false) {
1255
-                $this->_other_html_attributes .= $disabled_attribute;
1256
-            }
1257
-            $this->_set_normalized_value($this->get_default());
1258
-        } else {
1259
-            $this->_other_html_attributes = str_replace($disabled_attribute, '', $this->_other_html_attributes);
1260
-        }
1261
-    }
1262
-
1263
-
1264
-
1265
-    /**
1266
-     * Returns whether or not this input is currently disabled.
1267
-     * @return bool
1268
-     */
1269
-    public function isDisabled()
1270
-    {
1271
-        return $this->disabled;
1272
-    }
18
+	/**
19
+	 * the input's name attribute
20
+	 *
21
+	 * @var string
22
+	 */
23
+	protected $_html_name;
24
+
25
+	/**
26
+	 * id for the html label tag
27
+	 *
28
+	 * @var string
29
+	 */
30
+	protected $_html_label_id;
31
+
32
+	/**
33
+	 * class for teh html label tag
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $_html_label_class;
38
+
39
+	/**
40
+	 * style for teh html label tag
41
+	 *
42
+	 * @var string
43
+	 */
44
+	protected $_html_label_style;
45
+
46
+	/**
47
+	 * text to be placed in the html label
48
+	 *
49
+	 * @var string
50
+	 */
51
+	protected $_html_label_text;
52
+
53
+	/**
54
+	 * the full html label. If used, all other html_label_* properties are invalid
55
+	 *
56
+	 * @var string
57
+	 */
58
+	protected $_html_label;
59
+
60
+	/**
61
+	 * HTML to use for help text (normally placed below form input), in a span which normally
62
+	 * has a class of 'description'
63
+	 *
64
+	 * @var string
65
+	 */
66
+	protected $_html_help_text;
67
+
68
+	/**
69
+	 * CSS classes for displaying the help span
70
+	 *
71
+	 * @var string
72
+	 */
73
+	protected $_html_help_class = 'description';
74
+
75
+	/**
76
+	 * CSS to put in the style attribute on the help span
77
+	 *
78
+	 * @var string
79
+	 */
80
+	protected $_html_help_style;
81
+
82
+	/**
83
+	 * Stores whether or not this input's response is required.
84
+	 * Because certain styling elements may also want to know that this
85
+	 * input is required etc.
86
+	 *
87
+	 * @var boolean
88
+	 */
89
+	protected $_required;
90
+
91
+	/**
92
+	 * css class added to required inputs
93
+	 *
94
+	 * @var string
95
+	 */
96
+	protected $_required_css_class = 'ee-required';
97
+
98
+	/**
99
+	 * css styles applied to button type inputs
100
+	 *
101
+	 * @var string
102
+	 */
103
+	protected $_button_css_attributes;
104
+
105
+	/**
106
+	 * The raw post data submitted for this
107
+	 * Generally unsafe for usage in client code
108
+	 *
109
+	 * @var mixed string or array
110
+	 */
111
+	protected $_raw_value;
112
+
113
+	/**
114
+	 * Value normalized according to the input's normalization strategy.
115
+	 * The normalization strategy dictates whether this is a string, int, float,
116
+	 * boolean, or array of any of those.
117
+	 *
118
+	 * @var mixed
119
+	 */
120
+	protected $_normalized_value;
121
+
122
+
123
+	/**
124
+	 * Normalized default value either initially set on the input, or provided by calling
125
+	 * set_default().
126
+	 * @var mixed
127
+	 */
128
+	protected $_default;
129
+
130
+	/**
131
+	 * Strategy used for displaying this field.
132
+	 * Child classes must use _get_display_strategy to access it.
133
+	 *
134
+	 * @var EE_Display_Strategy_Base
135
+	 */
136
+	private $_display_strategy;
137
+
138
+	/**
139
+	 * Gets all the validation strategies used on this field
140
+	 *
141
+	 * @var EE_Validation_Strategy_Base[]
142
+	 */
143
+	private $_validation_strategies = array();
144
+
145
+	/**
146
+	 * The normalization strategy for this field
147
+	 *
148
+	 * @var EE_Normalization_Strategy_Base
149
+	 */
150
+	private $_normalization_strategy;
151
+
152
+	/**
153
+	 * Strategy for removing sensitive data after we're done with the form input
154
+	 *
155
+	 * @var EE_Sensitive_Data_Removal_Base
156
+	 */
157
+	protected $_sensitive_data_removal_strategy;
158
+
159
+	/**
160
+	 * Whether this input has been disabled or not.
161
+	 * If it's disabled while rendering, an extra hidden input is added that indicates it has been knowingly disabled.
162
+	 * (Client-side code that wants to dynamically disable it must also add this hidden input).
163
+	 * When the form is submitted, if the input is disabled in the PHP form section, then input is ignored.
164
+	 * If the input is missing from the request data but the hidden input indicating the input is disabled, then the input is again ignored.
165
+	 *
166
+	 * @var boolean
167
+	 */
168
+	protected $disabled = false;
169
+
170
+
171
+
172
+	/**
173
+	 * @param array                         $input_args       {
174
+	 * @type string                         $html_name        the html name for the input
175
+	 * @type string                         $html_label_id    the id attribute to give to the html label tag
176
+	 * @type string                         $html_label_class the class attribute to give to the html label tag
177
+	 * @type string                         $html_label_style the style attribute to give ot teh label tag
178
+	 * @type string                         $html_label_text  the text to put in the label tag
179
+	 * @type string                         $html_label       the full html label. If used,
180
+	 *                                                        all other html_label_* args are invalid
181
+	 * @type string                         $html_help_text   text to put in help element
182
+	 * @type string                         $html_help_style  style attribute to give to teh help element
183
+	 * @type string                         $html_help_class  class attribute to give to the help element
184
+	 * @type string                         $default          default value NORMALIZED (eg, if providing the default
185
+	 *       for a Yes_No_Input, you should provide TRUE or FALSE, not '1' or '0')
186
+	 * @type EE_Display_Strategy_Base       $display          strategy
187
+	 * @type EE_Normalization_Strategy_Base $normalization_strategy
188
+	 * @type EE_Validation_Strategy_Base[]  $validation_strategies
189
+	 * @type boolean                        $ignore_input special argument which can be used to avoid adding any validation strategies,
190
+	 *                                                    and sets the normalization strategy to the Null normalization. This is good
191
+	 *                                                    when you want the input to be totally ignored server-side (like when using
192
+	 *                                                    React.js form inputs)
193
+	 *                                                        }
194
+	 */
195
+	public function __construct($input_args = array())
196
+	{
197
+		$input_args = (array) apply_filters('FHEE__EE_Form_Input_Base___construct__input_args', $input_args, $this);
198
+		// the following properties must be cast as arrays
199
+		if (isset($input_args['validation_strategies'])) {
200
+			foreach ((array) $input_args['validation_strategies'] as $validation_strategy) {
201
+				if ($validation_strategy instanceof EE_Validation_Strategy_Base && empty($input_args['ignore_input'])) {
202
+					$this->_validation_strategies[ get_class($validation_strategy) ] = $validation_strategy;
203
+				}
204
+			}
205
+			unset($input_args['validation_strategies']);
206
+		}
207
+		if (isset($input_args['ignore_input'])) {
208
+			$this->_validation_strategies = array();
209
+		}
210
+		// loop thru incoming options
211
+		foreach ($input_args as $key => $value) {
212
+			// add underscore to $key to match property names
213
+			$_key = '_' . $key;
214
+			if (property_exists($this, $_key)) {
215
+				$this->{$_key} = $value;
216
+			}
217
+		}
218
+		// ensure that "required" is set correctly
219
+		$this->set_required(
220
+			$this->_required,
221
+			isset($input_args['required_validation_error_message'])
222
+			? $input_args['required_validation_error_message']
223
+			: null
224
+		);
225
+		// $this->_html_name_specified = isset( $input_args['html_name'] ) ? TRUE : FALSE;
226
+		$this->_display_strategy->_construct_finalize($this);
227
+		foreach ($this->_validation_strategies as $validation_strategy) {
228
+			$validation_strategy->_construct_finalize($this);
229
+		}
230
+		if (isset($input_args['ignore_input'])) {
231
+			$this->_normalization_strategy = new EE_Null_Normalization();
232
+		}
233
+		if (! $this->_normalization_strategy) {
234
+				$this->_normalization_strategy = new EE_Text_Normalization();
235
+		}
236
+		$this->_normalization_strategy->_construct_finalize($this);
237
+		// at least we can use the normalization strategy to populate the default
238
+		if (isset($input_args['default'])) {
239
+			$this->set_default($input_args['default']);
240
+			unset($input_args['default']);
241
+		}
242
+		if (! $this->_sensitive_data_removal_strategy) {
243
+			$this->_sensitive_data_removal_strategy = new EE_No_Sensitive_Data_Removal();
244
+		}
245
+		$this->_sensitive_data_removal_strategy->_construct_finalize($this);
246
+		parent::__construct($input_args);
247
+	}
248
+
249
+
250
+
251
+	/**
252
+	 * Sets the html_name to its default value, if none was specified in teh constructor.
253
+	 * Calculation involves using the name and the parent's html_name
254
+	 *
255
+	 * @throws EE_Error
256
+	 */
257
+	protected function _set_default_html_name_if_empty()
258
+	{
259
+		if (! $this->_html_name) {
260
+			$this->_html_name = $this->name();
261
+			if ($this->_parent_section && $this->_parent_section instanceof EE_Form_Section_Proper) {
262
+				$this->_html_name = $this->_parent_section->html_name_prefix() . "[{$this->name()}]";
263
+			}
264
+		}
265
+	}
266
+
267
+
268
+
269
+	/**
270
+	 * @param $parent_form_section
271
+	 * @param $name
272
+	 * @throws EE_Error
273
+	 */
274
+	public function _construct_finalize($parent_form_section, $name)
275
+	{
276
+		parent::_construct_finalize($parent_form_section, $name);
277
+		if ($this->_html_label === null && $this->_html_label_text === null) {
278
+			$this->_html_label_text = ucwords(str_replace("_", " ", $name));
279
+		}
280
+		do_action('AHEE__EE_Form_Input_Base___construct_finalize__end', $this, $parent_form_section, $name);
281
+	}
282
+
283
+
284
+
285
+	/**
286
+	 * Returns the strategy for displaying this form input. If none is set, throws an exception.
287
+	 *
288
+	 * @return EE_Display_Strategy_Base
289
+	 * @throws EE_Error
290
+	 */
291
+	protected function _get_display_strategy()
292
+	{
293
+		$this->ensure_construct_finalized_called();
294
+		if (! $this->_display_strategy || ! $this->_display_strategy instanceof EE_Display_Strategy_Base) {
295
+			throw new EE_Error(
296
+				sprintf(
297
+					__(
298
+						"Cannot get display strategy for form input with name %s and id %s, because it has not been set in the constructor",
299
+						"event_espresso"
300
+					),
301
+					$this->html_name(),
302
+					$this->html_id()
303
+				)
304
+			);
305
+		} else {
306
+			return $this->_display_strategy;
307
+		}
308
+	}
309
+
310
+
311
+
312
+	/**
313
+	 * Sets the display strategy.
314
+	 *
315
+	 * @param EE_Display_Strategy_Base $strategy
316
+	 */
317
+	protected function _set_display_strategy(EE_Display_Strategy_Base $strategy)
318
+	{
319
+		$this->_display_strategy = $strategy;
320
+	}
321
+
322
+
323
+
324
+	/**
325
+	 * Sets the sanitization strategy
326
+	 *
327
+	 * @param EE_Normalization_Strategy_Base $strategy
328
+	 */
329
+	protected function _set_normalization_strategy(EE_Normalization_Strategy_Base $strategy)
330
+	{
331
+		$this->_normalization_strategy = $strategy;
332
+	}
333
+
334
+
335
+
336
+	/**
337
+	 * Gets sensitive_data_removal_strategy
338
+	 *
339
+	 * @return EE_Sensitive_Data_Removal_Base
340
+	 */
341
+	public function get_sensitive_data_removal_strategy()
342
+	{
343
+		return $this->_sensitive_data_removal_strategy;
344
+	}
345
+
346
+
347
+
348
+	/**
349
+	 * Sets sensitive_data_removal_strategy
350
+	 *
351
+	 * @param EE_Sensitive_Data_Removal_Base $sensitive_data_removal_strategy
352
+	 * @return void
353
+	 */
354
+	public function set_sensitive_data_removal_strategy($sensitive_data_removal_strategy)
355
+	{
356
+		$this->_sensitive_data_removal_strategy = $sensitive_data_removal_strategy;
357
+	}
358
+
359
+
360
+
361
+	/**
362
+	 * Gets the display strategy for this input
363
+	 *
364
+	 * @return EE_Display_Strategy_Base
365
+	 */
366
+	public function get_display_strategy()
367
+	{
368
+		return $this->_display_strategy;
369
+	}
370
+
371
+
372
+
373
+	/**
374
+	 * Overwrites the display strategy
375
+	 *
376
+	 * @param EE_Display_Strategy_Base $display_strategy
377
+	 */
378
+	public function set_display_strategy($display_strategy)
379
+	{
380
+		$this->_display_strategy = $display_strategy;
381
+		$this->_display_strategy->_construct_finalize($this);
382
+	}
383
+
384
+
385
+
386
+	/**
387
+	 * Gets the normalization strategy set on this input
388
+	 *
389
+	 * @return EE_Normalization_Strategy_Base
390
+	 */
391
+	public function get_normalization_strategy()
392
+	{
393
+		return $this->_normalization_strategy;
394
+	}
395
+
396
+
397
+
398
+	/**
399
+	 * Overwrites the normalization strategy
400
+	 *
401
+	 * @param EE_Normalization_Strategy_Base $normalization_strategy
402
+	 */
403
+	public function set_normalization_strategy($normalization_strategy)
404
+	{
405
+		$this->_normalization_strategy = $normalization_strategy;
406
+		$this->_normalization_strategy->_construct_finalize($this);
407
+	}
408
+
409
+
410
+
411
+	/**
412
+	 * Returns all teh validation strategies which apply to this field, numerically indexed
413
+	 *
414
+	 * @return EE_Validation_Strategy_Base[]
415
+	 */
416
+	public function get_validation_strategies()
417
+	{
418
+		return $this->_validation_strategies;
419
+	}
420
+
421
+
422
+
423
+	/**
424
+	 * Adds this strategy to the field so it will be used in both JS validation and server-side validation
425
+	 *
426
+	 * @param EE_Validation_Strategy_Base $validation_strategy
427
+	 * @return void
428
+	 */
429
+	protected function _add_validation_strategy(EE_Validation_Strategy_Base $validation_strategy)
430
+	{
431
+		$validation_strategy->_construct_finalize($this);
432
+		$this->_validation_strategies[] = $validation_strategy;
433
+	}
434
+
435
+
436
+
437
+	/**
438
+	 * Adds a new validation strategy onto the form input
439
+	 *
440
+	 * @param EE_Validation_Strategy_Base $validation_strategy
441
+	 * @return void
442
+	 */
443
+	public function add_validation_strategy(EE_Validation_Strategy_Base $validation_strategy)
444
+	{
445
+		$this->_add_validation_strategy($validation_strategy);
446
+	}
447
+
448
+
449
+
450
+	/**
451
+	 * The classname of the validation strategy to remove
452
+	 *
453
+	 * @param string $validation_strategy_classname
454
+	 */
455
+	public function remove_validation_strategy($validation_strategy_classname)
456
+	{
457
+		foreach ($this->_validation_strategies as $key => $validation_strategy) {
458
+			if ($validation_strategy instanceof $validation_strategy_classname
459
+				|| is_subclass_of($validation_strategy, $validation_strategy_classname)
460
+			) {
461
+				unset($this->_validation_strategies[ $key ]);
462
+			}
463
+		}
464
+	}
465
+
466
+
467
+
468
+	/**
469
+	 * returns true if input employs any of the validation strategy defined by the supplied array of classnames
470
+	 *
471
+	 * @param array $validation_strategy_classnames
472
+	 * @return bool
473
+	 */
474
+	public function has_validation_strategy($validation_strategy_classnames)
475
+	{
476
+		$validation_strategy_classnames = is_array($validation_strategy_classnames)
477
+			? $validation_strategy_classnames
478
+			: array($validation_strategy_classnames);
479
+		foreach ($this->_validation_strategies as $key => $validation_strategy) {
480
+			if (in_array($key, $validation_strategy_classnames)) {
481
+				return true;
482
+			}
483
+		}
484
+		return false;
485
+	}
486
+
487
+
488
+
489
+	/**
490
+	 * Gets the HTML
491
+	 *
492
+	 * @return string
493
+	 */
494
+	public function get_html()
495
+	{
496
+		return $this->_parent_section->get_html_for_input($this);
497
+	}
498
+
499
+
500
+
501
+	/**
502
+	 * Gets the HTML for the input itself (no label or errors) according to the
503
+	 * input's display strategy
504
+	 * Makes sure the JS and CSS are enqueued for it
505
+	 *
506
+	 * @return string
507
+	 * @throws EE_Error
508
+	 */
509
+	public function get_html_for_input()
510
+	{
511
+		return $this->_form_html_filter
512
+			? $this->_form_html_filter->filterHtml(
513
+				$this->_get_display_strategy()->display(),
514
+				$this
515
+			)
516
+			: $this->_get_display_strategy()->display();
517
+	}
518
+
519
+
520
+
521
+	/**
522
+	 * @return string
523
+	 */
524
+	public function html_other_attributes()
525
+	{
526
+		EE_Error::doing_it_wrong(
527
+			__METHOD__,
528
+			sprintf(
529
+				esc_html__(
530
+					'This method is no longer in use. You should replace it by %s',
531
+					'event_espresso'
532
+				),
533
+				'EE_Form_Section_Base::other_html_attributes()'
534
+			),
535
+			'4.10.2.p'
536
+		);
537
+
538
+		return $this->other_html_attributes();
539
+	}
540
+
541
+
542
+
543
+	/**
544
+	 * @param string $html_other_attributes
545
+	 */
546
+	public function set_html_other_attributes($html_other_attributes)
547
+	{
548
+		EE_Error::doing_it_wrong(
549
+			__METHOD__,
550
+			sprintf(
551
+				esc_html__(
552
+					'This method is no longer in use. You should replace it by %s',
553
+					'event_espresso'
554
+				),
555
+				'EE_Form_Section_Base::set_other_html_attributes()'
556
+			),
557
+			'4.10.2.p'
558
+		);
559
+
560
+		$this->set_other_html_attributes($html_other_attributes);
561
+	}
562
+
563
+
564
+
565
+	/**
566
+	 * Gets the HTML for displaying the label for this form input
567
+	 * according to the form section's layout strategy
568
+	 *
569
+	 * @return string
570
+	 */
571
+	public function get_html_for_label()
572
+	{
573
+		return $this->_parent_section->get_layout_strategy()->display_label($this);
574
+	}
575
+
576
+
577
+
578
+	/**
579
+	 * Gets the HTML for displaying the errors section for this form input
580
+	 * according to the form section's layout strategy
581
+	 *
582
+	 * @return string
583
+	 */
584
+	public function get_html_for_errors()
585
+	{
586
+		return $this->_parent_section->get_layout_strategy()->display_errors($this);
587
+	}
588
+
589
+
590
+
591
+	/**
592
+	 * Gets the HTML for displaying the help text for this form input
593
+	 * according to the form section's layout strategy
594
+	 *
595
+	 * @return string
596
+	 */
597
+	public function get_html_for_help()
598
+	{
599
+		return $this->_parent_section->get_layout_strategy()->display_help_text($this);
600
+	}
601
+
602
+
603
+
604
+	/**
605
+	 * Validates the input's sanitized value (assumes _sanitize() has already been called)
606
+	 * and returns whether or not the form input's submitted value is value
607
+	 *
608
+	 * @return boolean
609
+	 */
610
+	protected function _validate()
611
+	{
612
+		if ($this->isDisabled()) {
613
+			return true;
614
+		}
615
+		foreach ($this->_validation_strategies as $validation_strategy) {
616
+			if ($validation_strategy instanceof EE_Validation_Strategy_Base) {
617
+				try {
618
+					$validation_strategy->validate($this->normalized_value());
619
+				} catch (EE_Validation_Error $e) {
620
+					$this->add_validation_error($e);
621
+				}
622
+			}
623
+		}
624
+		if ($this->get_validation_errors()) {
625
+			return false;
626
+		} else {
627
+			return true;
628
+		}
629
+	}
630
+
631
+
632
+
633
+	/**
634
+	 * Performs basic sanitization on this value. But what sanitization can be performed anyways?
635
+	 * This value MIGHT be allowed to have tags, so we can't really remove them.
636
+	 *
637
+	 * @param string $value
638
+	 * @return null|string
639
+	 */
640
+	protected function _sanitize($value)
641
+	{
642
+		return $value !== null ? stripslashes(html_entity_decode(trim($value))) : null;
643
+	}
644
+
645
+
646
+
647
+	/**
648
+	 * Picks out the form value that relates to this form input,
649
+	 * and stores it as the sanitized value on the form input, and sets the normalized value.
650
+	 * Returns whether or not any validation errors occurred
651
+	 *
652
+	 * @param array $req_data
653
+	 * @return boolean whether or not there was an error
654
+	 * @throws EE_Error
655
+	 */
656
+	protected function _normalize($req_data)
657
+	{
658
+		// any existing validation errors don't apply so clear them
659
+		$this->_validation_errors = array();
660
+		// if the input is disabled, ignore whatever input was sent in
661
+		if ($this->isDisabled()) {
662
+			$this->_set_raw_value(null);
663
+			$this->_set_normalized_value($this->get_default());
664
+			return false;
665
+		}
666
+		try {
667
+			$raw_input = $this->find_form_data_for_this_section($req_data);
668
+			// super simple sanitization for now
669
+			if (is_array($raw_input)) {
670
+				$raw_value = array();
671
+				foreach ($raw_input as $key => $value) {
672
+					$raw_value[ $key ] = $this->_sanitize($value);
673
+				}
674
+				$this->_set_raw_value($raw_value);
675
+			} else {
676
+				$this->_set_raw_value($this->_sanitize($raw_input));
677
+			}
678
+			// we want to mostly leave the input alone in case we need to re-display it to the user
679
+			$this->_set_normalized_value($this->_normalization_strategy->normalize($this->raw_value()));
680
+			return false;
681
+		} catch (EE_Validation_Error $e) {
682
+			$this->add_validation_error($e);
683
+			return true;
684
+		}
685
+	}
686
+
687
+
688
+	/**
689
+	 * @return string
690
+	 * @throws EE_Error
691
+	 */
692
+	public function html_name()
693
+	{
694
+		$this->_set_default_html_name_if_empty();
695
+		return $this->_html_name;
696
+	}
697
+
698
+
699
+	/**
700
+	 * @return string
701
+	 * @throws EE_Error
702
+	 */
703
+	public function html_label_id()
704
+	{
705
+		return ! empty($this->_html_label_id) ? $this->_html_label_id : $this->html_id() . '-lbl';
706
+	}
707
+
708
+
709
+
710
+	/**
711
+	 * @return string
712
+	 */
713
+	public function html_label_class()
714
+	{
715
+		return $this->_html_label_class;
716
+	}
717
+
718
+
719
+
720
+	/**
721
+	 * @return string
722
+	 */
723
+	public function html_label_style()
724
+	{
725
+		return $this->_html_label_style;
726
+	}
727
+
728
+
729
+
730
+	/**
731
+	 * @return string
732
+	 */
733
+	public function html_label_text()
734
+	{
735
+		return $this->_html_label_text;
736
+	}
737
+
738
+
739
+
740
+	/**
741
+	 * @return string
742
+	 */
743
+	public function html_help_text()
744
+	{
745
+		return $this->_html_help_text;
746
+	}
747
+
748
+
749
+
750
+	/**
751
+	 * @return string
752
+	 */
753
+	public function html_help_class()
754
+	{
755
+		return $this->_html_help_class;
756
+	}
757
+
758
+
759
+
760
+	/**
761
+	 * @return string
762
+	 */
763
+	public function html_help_style()
764
+	{
765
+		return $this->_html_style;
766
+	}
767
+
768
+
769
+
770
+	/**
771
+	 * returns the raw, UNSAFE, input, almost exactly as the user submitted it.
772
+	 * Please note that almost all client code should instead use the normalized_value;
773
+	 * or possibly raw_value_in_form (which prepares the string for displaying in an HTML attribute on a tag,
774
+	 * mostly by escaping quotes)
775
+	 * Note, we do not store the exact original value sent in the user's request because
776
+	 * it may have malicious content, and we MIGHT want to store the form input in a transient or something...
777
+	 * in which case, we would have stored the malicious content to our database.
778
+	 *
779
+	 * @return string
780
+	 */
781
+	public function raw_value()
782
+	{
783
+		return $this->_raw_value;
784
+	}
785
+
786
+
787
+
788
+	/**
789
+	 * Returns a string safe to usage in form inputs when displaying, because
790
+	 * it escapes all html entities
791
+	 *
792
+	 * @return string
793
+	 */
794
+	public function raw_value_in_form()
795
+	{
796
+		return htmlentities($this->raw_value(), ENT_QUOTES, 'UTF-8');
797
+	}
798
+
799
+
800
+
801
+	/**
802
+	 * returns the value after it's been sanitized, and then converted into it's proper type
803
+	 * in PHP. Eg, a string, an int, an array,
804
+	 *
805
+	 * @return mixed
806
+	 */
807
+	public function normalized_value()
808
+	{
809
+		return $this->_normalized_value;
810
+	}
811
+
812
+
813
+
814
+	/**
815
+	 * Returns the normalized value is a presentable way. By default this is just
816
+	 * the normalized value by itself, but it can be overridden for when that's not
817
+	 * the best thing to display
818
+	 *
819
+	 * @return string
820
+	 */
821
+	public function pretty_value()
822
+	{
823
+		return $this->_normalized_value;
824
+	}
825
+
826
+
827
+
828
+	/**
829
+	 * When generating the JS for the jquery validation rules like<br>
830
+	 * <code>$( "#myform" ).validate({
831
+	 * rules: {
832
+	 * password: "required",
833
+	 * password_again: {
834
+	 * equalTo: "#password"
835
+	 * }
836
+	 * }
837
+	 * });</code>
838
+	 * if this field had the name 'password_again', it should return
839
+	 * <br><code>password_again: {
840
+	 * equalTo: "#password"
841
+	 * }</code>
842
+	 *
843
+	 * @return array
844
+	 */
845
+	public function get_jquery_validation_rules()
846
+	{
847
+		$jquery_validation_js = array();
848
+		$jquery_validation_rules = array();
849
+		foreach ($this->get_validation_strategies() as $validation_strategy) {
850
+			$jquery_validation_rules = array_replace_recursive(
851
+				$jquery_validation_rules,
852
+				$validation_strategy->get_jquery_validation_rule_array()
853
+			);
854
+		}
855
+		if (! empty($jquery_validation_rules)) {
856
+			foreach ($this->get_display_strategy()->get_html_input_ids(true) as $html_id_with_pound_sign) {
857
+				$jquery_validation_js[ $html_id_with_pound_sign ] = $jquery_validation_rules;
858
+			}
859
+		}
860
+		return $jquery_validation_js;
861
+	}
862
+
863
+
864
+
865
+	/**
866
+	 * Sets the input's default value for use in displaying in the form. Note: value should be
867
+	 * normalized (Eg, if providing a default of ra Yes_NO_Input you would provide TRUE or FALSE, not '1' or '0')
868
+	 *
869
+	 * @param mixed $value
870
+	 * @return void
871
+	 */
872
+	public function set_default($value)
873
+	{
874
+		$this->_default = $value;
875
+		$this->_set_normalized_value($value);
876
+		$this->_set_raw_value($value);
877
+	}
878
+
879
+
880
+
881
+	/**
882
+	 * Sets the normalized value on this input
883
+	 *
884
+	 * @param mixed $value
885
+	 */
886
+	protected function _set_normalized_value($value)
887
+	{
888
+		$this->_normalized_value = $value;
889
+	}
890
+
891
+
892
+
893
+	/**
894
+	 * Sets the raw value on this input (ie, exactly as the user submitted it)
895
+	 *
896
+	 * @param mixed $value
897
+	 */
898
+	protected function _set_raw_value($value)
899
+	{
900
+		$this->_raw_value = $this->_normalization_strategy->unnormalize($value);
901
+	}
902
+
903
+
904
+
905
+	/**
906
+	 * Sets the HTML label text after it has already been defined
907
+	 *
908
+	 * @param string $label
909
+	 * @return void
910
+	 */
911
+	public function set_html_label_text($label)
912
+	{
913
+		$this->_html_label_text = $label;
914
+	}
915
+
916
+
917
+
918
+	/**
919
+	 * Sets whether or not this field is required, and adjusts the validation strategy.
920
+	 * If you want to use the EE_Conditionally_Required_Validation_Strategy,
921
+	 * please add it as a validation strategy using add_validation_strategy as normal
922
+	 *
923
+	 * @param boolean $required boolean
924
+	 * @param null    $required_text
925
+	 */
926
+	public function set_required($required = true, $required_text = null)
927
+	{
928
+		$required = filter_var($required, FILTER_VALIDATE_BOOLEAN);
929
+		// whether $required is a string or a boolean, we want to add a required validation strategy
930
+		if ($required) {
931
+			$this->_add_validation_strategy(new EE_Required_Validation_Strategy($required_text));
932
+		} else {
933
+			$this->remove_validation_strategy('EE_Required_Validation_Strategy');
934
+		}
935
+		$this->_required = $required;
936
+	}
937
+
938
+
939
+
940
+	/**
941
+	 * Returns whether or not this field is required
942
+	 *
943
+	 * @return boolean
944
+	 */
945
+	public function required()
946
+	{
947
+		return $this->_required;
948
+	}
949
+
950
+
951
+
952
+	/**
953
+	 * @param string $required_css_class
954
+	 */
955
+	public function set_required_css_class($required_css_class)
956
+	{
957
+		$this->_required_css_class = $required_css_class;
958
+	}
959
+
960
+
961
+
962
+	/**
963
+	 * @return string
964
+	 */
965
+	public function required_css_class()
966
+	{
967
+		return $this->_required_css_class;
968
+	}
969
+
970
+
971
+
972
+	/**
973
+	 * @param bool $add_required
974
+	 * @return string
975
+	 */
976
+	public function html_class($add_required = false)
977
+	{
978
+		return $add_required && $this->required()
979
+			? $this->required_css_class() . ' ' . $this->_html_class
980
+			: $this->_html_class;
981
+	}
982
+
983
+
984
+	/**
985
+	 * Sets the help text, in case
986
+	 *
987
+	 * @param string $text
988
+	 */
989
+	public function set_html_help_text($text)
990
+	{
991
+		$this->_html_help_text = $text;
992
+	}
993
+
994
+
995
+
996
+	/**
997
+	 * Uses the sensitive data removal strategy to remove the sensitive data from this
998
+	 * input. If there is any kind of sensitive data removal on this input, we clear
999
+	 * out the raw value completely
1000
+	 *
1001
+	 * @return void
1002
+	 */
1003
+	public function clean_sensitive_data()
1004
+	{
1005
+		// if we do ANY kind of sensitive data removal on this, then just clear out the raw value
1006
+		// if we need more logic than this we'll make a strategy for it
1007
+		if ($this->_sensitive_data_removal_strategy
1008
+			&& ! $this->_sensitive_data_removal_strategy instanceof EE_No_Sensitive_Data_Removal
1009
+		) {
1010
+			$this->_set_raw_value(null);
1011
+		}
1012
+		// and clean the normalized value according to the appropriate strategy
1013
+		$this->_set_normalized_value(
1014
+			$this->get_sensitive_data_removal_strategy()->remove_sensitive_data(
1015
+				$this->_normalized_value
1016
+			)
1017
+		);
1018
+	}
1019
+
1020
+
1021
+
1022
+	/**
1023
+	 * @param bool   $primary
1024
+	 * @param string $button_size
1025
+	 * @param string $other_attributes
1026
+	 */
1027
+	public function set_button_css_attributes($primary = true, $button_size = '', $other_attributes = '')
1028
+	{
1029
+		$button_css_attributes = 'button';
1030
+		$button_css_attributes .= $primary === true ? ' button-primary' : ' button-secondary';
1031
+		switch ($button_size) {
1032
+			case 'xs':
1033
+			case 'extra-small':
1034
+				$button_css_attributes .= ' button-xs';
1035
+				break;
1036
+			case 'sm':
1037
+			case 'small':
1038
+				$button_css_attributes .= ' button-sm';
1039
+				break;
1040
+			case 'lg':
1041
+			case 'large':
1042
+				$button_css_attributes .= ' button-lg';
1043
+				break;
1044
+			case 'block':
1045
+				$button_css_attributes .= ' button-block';
1046
+				break;
1047
+			case 'md':
1048
+			case 'medium':
1049
+			default:
1050
+				$button_css_attributes .= '';
1051
+		}
1052
+		$this->_button_css_attributes .= ! empty($other_attributes)
1053
+			? $button_css_attributes . ' ' . $other_attributes
1054
+			: $button_css_attributes;
1055
+	}
1056
+
1057
+
1058
+
1059
+	/**
1060
+	 * @return string
1061
+	 */
1062
+	public function button_css_attributes()
1063
+	{
1064
+		if (empty($this->_button_css_attributes)) {
1065
+			$this->set_button_css_attributes();
1066
+		}
1067
+		return $this->_button_css_attributes;
1068
+	}
1069
+
1070
+
1071
+
1072
+	/**
1073
+	 * find_form_data_for_this_section
1074
+	 * using this section's name and its parents, finds the value of the form data that corresponds to it.
1075
+	 * For example, if this form section's HTML name is my_form[subform][form_input_1],
1076
+	 * then it's value should be in request at request['my_form']['subform']['form_input_1'].
1077
+	 * (If that doesn't exist, we also check for this subsection's name
1078
+	 * at the TOP LEVEL of the request data. Eg request['form_input_1'].)
1079
+	 * This function finds its value in the form.
1080
+	 *
1081
+	 * @param array $req_data
1082
+	 * @return mixed whatever the raw value of this form section is in the request data
1083
+	 * @throws EE_Error
1084
+	 */
1085
+	public function find_form_data_for_this_section($req_data)
1086
+	{
1087
+		$name_parts = $this->getInputNameParts();
1088
+		// now get the value for the input
1089
+		$value = $this->findRequestForSectionUsingNameParts($name_parts, $req_data);
1090
+		// check if this thing's name is at the TOP level of the request data
1091
+		if ($value === null && isset($req_data[ $this->name() ])) {
1092
+			$value = $req_data[ $this->name() ];
1093
+		}
1094
+		return $value;
1095
+	}
1096
+
1097
+
1098
+	/**
1099
+	 * If this input's name is something like "foo[bar][baz]"
1100
+	 * returns an array like `array('foo','bar',baz')`
1101
+	 *
1102
+	 * @return array
1103
+	 * @throws EE_Error
1104
+	 */
1105
+	protected function getInputNameParts()
1106
+	{
1107
+		// break up the html name by "[]"
1108
+		if (strpos($this->html_name(), '[') !== false) {
1109
+			$before_any_brackets = substr($this->html_name(), 0, strpos($this->html_name(), '['));
1110
+		} else {
1111
+			$before_any_brackets = $this->html_name();
1112
+		}
1113
+		// grab all of the segments
1114
+		preg_match_all('~\[([^]]*)\]~', $this->html_name(), $matches);
1115
+		if (isset($matches[1]) && is_array($matches[1])) {
1116
+			$name_parts = $matches[1];
1117
+			array_unshift($name_parts, $before_any_brackets);
1118
+		} else {
1119
+			$name_parts = array($before_any_brackets);
1120
+		}
1121
+		return $name_parts;
1122
+	}
1123
+
1124
+
1125
+
1126
+	/**
1127
+	 * @param array $html_name_parts
1128
+	 * @param array $req_data
1129
+	 * @return array | NULL
1130
+	 */
1131
+	public function findRequestForSectionUsingNameParts($html_name_parts, $req_data)
1132
+	{
1133
+		$first_part_to_consider = array_shift($html_name_parts);
1134
+		if (isset($req_data[ $first_part_to_consider ])) {
1135
+			if (empty($html_name_parts)) {
1136
+				return $req_data[ $first_part_to_consider ];
1137
+			} else {
1138
+				return $this->findRequestForSectionUsingNameParts(
1139
+					$html_name_parts,
1140
+					$req_data[ $first_part_to_consider ]
1141
+				);
1142
+			}
1143
+		} else {
1144
+			return null;
1145
+		}
1146
+	}
1147
+
1148
+
1149
+
1150
+	/**
1151
+	 * Checks if this form input's data is in the request data
1152
+	 *
1153
+	 * @param array $req_data
1154
+	 * @return boolean
1155
+	 * @throws EE_Error
1156
+	 */
1157
+	public function form_data_present_in($req_data = null)
1158
+	{
1159
+		if ($req_data === null) {
1160
+			/** @var RequestInterface $request */
1161
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1162
+			$req_data = $request->postParams();
1163
+		}
1164
+		$checked_value = $this->find_form_data_for_this_section($req_data);
1165
+		if ($checked_value !== null) {
1166
+			return true;
1167
+		} else {
1168
+			return false;
1169
+		}
1170
+	}
1171
+
1172
+
1173
+
1174
+	/**
1175
+	 * Overrides parent to add js data from validation and display strategies
1176
+	 *
1177
+	 * @param array $form_other_js_data
1178
+	 * @return array
1179
+	 */
1180
+	public function get_other_js_data($form_other_js_data = array())
1181
+	{
1182
+		return $this->get_other_js_data_from_strategies($form_other_js_data);
1183
+	}
1184
+
1185
+
1186
+
1187
+	/**
1188
+	 * Gets other JS data for localization from this input's strategies, like
1189
+	 * the validation strategies and the display strategy
1190
+	 *
1191
+	 * @param array $form_other_js_data
1192
+	 * @return array
1193
+	 */
1194
+	public function get_other_js_data_from_strategies($form_other_js_data = array())
1195
+	{
1196
+		$form_other_js_data = $this->get_display_strategy()->get_other_js_data($form_other_js_data);
1197
+		foreach ($this->get_validation_strategies() as $validation_strategy) {
1198
+			$form_other_js_data = $validation_strategy->get_other_js_data($form_other_js_data);
1199
+		}
1200
+		return $form_other_js_data;
1201
+	}
1202
+
1203
+
1204
+
1205
+	/**
1206
+	 * Override parent because we want to give our strategies an opportunity to enqueue some js and css
1207
+	 *
1208
+	 * @return void
1209
+	 */
1210
+	public function enqueue_js()
1211
+	{
1212
+		// ask our display strategy and validation strategies if they have js to enqueue
1213
+		$this->enqueue_js_from_strategies();
1214
+	}
1215
+
1216
+
1217
+
1218
+	/**
1219
+	 * Tells strategies when its ok to enqueue their js and css
1220
+	 *
1221
+	 * @return void
1222
+	 */
1223
+	public function enqueue_js_from_strategies()
1224
+	{
1225
+		$this->get_display_strategy()->enqueue_js();
1226
+		foreach ($this->get_validation_strategies() as $validation_strategy) {
1227
+			$validation_strategy->enqueue_js();
1228
+		}
1229
+	}
1230
+
1231
+
1232
+
1233
+	/**
1234
+	 * Gets the default value set on the input (not the current value, which may have been
1235
+	 * changed because of a form submission). If no default was set, this us null.
1236
+	 * @return mixed
1237
+	 */
1238
+	public function get_default()
1239
+	{
1240
+		return $this->_default;
1241
+	}
1242
+
1243
+
1244
+
1245
+	/**
1246
+	 * Makes this input disabled. That means it will have the HTML attribute 'disabled="disabled"',
1247
+	 * and server-side if any input was received it will be ignored
1248
+	 */
1249
+	public function disable($disable = true)
1250
+	{
1251
+		$disabled_attribute = ' disabled="disabled"';
1252
+		$this->disabled = filter_var($disable, FILTER_VALIDATE_BOOLEAN);
1253
+		if ($this->disabled) {
1254
+			if (strpos($this->_other_html_attributes, $disabled_attribute) === false) {
1255
+				$this->_other_html_attributes .= $disabled_attribute;
1256
+			}
1257
+			$this->_set_normalized_value($this->get_default());
1258
+		} else {
1259
+			$this->_other_html_attributes = str_replace($disabled_attribute, '', $this->_other_html_attributes);
1260
+		}
1261
+	}
1262
+
1263
+
1264
+
1265
+	/**
1266
+	 * Returns whether or not this input is currently disabled.
1267
+	 * @return bool
1268
+	 */
1269
+	public function isDisabled()
1270
+	{
1271
+		return $this->disabled;
1272
+	}
1273 1273
 }
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Fixed_Hidden_Input.input.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -10,15 +10,15 @@
 block discarded – undo
10 10
 {
11 11
 
12 12
 
13
-    /**
14
-     * Fixed Inputs are inputs that do NOT accept user input
15
-     * therefore they will ALWAYS return the default value that was set upon their creation
16
-     * and NO normalization or sanitization will occur because the request value is being ignored
17
-     *
18
-     * @param array $req_data
19
-     * @return boolean whether or not there was an error
20
-     */
21
-    protected function _normalize($req_data)
22
-    {
23
-    }
13
+	/**
14
+	 * Fixed Inputs are inputs that do NOT accept user input
15
+	 * therefore they will ALWAYS return the default value that was set upon their creation
16
+	 * and NO normalization or sanitization will occur because the request value is being ignored
17
+	 *
18
+	 * @param array $req_data
19
+	 * @return boolean whether or not there was an error
20
+	 */
21
+	protected function _normalize($req_data)
22
+	{
23
+	}
24 24
 }
Please login to merge, or discard this patch.
core/libraries/form_sections/base/EE_Form_Section_Proper.form.php 1 patch
Indentation   +1526 added lines, -1526 removed lines patch added patch discarded remove patch
@@ -16,1530 +16,1530 @@
 block discarded – undo
16 16
 class EE_Form_Section_Proper extends EE_Form_Section_Validatable
17 17
 {
18 18
 
19
-    const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
20
-
21
-    /**
22
-     * Subsections
23
-     *
24
-     * @var EE_Form_Section_Validatable[]
25
-     */
26
-    protected $_subsections = array();
27
-
28
-    /**
29
-     * Strategy for laying out the form
30
-     *
31
-     * @var EE_Form_Section_Layout_Base
32
-     */
33
-    protected $_layout_strategy;
34
-
35
-    /**
36
-     * Whether or not this form has received and validated a form submission yet
37
-     *
38
-     * @var boolean
39
-     */
40
-    protected $_received_submission = false;
41
-
42
-    /**
43
-     * message displayed to users upon successful form submission
44
-     *
45
-     * @var string
46
-     */
47
-    protected $_form_submission_success_message = '';
48
-
49
-    /**
50
-     * message displayed to users upon unsuccessful form submission
51
-     *
52
-     * @var string
53
-     */
54
-    protected $_form_submission_error_message = '';
55
-
56
-    /**
57
-     * @var array like post / request
58
-     */
59
-    protected $cached_request_data;
60
-
61
-    /**
62
-     * Stores whether this form (and its sub-sections) were found to be valid or not.
63
-     * Starts off as null, but once the form is validated, it set to either true or false
64
-     * @var boolean|null
65
-     */
66
-    protected $is_valid;
67
-
68
-    /**
69
-     * Stores all the data that will localized for form validation
70
-     *
71
-     * @var array
72
-     */
73
-    static protected $_js_localization = array();
74
-
75
-    /**
76
-     * whether or not the form's localized validation JS vars have been set
77
-     *
78
-     * @type boolean
79
-     */
80
-    static protected $_scripts_localized = false;
81
-
82
-
83
-    /**
84
-     * when constructing a proper form section, calls _construct_finalize on children
85
-     * so that they know who their parent is, and what name they've been given.
86
-     *
87
-     * @param array[] $options_array   {
88
-     * @type          $subsections     EE_Form_Section_Validatable[] where keys are the section's name
89
-     * @type          $include         string[] numerically-indexed where values are section names to be included,
90
-     *                                 and in that order. This is handy if you want
91
-     *                                 the subsections to be ordered differently than the default, and if you override
92
-     *                                 which fields are shown
93
-     * @type          $exclude         string[] values are subsections to be excluded. This is handy if you want
94
-     *                                 to remove certain default subsections (note: if you specify BOTH 'include' AND
95
-     *                                 'exclude', the inclusions will be applied first, and the exclusions will exclude
96
-     *                                 items from that list of inclusions)
97
-     * @type          $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
98
-     *                                 } @see EE_Form_Section_Validatable::__construct()
99
-     * @throws EE_Error
100
-     */
101
-    public function __construct($options_array = array())
102
-    {
103
-        $options_array = (array) apply_filters(
104
-            'FHEE__EE_Form_Section_Proper___construct__options_array',
105
-            $options_array,
106
-            $this
107
-        );
108
-        // call parent first, as it may be setting the name
109
-        parent::__construct($options_array);
110
-        // if they've included subsections in the constructor, add them now
111
-        if (isset($options_array['include'])) {
112
-            // we are going to make sure we ONLY have those subsections to include
113
-            // AND we are going to make sure they're in that specified order
114
-            $reordered_subsections = array();
115
-            foreach ($options_array['include'] as $input_name) {
116
-                if (isset($this->_subsections[ $input_name ])) {
117
-                    $reordered_subsections[ $input_name ] = $this->_subsections[ $input_name ];
118
-                }
119
-            }
120
-            $this->_subsections = $reordered_subsections;
121
-        }
122
-        if (isset($options_array['exclude'])) {
123
-            $exclude            = $options_array['exclude'];
124
-            $this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
125
-        }
126
-        if (isset($options_array['layout_strategy'])) {
127
-            $this->_layout_strategy = $options_array['layout_strategy'];
128
-        }
129
-        if (! $this->_layout_strategy) {
130
-            $this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
131
-        }
132
-        $this->_layout_strategy->_construct_finalize($this);
133
-        // ok so we are definitely going to want the forms JS,
134
-        // so enqueue it or remember to enqueue it during wp_enqueue_scripts
135
-        if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
136
-            // ok so they've constructed this object after when they should have.
137
-            // just enqueue the generic form scripts and initialize the form immediately in the JS
138
-            EE_Form_Section_Proper::wp_enqueue_scripts(true);
139
-        } else {
140
-            add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
141
-            add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
142
-        }
143
-        add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
144
-        /**
145
-         * Gives other plugins a chance to hook in before construct finalize is called.
146
-         * The form probably doesn't yet have a parent form section.
147
-         * Since 4.9.32, when this action was introduced, this is the best place to add a subsection onto a form,
148
-         * assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
149
-         * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
150
-         *
151
-         * @since 4.9.32
152
-         * @param EE_Form_Section_Proper $this          before __construct is done, but all of its logic,
153
-         *                                              except maybe calling _construct_finalize has been done
154
-         * @param array                  $options_array options passed into the constructor
155
-         */
156
-        do_action(
157
-            'AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called',
158
-            $this,
159
-            $options_array
160
-        );
161
-        if (isset($options_array['name'])) {
162
-            $this->_construct_finalize(null, $options_array['name']);
163
-        }
164
-    }
165
-
166
-
167
-    /**
168
-     * Finishes construction given the parent form section and this form section's name
169
-     *
170
-     * @param EE_Form_Section_Proper $parent_form_section
171
-     * @param string                 $name
172
-     * @throws EE_Error
173
-     */
174
-    public function _construct_finalize($parent_form_section, $name)
175
-    {
176
-        parent::_construct_finalize($parent_form_section, $name);
177
-        $this->_set_default_name_if_empty();
178
-        $this->_set_default_html_id_if_empty();
179
-        foreach ($this->_subsections as $subsection_name => $subsection) {
180
-            if ($subsection instanceof EE_Form_Section_Base) {
181
-                $subsection->_construct_finalize($this, $subsection_name);
182
-            } else {
183
-                throw new EE_Error(
184
-                    sprintf(
185
-                        esc_html__(
186
-                            'Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
187
-                            'event_espresso'
188
-                        ),
189
-                        $subsection_name,
190
-                        get_class($this),
191
-                        $subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
192
-                    )
193
-                );
194
-            }
195
-        }
196
-        /**
197
-         * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
198
-         * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID
199
-         * (or other attributes derived from the name like the HTML label id, etc), this is where it should be done.
200
-         * This might only happen just before displaying the form, or just before it receives form submission data.
201
-         * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
202
-         * ensured it has a name, HTML IDs, etc
203
-         *
204
-         * @param EE_Form_Section_Proper      $this
205
-         * @param EE_Form_Section_Proper|null $parent_form_section
206
-         * @param string                      $name
207
-         */
208
-        do_action(
209
-            'AHEE__EE_Form_Section_Proper___construct_finalize__end',
210
-            $this,
211
-            $parent_form_section,
212
-            $name
213
-        );
214
-    }
215
-
216
-
217
-    /**
218
-     * Gets the layout strategy for this form section
219
-     *
220
-     * @return EE_Form_Section_Layout_Base
221
-     */
222
-    public function get_layout_strategy()
223
-    {
224
-        return $this->_layout_strategy;
225
-    }
226
-
227
-
228
-    /**
229
-     * Gets the HTML for a single input for this form section according
230
-     * to the layout strategy
231
-     *
232
-     * @param EE_Form_Input_Base $input
233
-     * @return string
234
-     */
235
-    public function get_html_for_input($input)
236
-    {
237
-        return $this->_layout_strategy->layout_input($input);
238
-    }
239
-
240
-
241
-    /**
242
-     * was_submitted - checks if form inputs are present in request data
243
-     * Basically an alias for form_data_present_in() (which is used by both
244
-     * proper form sections and form inputs)
245
-     *
246
-     * @param null $form_data
247
-     * @return boolean
248
-     * @throws EE_Error
249
-     */
250
-    public function was_submitted($form_data = null)
251
-    {
252
-        return $this->form_data_present_in($form_data);
253
-    }
254
-
255
-    /**
256
-     * Gets the cached request data; but if there is none, or $req_data was set with
257
-     * something different, refresh the cache, and then return it
258
-     * @param null $req_data
259
-     * @return array
260
-     */
261
-    protected function getCachedRequest($req_data = null)
262
-    {
263
-        if ($this->cached_request_data === null
264
-            || (
265
-                $req_data !== null &&
266
-                $req_data !== $this->cached_request_data
267
-            )
268
-        ) {
269
-            $req_data = apply_filters(
270
-                'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
271
-                $req_data,
272
-                $this
273
-            );
274
-            if ($req_data === null) {
275
-                /** @var RequestInterface $request */
276
-                $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
277
-                $req_data = $request->requestParams();
278
-            }
279
-            $req_data = apply_filters(
280
-                'FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
281
-                $req_data,
282
-                $this
283
-            );
284
-            $this->cached_request_data = (array) $req_data;
285
-        }
286
-        return $this->cached_request_data;
287
-    }
288
-
289
-
290
-    /**
291
-     * After the form section is initially created, call this to sanitize the data in the submission
292
-     * which relates to this form section, validate it, and set it as properties on the form.
293
-     *
294
-     * @param array|null $req_data should usually be post data (the default).
295
-     *                             However, you CAN supply a different array.
296
-     *                             Consider using set_defaults() instead however.
297
-     *                             (If you rendered the form in the page using echo $form_x->get_html()
298
-     *                             the inputs will have the correct name in the request data for this function
299
-     *                             to find them and populate the form with them.
300
-     *                             If you have a flat form (with only input subsections),
301
-     *                             you can supply a flat array where keys
302
-     *                             are the form input names and values are their values)
303
-     * @param boolean    $validate whether or not to perform validation on this data. Default is,
304
-     *                             of course, to validate that data, and set errors on the invalid values.
305
-     *                             But if the data has already been validated
306
-     *                             (eg you validated the data then stored it in the DB)
307
-     *                             you may want to skip this step.
308
-     * @throws InvalidArgumentException
309
-     * @throws InvalidInterfaceException
310
-     * @throws InvalidDataTypeException
311
-     * @throws EE_Error
312
-     */
313
-    public function receive_form_submission($req_data = null, $validate = true)
314
-    {
315
-        $req_data = $this->getCachedRequest($req_data);
316
-        $this->_normalize($req_data);
317
-        if ($validate) {
318
-            $this->_validate();
319
-            // if it's invalid, we're going to want to re-display so remember what they submitted
320
-            if (! $this->is_valid()) {
321
-                $this->store_submitted_form_data_in_session();
322
-            }
323
-        }
324
-        if ($this->submission_error_message() === '' && ! $this->is_valid()) {
325
-            $this->set_submission_error_message();
326
-        }
327
-        do_action(
328
-            'AHEE__EE_Form_Section_Proper__receive_form_submission__end',
329
-            $req_data,
330
-            $this,
331
-            $validate
332
-        );
333
-    }
334
-
335
-
336
-    /**
337
-     * caches the originally submitted input values in the session
338
-     * so that they can be used to repopulate the form if it failed validation
339
-     *
340
-     * @return boolean whether or not the data was successfully stored in the session
341
-     * @throws InvalidArgumentException
342
-     * @throws InvalidInterfaceException
343
-     * @throws InvalidDataTypeException
344
-     * @throws EE_Error
345
-     */
346
-    protected function store_submitted_form_data_in_session()
347
-    {
348
-        return EE_Registry::instance()->SSN->set_session_data(
349
-            array(
350
-                EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
351
-            )
352
-        );
353
-    }
354
-
355
-
356
-    /**
357
-     * retrieves the originally submitted input values in the session
358
-     * so that they can be used to repopulate the form if it failed validation
359
-     *
360
-     * @return array
361
-     * @throws InvalidArgumentException
362
-     * @throws InvalidInterfaceException
363
-     * @throws InvalidDataTypeException
364
-     */
365
-    protected function get_submitted_form_data_from_session()
366
-    {
367
-        $session = EE_Registry::instance()->SSN;
368
-        if ($session instanceof EE_Session) {
369
-            return $session->get_session_data(
370
-                EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
371
-            );
372
-        }
373
-        return array();
374
-    }
375
-
376
-
377
-    /**
378
-     * flushed the originally submitted input values from the session
379
-     *
380
-     * @return boolean whether or not the data was successfully removed from the session
381
-     * @throws InvalidArgumentException
382
-     * @throws InvalidInterfaceException
383
-     * @throws InvalidDataTypeException
384
-     */
385
-    public static function flush_submitted_form_data_from_session()
386
-    {
387
-        return EE_Registry::instance()->SSN->reset_data(
388
-            array(EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
389
-        );
390
-    }
391
-
392
-
393
-    /**
394
-     * Populates this form and its subsections with data from the session.
395
-     * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
396
-     * validation errors when displaying too)
397
-     * Returns true if the form was populated from the session, false otherwise
398
-     *
399
-     * @return boolean
400
-     * @throws InvalidArgumentException
401
-     * @throws InvalidInterfaceException
402
-     * @throws InvalidDataTypeException
403
-     * @throws EE_Error
404
-     */
405
-    public function populate_from_session()
406
-    {
407
-        $form_data_in_session = $this->get_submitted_form_data_from_session();
408
-        if (empty($form_data_in_session)) {
409
-            return false;
410
-        }
411
-        $this->receive_form_submission($form_data_in_session);
412
-        add_action('shutdown', array('EE_Form_Section_Proper', 'flush_submitted_form_data_from_session'));
413
-        if ($this->form_data_present_in($form_data_in_session)) {
414
-            return true;
415
-        }
416
-        return false;
417
-    }
418
-
419
-
420
-    /**
421
-     * Populates the default data for the form, given an array where keys are
422
-     * the input names, and values are their values (preferably normalized to be their
423
-     * proper PHP types, not all strings... although that should be ok too).
424
-     * Proper subsections are sub-arrays, the key being the subsection's name, and
425
-     * the value being an array formatted in teh same way
426
-     *
427
-     * @param array $default_data
428
-     * @throws EE_Error
429
-     */
430
-    public function populate_defaults($default_data)
431
-    {
432
-        foreach ($this->subsections(false) as $subsection_name => $subsection) {
433
-            if (isset($default_data[ $subsection_name ])) {
434
-                if ($subsection instanceof EE_Form_Input_Base) {
435
-                    $subsection->set_default($default_data[ $subsection_name ]);
436
-                } elseif ($subsection instanceof EE_Form_Section_Proper) {
437
-                    $subsection->populate_defaults($default_data[ $subsection_name ]);
438
-                }
439
-            }
440
-        }
441
-    }
442
-
443
-
444
-    /**
445
-     * returns true if subsection exists
446
-     *
447
-     * @param string $name
448
-     * @return boolean
449
-     */
450
-    public function subsection_exists($name)
451
-    {
452
-        return isset($this->_subsections[ $name ]) ? true : false;
453
-    }
454
-
455
-
456
-    /**
457
-     * Gets the subsection specified by its name
458
-     *
459
-     * @param string  $name
460
-     * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
461
-     *                                                      so that the inputs will be properly configured.
462
-     *                                                      However, some client code may be ok
463
-     *                                                      with construction finalize being called later
464
-     *                                                      (realizing that the subsections' html names
465
-     *                                                      might not be set yet, etc.)
466
-     * @return EE_Form_Section_Base
467
-     * @throws EE_Error
468
-     */
469
-    public function get_subsection($name, $require_construction_to_be_finalized = true)
470
-    {
471
-        if ($require_construction_to_be_finalized) {
472
-            $this->ensure_construct_finalized_called();
473
-        }
474
-        return $this->subsection_exists($name) ? $this->_subsections[ $name ] : null;
475
-    }
476
-
477
-
478
-    /**
479
-     * Gets all the validatable subsections of this form section
480
-     *
481
-     * @return EE_Form_Section_Validatable[]
482
-     * @throws EE_Error
483
-     */
484
-    public function get_validatable_subsections()
485
-    {
486
-        $validatable_subsections = array();
487
-        foreach ($this->subsections() as $name => $obj) {
488
-            if ($obj instanceof EE_Form_Section_Validatable) {
489
-                $validatable_subsections[ $name ] = $obj;
490
-            }
491
-        }
492
-        return $validatable_subsections;
493
-    }
494
-
495
-
496
-    /**
497
-     * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
498
-     * throw an EE_Error.
499
-     *
500
-     * @param string  $name
501
-     * @param boolean $require_construction_to_be_finalized most client code should
502
-     *                                                      leave this as TRUE so that the inputs will be properly
503
-     *                                                      configured. However, some client code may be ok with
504
-     *                                                      construction finalize being called later
505
-     *                                                      (realizing that the subsections' html names might not be
506
-     *                                                      set yet, etc.)
507
-     * @return EE_Form_Input_Base
508
-     * @throws EE_Error
509
-     */
510
-    public function get_input($name, $require_construction_to_be_finalized = true)
511
-    {
512
-        $subsection = $this->get_subsection(
513
-            $name,
514
-            $require_construction_to_be_finalized
515
-        );
516
-        if (! $subsection instanceof EE_Form_Input_Base) {
517
-            throw new EE_Error(
518
-                sprintf(
519
-                    esc_html__(
520
-                        "Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
521
-                        'event_espresso'
522
-                    ),
523
-                    $name,
524
-                    get_class($this),
525
-                    $subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
526
-                )
527
-            );
528
-        }
529
-        return $subsection;
530
-    }
531
-
532
-
533
-    /**
534
-     * Like get_input(), gets the proper subsection of the form given the name,
535
-     * otherwise throws an EE_Error
536
-     *
537
-     * @param string  $name
538
-     * @param boolean $require_construction_to_be_finalized most client code should
539
-     *                                                      leave this as TRUE so that the inputs will be properly
540
-     *                                                      configured. However, some client code may be ok with
541
-     *                                                      construction finalize being called later
542
-     *                                                      (realizing that the subsections' html names might not be
543
-     *                                                      set yet, etc.)
544
-     * @return EE_Form_Section_Proper
545
-     * @throws EE_Error
546
-     */
547
-    public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
548
-    {
549
-        $subsection = $this->get_subsection(
550
-            $name,
551
-            $require_construction_to_be_finalized
552
-        );
553
-        if (! $subsection instanceof EE_Form_Section_Proper) {
554
-            throw new EE_Error(
555
-                sprintf(
556
-                    esc_html__(
557
-                        "Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'",
558
-                        'event_espresso'
559
-                    ),
560
-                    $name,
561
-                    get_class($this)
562
-                )
563
-            );
564
-        }
565
-        return $subsection;
566
-    }
567
-
568
-
569
-    /**
570
-     * Gets the value of the specified input. Should be called after receive_form_submission()
571
-     * or populate_defaults() on the form, where the normalized value on the input is set.
572
-     *
573
-     * @param string $name
574
-     * @return mixed depending on the input's type and its normalization strategy
575
-     * @throws EE_Error
576
-     */
577
-    public function get_input_value($name)
578
-    {
579
-        $input = $this->get_input($name);
580
-        return $input->normalized_value();
581
-    }
582
-
583
-
584
-    /**
585
-     * Checks if this form section itself is valid, and then checks its subsections
586
-     *
587
-     * @throws EE_Error
588
-     * @return boolean
589
-     */
590
-    public function is_valid()
591
-    {
592
-        if ($this->is_valid === null) {
593
-            if (! $this->has_received_submission()) {
594
-                throw new EE_Error(
595
-                    sprintf(
596
-                        esc_html__(
597
-                            'You cannot check if a form is valid before receiving the form submission using receive_form_submission',
598
-                            'event_espresso'
599
-                        )
600
-                    )
601
-                );
602
-            }
603
-            if (! parent::is_valid()) {
604
-                $this->is_valid = false;
605
-            } else {
606
-                // ok so no general errors to this entire form section.
607
-                // so let's check the subsections, but only set errors if that hasn't been done yet
608
-                $this->is_valid = true;
609
-                foreach ($this->get_validatable_subsections() as $subsection) {
610
-                    if (! $subsection->is_valid()) {
611
-                        $this->is_valid = false;
612
-                    }
613
-                }
614
-            }
615
-        }
616
-        return $this->is_valid;
617
-    }
618
-
619
-
620
-    /**
621
-     * gets the default name of this form section if none is specified
622
-     *
623
-     * @return void
624
-     */
625
-    protected function _set_default_name_if_empty()
626
-    {
627
-        if (! $this->_name) {
628
-            $classname    = get_class($this);
629
-            $default_name = str_replace('EE_', '', $classname);
630
-            $this->_name  = $default_name;
631
-        }
632
-    }
633
-
634
-
635
-    /**
636
-     * Returns the HTML for the form, except for the form opening and closing tags
637
-     * (as the form section doesn't know where you necessarily want to send the information to),
638
-     * and except for a submit button. Enqueues JS and CSS; if called early enough we will
639
-     * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
640
-     * Not doing_it_wrong because theoretically this CAN be used properly,
641
-     * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
642
-     * any CSS.
643
-     *
644
-     * @throws InvalidArgumentException
645
-     * @throws InvalidInterfaceException
646
-     * @throws InvalidDataTypeException
647
-     * @throws EE_Error
648
-     */
649
-    public function get_html_and_js()
650
-    {
651
-        $this->enqueue_js();
652
-        return $this->get_html();
653
-    }
654
-
655
-
656
-    /**
657
-     * returns HTML for displaying this form section. recursively calls display_section() on all subsections
658
-     *
659
-     * @param bool $display_previously_submitted_data
660
-     * @return string
661
-     * @throws InvalidArgumentException
662
-     * @throws InvalidInterfaceException
663
-     * @throws InvalidDataTypeException
664
-     * @throws EE_Error
665
-     * @throws EE_Error
666
-     * @throws EE_Error
667
-     */
668
-    public function get_html($display_previously_submitted_data = true)
669
-    {
670
-        $this->ensure_construct_finalized_called();
671
-        if ($display_previously_submitted_data) {
672
-            $this->populate_from_session();
673
-        }
674
-        return $this->_form_html_filter
675
-            ? $this->_form_html_filter->filterHtml($this->_layout_strategy->layout_form(), $this)
676
-            : $this->_layout_strategy->layout_form();
677
-    }
678
-
679
-
680
-    /**
681
-     * enqueues JS and CSS for the form.
682
-     * It is preferred to call this before wp_enqueue_scripts so the
683
-     * scripts and styles can be put in the header, but if called later
684
-     * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
685
-     * only be in the header; but in HTML5 its ok in the body.
686
-     * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
687
-     * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
688
-     *
689
-     * @return void
690
-     * @throws EE_Error
691
-     */
692
-    public function enqueue_js()
693
-    {
694
-        $this->_enqueue_and_localize_form_js();
695
-        foreach ($this->subsections() as $subsection) {
696
-            $subsection->enqueue_js();
697
-        }
698
-    }
699
-
700
-
701
-    /**
702
-     * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
703
-     * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
704
-     * the wp_enqueue_scripts hook.
705
-     * However, registering the form js and localizing it can happen when we
706
-     * actually output the form (which is preferred, seeing how teh form's fields
707
-     * could change until it's actually outputted)
708
-     *
709
-     * @param boolean $init_form_validation_automatically whether or not we want the form validation
710
-     *                                                    to be triggered automatically or not
711
-     * @return void
712
-     */
713
-    public static function wp_enqueue_scripts($init_form_validation_automatically = true)
714
-    {
715
-        wp_register_script(
716
-            'ee_form_section_validation',
717
-            EE_GLOBAL_ASSETS_URL . 'scripts' . '/form_section_validation.js',
718
-            array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
719
-            EVENT_ESPRESSO_VERSION,
720
-            true
721
-        );
722
-        wp_localize_script(
723
-            'ee_form_section_validation',
724
-            'ee_form_section_validation_init',
725
-            array('init' => $init_form_validation_automatically ? '1' : '0')
726
-        );
727
-    }
728
-
729
-
730
-    /**
731
-     * gets the variables used by form_section_validation.js.
732
-     * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
733
-     * but before the wordpress hook wp_loaded
734
-     *
735
-     * @throws EE_Error
736
-     */
737
-    public function _enqueue_and_localize_form_js()
738
-    {
739
-        $this->ensure_construct_finalized_called();
740
-        // actually, we don't want to localize just yet. There may be other forms on the page.
741
-        // so we need to add our form section data to a static variable accessible by all form sections
742
-        // and localize it just before the footer
743
-        $this->localize_validation_rules();
744
-        add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
745
-        add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
746
-    }
747
-
748
-
749
-    /**
750
-     * add our form section data to a static variable accessible by all form sections
751
-     *
752
-     * @param bool $return_for_subsection
753
-     * @return void
754
-     * @throws EE_Error
755
-     */
756
-    public function localize_validation_rules($return_for_subsection = false)
757
-    {
758
-        // we only want to localize vars ONCE for the entire form,
759
-        // so if the form section doesn't have a parent, then it must be the top dog
760
-        if ($return_for_subsection || ! $this->parent_section()) {
761
-            EE_Form_Section_Proper::$_js_localization['form_data'][ $this->html_id() ] = array(
762
-                'form_section_id'  => $this->html_id(true),
763
-                'validation_rules' => $this->get_jquery_validation_rules(),
764
-                'other_data'       => $this->get_other_js_data(),
765
-                'errors'           => $this->subsection_validation_errors_by_html_name(),
766
-            );
767
-            EE_Form_Section_Proper::$_scripts_localized                                = true;
768
-        }
769
-    }
770
-
771
-
772
-    /**
773
-     * Gets an array of extra data that will be useful for client-side javascript.
774
-     * This is primarily data added by inputs and forms in addition to any
775
-     * scripts they might enqueue
776
-     *
777
-     * @param array $form_other_js_data
778
-     * @return array
779
-     * @throws EE_Error
780
-     */
781
-    public function get_other_js_data($form_other_js_data = array())
782
-    {
783
-        foreach ($this->subsections() as $subsection) {
784
-            $form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
785
-        }
786
-        return $form_other_js_data;
787
-    }
788
-
789
-
790
-    /**
791
-     * Gets a flat array of inputs for this form section and its subsections.
792
-     * Keys are their form names, and values are the inputs themselves
793
-     *
794
-     * @return EE_Form_Input_Base
795
-     * @throws EE_Error
796
-     */
797
-    public function inputs_in_subsections()
798
-    {
799
-        $inputs = array();
800
-        foreach ($this->subsections() as $subsection) {
801
-            if ($subsection instanceof EE_Form_Input_Base) {
802
-                $inputs[ $subsection->html_name() ] = $subsection;
803
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
804
-                $inputs += $subsection->inputs_in_subsections();
805
-            }
806
-        }
807
-        return $inputs;
808
-    }
809
-
810
-
811
-    /**
812
-     * Gets a flat array of all the validation errors.
813
-     * Keys are html names (because those should be unique)
814
-     * and values are a string of all their validation errors
815
-     *
816
-     * @return string[]
817
-     * @throws EE_Error
818
-     */
819
-    public function subsection_validation_errors_by_html_name()
820
-    {
821
-        $inputs = $this->inputs();
822
-        $errors = array();
823
-        foreach ($inputs as $form_input) {
824
-            if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
825
-                $errors[ $form_input->html_name() ] = $form_input->get_validation_error_string();
826
-            }
827
-        }
828
-        return $errors;
829
-    }
830
-
831
-
832
-    /**
833
-     * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
834
-     * Should be setup by each form during the _enqueues_and_localize_form_js
835
-     *
836
-     * @throws InvalidArgumentException
837
-     * @throws InvalidInterfaceException
838
-     * @throws InvalidDataTypeException
839
-     */
840
-    public static function localize_script_for_all_forms()
841
-    {
842
-        // allow inputs and stuff to hook in their JS and stuff here
843
-        do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
844
-        EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
845
-        $email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
846
-            ? EE_Registry::instance()->CFG->registration->email_validation_level
847
-            : 'wp_default';
848
-        EE_Form_Section_Proper::$_js_localization['email_validation_level']   = $email_validation_level;
849
-        wp_enqueue_script('ee_form_section_validation');
850
-        wp_localize_script(
851
-            'ee_form_section_validation',
852
-            'ee_form_section_vars',
853
-            EE_Form_Section_Proper::$_js_localization
854
-        );
855
-    }
856
-
857
-
858
-    /**
859
-     * ensure_scripts_localized
860
-     *
861
-     * @throws EE_Error
862
-     */
863
-    public function ensure_scripts_localized()
864
-    {
865
-        if (! EE_Form_Section_Proper::$_scripts_localized) {
866
-            $this->_enqueue_and_localize_form_js();
867
-        }
868
-    }
869
-
870
-
871
-    /**
872
-     * Gets the hard-coded validation error messages to be used in the JS. The convention
873
-     * is that the key here should be the same as the custom validation rule put in the JS file
874
-     *
875
-     * @return array keys are custom validation rules, and values are internationalized strings
876
-     */
877
-    private static function _get_localized_error_messages()
878
-    {
879
-        return array(
880
-            'validUrl' => esc_html__('This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg', 'event_espresso'),
881
-            'regex'    => esc_html__('Please check your input', 'event_espresso'),
882
-        );
883
-    }
884
-
885
-
886
-    /**
887
-     * @return array
888
-     */
889
-    public static function js_localization()
890
-    {
891
-        return self::$_js_localization;
892
-    }
893
-
894
-
895
-    /**
896
-     * @return void
897
-     */
898
-    public static function reset_js_localization()
899
-    {
900
-        self::$_js_localization = array();
901
-    }
902
-
903
-
904
-    /**
905
-     * Gets the JS to put inside the jquery validation rules for subsection of this form section.
906
-     * See parent function for more...
907
-     *
908
-     * @return array
909
-     * @throws EE_Error
910
-     */
911
-    public function get_jquery_validation_rules()
912
-    {
913
-        $jquery_validation_rules = array();
914
-        foreach ($this->get_validatable_subsections() as $subsection) {
915
-            $jquery_validation_rules = array_merge(
916
-                $jquery_validation_rules,
917
-                $subsection->get_jquery_validation_rules()
918
-            );
919
-        }
920
-        return $jquery_validation_rules;
921
-    }
922
-
923
-
924
-    /**
925
-     * Sanitizes all the data and sets the sanitized value of each field
926
-     *
927
-     * @param array $req_data
928
-     * @return void
929
-     * @throws EE_Error
930
-     */
931
-    protected function _normalize($req_data)
932
-    {
933
-        $this->_received_submission = true;
934
-        $this->_validation_errors   = array();
935
-        foreach ($this->get_validatable_subsections() as $subsection) {
936
-            try {
937
-                $subsection->_normalize($req_data);
938
-            } catch (EE_Validation_Error $e) {
939
-                $subsection->add_validation_error($e);
940
-            }
941
-        }
942
-    }
943
-
944
-
945
-    /**
946
-     * Performs validation on this form section and its subsections.
947
-     * For each subsection,
948
-     * calls _validate_{subsection_name} on THIS form (if the function exists)
949
-     * and passes it the subsection, then calls _validate on that subsection.
950
-     * If you need to perform validation on the form as a whole (considering multiple)
951
-     * you would be best to override this _validate method,
952
-     * calling parent::_validate() first.
953
-     *
954
-     * @throws EE_Error
955
-     */
956
-    protected function _validate()
957
-    {
958
-        // reset the cache of whether this form is valid or not- we're re-validating it now
959
-        $this->is_valid = null;
960
-        foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
961
-            if (method_exists($this, '_validate_' . $subsection_name)) {
962
-                call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
963
-            }
964
-            $subsection->_validate();
965
-        }
966
-    }
967
-
968
-
969
-    /**
970
-     * Gets all the validated inputs for the form section
971
-     *
972
-     * @return array
973
-     * @throws EE_Error
974
-     */
975
-    public function valid_data()
976
-    {
977
-        $inputs = array();
978
-        foreach ($this->subsections() as $subsection_name => $subsection) {
979
-            if ($subsection instanceof EE_Form_Section_Proper) {
980
-                $inputs[ $subsection_name ] = $subsection->valid_data();
981
-            } elseif ($subsection instanceof EE_Form_Input_Base) {
982
-                $inputs[ $subsection_name ] = $subsection->normalized_value();
983
-            }
984
-        }
985
-        return $inputs;
986
-    }
987
-
988
-
989
-    /**
990
-     * Gets all the inputs on this form section
991
-     *
992
-     * @return EE_Form_Input_Base[]
993
-     * @throws EE_Error
994
-     */
995
-    public function inputs()
996
-    {
997
-        $inputs = array();
998
-        foreach ($this->subsections() as $subsection_name => $subsection) {
999
-            if ($subsection instanceof EE_Form_Input_Base) {
1000
-                $inputs[ $subsection_name ] = $subsection;
1001
-            }
1002
-        }
1003
-        return $inputs;
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * Gets all the subsections which are a proper form
1009
-     *
1010
-     * @return EE_Form_Section_Proper[]
1011
-     * @throws EE_Error
1012
-     */
1013
-    public function subforms()
1014
-    {
1015
-        $form_sections = array();
1016
-        foreach ($this->subsections() as $name => $obj) {
1017
-            if ($obj instanceof EE_Form_Section_Proper) {
1018
-                $form_sections[ $name ] = $obj;
1019
-            }
1020
-        }
1021
-        return $form_sections;
1022
-    }
1023
-
1024
-
1025
-    /**
1026
-     * Gets all the subsections (inputs, proper subsections, or html-only sections).
1027
-     * Consider using inputs() or subforms()
1028
-     * if you only want form inputs or proper form sections.
1029
-     *
1030
-     * @param boolean $require_construction_to_be_finalized most client code should
1031
-     *                                                      leave this as TRUE so that the inputs will be properly
1032
-     *                                                      configured. However, some client code may be ok with
1033
-     *                                                      construction finalize being called later
1034
-     *                                                      (realizing that the subsections' html names might not be
1035
-     *                                                      set yet, etc.)
1036
-     * @return EE_Form_Section_Proper[]
1037
-     * @throws EE_Error
1038
-     */
1039
-    public function subsections($require_construction_to_be_finalized = true)
1040
-    {
1041
-        if ($require_construction_to_be_finalized) {
1042
-            $this->ensure_construct_finalized_called();
1043
-        }
1044
-        return $this->_subsections;
1045
-    }
1046
-
1047
-
1048
-    /**
1049
-     * Returns whether this form has any subforms or inputs
1050
-     * @return bool
1051
-     */
1052
-    public function hasSubsections()
1053
-    {
1054
-        return ! empty($this->_subsections);
1055
-    }
1056
-
1057
-
1058
-    /**
1059
-     * Returns a simple array where keys are input names, and values are their normalized
1060
-     * values. (Similar to calling get_input_value on inputs)
1061
-     *
1062
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1063
-     *                                        or just this forms' direct children inputs
1064
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1065
-     *                                        or allow multidimensional array
1066
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
1067
-     *                                        with array keys being input names
1068
-     *                                        (regardless of whether they are from a subsection or not),
1069
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1070
-     *                                        where keys are always subsection names and values are either
1071
-     *                                        the input's normalized value, or an array like the top-level array
1072
-     * @throws EE_Error
1073
-     */
1074
-    public function input_values($include_subform_inputs = false, $flatten = false)
1075
-    {
1076
-        return $this->_input_values(false, $include_subform_inputs, $flatten);
1077
-    }
1078
-
1079
-
1080
-    /**
1081
-     * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
1082
-     * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
1083
-     * is not necessarily the value we want to display to users. This creates an array
1084
-     * where keys are the input names, and values are their display values
1085
-     *
1086
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1087
-     *                                        or just this forms' direct children inputs
1088
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1089
-     *                                        or allow multidimensional array
1090
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
1091
-     *                                        with array keys being input names
1092
-     *                                        (regardless of whether they are from a subsection or not),
1093
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1094
-     *                                        where keys are always subsection names and values are either
1095
-     *                                        the input's normalized value, or an array like the top-level array
1096
-     * @throws EE_Error
1097
-     */
1098
-    public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1099
-    {
1100
-        return $this->_input_values(true, $include_subform_inputs, $flatten);
1101
-    }
1102
-
1103
-
1104
-    /**
1105
-     * Gets the input values from the form
1106
-     *
1107
-     * @param boolean $pretty                 Whether to retrieve the pretty value,
1108
-     *                                        or just the normalized value
1109
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1110
-     *                                        or just this forms' direct children inputs
1111
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1112
-     *                                        or allow multidimensional array
1113
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1114
-     *                                        input names (regardless of whether they are from a subsection or not),
1115
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1116
-     *                                        where keys are always subsection names and values are either
1117
-     *                                        the input's normalized value, or an array like the top-level array
1118
-     * @throws EE_Error
1119
-     */
1120
-    public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1121
-    {
1122
-        $input_values = array();
1123
-        foreach ($this->subsections() as $subsection_name => $subsection) {
1124
-            if ($subsection instanceof EE_Form_Input_Base) {
1125
-                $input_values[ $subsection_name ] = $pretty
1126
-                    ? $subsection->pretty_value()
1127
-                    : $subsection->normalized_value();
1128
-            } elseif ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1129
-                $subform_input_values = $subsection->_input_values(
1130
-                    $pretty,
1131
-                    $include_subform_inputs,
1132
-                    $flatten
1133
-                );
1134
-                if ($flatten) {
1135
-                    $input_values = array_merge($input_values, $subform_input_values);
1136
-                } else {
1137
-                    $input_values[ $subsection_name ] = $subform_input_values;
1138
-                }
1139
-            }
1140
-        }
1141
-        return $input_values;
1142
-    }
1143
-
1144
-
1145
-    /**
1146
-     * Gets the originally submitted input values from the form
1147
-     *
1148
-     * @param boolean $include_subforms  Whether to include inputs from subforms,
1149
-     *                                   or just this forms' direct children inputs
1150
-     * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1151
-     *                                   with array keys being input names
1152
-     *                                   (regardless of whether they are from a subsection or not),
1153
-     *                                   and if $flatten is FALSE it can be a multidimensional array
1154
-     *                                   where keys are always subsection names and values are either
1155
-     *                                   the input's normalized value, or an array like the top-level array
1156
-     * @throws EE_Error
1157
-     */
1158
-    public function submitted_values($include_subforms = false)
1159
-    {
1160
-        $submitted_values = array();
1161
-        foreach ($this->subsections() as $subsection) {
1162
-            if ($subsection instanceof EE_Form_Input_Base) {
1163
-                // is this input part of an array of inputs?
1164
-                if (strpos($subsection->html_name(), '[') !== false) {
1165
-                    $full_input_name  = EEH_Array::convert_array_values_to_keys(
1166
-                        explode(
1167
-                            '[',
1168
-                            str_replace(']', '', $subsection->html_name())
1169
-                        ),
1170
-                        $subsection->raw_value()
1171
-                    );
1172
-                    $submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1173
-                } else {
1174
-                    $submitted_values[ $subsection->html_name() ] = $subsection->raw_value();
1175
-                }
1176
-            } elseif ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1177
-                $subform_input_values = $subsection->submitted_values($include_subforms);
1178
-                $submitted_values     = array_replace_recursive($submitted_values, $subform_input_values);
1179
-            }
1180
-        }
1181
-        return $submitted_values;
1182
-    }
1183
-
1184
-
1185
-    /**
1186
-     * Indicates whether or not this form has received a submission yet
1187
-     * (ie, had receive_form_submission called on it yet)
1188
-     *
1189
-     * @return boolean
1190
-     * @throws EE_Error
1191
-     */
1192
-    public function has_received_submission()
1193
-    {
1194
-        $this->ensure_construct_finalized_called();
1195
-        return $this->_received_submission;
1196
-    }
1197
-
1198
-
1199
-    /**
1200
-     * Equivalent to passing 'exclude' in the constructor's options array.
1201
-     * Removes the listed inputs from the form
1202
-     *
1203
-     * @param array $inputs_to_exclude values are the input names
1204
-     * @return void
1205
-     */
1206
-    public function exclude(array $inputs_to_exclude = array())
1207
-    {
1208
-        foreach ($inputs_to_exclude as $input_to_exclude_name) {
1209
-            unset($this->_subsections[ $input_to_exclude_name ]);
1210
-        }
1211
-    }
1212
-
1213
-
1214
-    /**
1215
-     * Changes these inputs' display strategy to be EE_Hidden_Display_Strategy.
1216
-     * @param array $inputs_to_hide
1217
-     * @throws EE_Error
1218
-     */
1219
-    public function hide(array $inputs_to_hide = array())
1220
-    {
1221
-        foreach ($inputs_to_hide as $input_to_hide) {
1222
-            $input = $this->get_input($input_to_hide);
1223
-            $input->set_display_strategy(new EE_Hidden_Display_Strategy());
1224
-        }
1225
-    }
1226
-
1227
-
1228
-    /**
1229
-     * add_subsections
1230
-     * Adds the listed subsections to the form section.
1231
-     * If $subsection_name_to_target is provided,
1232
-     * then new subsections are added before or after that subsection,
1233
-     * otherwise to the start or end of the entire subsections array.
1234
-     *
1235
-     * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1236
-     *                                                          where keys are their names
1237
-     * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1238
-     *                                                          should be added before or after
1239
-     *                                                          IF $subsection_name_to_target is null,
1240
-     *                                                          then $new_subsections will be added to
1241
-     *                                                          the beginning or end of the entire subsections array
1242
-     * @param boolean                $add_before                whether to add $new_subsections, before or after
1243
-     *                                                          $subsection_name_to_target,
1244
-     *                                                          or if $subsection_name_to_target is null,
1245
-     *                                                          before or after entire subsections array
1246
-     * @return void
1247
-     * @throws EE_Error
1248
-     */
1249
-    public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1250
-    {
1251
-        foreach ($new_subsections as $subsection_name => $subsection) {
1252
-            if (! $subsection instanceof EE_Form_Section_Base) {
1253
-                EE_Error::add_error(
1254
-                    sprintf(
1255
-                        esc_html__(
1256
-                            "Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1257
-                            'event_espresso'
1258
-                        ),
1259
-                        get_class($subsection),
1260
-                        $subsection_name,
1261
-                        $this->name()
1262
-                    )
1263
-                );
1264
-                unset($new_subsections[ $subsection_name ]);
1265
-            }
1266
-        }
1267
-        $this->_subsections = EEH_Array::insert_into_array(
1268
-            $this->_subsections,
1269
-            $new_subsections,
1270
-            $subsection_name_to_target,
1271
-            $add_before
1272
-        );
1273
-        if ($this->_construction_finalized) {
1274
-            foreach ($this->_subsections as $name => $subsection) {
1275
-                $subsection->_construct_finalize($this, $name);
1276
-            }
1277
-        }
1278
-    }
1279
-
1280
-
1281
-    /**
1282
-     * @param string $subsection_name
1283
-     * @param bool   $recursive
1284
-     * @return bool
1285
-     */
1286
-    public function has_subsection($subsection_name, $recursive = false)
1287
-    {
1288
-        foreach ($this->_subsections as $name => $subsection) {
1289
-            if ($name === $subsection_name
1290
-                || (
1291
-                    $recursive
1292
-                    && $subsection instanceof EE_Form_Section_Proper
1293
-                    && $subsection->has_subsection($subsection_name, $recursive)
1294
-                )
1295
-            ) {
1296
-                return true;
1297
-            }
1298
-        }
1299
-        return false;
1300
-    }
1301
-
1302
-
1303
-
1304
-    /**
1305
-     * Just gets all validatable subsections to clean their sensitive data
1306
-     *
1307
-     * @throws EE_Error
1308
-     */
1309
-    public function clean_sensitive_data()
1310
-    {
1311
-        foreach ($this->get_validatable_subsections() as $subsection) {
1312
-            $subsection->clean_sensitive_data();
1313
-        }
1314
-    }
1315
-
1316
-
1317
-    /**
1318
-     * Sets the submission error message (aka validation error message for this form section and all sub-sections)
1319
-     * @param string                           $form_submission_error_message
1320
-     * @param EE_Form_Section_Validatable $form_section unused
1321
-     * @throws EE_Error
1322
-     */
1323
-    public function set_submission_error_message(
1324
-        $form_submission_error_message = ''
1325
-    ) {
1326
-        $this->_form_submission_error_message = ! empty($form_submission_error_message)
1327
-            ? $form_submission_error_message
1328
-            : $this->getAllValidationErrorsString();
1329
-    }
1330
-
1331
-
1332
-    /**
1333
-     * Returns the cached error message. A default value is set for this during _validate(),
1334
-     * (called during receive_form_submission) but it can be explicitly set using
1335
-     * set_submission_error_message
1336
-     *
1337
-     * @return string
1338
-     */
1339
-    public function submission_error_message()
1340
-    {
1341
-        return $this->_form_submission_error_message;
1342
-    }
1343
-
1344
-
1345
-    /**
1346
-     * Sets a message to display if the data submitted to the form was valid.
1347
-     * @param string $form_submission_success_message
1348
-     */
1349
-    public function set_submission_success_message($form_submission_success_message = '')
1350
-    {
1351
-        $this->_form_submission_success_message = ! empty($form_submission_success_message)
1352
-            ? $form_submission_success_message
1353
-            : esc_html__('Form submitted successfully', 'event_espresso');
1354
-    }
1355
-
1356
-
1357
-    /**
1358
-     * Gets a message appropriate for display when the form is correctly submitted
1359
-     * @return string
1360
-     */
1361
-    public function submission_success_message()
1362
-    {
1363
-        return $this->_form_submission_success_message;
1364
-    }
1365
-
1366
-
1367
-    /**
1368
-     * Returns the prefix that should be used on child of this form section for
1369
-     * their html names. If this form section itself has a parent, prepends ITS
1370
-     * prefix onto this form section's prefix. Used primarily by
1371
-     * EE_Form_Input_Base::_set_default_html_name_if_empty
1372
-     *
1373
-     * @return string
1374
-     * @throws EE_Error
1375
-     */
1376
-    public function html_name_prefix()
1377
-    {
1378
-        if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1379
-            return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1380
-        }
1381
-        return $this->name();
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * Gets the name, but first checks _construct_finalize has been called. If not,
1387
-     * calls it (assumes there is no parent and that we want the name to be whatever
1388
-     * was set, which is probably nothing, or the classname)
1389
-     *
1390
-     * @return string
1391
-     * @throws EE_Error
1392
-     */
1393
-    public function name()
1394
-    {
1395
-        $this->ensure_construct_finalized_called();
1396
-        return parent::name();
1397
-    }
1398
-
1399
-
1400
-    /**
1401
-     * @return EE_Form_Section_Proper
1402
-     * @throws EE_Error
1403
-     */
1404
-    public function parent_section()
1405
-    {
1406
-        $this->ensure_construct_finalized_called();
1407
-        return parent::parent_section();
1408
-    }
1409
-
1410
-
1411
-    /**
1412
-     * make sure construction finalized was called, otherwise children might not be ready
1413
-     *
1414
-     * @return void
1415
-     * @throws EE_Error
1416
-     */
1417
-    public function ensure_construct_finalized_called()
1418
-    {
1419
-        if (! $this->_construction_finalized) {
1420
-            $this->_construct_finalize($this->_parent_section, $this->_name);
1421
-        }
1422
-    }
1423
-
1424
-
1425
-    /**
1426
-     * Checks if any of this form section's inputs, or any of its children's inputs,
1427
-     * are in teh form data. If any are found, returns true. Else false
1428
-     *
1429
-     * @param array $req_data
1430
-     * @return boolean
1431
-     * @throws EE_Error
1432
-     */
1433
-    public function form_data_present_in($req_data = null)
1434
-    {
1435
-        $req_data = $this->getCachedRequest($req_data);
1436
-        foreach ($this->subsections() as $subsection) {
1437
-            if ($subsection instanceof EE_Form_Input_Base) {
1438
-                if ($subsection->form_data_present_in($req_data)) {
1439
-                    return true;
1440
-                }
1441
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
1442
-                if ($subsection->form_data_present_in($req_data)) {
1443
-                    return true;
1444
-                }
1445
-            }
1446
-        }
1447
-        return false;
1448
-    }
1449
-
1450
-
1451
-    /**
1452
-     * Gets validation errors for this form section and subsections
1453
-     * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1454
-     * gets the validation errors for ALL subsection
1455
-     *
1456
-     * @return EE_Validation_Error[]
1457
-     * @throws EE_Error
1458
-     */
1459
-    public function get_validation_errors_accumulated()
1460
-    {
1461
-        $validation_errors = $this->get_validation_errors();
1462
-        foreach ($this->get_validatable_subsections() as $subsection) {
1463
-            if ($subsection instanceof EE_Form_Section_Proper) {
1464
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1465
-            } else {
1466
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors();
1467
-            }
1468
-            if ($validation_errors_on_this_subsection) {
1469
-                $validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1470
-            }
1471
-        }
1472
-        return $validation_errors;
1473
-    }
1474
-
1475
-    /**
1476
-     * Fetch validation errors from children and grandchildren and puts them in a single string.
1477
-     * This traverses the form section tree to generate this, but you probably want to instead use
1478
-     * get_form_submission_error_message() which is usually this message cached (or a custom validation error message)
1479
-     *
1480
-     * @return string
1481
-     * @since 4.9.59.p
1482
-     */
1483
-    protected function getAllValidationErrorsString()
1484
-    {
1485
-        $submission_error_messages = array();
1486
-        // bad, bad, bad registrant
1487
-        foreach ($this->get_validation_errors_accumulated() as $validation_error) {
1488
-            if ($validation_error instanceof EE_Validation_Error) {
1489
-                $form_section = $validation_error->get_form_section();
1490
-                if ($form_section instanceof EE_Form_Input_Base) {
1491
-                    $label = $validation_error->get_form_section()->html_label_text();
1492
-                } elseif ($form_section instanceof EE_Form_Section_Validatable) {
1493
-                    $label = $validation_error->get_form_section()->name();
1494
-                } else {
1495
-                    $label = esc_html__('Unknown', 'event_espresso');
1496
-                }
1497
-                $submission_error_messages[] = sprintf(
1498
-                    __('%s : %s', 'event_espresso'),
1499
-                    $label,
1500
-                    $validation_error->getMessage()
1501
-                );
1502
-            }
1503
-        }
1504
-        return implode('<br>', $submission_error_messages);
1505
-    }
1506
-
1507
-
1508
-    /**
1509
-     * This isn't just the name of an input, it's a path pointing to an input. The
1510
-     * path is similar to a folder path: slash (/) means to descend into a subsection,
1511
-     * dot-dot-slash (../) means to ascend into the parent section.
1512
-     * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1513
-     * which will be returned.
1514
-     * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1515
-     * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1516
-     * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1517
-     * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1518
-     * Etc
1519
-     *
1520
-     * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1521
-     * @return EE_Form_Section_Base
1522
-     * @throws EE_Error
1523
-     */
1524
-    public function find_section_from_path($form_section_path)
1525
-    {
1526
-        // check if we can find the input from purely going straight up the tree
1527
-        $input = parent::find_section_from_path($form_section_path);
1528
-        if ($input instanceof EE_Form_Section_Base) {
1529
-            return $input;
1530
-        }
1531
-        $next_slash_pos = strpos($form_section_path, '/');
1532
-        if ($next_slash_pos !== false) {
1533
-            $child_section_name = substr($form_section_path, 0, $next_slash_pos);
1534
-            $subpath            = substr($form_section_path, $next_slash_pos + 1);
1535
-        } else {
1536
-            $child_section_name = $form_section_path;
1537
-            $subpath            = '';
1538
-        }
1539
-        $child_section = $this->get_subsection($child_section_name);
1540
-        if ($child_section instanceof EE_Form_Section_Base) {
1541
-            return $child_section->find_section_from_path($subpath);
1542
-        }
1543
-        return null;
1544
-    }
19
+	const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
20
+
21
+	/**
22
+	 * Subsections
23
+	 *
24
+	 * @var EE_Form_Section_Validatable[]
25
+	 */
26
+	protected $_subsections = array();
27
+
28
+	/**
29
+	 * Strategy for laying out the form
30
+	 *
31
+	 * @var EE_Form_Section_Layout_Base
32
+	 */
33
+	protected $_layout_strategy;
34
+
35
+	/**
36
+	 * Whether or not this form has received and validated a form submission yet
37
+	 *
38
+	 * @var boolean
39
+	 */
40
+	protected $_received_submission = false;
41
+
42
+	/**
43
+	 * message displayed to users upon successful form submission
44
+	 *
45
+	 * @var string
46
+	 */
47
+	protected $_form_submission_success_message = '';
48
+
49
+	/**
50
+	 * message displayed to users upon unsuccessful form submission
51
+	 *
52
+	 * @var string
53
+	 */
54
+	protected $_form_submission_error_message = '';
55
+
56
+	/**
57
+	 * @var array like post / request
58
+	 */
59
+	protected $cached_request_data;
60
+
61
+	/**
62
+	 * Stores whether this form (and its sub-sections) were found to be valid or not.
63
+	 * Starts off as null, but once the form is validated, it set to either true or false
64
+	 * @var boolean|null
65
+	 */
66
+	protected $is_valid;
67
+
68
+	/**
69
+	 * Stores all the data that will localized for form validation
70
+	 *
71
+	 * @var array
72
+	 */
73
+	static protected $_js_localization = array();
74
+
75
+	/**
76
+	 * whether or not the form's localized validation JS vars have been set
77
+	 *
78
+	 * @type boolean
79
+	 */
80
+	static protected $_scripts_localized = false;
81
+
82
+
83
+	/**
84
+	 * when constructing a proper form section, calls _construct_finalize on children
85
+	 * so that they know who their parent is, and what name they've been given.
86
+	 *
87
+	 * @param array[] $options_array   {
88
+	 * @type          $subsections     EE_Form_Section_Validatable[] where keys are the section's name
89
+	 * @type          $include         string[] numerically-indexed where values are section names to be included,
90
+	 *                                 and in that order. This is handy if you want
91
+	 *                                 the subsections to be ordered differently than the default, and if you override
92
+	 *                                 which fields are shown
93
+	 * @type          $exclude         string[] values are subsections to be excluded. This is handy if you want
94
+	 *                                 to remove certain default subsections (note: if you specify BOTH 'include' AND
95
+	 *                                 'exclude', the inclusions will be applied first, and the exclusions will exclude
96
+	 *                                 items from that list of inclusions)
97
+	 * @type          $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
98
+	 *                                 } @see EE_Form_Section_Validatable::__construct()
99
+	 * @throws EE_Error
100
+	 */
101
+	public function __construct($options_array = array())
102
+	{
103
+		$options_array = (array) apply_filters(
104
+			'FHEE__EE_Form_Section_Proper___construct__options_array',
105
+			$options_array,
106
+			$this
107
+		);
108
+		// call parent first, as it may be setting the name
109
+		parent::__construct($options_array);
110
+		// if they've included subsections in the constructor, add them now
111
+		if (isset($options_array['include'])) {
112
+			// we are going to make sure we ONLY have those subsections to include
113
+			// AND we are going to make sure they're in that specified order
114
+			$reordered_subsections = array();
115
+			foreach ($options_array['include'] as $input_name) {
116
+				if (isset($this->_subsections[ $input_name ])) {
117
+					$reordered_subsections[ $input_name ] = $this->_subsections[ $input_name ];
118
+				}
119
+			}
120
+			$this->_subsections = $reordered_subsections;
121
+		}
122
+		if (isset($options_array['exclude'])) {
123
+			$exclude            = $options_array['exclude'];
124
+			$this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
125
+		}
126
+		if (isset($options_array['layout_strategy'])) {
127
+			$this->_layout_strategy = $options_array['layout_strategy'];
128
+		}
129
+		if (! $this->_layout_strategy) {
130
+			$this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
131
+		}
132
+		$this->_layout_strategy->_construct_finalize($this);
133
+		// ok so we are definitely going to want the forms JS,
134
+		// so enqueue it or remember to enqueue it during wp_enqueue_scripts
135
+		if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
136
+			// ok so they've constructed this object after when they should have.
137
+			// just enqueue the generic form scripts and initialize the form immediately in the JS
138
+			EE_Form_Section_Proper::wp_enqueue_scripts(true);
139
+		} else {
140
+			add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
141
+			add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
142
+		}
143
+		add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
144
+		/**
145
+		 * Gives other plugins a chance to hook in before construct finalize is called.
146
+		 * The form probably doesn't yet have a parent form section.
147
+		 * Since 4.9.32, when this action was introduced, this is the best place to add a subsection onto a form,
148
+		 * assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
149
+		 * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
150
+		 *
151
+		 * @since 4.9.32
152
+		 * @param EE_Form_Section_Proper $this          before __construct is done, but all of its logic,
153
+		 *                                              except maybe calling _construct_finalize has been done
154
+		 * @param array                  $options_array options passed into the constructor
155
+		 */
156
+		do_action(
157
+			'AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called',
158
+			$this,
159
+			$options_array
160
+		);
161
+		if (isset($options_array['name'])) {
162
+			$this->_construct_finalize(null, $options_array['name']);
163
+		}
164
+	}
165
+
166
+
167
+	/**
168
+	 * Finishes construction given the parent form section and this form section's name
169
+	 *
170
+	 * @param EE_Form_Section_Proper $parent_form_section
171
+	 * @param string                 $name
172
+	 * @throws EE_Error
173
+	 */
174
+	public function _construct_finalize($parent_form_section, $name)
175
+	{
176
+		parent::_construct_finalize($parent_form_section, $name);
177
+		$this->_set_default_name_if_empty();
178
+		$this->_set_default_html_id_if_empty();
179
+		foreach ($this->_subsections as $subsection_name => $subsection) {
180
+			if ($subsection instanceof EE_Form_Section_Base) {
181
+				$subsection->_construct_finalize($this, $subsection_name);
182
+			} else {
183
+				throw new EE_Error(
184
+					sprintf(
185
+						esc_html__(
186
+							'Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
187
+							'event_espresso'
188
+						),
189
+						$subsection_name,
190
+						get_class($this),
191
+						$subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
192
+					)
193
+				);
194
+			}
195
+		}
196
+		/**
197
+		 * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
198
+		 * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID
199
+		 * (or other attributes derived from the name like the HTML label id, etc), this is where it should be done.
200
+		 * This might only happen just before displaying the form, or just before it receives form submission data.
201
+		 * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
202
+		 * ensured it has a name, HTML IDs, etc
203
+		 *
204
+		 * @param EE_Form_Section_Proper      $this
205
+		 * @param EE_Form_Section_Proper|null $parent_form_section
206
+		 * @param string                      $name
207
+		 */
208
+		do_action(
209
+			'AHEE__EE_Form_Section_Proper___construct_finalize__end',
210
+			$this,
211
+			$parent_form_section,
212
+			$name
213
+		);
214
+	}
215
+
216
+
217
+	/**
218
+	 * Gets the layout strategy for this form section
219
+	 *
220
+	 * @return EE_Form_Section_Layout_Base
221
+	 */
222
+	public function get_layout_strategy()
223
+	{
224
+		return $this->_layout_strategy;
225
+	}
226
+
227
+
228
+	/**
229
+	 * Gets the HTML for a single input for this form section according
230
+	 * to the layout strategy
231
+	 *
232
+	 * @param EE_Form_Input_Base $input
233
+	 * @return string
234
+	 */
235
+	public function get_html_for_input($input)
236
+	{
237
+		return $this->_layout_strategy->layout_input($input);
238
+	}
239
+
240
+
241
+	/**
242
+	 * was_submitted - checks if form inputs are present in request data
243
+	 * Basically an alias for form_data_present_in() (which is used by both
244
+	 * proper form sections and form inputs)
245
+	 *
246
+	 * @param null $form_data
247
+	 * @return boolean
248
+	 * @throws EE_Error
249
+	 */
250
+	public function was_submitted($form_data = null)
251
+	{
252
+		return $this->form_data_present_in($form_data);
253
+	}
254
+
255
+	/**
256
+	 * Gets the cached request data; but if there is none, or $req_data was set with
257
+	 * something different, refresh the cache, and then return it
258
+	 * @param null $req_data
259
+	 * @return array
260
+	 */
261
+	protected function getCachedRequest($req_data = null)
262
+	{
263
+		if ($this->cached_request_data === null
264
+			|| (
265
+				$req_data !== null &&
266
+				$req_data !== $this->cached_request_data
267
+			)
268
+		) {
269
+			$req_data = apply_filters(
270
+				'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
271
+				$req_data,
272
+				$this
273
+			);
274
+			if ($req_data === null) {
275
+				/** @var RequestInterface $request */
276
+				$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
277
+				$req_data = $request->requestParams();
278
+			}
279
+			$req_data = apply_filters(
280
+				'FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
281
+				$req_data,
282
+				$this
283
+			);
284
+			$this->cached_request_data = (array) $req_data;
285
+		}
286
+		return $this->cached_request_data;
287
+	}
288
+
289
+
290
+	/**
291
+	 * After the form section is initially created, call this to sanitize the data in the submission
292
+	 * which relates to this form section, validate it, and set it as properties on the form.
293
+	 *
294
+	 * @param array|null $req_data should usually be post data (the default).
295
+	 *                             However, you CAN supply a different array.
296
+	 *                             Consider using set_defaults() instead however.
297
+	 *                             (If you rendered the form in the page using echo $form_x->get_html()
298
+	 *                             the inputs will have the correct name in the request data for this function
299
+	 *                             to find them and populate the form with them.
300
+	 *                             If you have a flat form (with only input subsections),
301
+	 *                             you can supply a flat array where keys
302
+	 *                             are the form input names and values are their values)
303
+	 * @param boolean    $validate whether or not to perform validation on this data. Default is,
304
+	 *                             of course, to validate that data, and set errors on the invalid values.
305
+	 *                             But if the data has already been validated
306
+	 *                             (eg you validated the data then stored it in the DB)
307
+	 *                             you may want to skip this step.
308
+	 * @throws InvalidArgumentException
309
+	 * @throws InvalidInterfaceException
310
+	 * @throws InvalidDataTypeException
311
+	 * @throws EE_Error
312
+	 */
313
+	public function receive_form_submission($req_data = null, $validate = true)
314
+	{
315
+		$req_data = $this->getCachedRequest($req_data);
316
+		$this->_normalize($req_data);
317
+		if ($validate) {
318
+			$this->_validate();
319
+			// if it's invalid, we're going to want to re-display so remember what they submitted
320
+			if (! $this->is_valid()) {
321
+				$this->store_submitted_form_data_in_session();
322
+			}
323
+		}
324
+		if ($this->submission_error_message() === '' && ! $this->is_valid()) {
325
+			$this->set_submission_error_message();
326
+		}
327
+		do_action(
328
+			'AHEE__EE_Form_Section_Proper__receive_form_submission__end',
329
+			$req_data,
330
+			$this,
331
+			$validate
332
+		);
333
+	}
334
+
335
+
336
+	/**
337
+	 * caches the originally submitted input values in the session
338
+	 * so that they can be used to repopulate the form if it failed validation
339
+	 *
340
+	 * @return boolean whether or not the data was successfully stored in the session
341
+	 * @throws InvalidArgumentException
342
+	 * @throws InvalidInterfaceException
343
+	 * @throws InvalidDataTypeException
344
+	 * @throws EE_Error
345
+	 */
346
+	protected function store_submitted_form_data_in_session()
347
+	{
348
+		return EE_Registry::instance()->SSN->set_session_data(
349
+			array(
350
+				EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
351
+			)
352
+		);
353
+	}
354
+
355
+
356
+	/**
357
+	 * retrieves the originally submitted input values in the session
358
+	 * so that they can be used to repopulate the form if it failed validation
359
+	 *
360
+	 * @return array
361
+	 * @throws InvalidArgumentException
362
+	 * @throws InvalidInterfaceException
363
+	 * @throws InvalidDataTypeException
364
+	 */
365
+	protected function get_submitted_form_data_from_session()
366
+	{
367
+		$session = EE_Registry::instance()->SSN;
368
+		if ($session instanceof EE_Session) {
369
+			return $session->get_session_data(
370
+				EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
371
+			);
372
+		}
373
+		return array();
374
+	}
375
+
376
+
377
+	/**
378
+	 * flushed the originally submitted input values from the session
379
+	 *
380
+	 * @return boolean whether or not the data was successfully removed from the session
381
+	 * @throws InvalidArgumentException
382
+	 * @throws InvalidInterfaceException
383
+	 * @throws InvalidDataTypeException
384
+	 */
385
+	public static function flush_submitted_form_data_from_session()
386
+	{
387
+		return EE_Registry::instance()->SSN->reset_data(
388
+			array(EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
389
+		);
390
+	}
391
+
392
+
393
+	/**
394
+	 * Populates this form and its subsections with data from the session.
395
+	 * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
396
+	 * validation errors when displaying too)
397
+	 * Returns true if the form was populated from the session, false otherwise
398
+	 *
399
+	 * @return boolean
400
+	 * @throws InvalidArgumentException
401
+	 * @throws InvalidInterfaceException
402
+	 * @throws InvalidDataTypeException
403
+	 * @throws EE_Error
404
+	 */
405
+	public function populate_from_session()
406
+	{
407
+		$form_data_in_session = $this->get_submitted_form_data_from_session();
408
+		if (empty($form_data_in_session)) {
409
+			return false;
410
+		}
411
+		$this->receive_form_submission($form_data_in_session);
412
+		add_action('shutdown', array('EE_Form_Section_Proper', 'flush_submitted_form_data_from_session'));
413
+		if ($this->form_data_present_in($form_data_in_session)) {
414
+			return true;
415
+		}
416
+		return false;
417
+	}
418
+
419
+
420
+	/**
421
+	 * Populates the default data for the form, given an array where keys are
422
+	 * the input names, and values are their values (preferably normalized to be their
423
+	 * proper PHP types, not all strings... although that should be ok too).
424
+	 * Proper subsections are sub-arrays, the key being the subsection's name, and
425
+	 * the value being an array formatted in teh same way
426
+	 *
427
+	 * @param array $default_data
428
+	 * @throws EE_Error
429
+	 */
430
+	public function populate_defaults($default_data)
431
+	{
432
+		foreach ($this->subsections(false) as $subsection_name => $subsection) {
433
+			if (isset($default_data[ $subsection_name ])) {
434
+				if ($subsection instanceof EE_Form_Input_Base) {
435
+					$subsection->set_default($default_data[ $subsection_name ]);
436
+				} elseif ($subsection instanceof EE_Form_Section_Proper) {
437
+					$subsection->populate_defaults($default_data[ $subsection_name ]);
438
+				}
439
+			}
440
+		}
441
+	}
442
+
443
+
444
+	/**
445
+	 * returns true if subsection exists
446
+	 *
447
+	 * @param string $name
448
+	 * @return boolean
449
+	 */
450
+	public function subsection_exists($name)
451
+	{
452
+		return isset($this->_subsections[ $name ]) ? true : false;
453
+	}
454
+
455
+
456
+	/**
457
+	 * Gets the subsection specified by its name
458
+	 *
459
+	 * @param string  $name
460
+	 * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
461
+	 *                                                      so that the inputs will be properly configured.
462
+	 *                                                      However, some client code may be ok
463
+	 *                                                      with construction finalize being called later
464
+	 *                                                      (realizing that the subsections' html names
465
+	 *                                                      might not be set yet, etc.)
466
+	 * @return EE_Form_Section_Base
467
+	 * @throws EE_Error
468
+	 */
469
+	public function get_subsection($name, $require_construction_to_be_finalized = true)
470
+	{
471
+		if ($require_construction_to_be_finalized) {
472
+			$this->ensure_construct_finalized_called();
473
+		}
474
+		return $this->subsection_exists($name) ? $this->_subsections[ $name ] : null;
475
+	}
476
+
477
+
478
+	/**
479
+	 * Gets all the validatable subsections of this form section
480
+	 *
481
+	 * @return EE_Form_Section_Validatable[]
482
+	 * @throws EE_Error
483
+	 */
484
+	public function get_validatable_subsections()
485
+	{
486
+		$validatable_subsections = array();
487
+		foreach ($this->subsections() as $name => $obj) {
488
+			if ($obj instanceof EE_Form_Section_Validatable) {
489
+				$validatable_subsections[ $name ] = $obj;
490
+			}
491
+		}
492
+		return $validatable_subsections;
493
+	}
494
+
495
+
496
+	/**
497
+	 * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
498
+	 * throw an EE_Error.
499
+	 *
500
+	 * @param string  $name
501
+	 * @param boolean $require_construction_to_be_finalized most client code should
502
+	 *                                                      leave this as TRUE so that the inputs will be properly
503
+	 *                                                      configured. However, some client code may be ok with
504
+	 *                                                      construction finalize being called later
505
+	 *                                                      (realizing that the subsections' html names might not be
506
+	 *                                                      set yet, etc.)
507
+	 * @return EE_Form_Input_Base
508
+	 * @throws EE_Error
509
+	 */
510
+	public function get_input($name, $require_construction_to_be_finalized = true)
511
+	{
512
+		$subsection = $this->get_subsection(
513
+			$name,
514
+			$require_construction_to_be_finalized
515
+		);
516
+		if (! $subsection instanceof EE_Form_Input_Base) {
517
+			throw new EE_Error(
518
+				sprintf(
519
+					esc_html__(
520
+						"Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
521
+						'event_espresso'
522
+					),
523
+					$name,
524
+					get_class($this),
525
+					$subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
526
+				)
527
+			);
528
+		}
529
+		return $subsection;
530
+	}
531
+
532
+
533
+	/**
534
+	 * Like get_input(), gets the proper subsection of the form given the name,
535
+	 * otherwise throws an EE_Error
536
+	 *
537
+	 * @param string  $name
538
+	 * @param boolean $require_construction_to_be_finalized most client code should
539
+	 *                                                      leave this as TRUE so that the inputs will be properly
540
+	 *                                                      configured. However, some client code may be ok with
541
+	 *                                                      construction finalize being called later
542
+	 *                                                      (realizing that the subsections' html names might not be
543
+	 *                                                      set yet, etc.)
544
+	 * @return EE_Form_Section_Proper
545
+	 * @throws EE_Error
546
+	 */
547
+	public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
548
+	{
549
+		$subsection = $this->get_subsection(
550
+			$name,
551
+			$require_construction_to_be_finalized
552
+		);
553
+		if (! $subsection instanceof EE_Form_Section_Proper) {
554
+			throw new EE_Error(
555
+				sprintf(
556
+					esc_html__(
557
+						"Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'",
558
+						'event_espresso'
559
+					),
560
+					$name,
561
+					get_class($this)
562
+				)
563
+			);
564
+		}
565
+		return $subsection;
566
+	}
567
+
568
+
569
+	/**
570
+	 * Gets the value of the specified input. Should be called after receive_form_submission()
571
+	 * or populate_defaults() on the form, where the normalized value on the input is set.
572
+	 *
573
+	 * @param string $name
574
+	 * @return mixed depending on the input's type and its normalization strategy
575
+	 * @throws EE_Error
576
+	 */
577
+	public function get_input_value($name)
578
+	{
579
+		$input = $this->get_input($name);
580
+		return $input->normalized_value();
581
+	}
582
+
583
+
584
+	/**
585
+	 * Checks if this form section itself is valid, and then checks its subsections
586
+	 *
587
+	 * @throws EE_Error
588
+	 * @return boolean
589
+	 */
590
+	public function is_valid()
591
+	{
592
+		if ($this->is_valid === null) {
593
+			if (! $this->has_received_submission()) {
594
+				throw new EE_Error(
595
+					sprintf(
596
+						esc_html__(
597
+							'You cannot check if a form is valid before receiving the form submission using receive_form_submission',
598
+							'event_espresso'
599
+						)
600
+					)
601
+				);
602
+			}
603
+			if (! parent::is_valid()) {
604
+				$this->is_valid = false;
605
+			} else {
606
+				// ok so no general errors to this entire form section.
607
+				// so let's check the subsections, but only set errors if that hasn't been done yet
608
+				$this->is_valid = true;
609
+				foreach ($this->get_validatable_subsections() as $subsection) {
610
+					if (! $subsection->is_valid()) {
611
+						$this->is_valid = false;
612
+					}
613
+				}
614
+			}
615
+		}
616
+		return $this->is_valid;
617
+	}
618
+
619
+
620
+	/**
621
+	 * gets the default name of this form section if none is specified
622
+	 *
623
+	 * @return void
624
+	 */
625
+	protected function _set_default_name_if_empty()
626
+	{
627
+		if (! $this->_name) {
628
+			$classname    = get_class($this);
629
+			$default_name = str_replace('EE_', '', $classname);
630
+			$this->_name  = $default_name;
631
+		}
632
+	}
633
+
634
+
635
+	/**
636
+	 * Returns the HTML for the form, except for the form opening and closing tags
637
+	 * (as the form section doesn't know where you necessarily want to send the information to),
638
+	 * and except for a submit button. Enqueues JS and CSS; if called early enough we will
639
+	 * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
640
+	 * Not doing_it_wrong because theoretically this CAN be used properly,
641
+	 * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
642
+	 * any CSS.
643
+	 *
644
+	 * @throws InvalidArgumentException
645
+	 * @throws InvalidInterfaceException
646
+	 * @throws InvalidDataTypeException
647
+	 * @throws EE_Error
648
+	 */
649
+	public function get_html_and_js()
650
+	{
651
+		$this->enqueue_js();
652
+		return $this->get_html();
653
+	}
654
+
655
+
656
+	/**
657
+	 * returns HTML for displaying this form section. recursively calls display_section() on all subsections
658
+	 *
659
+	 * @param bool $display_previously_submitted_data
660
+	 * @return string
661
+	 * @throws InvalidArgumentException
662
+	 * @throws InvalidInterfaceException
663
+	 * @throws InvalidDataTypeException
664
+	 * @throws EE_Error
665
+	 * @throws EE_Error
666
+	 * @throws EE_Error
667
+	 */
668
+	public function get_html($display_previously_submitted_data = true)
669
+	{
670
+		$this->ensure_construct_finalized_called();
671
+		if ($display_previously_submitted_data) {
672
+			$this->populate_from_session();
673
+		}
674
+		return $this->_form_html_filter
675
+			? $this->_form_html_filter->filterHtml($this->_layout_strategy->layout_form(), $this)
676
+			: $this->_layout_strategy->layout_form();
677
+	}
678
+
679
+
680
+	/**
681
+	 * enqueues JS and CSS for the form.
682
+	 * It is preferred to call this before wp_enqueue_scripts so the
683
+	 * scripts and styles can be put in the header, but if called later
684
+	 * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
685
+	 * only be in the header; but in HTML5 its ok in the body.
686
+	 * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
687
+	 * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
688
+	 *
689
+	 * @return void
690
+	 * @throws EE_Error
691
+	 */
692
+	public function enqueue_js()
693
+	{
694
+		$this->_enqueue_and_localize_form_js();
695
+		foreach ($this->subsections() as $subsection) {
696
+			$subsection->enqueue_js();
697
+		}
698
+	}
699
+
700
+
701
+	/**
702
+	 * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
703
+	 * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
704
+	 * the wp_enqueue_scripts hook.
705
+	 * However, registering the form js and localizing it can happen when we
706
+	 * actually output the form (which is preferred, seeing how teh form's fields
707
+	 * could change until it's actually outputted)
708
+	 *
709
+	 * @param boolean $init_form_validation_automatically whether or not we want the form validation
710
+	 *                                                    to be triggered automatically or not
711
+	 * @return void
712
+	 */
713
+	public static function wp_enqueue_scripts($init_form_validation_automatically = true)
714
+	{
715
+		wp_register_script(
716
+			'ee_form_section_validation',
717
+			EE_GLOBAL_ASSETS_URL . 'scripts' . '/form_section_validation.js',
718
+			array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
719
+			EVENT_ESPRESSO_VERSION,
720
+			true
721
+		);
722
+		wp_localize_script(
723
+			'ee_form_section_validation',
724
+			'ee_form_section_validation_init',
725
+			array('init' => $init_form_validation_automatically ? '1' : '0')
726
+		);
727
+	}
728
+
729
+
730
+	/**
731
+	 * gets the variables used by form_section_validation.js.
732
+	 * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
733
+	 * but before the wordpress hook wp_loaded
734
+	 *
735
+	 * @throws EE_Error
736
+	 */
737
+	public function _enqueue_and_localize_form_js()
738
+	{
739
+		$this->ensure_construct_finalized_called();
740
+		// actually, we don't want to localize just yet. There may be other forms on the page.
741
+		// so we need to add our form section data to a static variable accessible by all form sections
742
+		// and localize it just before the footer
743
+		$this->localize_validation_rules();
744
+		add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
745
+		add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
746
+	}
747
+
748
+
749
+	/**
750
+	 * add our form section data to a static variable accessible by all form sections
751
+	 *
752
+	 * @param bool $return_for_subsection
753
+	 * @return void
754
+	 * @throws EE_Error
755
+	 */
756
+	public function localize_validation_rules($return_for_subsection = false)
757
+	{
758
+		// we only want to localize vars ONCE for the entire form,
759
+		// so if the form section doesn't have a parent, then it must be the top dog
760
+		if ($return_for_subsection || ! $this->parent_section()) {
761
+			EE_Form_Section_Proper::$_js_localization['form_data'][ $this->html_id() ] = array(
762
+				'form_section_id'  => $this->html_id(true),
763
+				'validation_rules' => $this->get_jquery_validation_rules(),
764
+				'other_data'       => $this->get_other_js_data(),
765
+				'errors'           => $this->subsection_validation_errors_by_html_name(),
766
+			);
767
+			EE_Form_Section_Proper::$_scripts_localized                                = true;
768
+		}
769
+	}
770
+
771
+
772
+	/**
773
+	 * Gets an array of extra data that will be useful for client-side javascript.
774
+	 * This is primarily data added by inputs and forms in addition to any
775
+	 * scripts they might enqueue
776
+	 *
777
+	 * @param array $form_other_js_data
778
+	 * @return array
779
+	 * @throws EE_Error
780
+	 */
781
+	public function get_other_js_data($form_other_js_data = array())
782
+	{
783
+		foreach ($this->subsections() as $subsection) {
784
+			$form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
785
+		}
786
+		return $form_other_js_data;
787
+	}
788
+
789
+
790
+	/**
791
+	 * Gets a flat array of inputs for this form section and its subsections.
792
+	 * Keys are their form names, and values are the inputs themselves
793
+	 *
794
+	 * @return EE_Form_Input_Base
795
+	 * @throws EE_Error
796
+	 */
797
+	public function inputs_in_subsections()
798
+	{
799
+		$inputs = array();
800
+		foreach ($this->subsections() as $subsection) {
801
+			if ($subsection instanceof EE_Form_Input_Base) {
802
+				$inputs[ $subsection->html_name() ] = $subsection;
803
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
804
+				$inputs += $subsection->inputs_in_subsections();
805
+			}
806
+		}
807
+		return $inputs;
808
+	}
809
+
810
+
811
+	/**
812
+	 * Gets a flat array of all the validation errors.
813
+	 * Keys are html names (because those should be unique)
814
+	 * and values are a string of all their validation errors
815
+	 *
816
+	 * @return string[]
817
+	 * @throws EE_Error
818
+	 */
819
+	public function subsection_validation_errors_by_html_name()
820
+	{
821
+		$inputs = $this->inputs();
822
+		$errors = array();
823
+		foreach ($inputs as $form_input) {
824
+			if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
825
+				$errors[ $form_input->html_name() ] = $form_input->get_validation_error_string();
826
+			}
827
+		}
828
+		return $errors;
829
+	}
830
+
831
+
832
+	/**
833
+	 * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
834
+	 * Should be setup by each form during the _enqueues_and_localize_form_js
835
+	 *
836
+	 * @throws InvalidArgumentException
837
+	 * @throws InvalidInterfaceException
838
+	 * @throws InvalidDataTypeException
839
+	 */
840
+	public static function localize_script_for_all_forms()
841
+	{
842
+		// allow inputs and stuff to hook in their JS and stuff here
843
+		do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
844
+		EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
845
+		$email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
846
+			? EE_Registry::instance()->CFG->registration->email_validation_level
847
+			: 'wp_default';
848
+		EE_Form_Section_Proper::$_js_localization['email_validation_level']   = $email_validation_level;
849
+		wp_enqueue_script('ee_form_section_validation');
850
+		wp_localize_script(
851
+			'ee_form_section_validation',
852
+			'ee_form_section_vars',
853
+			EE_Form_Section_Proper::$_js_localization
854
+		);
855
+	}
856
+
857
+
858
+	/**
859
+	 * ensure_scripts_localized
860
+	 *
861
+	 * @throws EE_Error
862
+	 */
863
+	public function ensure_scripts_localized()
864
+	{
865
+		if (! EE_Form_Section_Proper::$_scripts_localized) {
866
+			$this->_enqueue_and_localize_form_js();
867
+		}
868
+	}
869
+
870
+
871
+	/**
872
+	 * Gets the hard-coded validation error messages to be used in the JS. The convention
873
+	 * is that the key here should be the same as the custom validation rule put in the JS file
874
+	 *
875
+	 * @return array keys are custom validation rules, and values are internationalized strings
876
+	 */
877
+	private static function _get_localized_error_messages()
878
+	{
879
+		return array(
880
+			'validUrl' => esc_html__('This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg', 'event_espresso'),
881
+			'regex'    => esc_html__('Please check your input', 'event_espresso'),
882
+		);
883
+	}
884
+
885
+
886
+	/**
887
+	 * @return array
888
+	 */
889
+	public static function js_localization()
890
+	{
891
+		return self::$_js_localization;
892
+	}
893
+
894
+
895
+	/**
896
+	 * @return void
897
+	 */
898
+	public static function reset_js_localization()
899
+	{
900
+		self::$_js_localization = array();
901
+	}
902
+
903
+
904
+	/**
905
+	 * Gets the JS to put inside the jquery validation rules for subsection of this form section.
906
+	 * See parent function for more...
907
+	 *
908
+	 * @return array
909
+	 * @throws EE_Error
910
+	 */
911
+	public function get_jquery_validation_rules()
912
+	{
913
+		$jquery_validation_rules = array();
914
+		foreach ($this->get_validatable_subsections() as $subsection) {
915
+			$jquery_validation_rules = array_merge(
916
+				$jquery_validation_rules,
917
+				$subsection->get_jquery_validation_rules()
918
+			);
919
+		}
920
+		return $jquery_validation_rules;
921
+	}
922
+
923
+
924
+	/**
925
+	 * Sanitizes all the data and sets the sanitized value of each field
926
+	 *
927
+	 * @param array $req_data
928
+	 * @return void
929
+	 * @throws EE_Error
930
+	 */
931
+	protected function _normalize($req_data)
932
+	{
933
+		$this->_received_submission = true;
934
+		$this->_validation_errors   = array();
935
+		foreach ($this->get_validatable_subsections() as $subsection) {
936
+			try {
937
+				$subsection->_normalize($req_data);
938
+			} catch (EE_Validation_Error $e) {
939
+				$subsection->add_validation_error($e);
940
+			}
941
+		}
942
+	}
943
+
944
+
945
+	/**
946
+	 * Performs validation on this form section and its subsections.
947
+	 * For each subsection,
948
+	 * calls _validate_{subsection_name} on THIS form (if the function exists)
949
+	 * and passes it the subsection, then calls _validate on that subsection.
950
+	 * If you need to perform validation on the form as a whole (considering multiple)
951
+	 * you would be best to override this _validate method,
952
+	 * calling parent::_validate() first.
953
+	 *
954
+	 * @throws EE_Error
955
+	 */
956
+	protected function _validate()
957
+	{
958
+		// reset the cache of whether this form is valid or not- we're re-validating it now
959
+		$this->is_valid = null;
960
+		foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
961
+			if (method_exists($this, '_validate_' . $subsection_name)) {
962
+				call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
963
+			}
964
+			$subsection->_validate();
965
+		}
966
+	}
967
+
968
+
969
+	/**
970
+	 * Gets all the validated inputs for the form section
971
+	 *
972
+	 * @return array
973
+	 * @throws EE_Error
974
+	 */
975
+	public function valid_data()
976
+	{
977
+		$inputs = array();
978
+		foreach ($this->subsections() as $subsection_name => $subsection) {
979
+			if ($subsection instanceof EE_Form_Section_Proper) {
980
+				$inputs[ $subsection_name ] = $subsection->valid_data();
981
+			} elseif ($subsection instanceof EE_Form_Input_Base) {
982
+				$inputs[ $subsection_name ] = $subsection->normalized_value();
983
+			}
984
+		}
985
+		return $inputs;
986
+	}
987
+
988
+
989
+	/**
990
+	 * Gets all the inputs on this form section
991
+	 *
992
+	 * @return EE_Form_Input_Base[]
993
+	 * @throws EE_Error
994
+	 */
995
+	public function inputs()
996
+	{
997
+		$inputs = array();
998
+		foreach ($this->subsections() as $subsection_name => $subsection) {
999
+			if ($subsection instanceof EE_Form_Input_Base) {
1000
+				$inputs[ $subsection_name ] = $subsection;
1001
+			}
1002
+		}
1003
+		return $inputs;
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * Gets all the subsections which are a proper form
1009
+	 *
1010
+	 * @return EE_Form_Section_Proper[]
1011
+	 * @throws EE_Error
1012
+	 */
1013
+	public function subforms()
1014
+	{
1015
+		$form_sections = array();
1016
+		foreach ($this->subsections() as $name => $obj) {
1017
+			if ($obj instanceof EE_Form_Section_Proper) {
1018
+				$form_sections[ $name ] = $obj;
1019
+			}
1020
+		}
1021
+		return $form_sections;
1022
+	}
1023
+
1024
+
1025
+	/**
1026
+	 * Gets all the subsections (inputs, proper subsections, or html-only sections).
1027
+	 * Consider using inputs() or subforms()
1028
+	 * if you only want form inputs or proper form sections.
1029
+	 *
1030
+	 * @param boolean $require_construction_to_be_finalized most client code should
1031
+	 *                                                      leave this as TRUE so that the inputs will be properly
1032
+	 *                                                      configured. However, some client code may be ok with
1033
+	 *                                                      construction finalize being called later
1034
+	 *                                                      (realizing that the subsections' html names might not be
1035
+	 *                                                      set yet, etc.)
1036
+	 * @return EE_Form_Section_Proper[]
1037
+	 * @throws EE_Error
1038
+	 */
1039
+	public function subsections($require_construction_to_be_finalized = true)
1040
+	{
1041
+		if ($require_construction_to_be_finalized) {
1042
+			$this->ensure_construct_finalized_called();
1043
+		}
1044
+		return $this->_subsections;
1045
+	}
1046
+
1047
+
1048
+	/**
1049
+	 * Returns whether this form has any subforms or inputs
1050
+	 * @return bool
1051
+	 */
1052
+	public function hasSubsections()
1053
+	{
1054
+		return ! empty($this->_subsections);
1055
+	}
1056
+
1057
+
1058
+	/**
1059
+	 * Returns a simple array where keys are input names, and values are their normalized
1060
+	 * values. (Similar to calling get_input_value on inputs)
1061
+	 *
1062
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1063
+	 *                                        or just this forms' direct children inputs
1064
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1065
+	 *                                        or allow multidimensional array
1066
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
1067
+	 *                                        with array keys being input names
1068
+	 *                                        (regardless of whether they are from a subsection or not),
1069
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1070
+	 *                                        where keys are always subsection names and values are either
1071
+	 *                                        the input's normalized value, or an array like the top-level array
1072
+	 * @throws EE_Error
1073
+	 */
1074
+	public function input_values($include_subform_inputs = false, $flatten = false)
1075
+	{
1076
+		return $this->_input_values(false, $include_subform_inputs, $flatten);
1077
+	}
1078
+
1079
+
1080
+	/**
1081
+	 * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
1082
+	 * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
1083
+	 * is not necessarily the value we want to display to users. This creates an array
1084
+	 * where keys are the input names, and values are their display values
1085
+	 *
1086
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1087
+	 *                                        or just this forms' direct children inputs
1088
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1089
+	 *                                        or allow multidimensional array
1090
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
1091
+	 *                                        with array keys being input names
1092
+	 *                                        (regardless of whether they are from a subsection or not),
1093
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1094
+	 *                                        where keys are always subsection names and values are either
1095
+	 *                                        the input's normalized value, or an array like the top-level array
1096
+	 * @throws EE_Error
1097
+	 */
1098
+	public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1099
+	{
1100
+		return $this->_input_values(true, $include_subform_inputs, $flatten);
1101
+	}
1102
+
1103
+
1104
+	/**
1105
+	 * Gets the input values from the form
1106
+	 *
1107
+	 * @param boolean $pretty                 Whether to retrieve the pretty value,
1108
+	 *                                        or just the normalized value
1109
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1110
+	 *                                        or just this forms' direct children inputs
1111
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1112
+	 *                                        or allow multidimensional array
1113
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1114
+	 *                                        input names (regardless of whether they are from a subsection or not),
1115
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1116
+	 *                                        where keys are always subsection names and values are either
1117
+	 *                                        the input's normalized value, or an array like the top-level array
1118
+	 * @throws EE_Error
1119
+	 */
1120
+	public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1121
+	{
1122
+		$input_values = array();
1123
+		foreach ($this->subsections() as $subsection_name => $subsection) {
1124
+			if ($subsection instanceof EE_Form_Input_Base) {
1125
+				$input_values[ $subsection_name ] = $pretty
1126
+					? $subsection->pretty_value()
1127
+					: $subsection->normalized_value();
1128
+			} elseif ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1129
+				$subform_input_values = $subsection->_input_values(
1130
+					$pretty,
1131
+					$include_subform_inputs,
1132
+					$flatten
1133
+				);
1134
+				if ($flatten) {
1135
+					$input_values = array_merge($input_values, $subform_input_values);
1136
+				} else {
1137
+					$input_values[ $subsection_name ] = $subform_input_values;
1138
+				}
1139
+			}
1140
+		}
1141
+		return $input_values;
1142
+	}
1143
+
1144
+
1145
+	/**
1146
+	 * Gets the originally submitted input values from the form
1147
+	 *
1148
+	 * @param boolean $include_subforms  Whether to include inputs from subforms,
1149
+	 *                                   or just this forms' direct children inputs
1150
+	 * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1151
+	 *                                   with array keys being input names
1152
+	 *                                   (regardless of whether they are from a subsection or not),
1153
+	 *                                   and if $flatten is FALSE it can be a multidimensional array
1154
+	 *                                   where keys are always subsection names and values are either
1155
+	 *                                   the input's normalized value, or an array like the top-level array
1156
+	 * @throws EE_Error
1157
+	 */
1158
+	public function submitted_values($include_subforms = false)
1159
+	{
1160
+		$submitted_values = array();
1161
+		foreach ($this->subsections() as $subsection) {
1162
+			if ($subsection instanceof EE_Form_Input_Base) {
1163
+				// is this input part of an array of inputs?
1164
+				if (strpos($subsection->html_name(), '[') !== false) {
1165
+					$full_input_name  = EEH_Array::convert_array_values_to_keys(
1166
+						explode(
1167
+							'[',
1168
+							str_replace(']', '', $subsection->html_name())
1169
+						),
1170
+						$subsection->raw_value()
1171
+					);
1172
+					$submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1173
+				} else {
1174
+					$submitted_values[ $subsection->html_name() ] = $subsection->raw_value();
1175
+				}
1176
+			} elseif ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1177
+				$subform_input_values = $subsection->submitted_values($include_subforms);
1178
+				$submitted_values     = array_replace_recursive($submitted_values, $subform_input_values);
1179
+			}
1180
+		}
1181
+		return $submitted_values;
1182
+	}
1183
+
1184
+
1185
+	/**
1186
+	 * Indicates whether or not this form has received a submission yet
1187
+	 * (ie, had receive_form_submission called on it yet)
1188
+	 *
1189
+	 * @return boolean
1190
+	 * @throws EE_Error
1191
+	 */
1192
+	public function has_received_submission()
1193
+	{
1194
+		$this->ensure_construct_finalized_called();
1195
+		return $this->_received_submission;
1196
+	}
1197
+
1198
+
1199
+	/**
1200
+	 * Equivalent to passing 'exclude' in the constructor's options array.
1201
+	 * Removes the listed inputs from the form
1202
+	 *
1203
+	 * @param array $inputs_to_exclude values are the input names
1204
+	 * @return void
1205
+	 */
1206
+	public function exclude(array $inputs_to_exclude = array())
1207
+	{
1208
+		foreach ($inputs_to_exclude as $input_to_exclude_name) {
1209
+			unset($this->_subsections[ $input_to_exclude_name ]);
1210
+		}
1211
+	}
1212
+
1213
+
1214
+	/**
1215
+	 * Changes these inputs' display strategy to be EE_Hidden_Display_Strategy.
1216
+	 * @param array $inputs_to_hide
1217
+	 * @throws EE_Error
1218
+	 */
1219
+	public function hide(array $inputs_to_hide = array())
1220
+	{
1221
+		foreach ($inputs_to_hide as $input_to_hide) {
1222
+			$input = $this->get_input($input_to_hide);
1223
+			$input->set_display_strategy(new EE_Hidden_Display_Strategy());
1224
+		}
1225
+	}
1226
+
1227
+
1228
+	/**
1229
+	 * add_subsections
1230
+	 * Adds the listed subsections to the form section.
1231
+	 * If $subsection_name_to_target is provided,
1232
+	 * then new subsections are added before or after that subsection,
1233
+	 * otherwise to the start or end of the entire subsections array.
1234
+	 *
1235
+	 * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1236
+	 *                                                          where keys are their names
1237
+	 * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1238
+	 *                                                          should be added before or after
1239
+	 *                                                          IF $subsection_name_to_target is null,
1240
+	 *                                                          then $new_subsections will be added to
1241
+	 *                                                          the beginning or end of the entire subsections array
1242
+	 * @param boolean                $add_before                whether to add $new_subsections, before or after
1243
+	 *                                                          $subsection_name_to_target,
1244
+	 *                                                          or if $subsection_name_to_target is null,
1245
+	 *                                                          before or after entire subsections array
1246
+	 * @return void
1247
+	 * @throws EE_Error
1248
+	 */
1249
+	public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1250
+	{
1251
+		foreach ($new_subsections as $subsection_name => $subsection) {
1252
+			if (! $subsection instanceof EE_Form_Section_Base) {
1253
+				EE_Error::add_error(
1254
+					sprintf(
1255
+						esc_html__(
1256
+							"Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1257
+							'event_espresso'
1258
+						),
1259
+						get_class($subsection),
1260
+						$subsection_name,
1261
+						$this->name()
1262
+					)
1263
+				);
1264
+				unset($new_subsections[ $subsection_name ]);
1265
+			}
1266
+		}
1267
+		$this->_subsections = EEH_Array::insert_into_array(
1268
+			$this->_subsections,
1269
+			$new_subsections,
1270
+			$subsection_name_to_target,
1271
+			$add_before
1272
+		);
1273
+		if ($this->_construction_finalized) {
1274
+			foreach ($this->_subsections as $name => $subsection) {
1275
+				$subsection->_construct_finalize($this, $name);
1276
+			}
1277
+		}
1278
+	}
1279
+
1280
+
1281
+	/**
1282
+	 * @param string $subsection_name
1283
+	 * @param bool   $recursive
1284
+	 * @return bool
1285
+	 */
1286
+	public function has_subsection($subsection_name, $recursive = false)
1287
+	{
1288
+		foreach ($this->_subsections as $name => $subsection) {
1289
+			if ($name === $subsection_name
1290
+				|| (
1291
+					$recursive
1292
+					&& $subsection instanceof EE_Form_Section_Proper
1293
+					&& $subsection->has_subsection($subsection_name, $recursive)
1294
+				)
1295
+			) {
1296
+				return true;
1297
+			}
1298
+		}
1299
+		return false;
1300
+	}
1301
+
1302
+
1303
+
1304
+	/**
1305
+	 * Just gets all validatable subsections to clean their sensitive data
1306
+	 *
1307
+	 * @throws EE_Error
1308
+	 */
1309
+	public function clean_sensitive_data()
1310
+	{
1311
+		foreach ($this->get_validatable_subsections() as $subsection) {
1312
+			$subsection->clean_sensitive_data();
1313
+		}
1314
+	}
1315
+
1316
+
1317
+	/**
1318
+	 * Sets the submission error message (aka validation error message for this form section and all sub-sections)
1319
+	 * @param string                           $form_submission_error_message
1320
+	 * @param EE_Form_Section_Validatable $form_section unused
1321
+	 * @throws EE_Error
1322
+	 */
1323
+	public function set_submission_error_message(
1324
+		$form_submission_error_message = ''
1325
+	) {
1326
+		$this->_form_submission_error_message = ! empty($form_submission_error_message)
1327
+			? $form_submission_error_message
1328
+			: $this->getAllValidationErrorsString();
1329
+	}
1330
+
1331
+
1332
+	/**
1333
+	 * Returns the cached error message. A default value is set for this during _validate(),
1334
+	 * (called during receive_form_submission) but it can be explicitly set using
1335
+	 * set_submission_error_message
1336
+	 *
1337
+	 * @return string
1338
+	 */
1339
+	public function submission_error_message()
1340
+	{
1341
+		return $this->_form_submission_error_message;
1342
+	}
1343
+
1344
+
1345
+	/**
1346
+	 * Sets a message to display if the data submitted to the form was valid.
1347
+	 * @param string $form_submission_success_message
1348
+	 */
1349
+	public function set_submission_success_message($form_submission_success_message = '')
1350
+	{
1351
+		$this->_form_submission_success_message = ! empty($form_submission_success_message)
1352
+			? $form_submission_success_message
1353
+			: esc_html__('Form submitted successfully', 'event_espresso');
1354
+	}
1355
+
1356
+
1357
+	/**
1358
+	 * Gets a message appropriate for display when the form is correctly submitted
1359
+	 * @return string
1360
+	 */
1361
+	public function submission_success_message()
1362
+	{
1363
+		return $this->_form_submission_success_message;
1364
+	}
1365
+
1366
+
1367
+	/**
1368
+	 * Returns the prefix that should be used on child of this form section for
1369
+	 * their html names. If this form section itself has a parent, prepends ITS
1370
+	 * prefix onto this form section's prefix. Used primarily by
1371
+	 * EE_Form_Input_Base::_set_default_html_name_if_empty
1372
+	 *
1373
+	 * @return string
1374
+	 * @throws EE_Error
1375
+	 */
1376
+	public function html_name_prefix()
1377
+	{
1378
+		if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1379
+			return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1380
+		}
1381
+		return $this->name();
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * Gets the name, but first checks _construct_finalize has been called. If not,
1387
+	 * calls it (assumes there is no parent and that we want the name to be whatever
1388
+	 * was set, which is probably nothing, or the classname)
1389
+	 *
1390
+	 * @return string
1391
+	 * @throws EE_Error
1392
+	 */
1393
+	public function name()
1394
+	{
1395
+		$this->ensure_construct_finalized_called();
1396
+		return parent::name();
1397
+	}
1398
+
1399
+
1400
+	/**
1401
+	 * @return EE_Form_Section_Proper
1402
+	 * @throws EE_Error
1403
+	 */
1404
+	public function parent_section()
1405
+	{
1406
+		$this->ensure_construct_finalized_called();
1407
+		return parent::parent_section();
1408
+	}
1409
+
1410
+
1411
+	/**
1412
+	 * make sure construction finalized was called, otherwise children might not be ready
1413
+	 *
1414
+	 * @return void
1415
+	 * @throws EE_Error
1416
+	 */
1417
+	public function ensure_construct_finalized_called()
1418
+	{
1419
+		if (! $this->_construction_finalized) {
1420
+			$this->_construct_finalize($this->_parent_section, $this->_name);
1421
+		}
1422
+	}
1423
+
1424
+
1425
+	/**
1426
+	 * Checks if any of this form section's inputs, or any of its children's inputs,
1427
+	 * are in teh form data. If any are found, returns true. Else false
1428
+	 *
1429
+	 * @param array $req_data
1430
+	 * @return boolean
1431
+	 * @throws EE_Error
1432
+	 */
1433
+	public function form_data_present_in($req_data = null)
1434
+	{
1435
+		$req_data = $this->getCachedRequest($req_data);
1436
+		foreach ($this->subsections() as $subsection) {
1437
+			if ($subsection instanceof EE_Form_Input_Base) {
1438
+				if ($subsection->form_data_present_in($req_data)) {
1439
+					return true;
1440
+				}
1441
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
1442
+				if ($subsection->form_data_present_in($req_data)) {
1443
+					return true;
1444
+				}
1445
+			}
1446
+		}
1447
+		return false;
1448
+	}
1449
+
1450
+
1451
+	/**
1452
+	 * Gets validation errors for this form section and subsections
1453
+	 * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1454
+	 * gets the validation errors for ALL subsection
1455
+	 *
1456
+	 * @return EE_Validation_Error[]
1457
+	 * @throws EE_Error
1458
+	 */
1459
+	public function get_validation_errors_accumulated()
1460
+	{
1461
+		$validation_errors = $this->get_validation_errors();
1462
+		foreach ($this->get_validatable_subsections() as $subsection) {
1463
+			if ($subsection instanceof EE_Form_Section_Proper) {
1464
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1465
+			} else {
1466
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors();
1467
+			}
1468
+			if ($validation_errors_on_this_subsection) {
1469
+				$validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1470
+			}
1471
+		}
1472
+		return $validation_errors;
1473
+	}
1474
+
1475
+	/**
1476
+	 * Fetch validation errors from children and grandchildren and puts them in a single string.
1477
+	 * This traverses the form section tree to generate this, but you probably want to instead use
1478
+	 * get_form_submission_error_message() which is usually this message cached (or a custom validation error message)
1479
+	 *
1480
+	 * @return string
1481
+	 * @since 4.9.59.p
1482
+	 */
1483
+	protected function getAllValidationErrorsString()
1484
+	{
1485
+		$submission_error_messages = array();
1486
+		// bad, bad, bad registrant
1487
+		foreach ($this->get_validation_errors_accumulated() as $validation_error) {
1488
+			if ($validation_error instanceof EE_Validation_Error) {
1489
+				$form_section = $validation_error->get_form_section();
1490
+				if ($form_section instanceof EE_Form_Input_Base) {
1491
+					$label = $validation_error->get_form_section()->html_label_text();
1492
+				} elseif ($form_section instanceof EE_Form_Section_Validatable) {
1493
+					$label = $validation_error->get_form_section()->name();
1494
+				} else {
1495
+					$label = esc_html__('Unknown', 'event_espresso');
1496
+				}
1497
+				$submission_error_messages[] = sprintf(
1498
+					__('%s : %s', 'event_espresso'),
1499
+					$label,
1500
+					$validation_error->getMessage()
1501
+				);
1502
+			}
1503
+		}
1504
+		return implode('<br>', $submission_error_messages);
1505
+	}
1506
+
1507
+
1508
+	/**
1509
+	 * This isn't just the name of an input, it's a path pointing to an input. The
1510
+	 * path is similar to a folder path: slash (/) means to descend into a subsection,
1511
+	 * dot-dot-slash (../) means to ascend into the parent section.
1512
+	 * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1513
+	 * which will be returned.
1514
+	 * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1515
+	 * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1516
+	 * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1517
+	 * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1518
+	 * Etc
1519
+	 *
1520
+	 * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1521
+	 * @return EE_Form_Section_Base
1522
+	 * @throws EE_Error
1523
+	 */
1524
+	public function find_section_from_path($form_section_path)
1525
+	{
1526
+		// check if we can find the input from purely going straight up the tree
1527
+		$input = parent::find_section_from_path($form_section_path);
1528
+		if ($input instanceof EE_Form_Section_Base) {
1529
+			return $input;
1530
+		}
1531
+		$next_slash_pos = strpos($form_section_path, '/');
1532
+		if ($next_slash_pos !== false) {
1533
+			$child_section_name = substr($form_section_path, 0, $next_slash_pos);
1534
+			$subpath            = substr($form_section_path, $next_slash_pos + 1);
1535
+		} else {
1536
+			$child_section_name = $form_section_path;
1537
+			$subpath            = '';
1538
+		}
1539
+		$child_section = $this->get_subsection($child_section_name);
1540
+		if ($child_section instanceof EE_Form_Section_Base) {
1541
+			return $child_section->find_section_from_path($subpath);
1542
+		}
1543
+		return null;
1544
+	}
1545 1545
 }
Please login to merge, or discard this patch.
core/libraries/form_sections/base/EE_Model_Form_Section.form.php 1 patch
Indentation   +455 added lines, -455 removed lines patch added patch discarded remove patch
@@ -14,459 +14,459 @@
 block discarded – undo
14 14
 class EE_Model_Form_Section extends EE_Form_Section_Proper
15 15
 {
16 16
 
17
-    /**
18
-     * @var EEM_Base
19
-     */
20
-    protected $_model = null;
21
-
22
-    /**
23
-     * @var EE_Base_Class
24
-     */
25
-    protected $_model_object = null;
26
-
27
-
28
-
29
-    /**
30
-     * @param array        $options_array   keys: {
31
-     * @type EEM_Base      $model
32
-     * @type EE_Base_Class $model_object
33
-     * @type array         $subsection_args array keys should be subsection names (that either do or will exist), and
34
-     *       values are the arrays as you would pass them to that subsection
35
-     *                                      }
36
-     * @throws EE_Error
37
-     */
38
-    public function __construct($options_array = array())
39
-    {
40
-        if (isset($options_array['model']) && $options_array['model'] instanceof EEM_Base) {
41
-            $this->_model = $options_array['model'];
42
-        }
43
-        if (! $this->_model || ! $this->_model instanceof EEM_Base) {
44
-            throw new EE_Error(sprintf(__(
45
-                "Model Form Sections must first specify the _model property to be a subclass of EEM_Base",
46
-                "event_espresso"
47
-            )));
48
-        }
49
-        if (isset($options_array['subsection_args'])) {
50
-            $subsection_args = $options_array['subsection_args'];
51
-        } else {
52
-            $subsection_args = array();
53
-        }
54
-        // gather fields and relations to convert to inputs
55
-        // but if they're just going to exclude a field anyways, don't bother converting it to an input
56
-        $exclude = $this->_subsections;
57
-        if (isset($options_array['exclude'])) {
58
-            $exclude = array_merge($exclude, array_flip($options_array['exclude']));
59
-        }
60
-        $model_fields = array_diff_key($this->_model->field_settings(), $exclude);
61
-        $model_relations = array_diff_key($this->_model->relation_settings(), $exclude);
62
-        // convert fields and relations to inputs
63
-        $this->_subsections = array_merge(
64
-            $this->_convert_model_fields_to_inputs($model_fields),
65
-            $this->_convert_model_relations_to_inputs($model_relations, $subsection_args),
66
-            $this->_subsections
67
-        );
68
-        parent::__construct($options_array);
69
-        if (isset($options_array['model_object']) && $options_array['model_object'] instanceof EE_Base_Class) {
70
-            $this->populate_model_obj($options_array['model_object']);
71
-        }
72
-    }
73
-
74
-
75
-
76
-    /**
77
-     * For now, just makes inputs for only HABTM relations
78
-     *
79
-     * @param EE_Model_Relation_Base[] $relations
80
-     * @param array                    $subsection_args keys should be existing or soon-to-be-existing input names, and
81
-     *                                                  their values are {
82
-     * @type array {
83
-     * @type EE_Base_Class[]           $model_objects   if the subsection is an EE_Select_Multi_Model_Input
84
-     *                                                  }
85
-     *                                                  }
86
-     * @return array
87
-     */
88
-    protected function _convert_model_relations_to_inputs($relations, $subsection_args = array())
89
-    {
90
-        $inputs = array();
91
-        foreach ($relations as $relation_name => $relation_obj) {
92
-            $input_constructor_args = array(
93
-                array_merge(
94
-                    array(
95
-                        'required'        => $relation_obj instanceof EE_Belongs_To_Relation,
96
-                        'html_label_text' => $relation_obj instanceof EE_Belongs_To_Relation
97
-                            ? $relation_obj->get_other_model()->item_name(1)
98
-                            : $relation_obj->get_other_model()
99
-                                           ->item_name(2),
100
-                    ),
101
-                    $subsection_args
102
-                ),
103
-            );
104
-            $input = null;
105
-            switch (get_class($relation_obj)) {
106
-                case 'EE_HABTM_Relation':
107
-                    if (isset($subsection_args[ $relation_name ])
108
-                        && isset($subsection_args[ $relation_name ]['model_objects'])
109
-                    ) {
110
-                        $model_objects = $subsection_args[ $relation_name ]['model_objects'];
111
-                    } else {
112
-                        $model_objects = $relation_obj->get_other_model()->get_all();
113
-                    }
114
-                    $input = new EE_Select_Multi_Model_Input($model_objects, $input_constructor_args);
115
-                    break;
116
-                default:
117
-            }
118
-            if ($input) {
119
-                $inputs[ $relation_name ] = $input;
120
-            }
121
-        }
122
-        return $inputs;
123
-    }
124
-
125
-
126
-
127
-    /**
128
-     * Changes model fields into form section inputs
129
-     *
130
-     * @param EE_Model_Field_Base[] $model_fields keys are the model's name
131
-     * @throws EE_Error
132
-     * @return EE_Form_Input_Base[]
133
-     */
134
-    protected function _convert_model_fields_to_inputs($model_fields = array())
135
-    {
136
-        $inputs = array();
137
-        foreach ($model_fields as $field_name => $model_field) {
138
-            if ($model_field instanceof EE_Model_Field_Base) {
139
-                $input_constructor_args = array(
140
-                    array(
141
-                        'required'        => ! $model_field->is_nullable()
142
-                                             && $model_field->get_default_value()
143
-                                                === null,
144
-                        'html_label_text' => $model_field->get_nicename(),
145
-                        'default'         => $model_field->get_default_value(),
146
-                    ),
147
-                );
148
-                switch (get_class($model_field)) {
149
-                    case 'EE_All_Caps_Text_Field':
150
-                    case 'EE_Any_Foreign_Model_Name_Field':
151
-                        $input_class = 'EE_Text_Input';
152
-                        break;
153
-                    case 'EE_Boolean_Field':
154
-                        $input_class = 'EE_Yes_No_Input';
155
-                        break;
156
-                    case 'EE_Datetime_Field':
157
-                        throw new EE_Error(sprintf(__(
158
-                            "Model field '%s' does not yet have a known conversion to form input",
159
-                            "event_espresso"
160
-                        ), get_class($model_field)));
161
-                        break;
162
-                    case 'EE_Email_Field':
163
-                        $input_class = 'EE_Email_Input';
164
-                        break;
165
-                    case 'EE_Enum_Integer_Field':
166
-                        throw new EE_Error(sprintf(__(
167
-                            "Model field '%s' does not yet have a known conversion to form input",
168
-                            "event_espresso"
169
-                        ), get_class($model_field)));
170
-                        break;
171
-                    case 'EE_Enum_Text_Field':
172
-                        throw new EE_Error(sprintf(__(
173
-                            "Model field '%s' does not yet have a known conversion to form input",
174
-                            "event_espresso"
175
-                        ), get_class($model_field)));
176
-                        break;
177
-                    case 'EE_Float_Field':
178
-                        $input_class = 'EE_Float_Input';
179
-                        break;
180
-                    case 'EE_Foreign_Key_Int_Field':
181
-                    case 'EE_Foreign_Key_String_Field':
182
-                    case 'EE_WP_User_Field':
183
-                        $models_pointed_to = $model_field instanceof EE_Field_With_Model_Name
184
-                            ? $model_field->get_model_class_names_pointed_to() : array();
185
-                        if (true || is_array($models_pointed_to) && count($models_pointed_to) > 1) {
186
-                            $input_class = 'EE_Text_Input';
187
-                        } else {
188
-                            // so its just one model
189
-                            $model_name = is_array($models_pointed_to) ? reset($models_pointed_to) : $models_pointed_to;
190
-                            $model = EE_Registry::instance()->load_model($model_name);
191
-                            $model_names = $model->get_all_names(array('limit' => 10));
192
-                            if ($model_field->is_nullable()) {
193
-                                array_unshift($model_names, __("Please Select", 'event_espresso'));
194
-                            }
195
-                            $input_constructor_args[1] = $input_constructor_args[0];
196
-                            $input_constructor_args[0] = $model_names;
197
-                            $input_class = 'EE_Select_Input';
198
-                        }
199
-                        break;
200
-                    case 'EE_Full_HTML_Field':
201
-                        $input_class = 'EE_Text_Area_Input';
202
-                        $input_constructor_args[0]['validation_strategies'] = array(new EE_Full_HTML_Validation_Strategy());
203
-                        break;
204
-                    case 'EE_Infinite_Integer':
205
-                        throw new EE_Error(sprintf(__(
206
-                            "Model field '%s' does not yet have a known conversion to form input",
207
-                            "event_espresso"
208
-                        ), get_class($model_field)));
209
-                        break;
210
-                    case 'EE_Integer_Field':
211
-                        $input_class = 'EE_Text_Input';
212
-                        break;
213
-                    case 'EE_Maybe_Serialized_Text_Field':
214
-                        $input_class = 'EE_Text_Area_Input';
215
-                        break;
216
-                    case 'EE_Money_Field':
217
-                        throw new EE_Error(sprintf(__(
218
-                            "Model field '%s' does not yet have a known conversion to form input",
219
-                            "event_espresso"
220
-                        ), get_class($model_field)));
221
-                        break;
222
-                    case 'EE_Post_Content_Field':
223
-                        $input_class = 'EE_Text_Area_Input';
224
-                        $input_constructor_args[0]['validation_strategies'] = array(new EE_Full_HTML_Validation_Strategy());
225
-                        break;
226
-                    case 'EE_Plain_Text_Field':
227
-                        $input_class = 'EE_Text_Input';
228
-                        break;
229
-                    case 'EE_Primary_Key_Int_Field':
230
-                        $input_class = 'EE_Hidden_Input';
231
-                        $input_constructor_args[0]['normalization_strategy'] = new EE_Int_Normalization();
232
-                        break;
233
-                    case 'EE_Primary_Key_String_Field':
234
-                        $input_class = 'EE_Hidden_Input';
235
-                        break;
236
-                    case 'EE_Serialized_Text_Field':
237
-                        $input_class = 'EE_Text_Area_Input';
238
-                        break;
239
-                    case 'EE_Simple_HTML_Field':
240
-                        $input_class = 'EE_Text_Area_Input';
241
-                        $input_constructor_args[0]['validation_strategies'] = array(new EE_Simple_HTML_Validation_Strategy());
242
-                        break;
243
-                    case 'EE_Slug_Field':
244
-                        $input_class = 'EE_Text_Input';
245
-                        break;
246
-                    case 'EE_Trashed_Flag_Field':
247
-                        $input_class = 'EE_Yes_No_Input';
248
-                        break;
249
-                    case 'EE_WP_Post_Status_Field':
250
-                        throw new EE_Error(sprintf(__(
251
-                            "Model field '%s' does not yet have a known conversion to form input",
252
-                            "event_espresso"
253
-                        ), get_class($model_field)));
254
-                        break;
255
-                    case 'EE_WP_Post_Type_Field':
256
-                        throw new EE_Error(sprintf(__(
257
-                            "Model field '%s' does not yet have a known conversion to form input",
258
-                            "event_espresso"
259
-                        ), get_class($model_field)));
260
-                        break;
261
-                    default:
262
-                        throw new EE_Error(sprintf(__(
263
-                            "Model field of type '%s' does not convert to any known Form Input. Please add a case to EE_Model_Form_section's _convert_model_fields_to_inputs switch statement",
264
-                            "event_espresso"
265
-                        ), get_class($model_field)));
266
-                }
267
-                $reflection = new ReflectionClass($input_class);
268
-                $input = $reflection->newInstanceArgs($input_constructor_args);
269
-                $inputs[ $field_name ] = $input;
270
-            }
271
-        }
272
-        return $inputs;
273
-    }
274
-
275
-
276
-
277
-    /**
278
-     * Mostly the same as populate_defaults , except takes a model object as input, not an array,
279
-     * and also sets the form's _model_object
280
-     *
281
-     * @param EE_Base_Class $model_obj
282
-     * @return void
283
-     */
284
-    public function populate_model_obj($model_obj)
285
-    {
286
-        $model_obj = $this->_model->ensure_is_obj($model_obj);
287
-        $this->_model_object = $model_obj;
288
-        $defaults = $model_obj->model_field_array();
289
-        foreach ($this->_model->relation_settings() as $relation_name => $relation_obj) {
290
-            $subsection = $this->get_subsection($relation_name, false);
291
-            if ($subsection instanceof EE_Form_Input_Base) {
292
-                if ($relation_obj instanceof EE_Belongs_To_Relation) {
293
-                    // then we only expect there to be one
294
-                    $related_item = $this->_model_object->get_first_related($relation_name);
295
-                    $defaults[ $relation_name ] = $related_item->ID();
296
-                } else {
297
-                    $related_items = $this->_model_object->get_many_related($relation_name);
298
-                    $ids = array();
299
-                    foreach ($related_items as $related_item) {
300
-                        $ids[] = $related_item->ID();
301
-                    }
302
-                    $defaults[ $relation_name ] = $ids;
303
-                }
304
-            }
305
-        }
306
-        $defaults = apply_filters(
307
-            'FHEE__EE_Model_Form_Section__populate_model_obj',
308
-            $defaults,
309
-            $this
310
-        );
311
-        $this->populate_defaults($defaults);
312
-    }
313
-
314
-
315
-
316
-    /**
317
-     * Gets all the input values that correspond to model fields. Keys are the input/field names,
318
-     * values are their normalized values
319
-     *
320
-     * @return array
321
-     */
322
-    public function inputs_values_corresponding_to_model_fields()
323
-    {
324
-        return array_intersect_key($this->input_values(), $this->_model->field_settings());
325
-    }
326
-
327
-
328
-
329
-    /**
330
-     * After we've normalized the data as normal, set the corresponding model object
331
-     * on the form.
332
-     *
333
-     * @param array $req_data should usually be the form post/request data (the default).
334
-     * @return void
335
-     */
336
-    public function _normalize($req_data)
337
-    {
338
-        parent::_normalize($req_data);
339
-        // create or set the model object, if it isn't already
340
-        if (! $this->_model_object) {
341
-            // check to see if the form indicates a PK, in which case we want to only retrieve it and update it
342
-            $pk_name = $this->_model->primary_key_name();
343
-            $model_obj = $this->_model->get_one_by_ID($this->get_input_value($pk_name));
344
-            if ($model_obj) {
345
-                $this->_model_object = $model_obj;
346
-            } else {
347
-                $this->_model_object = EE_Registry::instance()->load_class($this->_model->get_this_model_name());
348
-            }
349
-        }
350
-    }
351
-
352
-
353
-
354
-    /**
355
-     * After this form has been initialized and is verified to be valid,
356
-     * either creates a model object from its data and saves it, or updates
357
-     * the model object its data represents
358
-     *
359
-     * @throws EE_Error
360
-     * @return int, 1 on a successful update, the ID of
361
-     *                    the new entry on insert; 0 on failure
362
-     */
363
-    public function save()
364
-    {
365
-        if (! $this->_model_object) {
366
-            throw new EE_Error(sprintf(__(
367
-                "Cannot save the model form's model object (model is '%s') because there is no model object set. You must either set it, or call receive_form_submission where it is set automatically",
368
-                "event_espresso"
369
-            ), get_class($this->_model)));
370
-        }
371
-        // ok so the model object is set. Just set it with the submitted form data
372
-        foreach ($this->inputs_values_corresponding_to_model_fields() as $field_name => $field_value) {
373
-            // only set the non-primary key
374
-            if ($field_name != $this->_model->primary_key_name()) {
375
-                $this->_model_object->set($field_name, $field_value);
376
-            }
377
-        }
378
-        $success = $this->_model_object->save();
379
-        foreach ($this->_model->relation_settings() as $relation_name => $relation_obj) {
380
-            if (isset($this->_subsections[ $relation_name ])) {
381
-                $success = $this->_save_related_info($relation_name);
382
-            }
383
-        }
384
-        do_action('AHEE__EE_Model_Form_Section__save__done', $this, $success);
385
-        return $success;
386
-    }
387
-
388
-
389
-
390
-    /**
391
-     * Automatically finds the related model info from the form, if present, and
392
-     * save the relations indicated
393
-     *
394
-     * @type string $relation_name
395
-     * @return bool
396
-     * @throws EE_Error
397
-     */
398
-    protected function _save_related_info($relation_name)
399
-    {
400
-        $relation_obj = $this->_model->related_settings_for($relation_name);
401
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
402
-            // there is just a foreign key on this model pointing to that one
403
-            $this->_model_object->_add_relation_to($this->get_input_value($relation_name), $relation_name);
404
-        } elseif ($relation_obj instanceof EE_Has_Many_Relation) {
405
-            // then we want to consider all of its currently-related things.
406
-            // if they're in this list, keep them
407
-            // if they're not in this list, remove them
408
-            // and lastly add all the new items
409
-            throw new EE_Error(sprintf(__(
410
-                'Automatic saving of related info across a "has many" relation is not yet supported',
411
-                "event_espresso"
412
-            )));
413
-        } elseif ($relation_obj instanceof EE_HABTM_Relation) {
414
-            // delete everything NOT in this list
415
-            $normalized_input_value = $this->get_input_value($relation_name);
416
-            if ($normalized_input_value && is_array($normalized_input_value)) {
417
-                $where_query_params = array(
418
-                    $relation_obj->get_other_model()->primary_key_name() => array('NOT_IN', $normalized_input_value),
419
-                );
420
-            } else {
421
-                $where_query_params = array();
422
-            }
423
-            $this->_model_object->_remove_relations($relation_name, $where_query_params);
424
-            foreach ($normalized_input_value as $id) {
425
-                $this->_model_object->_add_relation_to($id, $relation_name);
426
-            }
427
-        }
428
-        return true;
429
-    }
430
-
431
-
432
-
433
-    /**
434
-     * Gets the model of this model form
435
-     *
436
-     * @return EEM_Base
437
-     */
438
-    public function get_model()
439
-    {
440
-        return $this->_model;
441
-    }
442
-
443
-
444
-
445
-    /**
446
-     * Gets the model object for this model form, which was either set
447
-     * upon construction (using the $options_array arg 'model_object'), by using
448
-     * set_model_object($model_obj), or implicitly
449
-     * when receive_form_submission($req_data) was called.
450
-     *
451
-     * @return EE_Base_Class
452
-     */
453
-    public function get_model_object()
454
-    {
455
-        return $this->_model_object;
456
-    }
457
-
458
-
459
-
460
-    /**
461
-     * gets teh default name of this form section if none is specified
462
-     *
463
-     * @return string
464
-     */
465
-    protected function _set_default_name_if_empty()
466
-    {
467
-        if (! $this->_name) {
468
-            $default_name = str_replace("EEM_", "", get_class($this->_model)) . "_Model_Form";
469
-            $this->_name = $default_name;
470
-        }
471
-    }
17
+	/**
18
+	 * @var EEM_Base
19
+	 */
20
+	protected $_model = null;
21
+
22
+	/**
23
+	 * @var EE_Base_Class
24
+	 */
25
+	protected $_model_object = null;
26
+
27
+
28
+
29
+	/**
30
+	 * @param array        $options_array   keys: {
31
+	 * @type EEM_Base      $model
32
+	 * @type EE_Base_Class $model_object
33
+	 * @type array         $subsection_args array keys should be subsection names (that either do or will exist), and
34
+	 *       values are the arrays as you would pass them to that subsection
35
+	 *                                      }
36
+	 * @throws EE_Error
37
+	 */
38
+	public function __construct($options_array = array())
39
+	{
40
+		if (isset($options_array['model']) && $options_array['model'] instanceof EEM_Base) {
41
+			$this->_model = $options_array['model'];
42
+		}
43
+		if (! $this->_model || ! $this->_model instanceof EEM_Base) {
44
+			throw new EE_Error(sprintf(__(
45
+				"Model Form Sections must first specify the _model property to be a subclass of EEM_Base",
46
+				"event_espresso"
47
+			)));
48
+		}
49
+		if (isset($options_array['subsection_args'])) {
50
+			$subsection_args = $options_array['subsection_args'];
51
+		} else {
52
+			$subsection_args = array();
53
+		}
54
+		// gather fields and relations to convert to inputs
55
+		// but if they're just going to exclude a field anyways, don't bother converting it to an input
56
+		$exclude = $this->_subsections;
57
+		if (isset($options_array['exclude'])) {
58
+			$exclude = array_merge($exclude, array_flip($options_array['exclude']));
59
+		}
60
+		$model_fields = array_diff_key($this->_model->field_settings(), $exclude);
61
+		$model_relations = array_diff_key($this->_model->relation_settings(), $exclude);
62
+		// convert fields and relations to inputs
63
+		$this->_subsections = array_merge(
64
+			$this->_convert_model_fields_to_inputs($model_fields),
65
+			$this->_convert_model_relations_to_inputs($model_relations, $subsection_args),
66
+			$this->_subsections
67
+		);
68
+		parent::__construct($options_array);
69
+		if (isset($options_array['model_object']) && $options_array['model_object'] instanceof EE_Base_Class) {
70
+			$this->populate_model_obj($options_array['model_object']);
71
+		}
72
+	}
73
+
74
+
75
+
76
+	/**
77
+	 * For now, just makes inputs for only HABTM relations
78
+	 *
79
+	 * @param EE_Model_Relation_Base[] $relations
80
+	 * @param array                    $subsection_args keys should be existing or soon-to-be-existing input names, and
81
+	 *                                                  their values are {
82
+	 * @type array {
83
+	 * @type EE_Base_Class[]           $model_objects   if the subsection is an EE_Select_Multi_Model_Input
84
+	 *                                                  }
85
+	 *                                                  }
86
+	 * @return array
87
+	 */
88
+	protected function _convert_model_relations_to_inputs($relations, $subsection_args = array())
89
+	{
90
+		$inputs = array();
91
+		foreach ($relations as $relation_name => $relation_obj) {
92
+			$input_constructor_args = array(
93
+				array_merge(
94
+					array(
95
+						'required'        => $relation_obj instanceof EE_Belongs_To_Relation,
96
+						'html_label_text' => $relation_obj instanceof EE_Belongs_To_Relation
97
+							? $relation_obj->get_other_model()->item_name(1)
98
+							: $relation_obj->get_other_model()
99
+										   ->item_name(2),
100
+					),
101
+					$subsection_args
102
+				),
103
+			);
104
+			$input = null;
105
+			switch (get_class($relation_obj)) {
106
+				case 'EE_HABTM_Relation':
107
+					if (isset($subsection_args[ $relation_name ])
108
+						&& isset($subsection_args[ $relation_name ]['model_objects'])
109
+					) {
110
+						$model_objects = $subsection_args[ $relation_name ]['model_objects'];
111
+					} else {
112
+						$model_objects = $relation_obj->get_other_model()->get_all();
113
+					}
114
+					$input = new EE_Select_Multi_Model_Input($model_objects, $input_constructor_args);
115
+					break;
116
+				default:
117
+			}
118
+			if ($input) {
119
+				$inputs[ $relation_name ] = $input;
120
+			}
121
+		}
122
+		return $inputs;
123
+	}
124
+
125
+
126
+
127
+	/**
128
+	 * Changes model fields into form section inputs
129
+	 *
130
+	 * @param EE_Model_Field_Base[] $model_fields keys are the model's name
131
+	 * @throws EE_Error
132
+	 * @return EE_Form_Input_Base[]
133
+	 */
134
+	protected function _convert_model_fields_to_inputs($model_fields = array())
135
+	{
136
+		$inputs = array();
137
+		foreach ($model_fields as $field_name => $model_field) {
138
+			if ($model_field instanceof EE_Model_Field_Base) {
139
+				$input_constructor_args = array(
140
+					array(
141
+						'required'        => ! $model_field->is_nullable()
142
+											 && $model_field->get_default_value()
143
+												=== null,
144
+						'html_label_text' => $model_field->get_nicename(),
145
+						'default'         => $model_field->get_default_value(),
146
+					),
147
+				);
148
+				switch (get_class($model_field)) {
149
+					case 'EE_All_Caps_Text_Field':
150
+					case 'EE_Any_Foreign_Model_Name_Field':
151
+						$input_class = 'EE_Text_Input';
152
+						break;
153
+					case 'EE_Boolean_Field':
154
+						$input_class = 'EE_Yes_No_Input';
155
+						break;
156
+					case 'EE_Datetime_Field':
157
+						throw new EE_Error(sprintf(__(
158
+							"Model field '%s' does not yet have a known conversion to form input",
159
+							"event_espresso"
160
+						), get_class($model_field)));
161
+						break;
162
+					case 'EE_Email_Field':
163
+						$input_class = 'EE_Email_Input';
164
+						break;
165
+					case 'EE_Enum_Integer_Field':
166
+						throw new EE_Error(sprintf(__(
167
+							"Model field '%s' does not yet have a known conversion to form input",
168
+							"event_espresso"
169
+						), get_class($model_field)));
170
+						break;
171
+					case 'EE_Enum_Text_Field':
172
+						throw new EE_Error(sprintf(__(
173
+							"Model field '%s' does not yet have a known conversion to form input",
174
+							"event_espresso"
175
+						), get_class($model_field)));
176
+						break;
177
+					case 'EE_Float_Field':
178
+						$input_class = 'EE_Float_Input';
179
+						break;
180
+					case 'EE_Foreign_Key_Int_Field':
181
+					case 'EE_Foreign_Key_String_Field':
182
+					case 'EE_WP_User_Field':
183
+						$models_pointed_to = $model_field instanceof EE_Field_With_Model_Name
184
+							? $model_field->get_model_class_names_pointed_to() : array();
185
+						if (true || is_array($models_pointed_to) && count($models_pointed_to) > 1) {
186
+							$input_class = 'EE_Text_Input';
187
+						} else {
188
+							// so its just one model
189
+							$model_name = is_array($models_pointed_to) ? reset($models_pointed_to) : $models_pointed_to;
190
+							$model = EE_Registry::instance()->load_model($model_name);
191
+							$model_names = $model->get_all_names(array('limit' => 10));
192
+							if ($model_field->is_nullable()) {
193
+								array_unshift($model_names, __("Please Select", 'event_espresso'));
194
+							}
195
+							$input_constructor_args[1] = $input_constructor_args[0];
196
+							$input_constructor_args[0] = $model_names;
197
+							$input_class = 'EE_Select_Input';
198
+						}
199
+						break;
200
+					case 'EE_Full_HTML_Field':
201
+						$input_class = 'EE_Text_Area_Input';
202
+						$input_constructor_args[0]['validation_strategies'] = array(new EE_Full_HTML_Validation_Strategy());
203
+						break;
204
+					case 'EE_Infinite_Integer':
205
+						throw new EE_Error(sprintf(__(
206
+							"Model field '%s' does not yet have a known conversion to form input",
207
+							"event_espresso"
208
+						), get_class($model_field)));
209
+						break;
210
+					case 'EE_Integer_Field':
211
+						$input_class = 'EE_Text_Input';
212
+						break;
213
+					case 'EE_Maybe_Serialized_Text_Field':
214
+						$input_class = 'EE_Text_Area_Input';
215
+						break;
216
+					case 'EE_Money_Field':
217
+						throw new EE_Error(sprintf(__(
218
+							"Model field '%s' does not yet have a known conversion to form input",
219
+							"event_espresso"
220
+						), get_class($model_field)));
221
+						break;
222
+					case 'EE_Post_Content_Field':
223
+						$input_class = 'EE_Text_Area_Input';
224
+						$input_constructor_args[0]['validation_strategies'] = array(new EE_Full_HTML_Validation_Strategy());
225
+						break;
226
+					case 'EE_Plain_Text_Field':
227
+						$input_class = 'EE_Text_Input';
228
+						break;
229
+					case 'EE_Primary_Key_Int_Field':
230
+						$input_class = 'EE_Hidden_Input';
231
+						$input_constructor_args[0]['normalization_strategy'] = new EE_Int_Normalization();
232
+						break;
233
+					case 'EE_Primary_Key_String_Field':
234
+						$input_class = 'EE_Hidden_Input';
235
+						break;
236
+					case 'EE_Serialized_Text_Field':
237
+						$input_class = 'EE_Text_Area_Input';
238
+						break;
239
+					case 'EE_Simple_HTML_Field':
240
+						$input_class = 'EE_Text_Area_Input';
241
+						$input_constructor_args[0]['validation_strategies'] = array(new EE_Simple_HTML_Validation_Strategy());
242
+						break;
243
+					case 'EE_Slug_Field':
244
+						$input_class = 'EE_Text_Input';
245
+						break;
246
+					case 'EE_Trashed_Flag_Field':
247
+						$input_class = 'EE_Yes_No_Input';
248
+						break;
249
+					case 'EE_WP_Post_Status_Field':
250
+						throw new EE_Error(sprintf(__(
251
+							"Model field '%s' does not yet have a known conversion to form input",
252
+							"event_espresso"
253
+						), get_class($model_field)));
254
+						break;
255
+					case 'EE_WP_Post_Type_Field':
256
+						throw new EE_Error(sprintf(__(
257
+							"Model field '%s' does not yet have a known conversion to form input",
258
+							"event_espresso"
259
+						), get_class($model_field)));
260
+						break;
261
+					default:
262
+						throw new EE_Error(sprintf(__(
263
+							"Model field of type '%s' does not convert to any known Form Input. Please add a case to EE_Model_Form_section's _convert_model_fields_to_inputs switch statement",
264
+							"event_espresso"
265
+						), get_class($model_field)));
266
+				}
267
+				$reflection = new ReflectionClass($input_class);
268
+				$input = $reflection->newInstanceArgs($input_constructor_args);
269
+				$inputs[ $field_name ] = $input;
270
+			}
271
+		}
272
+		return $inputs;
273
+	}
274
+
275
+
276
+
277
+	/**
278
+	 * Mostly the same as populate_defaults , except takes a model object as input, not an array,
279
+	 * and also sets the form's _model_object
280
+	 *
281
+	 * @param EE_Base_Class $model_obj
282
+	 * @return void
283
+	 */
284
+	public function populate_model_obj($model_obj)
285
+	{
286
+		$model_obj = $this->_model->ensure_is_obj($model_obj);
287
+		$this->_model_object = $model_obj;
288
+		$defaults = $model_obj->model_field_array();
289
+		foreach ($this->_model->relation_settings() as $relation_name => $relation_obj) {
290
+			$subsection = $this->get_subsection($relation_name, false);
291
+			if ($subsection instanceof EE_Form_Input_Base) {
292
+				if ($relation_obj instanceof EE_Belongs_To_Relation) {
293
+					// then we only expect there to be one
294
+					$related_item = $this->_model_object->get_first_related($relation_name);
295
+					$defaults[ $relation_name ] = $related_item->ID();
296
+				} else {
297
+					$related_items = $this->_model_object->get_many_related($relation_name);
298
+					$ids = array();
299
+					foreach ($related_items as $related_item) {
300
+						$ids[] = $related_item->ID();
301
+					}
302
+					$defaults[ $relation_name ] = $ids;
303
+				}
304
+			}
305
+		}
306
+		$defaults = apply_filters(
307
+			'FHEE__EE_Model_Form_Section__populate_model_obj',
308
+			$defaults,
309
+			$this
310
+		);
311
+		$this->populate_defaults($defaults);
312
+	}
313
+
314
+
315
+
316
+	/**
317
+	 * Gets all the input values that correspond to model fields. Keys are the input/field names,
318
+	 * values are their normalized values
319
+	 *
320
+	 * @return array
321
+	 */
322
+	public function inputs_values_corresponding_to_model_fields()
323
+	{
324
+		return array_intersect_key($this->input_values(), $this->_model->field_settings());
325
+	}
326
+
327
+
328
+
329
+	/**
330
+	 * After we've normalized the data as normal, set the corresponding model object
331
+	 * on the form.
332
+	 *
333
+	 * @param array $req_data should usually be the form post/request data (the default).
334
+	 * @return void
335
+	 */
336
+	public function _normalize($req_data)
337
+	{
338
+		parent::_normalize($req_data);
339
+		// create or set the model object, if it isn't already
340
+		if (! $this->_model_object) {
341
+			// check to see if the form indicates a PK, in which case we want to only retrieve it and update it
342
+			$pk_name = $this->_model->primary_key_name();
343
+			$model_obj = $this->_model->get_one_by_ID($this->get_input_value($pk_name));
344
+			if ($model_obj) {
345
+				$this->_model_object = $model_obj;
346
+			} else {
347
+				$this->_model_object = EE_Registry::instance()->load_class($this->_model->get_this_model_name());
348
+			}
349
+		}
350
+	}
351
+
352
+
353
+
354
+	/**
355
+	 * After this form has been initialized and is verified to be valid,
356
+	 * either creates a model object from its data and saves it, or updates
357
+	 * the model object its data represents
358
+	 *
359
+	 * @throws EE_Error
360
+	 * @return int, 1 on a successful update, the ID of
361
+	 *                    the new entry on insert; 0 on failure
362
+	 */
363
+	public function save()
364
+	{
365
+		if (! $this->_model_object) {
366
+			throw new EE_Error(sprintf(__(
367
+				"Cannot save the model form's model object (model is '%s') because there is no model object set. You must either set it, or call receive_form_submission where it is set automatically",
368
+				"event_espresso"
369
+			), get_class($this->_model)));
370
+		}
371
+		// ok so the model object is set. Just set it with the submitted form data
372
+		foreach ($this->inputs_values_corresponding_to_model_fields() as $field_name => $field_value) {
373
+			// only set the non-primary key
374
+			if ($field_name != $this->_model->primary_key_name()) {
375
+				$this->_model_object->set($field_name, $field_value);
376
+			}
377
+		}
378
+		$success = $this->_model_object->save();
379
+		foreach ($this->_model->relation_settings() as $relation_name => $relation_obj) {
380
+			if (isset($this->_subsections[ $relation_name ])) {
381
+				$success = $this->_save_related_info($relation_name);
382
+			}
383
+		}
384
+		do_action('AHEE__EE_Model_Form_Section__save__done', $this, $success);
385
+		return $success;
386
+	}
387
+
388
+
389
+
390
+	/**
391
+	 * Automatically finds the related model info from the form, if present, and
392
+	 * save the relations indicated
393
+	 *
394
+	 * @type string $relation_name
395
+	 * @return bool
396
+	 * @throws EE_Error
397
+	 */
398
+	protected function _save_related_info($relation_name)
399
+	{
400
+		$relation_obj = $this->_model->related_settings_for($relation_name);
401
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
402
+			// there is just a foreign key on this model pointing to that one
403
+			$this->_model_object->_add_relation_to($this->get_input_value($relation_name), $relation_name);
404
+		} elseif ($relation_obj instanceof EE_Has_Many_Relation) {
405
+			// then we want to consider all of its currently-related things.
406
+			// if they're in this list, keep them
407
+			// if they're not in this list, remove them
408
+			// and lastly add all the new items
409
+			throw new EE_Error(sprintf(__(
410
+				'Automatic saving of related info across a "has many" relation is not yet supported',
411
+				"event_espresso"
412
+			)));
413
+		} elseif ($relation_obj instanceof EE_HABTM_Relation) {
414
+			// delete everything NOT in this list
415
+			$normalized_input_value = $this->get_input_value($relation_name);
416
+			if ($normalized_input_value && is_array($normalized_input_value)) {
417
+				$where_query_params = array(
418
+					$relation_obj->get_other_model()->primary_key_name() => array('NOT_IN', $normalized_input_value),
419
+				);
420
+			} else {
421
+				$where_query_params = array();
422
+			}
423
+			$this->_model_object->_remove_relations($relation_name, $where_query_params);
424
+			foreach ($normalized_input_value as $id) {
425
+				$this->_model_object->_add_relation_to($id, $relation_name);
426
+			}
427
+		}
428
+		return true;
429
+	}
430
+
431
+
432
+
433
+	/**
434
+	 * Gets the model of this model form
435
+	 *
436
+	 * @return EEM_Base
437
+	 */
438
+	public function get_model()
439
+	{
440
+		return $this->_model;
441
+	}
442
+
443
+
444
+
445
+	/**
446
+	 * Gets the model object for this model form, which was either set
447
+	 * upon construction (using the $options_array arg 'model_object'), by using
448
+	 * set_model_object($model_obj), or implicitly
449
+	 * when receive_form_submission($req_data) was called.
450
+	 *
451
+	 * @return EE_Base_Class
452
+	 */
453
+	public function get_model_object()
454
+	{
455
+		return $this->_model_object;
456
+	}
457
+
458
+
459
+
460
+	/**
461
+	 * gets teh default name of this form section if none is specified
462
+	 *
463
+	 * @return string
464
+	 */
465
+	protected function _set_default_name_if_empty()
466
+	{
467
+		if (! $this->_name) {
468
+			$default_name = str_replace("EEM_", "", get_class($this->_model)) . "_Model_Form";
469
+			$this->_name = $default_name;
470
+		}
471
+	}
472 472
 }
Please login to merge, or discard this patch.
core/libraries/form_sections/base/EE_Form_Section_Validatable.form.php 1 patch
Indentation   +146 added lines, -146 removed lines patch added patch discarded remove patch
@@ -21,150 +21,150 @@
 block discarded – undo
21 21
 abstract class EE_Form_Section_Validatable extends EE_Form_Section_Base
22 22
 {
23 23
 
24
-    /**
25
-     * Array of validation errors in this section. Does not contain validation errors in subsections, however.
26
-     * Those are stored individually on each subsection.
27
-     *
28
-     * @var EE_Validation_Error[]
29
-     */
30
-    protected $_validation_errors = array();
31
-
32
-
33
-
34
-    /**
35
-     * Errors on this form section. Note: EE_Form_Section_Proper
36
-     * has another function for getting all errors in this form section and subsections
37
-     * called get_validation_errors_accumulated
38
-     *
39
-     * @return EE_Validation_Error[]
40
-     */
41
-    public function get_validation_errors()
42
-    {
43
-        return $this->_validation_errors;
44
-    }
45
-
46
-
47
-
48
-    /**
49
-     * returns a comma-separated list of all the validation errors in it.
50
-     * If we want this to be customizable, we may decide to create a strategy for displaying it
51
-     *
52
-     * @return string
53
-     */
54
-    public function get_validation_error_string()
55
-    {
56
-        $validation_error_messages = array();
57
-        if ($this->get_validation_errors()) {
58
-            foreach ($this->get_validation_errors() as $validation_error) {
59
-                if ($validation_error instanceof EE_Validation_Error) {
60
-                    $validation_error_messages[] = $validation_error->getMessage();
61
-                }
62
-            }
63
-        }
64
-        return implode(", ", $validation_error_messages);
65
-    }
66
-
67
-
68
-
69
-    /**
70
-     * Performs validation on this form section (and subsections). Should be called after _normalize()
71
-     *
72
-     * @return boolean of whether or not the form section is valid
73
-     */
74
-    abstract protected function _validate();
75
-
76
-
77
-
78
-    /**
79
-     * Checks if this field has any validation errors
80
-     *
81
-     * @return boolean
82
-     */
83
-    public function is_valid()
84
-    {
85
-        if (count($this->_validation_errors)) {
86
-            return false;
87
-        } else {
88
-            return true;
89
-        }
90
-    }
91
-
92
-
93
-
94
-    /**
95
-     * Sanitizes input for this form section
96
-     *
97
-     * @param array $req_data is the full request data
98
-     * @return boolean of whether a normalization error occurred
99
-     */
100
-    abstract protected function _normalize($req_data);
101
-
102
-
103
-
104
-    /**
105
-     * Creates a validation error from the arguments provided, and adds it to the form section's list.
106
-     * If such an EE_Validation_Error object is passed in as the first arg, simply sets this as its form section, and
107
-     * adds it to the list of validation errors of errors
108
-     *
109
-     * @param mixed     $message_or_object  internationalized string describing the validation error; or it could be a
110
-     *                                      proper EE_Validation_Error object
111
-     * @param string    $error_code         a short key which can be used to uniquely identify the error
112
-     * @param Exception $previous_exception if there was an exception that caused the error, that exception
113
-     * @return void
114
-     */
115
-    public function add_validation_error($message_or_object, $error_code = null, $previous_exception = null)
116
-    {
117
-        if ($message_or_object instanceof EE_Validation_Error) {
118
-            $validation_error = $message_or_object;
119
-            $validation_error->set_form_section($this);
120
-        } else {
121
-            $validation_error = new EE_Validation_Error($message_or_object, $error_code, $this, $previous_exception);
122
-        }
123
-        $this->_validation_errors[] = $validation_error;
124
-    }
125
-
126
-
127
-
128
-    /**
129
-     * When generating the JS for the jquery validation rules like<br>
130
-     * <code>$( "#myform" ).validate({
131
-     * rules: {
132
-     * password: "required",
133
-     * password_again: {
134
-     * equalTo: "#password"
135
-     * }
136
-     * }
137
-     * });</code>
138
-     * gets the sections like
139
-     * <br><code>password: "required",
140
-     * password_again: {
141
-     * equalTo: "#password"
142
-     * }</code>
143
-     * except we leave it as a PHP object, and leave wp_localize_script to
144
-     * turn it into a JSON object which can be used by the js
145
-     *
146
-     * @return array
147
-     */
148
-    abstract public function get_jquery_validation_rules();
149
-
150
-
151
-
152
-    /**
153
-     * Checks if this form section's data is present in the req data specified
154
-     *
155
-     * @param array $req_data usually post data, if null that's what's used
156
-     * @return boolean
157
-     */
158
-    abstract public function form_data_present_in($req_data = null);
159
-
160
-
161
-
162
-    /**
163
-     * Removes teh sensitive data from this form section (usually done after
164
-     * utilizing the data business function, but before saving it somewhere. Eg,
165
-     * may remove a password from the form after verifying it was correct)
166
-     *
167
-     * @return void
168
-     */
169
-    abstract public function clean_sensitive_data();
24
+	/**
25
+	 * Array of validation errors in this section. Does not contain validation errors in subsections, however.
26
+	 * Those are stored individually on each subsection.
27
+	 *
28
+	 * @var EE_Validation_Error[]
29
+	 */
30
+	protected $_validation_errors = array();
31
+
32
+
33
+
34
+	/**
35
+	 * Errors on this form section. Note: EE_Form_Section_Proper
36
+	 * has another function for getting all errors in this form section and subsections
37
+	 * called get_validation_errors_accumulated
38
+	 *
39
+	 * @return EE_Validation_Error[]
40
+	 */
41
+	public function get_validation_errors()
42
+	{
43
+		return $this->_validation_errors;
44
+	}
45
+
46
+
47
+
48
+	/**
49
+	 * returns a comma-separated list of all the validation errors in it.
50
+	 * If we want this to be customizable, we may decide to create a strategy for displaying it
51
+	 *
52
+	 * @return string
53
+	 */
54
+	public function get_validation_error_string()
55
+	{
56
+		$validation_error_messages = array();
57
+		if ($this->get_validation_errors()) {
58
+			foreach ($this->get_validation_errors() as $validation_error) {
59
+				if ($validation_error instanceof EE_Validation_Error) {
60
+					$validation_error_messages[] = $validation_error->getMessage();
61
+				}
62
+			}
63
+		}
64
+		return implode(", ", $validation_error_messages);
65
+	}
66
+
67
+
68
+
69
+	/**
70
+	 * Performs validation on this form section (and subsections). Should be called after _normalize()
71
+	 *
72
+	 * @return boolean of whether or not the form section is valid
73
+	 */
74
+	abstract protected function _validate();
75
+
76
+
77
+
78
+	/**
79
+	 * Checks if this field has any validation errors
80
+	 *
81
+	 * @return boolean
82
+	 */
83
+	public function is_valid()
84
+	{
85
+		if (count($this->_validation_errors)) {
86
+			return false;
87
+		} else {
88
+			return true;
89
+		}
90
+	}
91
+
92
+
93
+
94
+	/**
95
+	 * Sanitizes input for this form section
96
+	 *
97
+	 * @param array $req_data is the full request data
98
+	 * @return boolean of whether a normalization error occurred
99
+	 */
100
+	abstract protected function _normalize($req_data);
101
+
102
+
103
+
104
+	/**
105
+	 * Creates a validation error from the arguments provided, and adds it to the form section's list.
106
+	 * If such an EE_Validation_Error object is passed in as the first arg, simply sets this as its form section, and
107
+	 * adds it to the list of validation errors of errors
108
+	 *
109
+	 * @param mixed     $message_or_object  internationalized string describing the validation error; or it could be a
110
+	 *                                      proper EE_Validation_Error object
111
+	 * @param string    $error_code         a short key which can be used to uniquely identify the error
112
+	 * @param Exception $previous_exception if there was an exception that caused the error, that exception
113
+	 * @return void
114
+	 */
115
+	public function add_validation_error($message_or_object, $error_code = null, $previous_exception = null)
116
+	{
117
+		if ($message_or_object instanceof EE_Validation_Error) {
118
+			$validation_error = $message_or_object;
119
+			$validation_error->set_form_section($this);
120
+		} else {
121
+			$validation_error = new EE_Validation_Error($message_or_object, $error_code, $this, $previous_exception);
122
+		}
123
+		$this->_validation_errors[] = $validation_error;
124
+	}
125
+
126
+
127
+
128
+	/**
129
+	 * When generating the JS for the jquery validation rules like<br>
130
+	 * <code>$( "#myform" ).validate({
131
+	 * rules: {
132
+	 * password: "required",
133
+	 * password_again: {
134
+	 * equalTo: "#password"
135
+	 * }
136
+	 * }
137
+	 * });</code>
138
+	 * gets the sections like
139
+	 * <br><code>password: "required",
140
+	 * password_again: {
141
+	 * equalTo: "#password"
142
+	 * }</code>
143
+	 * except we leave it as a PHP object, and leave wp_localize_script to
144
+	 * turn it into a JSON object which can be used by the js
145
+	 *
146
+	 * @return array
147
+	 */
148
+	abstract public function get_jquery_validation_rules();
149
+
150
+
151
+
152
+	/**
153
+	 * Checks if this form section's data is present in the req data specified
154
+	 *
155
+	 * @param array $req_data usually post data, if null that's what's used
156
+	 * @return boolean
157
+	 */
158
+	abstract public function form_data_present_in($req_data = null);
159
+
160
+
161
+
162
+	/**
163
+	 * Removes teh sensitive data from this form section (usually done after
164
+	 * utilizing the data business function, but before saving it somewhere. Eg,
165
+	 * may remove a password from the form after verifying it was correct)
166
+	 *
167
+	 * @return void
168
+	 */
169
+	abstract public function clean_sensitive_data();
170 170
 }
Please login to merge, or discard this patch.
core/request_stack/EE_Request.core.php 1 patch
Indentation   +355 added lines, -355 removed lines patch added patch discarded remove patch
@@ -18,359 +18,359 @@
 block discarded – undo
18 18
 class EE_Request implements LegacyRequestInterface, InterminableInterface
19 19
 {
20 20
 
21
-    /**
22
-     * @var RequestInterface $request
23
-     */
24
-    private $request;
25
-
26
-    /**
27
-     * whether current request is for the admin but NOT via AJAX
28
-     *
29
-     * @var boolean $admin
30
-     */
31
-    public $admin = false;
32
-
33
-    /**
34
-     * whether current request is via AJAX
35
-     *
36
-     * @var boolean $ajax
37
-     */
38
-    public $ajax = false;
39
-
40
-    /**
41
-     * whether current request is via AJAX from the frontend of the site
42
-     *
43
-     * @var boolean $front_ajax
44
-     */
45
-    public $front_ajax = false;
46
-
47
-
48
-    /**
49
-     * @deprecated 4.9.53
50
-     * @param array $get
51
-     * @param array $post
52
-     * @param array $cookie
53
-     * @param array $server
54
-     */
55
-    public function __construct(
56
-        array $get = array(),
57
-        array $post = array(),
58
-        array $cookie = array(),
59
-        array $server = array()
60
-    ) {
61
-    }
62
-
63
-
64
-    /**
65
-     * @return RequestInterface
66
-     * @throws InvalidArgumentException
67
-     * @throws InvalidInterfaceException
68
-     * @throws InvalidDataTypeException
69
-     */
70
-    private function request()
71
-    {
72
-        if ($this->request instanceof RequestInterface) {
73
-            return $this->request;
74
-        }
75
-        $loader = LoaderFactory::getLoader();
76
-        $this->request = $loader->getShared('EventEspresso\core\services\request\RequestInterface');
77
-        return $this->request;
78
-    }
79
-
80
-
81
-    /**
82
-     * @param RequestInterface $request
83
-     */
84
-    public function setRequest(RequestInterface $request)
85
-    {
86
-        $this->request = $request;
87
-    }
88
-
89
-
90
-    /**
91
-     * @deprecated 4.9.53
92
-     * @return array
93
-     * @throws InvalidArgumentException
94
-     * @throws InvalidDataTypeException
95
-     * @throws InvalidInterfaceException
96
-     */
97
-    public function get_params()
98
-    {
99
-        return $this->request()->getParams();
100
-    }
101
-
102
-
103
-    /**
104
-     * @deprecated 4.9.53
105
-     * @return array
106
-     * @throws InvalidArgumentException
107
-     * @throws InvalidDataTypeException
108
-     * @throws InvalidInterfaceException
109
-     */
110
-    public function post_params()
111
-    {
112
-        return $this->request()->postParams();
113
-    }
114
-
115
-
116
-    /**
117
-     * @deprecated 4.9.53
118
-     * @return array
119
-     * @throws InvalidArgumentException
120
-     * @throws InvalidDataTypeException
121
-     * @throws InvalidInterfaceException
122
-     */
123
-    public function cookie_params()
124
-    {
125
-        return $this->request()->cookieParams();
126
-    }
127
-
128
-
129
-    /**
130
-     * @deprecated 4.9.53
131
-     * @return array
132
-     * @throws InvalidArgumentException
133
-     * @throws InvalidDataTypeException
134
-     * @throws InvalidInterfaceException
135
-     */
136
-    public function server_params()
137
-    {
138
-        return $this->request()->serverParams();
139
-    }
140
-
141
-
142
-    /**
143
-     * returns sanitized contents of $_REQUEST
144
-     *
145
-     * @deprecated 4.9.53
146
-     * @return array
147
-     * @throws InvalidArgumentException
148
-     * @throws InvalidDataTypeException
149
-     * @throws InvalidInterfaceException
150
-     */
151
-    public function params()
152
-    {
153
-        return $this->request()->requestParams();
154
-    }
155
-
156
-
157
-    /**
158
-     * @deprecated 4.9.53
159
-     * @param      $key
160
-     * @param      $value
161
-     * @param bool $override_ee
162
-     * @return void
163
-     * @throws InvalidArgumentException
164
-     * @throws InvalidDataTypeException
165
-     * @throws InvalidInterfaceException
166
-     */
167
-    public function set($key, $value, $override_ee = false)
168
-    {
169
-        $this->request()->setRequestParam($key, $value, $override_ee);
170
-    }
171
-
172
-
173
-    /**
174
-     * returns   the value for a request param if the given key exists
175
-     *
176
-     * @deprecated 4.9.53
177
-     * @param      $key
178
-     * @param null $default
179
-     * @return mixed
180
-     * @throws InvalidArgumentException
181
-     * @throws InvalidDataTypeException
182
-     * @throws InvalidInterfaceException
183
-     */
184
-    public function get($key, $default = null)
185
-    {
186
-        return $this->request()->getRequestParam($key, $default);
187
-    }
188
-
189
-
190
-    /**
191
-     * check if param exists
192
-     *
193
-     * @deprecated 4.9.53
194
-     * @param $key
195
-     * @return bool
196
-     * @throws InvalidArgumentException
197
-     * @throws InvalidDataTypeException
198
-     * @throws InvalidInterfaceException
199
-     */
200
-    public function is_set($key)
201
-    {
202
-        return $this->request()->requestParamIsSet($key);
203
-    }
204
-
205
-
206
-    /**
207
-     * remove param
208
-     *
209
-     * @deprecated 4.9.53
210
-     * @param      $key
211
-     * @param bool $unset_from_global_too
212
-     * @throws InvalidArgumentException
213
-     * @throws InvalidDataTypeException
214
-     * @throws InvalidInterfaceException
215
-     */
216
-    public function un_set($key, $unset_from_global_too = false)
217
-    {
218
-        $this->request()->unSetRequestParam($key, $unset_from_global_too);
219
-    }
220
-
221
-
222
-    /**
223
-     * @deprecated 4.9.53
224
-     * @return string
225
-     * @throws InvalidArgumentException
226
-     * @throws InvalidDataTypeException
227
-     * @throws InvalidInterfaceException
228
-     */
229
-    public function ip_address()
230
-    {
231
-        return $this->request()->ipAddress();
232
-    }
233
-
234
-
235
-    /**
236
-     * @deprecated 4.9.53
237
-     * @return bool
238
-     * @throws InvalidArgumentException
239
-     * @throws InvalidDataTypeException
240
-     * @throws InvalidInterfaceException
241
-     */
242
-    public function isAdmin()
243
-    {
244
-        return $this->request()->isAdmin();
245
-    }
246
-
247
-
248
-    /**
249
-     * @deprecated 4.9.53
250
-     * @return mixed
251
-     * @throws InvalidArgumentException
252
-     * @throws InvalidDataTypeException
253
-     * @throws InvalidInterfaceException
254
-     */
255
-    public function isAjax()
256
-    {
257
-        return $this->request()->isAjax();
258
-    }
259
-
260
-
261
-    /**
262
-     * @deprecated 4.9.53
263
-     * @return mixed
264
-     * @throws InvalidArgumentException
265
-     * @throws InvalidDataTypeException
266
-     * @throws InvalidInterfaceException
267
-     */
268
-    public function isFrontAjax()
269
-    {
270
-        return $this->request()->isFrontAjax();
271
-    }
272
-
273
-
274
-    /**
275
-     * @deprecated 4.9.53
276
-     * @return mixed|string
277
-     * @throws InvalidArgumentException
278
-     * @throws InvalidDataTypeException
279
-     * @throws InvalidInterfaceException
280
-     */
281
-    public function requestUri()
282
-    {
283
-        return $this->request()->requestUri();
284
-    }
285
-
286
-
287
-    /**
288
-     * @deprecated 4.9.53
289
-     * @return string
290
-     * @throws InvalidArgumentException
291
-     * @throws InvalidDataTypeException
292
-     * @throws InvalidInterfaceException
293
-     */
294
-    public function userAgent()
295
-    {
296
-        return $this->request()->userAgent();
297
-    }
298
-
299
-
300
-    /**
301
-     * @deprecated 4.9.53
302
-     * @param string $user_agent
303
-     * @throws InvalidArgumentException
304
-     * @throws InvalidDataTypeException
305
-     * @throws InvalidInterfaceException
306
-     */
307
-    public function setUserAgent($user_agent = '')
308
-    {
309
-        $this->request()->setUserAgent($user_agent);
310
-    }
311
-
312
-
313
-    /**
314
-     * @deprecated 4.9.53
315
-     * @return bool
316
-     * @throws InvalidArgumentException
317
-     * @throws InvalidDataTypeException
318
-     * @throws InvalidInterfaceException
319
-     */
320
-    public function isBot()
321
-    {
322
-        return $this->request()->isBot();
323
-    }
324
-
325
-
326
-    /**
327
-     * @deprecated 4.9.53
328
-     * @param bool $is_bot
329
-     * @throws InvalidArgumentException
330
-     * @throws InvalidDataTypeException
331
-     * @throws InvalidInterfaceException
332
-     */
333
-    public function setIsBot($is_bot)
334
-    {
335
-        $this->request()->setIsBot($is_bot);
336
-    }
337
-
338
-
339
-    /**
340
-     * check if a request parameter exists whose key that matches the supplied wildcard pattern
341
-     * and return the value for the first match found
342
-     * wildcards can be either of the following:
343
-     *      ? to represent a single character of any type
344
-     *      * to represent one or more characters of any type
345
-     *
346
-     * @param string     $pattern
347
-     * @param null|mixed $default
348
-     * @return false|int
349
-     * @throws InvalidArgumentException
350
-     * @throws InvalidInterfaceException
351
-     * @throws InvalidDataTypeException
352
-     */
353
-    public function getMatch($pattern, $default = null)
354
-    {
355
-        return $this->request()->getMatch($pattern, $default);
356
-    }
357
-
358
-
359
-    /**
360
-     * check if a request parameter exists whose key matches the supplied wildcard pattern
361
-     * wildcards can be either of the following:
362
-     *      ? to represent a single character of any type
363
-     *      * to represent one or more characters of any type
364
-     * returns true if a match is found or false if not
365
-     *
366
-     * @param string $pattern
367
-     * @return false|int
368
-     * @throws InvalidArgumentException
369
-     * @throws InvalidInterfaceException
370
-     * @throws InvalidDataTypeException
371
-     */
372
-    public function matches($pattern)
373
-    {
374
-        return $this->request()->matches($pattern);
375
-    }
21
+	/**
22
+	 * @var RequestInterface $request
23
+	 */
24
+	private $request;
25
+
26
+	/**
27
+	 * whether current request is for the admin but NOT via AJAX
28
+	 *
29
+	 * @var boolean $admin
30
+	 */
31
+	public $admin = false;
32
+
33
+	/**
34
+	 * whether current request is via AJAX
35
+	 *
36
+	 * @var boolean $ajax
37
+	 */
38
+	public $ajax = false;
39
+
40
+	/**
41
+	 * whether current request is via AJAX from the frontend of the site
42
+	 *
43
+	 * @var boolean $front_ajax
44
+	 */
45
+	public $front_ajax = false;
46
+
47
+
48
+	/**
49
+	 * @deprecated 4.9.53
50
+	 * @param array $get
51
+	 * @param array $post
52
+	 * @param array $cookie
53
+	 * @param array $server
54
+	 */
55
+	public function __construct(
56
+		array $get = array(),
57
+		array $post = array(),
58
+		array $cookie = array(),
59
+		array $server = array()
60
+	) {
61
+	}
62
+
63
+
64
+	/**
65
+	 * @return RequestInterface
66
+	 * @throws InvalidArgumentException
67
+	 * @throws InvalidInterfaceException
68
+	 * @throws InvalidDataTypeException
69
+	 */
70
+	private function request()
71
+	{
72
+		if ($this->request instanceof RequestInterface) {
73
+			return $this->request;
74
+		}
75
+		$loader = LoaderFactory::getLoader();
76
+		$this->request = $loader->getShared('EventEspresso\core\services\request\RequestInterface');
77
+		return $this->request;
78
+	}
79
+
80
+
81
+	/**
82
+	 * @param RequestInterface $request
83
+	 */
84
+	public function setRequest(RequestInterface $request)
85
+	{
86
+		$this->request = $request;
87
+	}
88
+
89
+
90
+	/**
91
+	 * @deprecated 4.9.53
92
+	 * @return array
93
+	 * @throws InvalidArgumentException
94
+	 * @throws InvalidDataTypeException
95
+	 * @throws InvalidInterfaceException
96
+	 */
97
+	public function get_params()
98
+	{
99
+		return $this->request()->getParams();
100
+	}
101
+
102
+
103
+	/**
104
+	 * @deprecated 4.9.53
105
+	 * @return array
106
+	 * @throws InvalidArgumentException
107
+	 * @throws InvalidDataTypeException
108
+	 * @throws InvalidInterfaceException
109
+	 */
110
+	public function post_params()
111
+	{
112
+		return $this->request()->postParams();
113
+	}
114
+
115
+
116
+	/**
117
+	 * @deprecated 4.9.53
118
+	 * @return array
119
+	 * @throws InvalidArgumentException
120
+	 * @throws InvalidDataTypeException
121
+	 * @throws InvalidInterfaceException
122
+	 */
123
+	public function cookie_params()
124
+	{
125
+		return $this->request()->cookieParams();
126
+	}
127
+
128
+
129
+	/**
130
+	 * @deprecated 4.9.53
131
+	 * @return array
132
+	 * @throws InvalidArgumentException
133
+	 * @throws InvalidDataTypeException
134
+	 * @throws InvalidInterfaceException
135
+	 */
136
+	public function server_params()
137
+	{
138
+		return $this->request()->serverParams();
139
+	}
140
+
141
+
142
+	/**
143
+	 * returns sanitized contents of $_REQUEST
144
+	 *
145
+	 * @deprecated 4.9.53
146
+	 * @return array
147
+	 * @throws InvalidArgumentException
148
+	 * @throws InvalidDataTypeException
149
+	 * @throws InvalidInterfaceException
150
+	 */
151
+	public function params()
152
+	{
153
+		return $this->request()->requestParams();
154
+	}
155
+
156
+
157
+	/**
158
+	 * @deprecated 4.9.53
159
+	 * @param      $key
160
+	 * @param      $value
161
+	 * @param bool $override_ee
162
+	 * @return void
163
+	 * @throws InvalidArgumentException
164
+	 * @throws InvalidDataTypeException
165
+	 * @throws InvalidInterfaceException
166
+	 */
167
+	public function set($key, $value, $override_ee = false)
168
+	{
169
+		$this->request()->setRequestParam($key, $value, $override_ee);
170
+	}
171
+
172
+
173
+	/**
174
+	 * returns   the value for a request param if the given key exists
175
+	 *
176
+	 * @deprecated 4.9.53
177
+	 * @param      $key
178
+	 * @param null $default
179
+	 * @return mixed
180
+	 * @throws InvalidArgumentException
181
+	 * @throws InvalidDataTypeException
182
+	 * @throws InvalidInterfaceException
183
+	 */
184
+	public function get($key, $default = null)
185
+	{
186
+		return $this->request()->getRequestParam($key, $default);
187
+	}
188
+
189
+
190
+	/**
191
+	 * check if param exists
192
+	 *
193
+	 * @deprecated 4.9.53
194
+	 * @param $key
195
+	 * @return bool
196
+	 * @throws InvalidArgumentException
197
+	 * @throws InvalidDataTypeException
198
+	 * @throws InvalidInterfaceException
199
+	 */
200
+	public function is_set($key)
201
+	{
202
+		return $this->request()->requestParamIsSet($key);
203
+	}
204
+
205
+
206
+	/**
207
+	 * remove param
208
+	 *
209
+	 * @deprecated 4.9.53
210
+	 * @param      $key
211
+	 * @param bool $unset_from_global_too
212
+	 * @throws InvalidArgumentException
213
+	 * @throws InvalidDataTypeException
214
+	 * @throws InvalidInterfaceException
215
+	 */
216
+	public function un_set($key, $unset_from_global_too = false)
217
+	{
218
+		$this->request()->unSetRequestParam($key, $unset_from_global_too);
219
+	}
220
+
221
+
222
+	/**
223
+	 * @deprecated 4.9.53
224
+	 * @return string
225
+	 * @throws InvalidArgumentException
226
+	 * @throws InvalidDataTypeException
227
+	 * @throws InvalidInterfaceException
228
+	 */
229
+	public function ip_address()
230
+	{
231
+		return $this->request()->ipAddress();
232
+	}
233
+
234
+
235
+	/**
236
+	 * @deprecated 4.9.53
237
+	 * @return bool
238
+	 * @throws InvalidArgumentException
239
+	 * @throws InvalidDataTypeException
240
+	 * @throws InvalidInterfaceException
241
+	 */
242
+	public function isAdmin()
243
+	{
244
+		return $this->request()->isAdmin();
245
+	}
246
+
247
+
248
+	/**
249
+	 * @deprecated 4.9.53
250
+	 * @return mixed
251
+	 * @throws InvalidArgumentException
252
+	 * @throws InvalidDataTypeException
253
+	 * @throws InvalidInterfaceException
254
+	 */
255
+	public function isAjax()
256
+	{
257
+		return $this->request()->isAjax();
258
+	}
259
+
260
+
261
+	/**
262
+	 * @deprecated 4.9.53
263
+	 * @return mixed
264
+	 * @throws InvalidArgumentException
265
+	 * @throws InvalidDataTypeException
266
+	 * @throws InvalidInterfaceException
267
+	 */
268
+	public function isFrontAjax()
269
+	{
270
+		return $this->request()->isFrontAjax();
271
+	}
272
+
273
+
274
+	/**
275
+	 * @deprecated 4.9.53
276
+	 * @return mixed|string
277
+	 * @throws InvalidArgumentException
278
+	 * @throws InvalidDataTypeException
279
+	 * @throws InvalidInterfaceException
280
+	 */
281
+	public function requestUri()
282
+	{
283
+		return $this->request()->requestUri();
284
+	}
285
+
286
+
287
+	/**
288
+	 * @deprecated 4.9.53
289
+	 * @return string
290
+	 * @throws InvalidArgumentException
291
+	 * @throws InvalidDataTypeException
292
+	 * @throws InvalidInterfaceException
293
+	 */
294
+	public function userAgent()
295
+	{
296
+		return $this->request()->userAgent();
297
+	}
298
+
299
+
300
+	/**
301
+	 * @deprecated 4.9.53
302
+	 * @param string $user_agent
303
+	 * @throws InvalidArgumentException
304
+	 * @throws InvalidDataTypeException
305
+	 * @throws InvalidInterfaceException
306
+	 */
307
+	public function setUserAgent($user_agent = '')
308
+	{
309
+		$this->request()->setUserAgent($user_agent);
310
+	}
311
+
312
+
313
+	/**
314
+	 * @deprecated 4.9.53
315
+	 * @return bool
316
+	 * @throws InvalidArgumentException
317
+	 * @throws InvalidDataTypeException
318
+	 * @throws InvalidInterfaceException
319
+	 */
320
+	public function isBot()
321
+	{
322
+		return $this->request()->isBot();
323
+	}
324
+
325
+
326
+	/**
327
+	 * @deprecated 4.9.53
328
+	 * @param bool $is_bot
329
+	 * @throws InvalidArgumentException
330
+	 * @throws InvalidDataTypeException
331
+	 * @throws InvalidInterfaceException
332
+	 */
333
+	public function setIsBot($is_bot)
334
+	{
335
+		$this->request()->setIsBot($is_bot);
336
+	}
337
+
338
+
339
+	/**
340
+	 * check if a request parameter exists whose key that matches the supplied wildcard pattern
341
+	 * and return the value for the first match found
342
+	 * wildcards can be either of the following:
343
+	 *      ? to represent a single character of any type
344
+	 *      * to represent one or more characters of any type
345
+	 *
346
+	 * @param string     $pattern
347
+	 * @param null|mixed $default
348
+	 * @return false|int
349
+	 * @throws InvalidArgumentException
350
+	 * @throws InvalidInterfaceException
351
+	 * @throws InvalidDataTypeException
352
+	 */
353
+	public function getMatch($pattern, $default = null)
354
+	{
355
+		return $this->request()->getMatch($pattern, $default);
356
+	}
357
+
358
+
359
+	/**
360
+	 * check if a request parameter exists whose key matches the supplied wildcard pattern
361
+	 * wildcards can be either of the following:
362
+	 *      ? to represent a single character of any type
363
+	 *      * to represent one or more characters of any type
364
+	 * returns true if a match is found or false if not
365
+	 *
366
+	 * @param string $pattern
367
+	 * @return false|int
368
+	 * @throws InvalidArgumentException
369
+	 * @throws InvalidInterfaceException
370
+	 * @throws InvalidDataTypeException
371
+	 */
372
+	public function matches($pattern)
373
+	{
374
+		return $this->request()->matches($pattern);
375
+	}
376 376
 }
Please login to merge, or discard this patch.
core/EE_Session.core.php 2 patches
Indentation   +1313 added lines, -1313 removed lines patch added patch discarded remove patch
@@ -24,1311 +24,1311 @@  discard block
 block discarded – undo
24 24
 class EE_Session implements SessionIdentifierInterface
25 25
 {
26 26
 
27
-    const session_id_prefix = 'ee_ssn_';
28
-
29
-    const hash_check_prefix = 'ee_shc_';
30
-
31
-    const OPTION_NAME_SETTINGS = 'ee_session_settings';
32
-
33
-    const STATUS_CLOSED = 0;
34
-
35
-    const STATUS_OPEN = 1;
36
-
37
-    const SAVE_STATE_CLEAN = 'clean';
38
-    const SAVE_STATE_DIRTY = 'dirty';
39
-
40
-
41
-    /**
42
-     * instance of the EE_Session object
43
-     *
44
-     * @var EE_Session
45
-     */
46
-    private static $_instance;
47
-
48
-    /**
49
-     * @var CacheStorageInterface $cache_storage
50
-     */
51
-    protected $cache_storage;
52
-
53
-    /**
54
-     * @var EE_Encryption $encryption
55
-     */
56
-    protected $encryption;
57
-
58
-    /**
59
-     * @var SessionStartHandler $session_start_handler
60
-     */
61
-    protected $session_start_handler;
62
-
63
-    /**
64
-     * the session id
65
-     *
66
-     * @var string
67
-     */
68
-    private $_sid;
69
-
70
-    /**
71
-     * session id salt
72
-     *
73
-     * @var string
74
-     */
75
-    private $_sid_salt;
76
-
77
-    /**
78
-     * session data
79
-     *
80
-     * @var array
81
-     */
82
-    private $_session_data = array();
83
-
84
-    /**
85
-     * how long an EE session lasts
86
-     * default session lifespan of 1 hour (for not so instant IPNs)
87
-     *
88
-     * @var SessionLifespan $session_lifespan
89
-     */
90
-    private $session_lifespan;
91
-
92
-    /**
93
-     * session expiration time as Unix timestamp in GMT
94
-     *
95
-     * @var int
96
-     */
97
-    private $_expiration;
98
-
99
-    /**
100
-     * whether or not session has expired at some point
101
-     *
102
-     * @var boolean
103
-     */
104
-    private $_expired = false;
105
-
106
-    /**
107
-     * current time as Unix timestamp in GMT
108
-     *
109
-     * @var int
110
-     */
111
-    private $_time;
112
-
113
-    /**
114
-     * whether to encrypt session data
115
-     *
116
-     * @var bool
117
-     */
118
-    private $_use_encryption;
119
-
120
-    /**
121
-     * well... according to the server...
122
-     *
123
-     * @var null
124
-     */
125
-    private $_user_agent;
126
-
127
-    /**
128
-     * do you really trust the server ?
129
-     *
130
-     * @var null
131
-     */
132
-    private $_ip_address;
133
-
134
-    /**
135
-     * current WP user_id
136
-     *
137
-     * @var null
138
-     */
139
-    private $_wp_user_id;
140
-
141
-    /**
142
-     * array for defining default session vars
143
-     *
144
-     * @var array
145
-     */
146
-    private $_default_session_vars = array(
147
-        'id'            => null,
148
-        'user_id'       => null,
149
-        'ip_address'    => null,
150
-        'user_agent'    => null,
151
-        'init_access'   => null,
152
-        'last_access'   => null,
153
-        'expiration'    => null,
154
-        'pages_visited' => array(),
155
-    );
156
-
157
-    /**
158
-     * timestamp for when last garbage collection cycle was performed
159
-     *
160
-     * @var int $_last_gc
161
-     */
162
-    private $_last_gc;
163
-
164
-    /**
165
-     * @var RequestInterface $request
166
-     */
167
-    protected $request;
168
-
169
-    /**
170
-     * whether session is active or not
171
-     *
172
-     * @var int $status
173
-     */
174
-    private $status = EE_Session::STATUS_CLOSED;
175
-
176
-    /**
177
-     * whether session data has changed therefore requiring a session save
178
-     *
179
-     * @var string $save_state
180
-     */
181
-    private $save_state = EE_Session::SAVE_STATE_CLEAN;
182
-
183
-
184
-    /**
185
-     * @singleton method used to instantiate class object
186
-     * @param CacheStorageInterface $cache_storage
187
-     * @param SessionLifespan|null  $lifespan
188
-     * @param RequestInterface      $request
189
-     * @param SessionStartHandler   $session_start_handler
190
-     * @param EE_Encryption         $encryption
191
-     * @return EE_Session
192
-     * @throws InvalidArgumentException
193
-     * @throws InvalidDataTypeException
194
-     * @throws InvalidInterfaceException
195
-     */
196
-    public static function instance(
197
-        CacheStorageInterface $cache_storage = null,
198
-        SessionLifespan $lifespan = null,
199
-        RequestInterface $request = null,
200
-        SessionStartHandler $session_start_handler = null,
201
-        EE_Encryption $encryption = null
202
-    ) {
203
-        // check if class object is instantiated
204
-        // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
205
-        // add_filter( 'FHEE_load_EE_Session', '__return_false' );
206
-        if (! self::$_instance instanceof EE_Session
207
-            && $cache_storage instanceof CacheStorageInterface
208
-            && $lifespan instanceof SessionLifespan
209
-            && $request instanceof RequestInterface
210
-            && $session_start_handler instanceof SessionStartHandler
211
-            && apply_filters('FHEE_load_EE_Session', true)
212
-        ) {
213
-            self::$_instance = new self(
214
-                $cache_storage,
215
-                $lifespan,
216
-                $request,
217
-                $session_start_handler,
218
-                $encryption
219
-            );
220
-        }
221
-        return self::$_instance;
222
-    }
223
-
224
-
225
-    /**
226
-     * protected constructor to prevent direct creation
227
-     *
228
-     * @param CacheStorageInterface $cache_storage
229
-     * @param SessionLifespan       $lifespan
230
-     * @param RequestInterface      $request
231
-     * @param SessionStartHandler   $session_start_handler
232
-     * @param EE_Encryption         $encryption
233
-     * @throws InvalidArgumentException
234
-     * @throws InvalidDataTypeException
235
-     * @throws InvalidInterfaceException
236
-     */
237
-    protected function __construct(
238
-        CacheStorageInterface $cache_storage,
239
-        SessionLifespan $lifespan,
240
-        RequestInterface $request,
241
-        SessionStartHandler $session_start_handler,
242
-        EE_Encryption $encryption = null
243
-    ) {
244
-        // session loading is turned ON by default,
245
-        // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
246
-        // (which currently fires on the init hook at priority 9),
247
-        // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
248
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
249
-            return;
250
-        }
251
-        $this->session_start_handler = $session_start_handler;
252
-        $this->session_lifespan = $lifespan;
253
-        $this->request = $request;
254
-        if (! defined('ESPRESSO_SESSION')) {
255
-            define('ESPRESSO_SESSION', true);
256
-        }
257
-        // retrieve session options from db
258
-        $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
259
-        if (! empty($session_settings)) {
260
-            // cycle though existing session options
261
-            foreach ($session_settings as $var_name => $session_setting) {
262
-                // set values for class properties
263
-                $var_name = '_' . $var_name;
264
-                $this->{$var_name} = $session_setting;
265
-            }
266
-        }
267
-        $this->cache_storage = $cache_storage;
268
-        // are we using encryption?
269
-        $this->_use_encryption = $encryption instanceof EE_Encryption
270
-                                 && EE_Registry::instance()->CFG->admin->encode_session_data();
271
-        // encrypt data via: $this->encryption->encrypt();
272
-        $this->encryption = $encryption;
273
-        // filter hook allows outside functions/classes/plugins to change default empty cart
274
-        $extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
275
-        array_merge($this->_default_session_vars, $extra_default_session_vars);
276
-        // apply default session vars
277
-        $this->_set_defaults();
278
-        add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
279
-        // check request for 'clear_session' param
280
-        add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
281
-        // once everything is all said and done,
282
-        add_action('shutdown', array($this, 'update'), 100);
283
-        add_action('shutdown', array($this, 'garbageCollection'), 1000);
284
-        $this->configure_garbage_collection_filters();
285
-    }
286
-
287
-
288
-    /**
289
-     * @return bool
290
-     * @throws InvalidArgumentException
291
-     * @throws InvalidDataTypeException
292
-     * @throws InvalidInterfaceException
293
-     */
294
-    public static function isLoadedAndActive()
295
-    {
296
-        return did_action('AHEE__EE_System__core_loaded_and_ready')
297
-               && EE_Session::instance() instanceof EE_Session
298
-               && EE_Session::instance()->isActive();
299
-    }
300
-
301
-
302
-    /**
303
-     * @return bool
304
-     */
305
-    public function isActive()
306
-    {
307
-        return $this->status === EE_Session::STATUS_OPEN;
308
-    }
309
-
310
-
311
-    /**
312
-     * @return void
313
-     * @throws EE_Error
314
-     * @throws InvalidArgumentException
315
-     * @throws InvalidDataTypeException
316
-     * @throws InvalidInterfaceException
317
-     * @throws InvalidSessionDataException
318
-     * @throws RuntimeException
319
-     * @throws ReflectionException
320
-     */
321
-    public function open_session()
322
-    {
323
-        // check for existing session and retrieve it from db
324
-        if (! $this->_espresso_session()) {
325
-            // or just start a new one
326
-            $this->_create_espresso_session();
327
-        }
328
-    }
329
-
330
-
331
-    /**
332
-     * @return bool
333
-     */
334
-    public function expired()
335
-    {
336
-        return $this->_expired;
337
-    }
338
-
339
-
340
-    /**
341
-     * @return void
342
-     */
343
-    public function reset_expired()
344
-    {
345
-        $this->_expired = false;
346
-    }
347
-
348
-
349
-    /**
350
-     * @return int
351
-     */
352
-    public function expiration()
353
-    {
354
-        return $this->_expiration;
355
-    }
356
-
357
-
358
-    /**
359
-     * @return int
360
-     */
361
-    public function extension()
362
-    {
363
-        return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
364
-    }
365
-
366
-
367
-    /**
368
-     * @param int $time number of seconds to add to session expiration
369
-     */
370
-    public function extend_expiration($time = 0)
371
-    {
372
-        $time = $time ? $time : $this->extension();
373
-        $this->_expiration += absint($time);
374
-    }
375
-
376
-
377
-    /**
378
-     * @return int
379
-     */
380
-    public function lifespan()
381
-    {
382
-        return $this->session_lifespan->inSeconds();
383
-    }
384
-
385
-
386
-    /**
387
-     * Marks whether the session data has been updated or not.
388
-     * Valid options are:
389
-     *      EE_Session::SAVE_STATE_CLEAN - session data remains unchanged and updating is not necessary
390
-     *      EE_Session::SAVE_STATE_DIRTY - session data has changed since last save and needs to be updated
391
-     * default value is EE_Session::SAVE_STATE_DIRTY
392
-     *
393
-     * @param string $save_state
394
-     */
395
-    public function setSaveState($save_state = EE_Session::SAVE_STATE_DIRTY)
396
-    {
397
-        $valid_save_states = [
398
-            EE_Session::SAVE_STATE_CLEAN,
399
-            EE_Session::SAVE_STATE_DIRTY,
400
-        ];
401
-        if (! in_array($save_state, $valid_save_states, true)) {
402
-            $save_state = EE_Session::SAVE_STATE_DIRTY;
403
-        }
404
-        $this->save_state = $save_state;
405
-    }
406
-
407
-
408
-
409
-    /**
410
-     * This just sets some defaults for the _session data property
411
-     *
412
-     * @return void
413
-     */
414
-    private function _set_defaults()
415
-    {
416
-        // set some defaults
417
-        foreach ($this->_default_session_vars as $key => $default_var) {
418
-            if (is_array($default_var)) {
419
-                $this->_session_data[ $key ] = array();
420
-            } else {
421
-                $this->_session_data[ $key ] = '';
422
-            }
423
-        }
424
-    }
425
-
426
-
427
-    /**
428
-     * @retrieve  session data
429
-     * @return    string
430
-     */
431
-    public function id()
432
-    {
433
-        return $this->_sid;
434
-    }
435
-
436
-
437
-    /**
438
-     * @param \EE_Cart $cart
439
-     * @return bool
440
-     */
441
-    public function set_cart(EE_Cart $cart)
442
-    {
443
-        $this->_session_data['cart'] = $cart;
444
-        $this->setSaveState();
445
-        return true;
446
-    }
447
-
448
-
449
-    /**
450
-     * reset_cart
451
-     */
452
-    public function reset_cart()
453
-    {
454
-        do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
455
-        $this->_session_data['cart'] = null;
456
-        $this->setSaveState();
457
-    }
458
-
459
-
460
-    /**
461
-     * @return \EE_Cart
462
-     */
463
-    public function cart()
464
-    {
465
-        return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
466
-            ? $this->_session_data['cart']
467
-            : null;
468
-    }
469
-
470
-
471
-    /**
472
-     * @param \EE_Checkout $checkout
473
-     * @return bool
474
-     */
475
-    public function set_checkout(EE_Checkout $checkout)
476
-    {
477
-        $this->_session_data['checkout'] = $checkout;
478
-        $this->setSaveState();
479
-        return true;
480
-    }
481
-
482
-
483
-    /**
484
-     * reset_checkout
485
-     */
486
-    public function reset_checkout()
487
-    {
488
-        do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
489
-        $this->_session_data['checkout'] = null;
490
-        $this->setSaveState();
491
-    }
492
-
493
-
494
-    /**
495
-     * @return \EE_Checkout
496
-     */
497
-    public function checkout()
498
-    {
499
-        return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
500
-            ? $this->_session_data['checkout']
501
-            : null;
502
-    }
503
-
504
-
505
-    /**
506
-     * @param \EE_Transaction $transaction
507
-     * @return bool
508
-     * @throws EE_Error
509
-     */
510
-    public function set_transaction(EE_Transaction $transaction)
511
-    {
512
-        // first remove the session from the transaction before we save the transaction in the session
513
-        $transaction->set_txn_session_data(null);
514
-        $this->_session_data['transaction'] = $transaction;
515
-        $this->setSaveState();
516
-        return true;
517
-    }
518
-
519
-
520
-    /**
521
-     * reset_transaction
522
-     */
523
-    public function reset_transaction()
524
-    {
525
-        do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
526
-        $this->_session_data['transaction'] = null;
527
-        $this->setSaveState();
528
-    }
529
-
530
-
531
-    /**
532
-     * @return \EE_Transaction
533
-     */
534
-    public function transaction()
535
-    {
536
-        return isset($this->_session_data['transaction'])
537
-               && $this->_session_data['transaction'] instanceof EE_Transaction
538
-            ? $this->_session_data['transaction']
539
-            : null;
540
-    }
541
-
542
-
543
-    /**
544
-     * retrieve session data
545
-     *
546
-     * @param null $key
547
-     * @param bool $reset_cache
548
-     * @return array
549
-     */
550
-    public function get_session_data($key = null, $reset_cache = false)
551
-    {
552
-        if ($reset_cache) {
553
-            $this->reset_cart();
554
-            $this->reset_checkout();
555
-            $this->reset_transaction();
556
-        }
557
-        if (! empty($key)) {
558
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
559
-        }
560
-        return $this->_session_data;
561
-    }
562
-
563
-
564
-    /**
565
-     * Returns TRUE on success, FALSE on fail
566
-     *
567
-     * @param array $data
568
-     * @return bool
569
-     */
570
-    public function set_session_data($data)
571
-    {
572
-        // nothing ??? bad data ??? go home!
573
-        if (empty($data) || ! is_array($data)) {
574
-            EE_Error::add_error(
575
-                esc_html__(
576
-                    'No session data or invalid session data was provided.',
577
-                    'event_espresso'
578
-                ),
579
-                __FILE__,
580
-                __FUNCTION__,
581
-                __LINE__
582
-            );
583
-            return false;
584
-        }
585
-        foreach ($data as $key => $value) {
586
-            if (isset($this->_default_session_vars[ $key ])) {
587
-                EE_Error::add_error(
588
-                    sprintf(
589
-                        esc_html__(
590
-                            'Sorry! %s is a default session datum and can not be reset.',
591
-                            'event_espresso'
592
-                        ),
593
-                        $key
594
-                    ),
595
-                    __FILE__,
596
-                    __FUNCTION__,
597
-                    __LINE__
598
-                );
599
-                return false;
600
-            }
601
-            $this->_session_data[ $key ] = $value;
602
-            $this->setSaveState();
603
-        }
604
-        return true;
605
-    }
606
-
607
-
608
-    /**
609
-     * @initiate session
610
-     * @return bool TRUE on success, FALSE on fail
611
-     * @throws EE_Error
612
-     * @throws InvalidArgumentException
613
-     * @throws InvalidDataTypeException
614
-     * @throws InvalidInterfaceException
615
-     * @throws InvalidSessionDataException
616
-     * @throws RuntimeException
617
-     * @throws ReflectionException
618
-     */
619
-    private function _espresso_session()
620
-    {
621
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
622
-        $this->session_start_handler->startSession();
623
-        $this->status = EE_Session::STATUS_OPEN;
624
-        // get our modified session ID
625
-        $this->_sid = $this->_generate_session_id();
626
-        // and the visitors IP
627
-        $this->_ip_address = $this->request->ipAddress();
628
-        // set the "user agent"
629
-        $this->_user_agent = $this->request->userAgent();
630
-        // now let's retrieve what's in the db
631
-        $session_data = $this->_retrieve_session_data();
632
-        if (! empty($session_data)) {
633
-            // get the current time in UTC
634
-            $this->_time = $this->_time !== null ? $this->_time : time();
635
-            // and reset the session expiration
636
-            $this->_expiration = isset($session_data['expiration'])
637
-                ? $session_data['expiration']
638
-                : $this->_time + $this->session_lifespan->inSeconds();
639
-        } else {
640
-            // set initial site access time and the session expiration
641
-            $this->_set_init_access_and_expiration();
642
-            // set referer
643
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
644
-                $this->request->getServerParam('HTTP_REFERER')
645
-            );
646
-            // no previous session = go back and create one (on top of the data above)
647
-            return false;
648
-        }
649
-        // now the user agent
650
-        if ($session_data['user_agent'] !== $this->_user_agent) {
651
-            return false;
652
-        }
653
-        // wait a minute... how old are you?
654
-        if ($this->_time > $this->_expiration) {
655
-            // yer too old fer me!
656
-            $this->_expired = true;
657
-            // wipe out everything that isn't a default session datum
658
-            $this->clear_session(__CLASS__, __FUNCTION__);
659
-        }
660
-        // make event espresso session data available to plugin
661
-        $this->_session_data = array_merge($this->_session_data, $session_data);
662
-        return true;
663
-    }
664
-
665
-
666
-    /**
667
-     * _get_session_data
668
-     * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
669
-     * databases
670
-     *
671
-     * @return array
672
-     * @throws EE_Error
673
-     * @throws InvalidArgumentException
674
-     * @throws InvalidSessionDataException
675
-     * @throws InvalidDataTypeException
676
-     * @throws InvalidInterfaceException
677
-     * @throws RuntimeException
678
-     */
679
-    protected function _retrieve_session_data()
680
-    {
681
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
682
-        try {
683
-            // we're using WP's Transient API to store session data using the PHP session ID as the option name
684
-            $session_data = $this->cache_storage->get($ssn_key, false);
685
-            if (empty($session_data)) {
686
-                return array();
687
-            }
688
-            if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
689
-                $hash_check = $this->cache_storage->get(
690
-                    EE_Session::hash_check_prefix . $this->_sid,
691
-                    false
692
-                );
693
-                if ($hash_check && $hash_check !== md5($session_data)) {
694
-                    EE_Error::add_error(
695
-                        sprintf(
696
-                            __(
697
-                                'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
698
-                                'event_espresso'
699
-                            ),
700
-                            EE_Session::session_id_prefix . $this->_sid
701
-                        ),
702
-                        __FILE__,
703
-                        __FUNCTION__,
704
-                        __LINE__
705
-                    );
706
-                }
707
-            }
708
-        } catch (Exception $e) {
709
-            // let's just eat that error for now and attempt to correct any corrupted data
710
-            global $wpdb;
711
-            $row = $wpdb->get_row(
712
-                $wpdb->prepare(
713
-                    "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
714
-                    '_transient_' . $ssn_key
715
-                )
716
-            );
717
-            $session_data = is_object($row) ? $row->option_value : null;
718
-            if ($session_data) {
719
-                $session_data = preg_replace_callback(
720
-                    '!s:(d+):"(.*?)";!',
721
-                    function ($match) {
722
-                        return $match[1] === strlen($match[2])
723
-                            ? $match[0]
724
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
725
-                    },
726
-                    $session_data
727
-                );
728
-            }
729
-            $session_data = maybe_unserialize($session_data);
730
-        }
731
-        // in case the data is encoded... try to decode it
732
-        $session_data = $this->encryption instanceof EE_Encryption
733
-            ? $this->encryption->base64_string_decode($session_data)
734
-            : $session_data;
735
-        if (! is_array($session_data)) {
736
-            try {
737
-                $session_data = maybe_unserialize($session_data);
738
-            } catch (Exception $e) {
739
-                $msg = esc_html__(
740
-                    'An error occurred while attempting to unserialize the session data.',
741
-                    'event_espresso'
742
-                );
743
-                $msg .= WP_DEBUG
744
-                    ? '<br><pre>'
745
-                      . print_r($session_data, true)
746
-                      . '</pre><br>'
747
-                      . $this->find_serialize_error($session_data)
748
-                    : '';
749
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
750
-                throw new InvalidSessionDataException($msg, 0, $e);
751
-            }
752
-        }
753
-        // just a check to make sure the session array is indeed an array
754
-        if (! is_array($session_data)) {
755
-            // no?!?! then something is wrong
756
-            $msg = esc_html__(
757
-                'The session data is missing, invalid, or corrupted.',
758
-                'event_espresso'
759
-            );
760
-            $msg .= WP_DEBUG
761
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
762
-                : '';
763
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
764
-            throw new InvalidSessionDataException($msg);
765
-        }
766
-        if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
767
-            $session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
768
-                $session_data['transaction']
769
-            );
770
-        }
771
-        return $session_data;
772
-    }
773
-
774
-
775
-    /**
776
-     * _generate_session_id
777
-     * Retrieves the PHP session id either directly from the PHP session,
778
-     * or from the request array if it was passed in from an AJAX request.
779
-     * The session id is then salted and hashed (mmm sounds tasty)
780
-     * so that it can be safely used as a request param
781
-     *
782
-     * @return string
783
-     */
784
-    protected function _generate_session_id()
785
-    {
786
-        // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
787
-        $session_id = $this->request->requestParamIsSet('EESID')
788
-            ? $this->request->getRequestParam('EESID')
789
-            : md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
790
-        return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
791
-    }
792
-
793
-
794
-    /**
795
-     * _get_sid_salt
796
-     *
797
-     * @return string
798
-     */
799
-    protected function _get_sid_salt()
800
-    {
801
-        // was session id salt already saved to db ?
802
-        if (empty($this->_sid_salt)) {
803
-            // no?  then maybe use WP defined constant
804
-            if (defined('AUTH_SALT')) {
805
-                $this->_sid_salt = AUTH_SALT;
806
-            }
807
-            // if salt doesn't exist or is too short
808
-            if (strlen($this->_sid_salt) < 32) {
809
-                // create a new one
810
-                $this->_sid_salt = wp_generate_password(64);
811
-            }
812
-            // and save it as a permanent session setting
813
-            $this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
814
-        }
815
-        return $this->_sid_salt;
816
-    }
817
-
818
-
819
-    /**
820
-     * _set_init_access_and_expiration
821
-     *
822
-     * @return void
823
-     */
824
-    protected function _set_init_access_and_expiration()
825
-    {
826
-        $this->_time = time();
827
-        $this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
828
-        // set initial site access time
829
-        $this->_session_data['init_access'] = $this->_time;
830
-        // and the session expiration
831
-        $this->_session_data['expiration'] = $this->_expiration;
832
-    }
833
-
834
-
835
-    /**
836
-     * @update session data  prior to saving to the db
837
-     * @param bool $new_session
838
-     * @return TRUE on success, FALSE on fail
839
-     * @throws EE_Error
840
-     * @throws InvalidArgumentException
841
-     * @throws InvalidDataTypeException
842
-     * @throws InvalidInterfaceException
843
-     * @throws ReflectionException
844
-     */
845
-    public function update($new_session = false)
846
-    {
847
-        $this->_session_data = $this->_session_data !== null
848
-                               && is_array($this->_session_data)
849
-                               && isset($this->_session_data['id'])
850
-            ? $this->_session_data
851
-            : array();
852
-        if (empty($this->_session_data)) {
853
-            $this->_set_defaults();
854
-        }
855
-        $session_data = array();
856
-        foreach ($this->_session_data as $key => $value) {
857
-            switch ($key) {
858
-                case 'id':
859
-                    // session ID
860
-                    $session_data['id'] = $this->_sid;
861
-                    break;
862
-                case 'ip_address':
863
-                    // visitor ip address
864
-                    $session_data['ip_address'] = $this->request->ipAddress();
865
-                    break;
866
-                case 'user_agent':
867
-                    // visitor user_agent
868
-                    $session_data['user_agent'] = $this->_user_agent;
869
-                    break;
870
-                case 'init_access':
871
-                    $session_data['init_access'] = absint($value);
872
-                    break;
873
-                case 'last_access':
874
-                    // current access time
875
-                    $session_data['last_access'] = $this->_time;
876
-                    break;
877
-                case 'expiration':
878
-                    // when the session expires
879
-                    $session_data['expiration'] = ! empty($this->_expiration)
880
-                        ? $this->_expiration
881
-                        : $session_data['init_access'] + $this->session_lifespan->inSeconds();
882
-                    break;
883
-                case 'user_id':
884
-                    // current user if logged in
885
-                    $session_data['user_id'] = $this->_wp_user_id();
886
-                    break;
887
-                case 'pages_visited':
888
-                    $page_visit = $this->_get_page_visit();
889
-                    if ($page_visit) {
890
-                        // set pages visited where the first will be the http referrer
891
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
892
-                        // we'll only save the last 10 page visits.
893
-                        $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
894
-                    }
895
-                    break;
896
-                default:
897
-                    // carry any other data over
898
-                    $session_data[ $key ] = $this->_session_data[ $key ];
899
-            }
900
-        }
901
-        $this->_session_data = $session_data;
902
-        // creating a new session does not require saving to the db just yet
903
-        if (! $new_session) {
904
-            // ready? let's save
905
-            if ($this->_save_session_to_db()) {
906
-                return true;
907
-            }
908
-            return false;
909
-        }
910
-        // meh, why not?
911
-        return true;
912
-    }
913
-
914
-
915
-    /**
916
-     * @create session data array
917
-     * @return bool
918
-     * @throws EE_Error
919
-     * @throws InvalidArgumentException
920
-     * @throws InvalidDataTypeException
921
-     * @throws InvalidInterfaceException
922
-     * @throws ReflectionException
923
-     */
924
-    private function _create_espresso_session()
925
-    {
926
-        do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
927
-        // use the update function for now with $new_session arg set to TRUE
928
-        return $this->update(true) ? true : false;
929
-    }
930
-
931
-    /**
932
-     * Detects if there is anything worth saving in the session (eg the cart is a good one, notices are pretty good
933
-     * too). This is used when determining if we want to save the session or not.
934
-     * @since 4.9.67.p
935
-     * @return bool
936
-     */
937
-    private function sessionHasStuffWorthSaving()
938
-    {
939
-        return $this->save_state === EE_Session::SAVE_STATE_DIRTY
940
-               // we may want to eventually remove the following
941
-               // on the assumption that the above check is enough
942
-               || $this->cart() instanceof EE_Cart
943
-               || (
944
-                   isset($this->_session_data['ee_notices'])
945
-                   && (
946
-                       ! empty($this->_session_data['ee_notices']['attention'])
947
-                       || ! empty($this->_session_data['ee_notices']['errors'])
948
-                       || ! empty($this->_session_data['ee_notices']['success'])
949
-                   )
950
-               );
951
-    }
952
-
953
-
954
-    /**
955
-     * _save_session_to_db
956
-     *
957
-     * @param bool $clear_session
958
-     * @return string
959
-     * @throws EE_Error
960
-     * @throws InvalidArgumentException
961
-     * @throws InvalidDataTypeException
962
-     * @throws InvalidInterfaceException
963
-     * @throws ReflectionException
964
-     */
965
-    private function _save_session_to_db($clear_session = false)
966
-    {
967
-        // don't save sessions for crawlers
968
-        // and unless we're deleting the session data, don't save anything if there isn't a cart
969
-        if ($this->request->isBot()
970
-            || (
971
-                ! $clear_session
972
-                && ! $this->sessionHasStuffWorthSaving()
973
-                && apply_filters('FHEE__EE_Session___save_session_to_db__abort_session_save', true)
974
-            )
975
-        ) {
976
-            return false;
977
-        }
978
-        $transaction = $this->transaction();
979
-        if ($transaction instanceof EE_Transaction) {
980
-            if (! $transaction->ID()) {
981
-                $transaction->save();
982
-            }
983
-            $this->_session_data['transaction'] = $transaction->ID();
984
-        }
985
-        // then serialize all of our session data
986
-        $session_data = serialize($this->_session_data);
987
-        // do we need to also encode it to avoid corrupted data when saved to the db?
988
-        $session_data = $this->_use_encryption
989
-            ? $this->encryption->base64_string_encode($session_data)
990
-            : $session_data;
991
-        // maybe save hash check
992
-        if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
993
-            $this->cache_storage->add(
994
-                EE_Session::hash_check_prefix . $this->_sid,
995
-                md5($session_data),
996
-                $this->session_lifespan->inSeconds()
997
-            );
998
-        }
999
-        // we're using the Transient API for storing session data,
1000
-        $saved = $this->cache_storage->add(
1001
-            EE_Session::session_id_prefix . $this->_sid,
1002
-            $session_data,
1003
-            $this->session_lifespan->inSeconds()
1004
-        );
1005
-        $this->setSaveState(EE_Session::SAVE_STATE_CLEAN);
1006
-        return $saved;
1007
-    }
1008
-
1009
-
1010
-    /**
1011
-     * @get    the full page request the visitor is accessing
1012
-     * @return string
1013
-     */
1014
-    public function _get_page_visit()
1015
-    {
1016
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1017
-        // check for request url
1018
-        if ($this->request->serverParamIsSet('REQUEST_URI')) {
1019
-            $page_id = '?';
1020
-            $e_reg = '';
1021
-            $request_uri = $this->request->getServerParam('REQUEST_URI');
1022
-            $ru_bits = explode('?', $request_uri);
1023
-            $request_uri = $ru_bits[0];
1024
-            $http_host = $this->request->getServerParam('HTTP_HOST');
1025
-            // check for page_id in SERVER REQUEST
1026
-            if ($this->request->requestParamIsSet('page_id')) {
1027
-                // rebuild $e_reg without any of the extra parameters
1028
-                $page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1029
-            }
1030
-            // check for $e_reg in SERVER REQUEST
1031
-            if ($this->request->requestParamIsSet('ee')) {
1032
-                // rebuild $e_reg without any of the extra parameters
1033
-                $e_reg = 'ee=' . $this->request->getRequestParam('ee');
1034
-            }
1035
-            $page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1036
-        }
1037
-        return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
1038
-    }
1039
-
1040
-
1041
-    /**
1042
-     * @the    current wp user id
1043
-     * @return int
1044
-     */
1045
-    public function _wp_user_id()
1046
-    {
1047
-        // if I need to explain the following lines of code, then you shouldn't be looking at this!
1048
-        $this->_wp_user_id = get_current_user_id();
1049
-        return $this->_wp_user_id;
1050
-    }
1051
-
1052
-
1053
-    /**
1054
-     * Clear EE_Session data
1055
-     *
1056
-     * @param string $class
1057
-     * @param string $function
1058
-     * @return void
1059
-     * @throws EE_Error
1060
-     * @throws InvalidArgumentException
1061
-     * @throws InvalidDataTypeException
1062
-     * @throws InvalidInterfaceException
1063
-     * @throws ReflectionException
1064
-     */
1065
-    public function clear_session($class = '', $function = '')
1066
-    {
27
+	const session_id_prefix = 'ee_ssn_';
28
+
29
+	const hash_check_prefix = 'ee_shc_';
30
+
31
+	const OPTION_NAME_SETTINGS = 'ee_session_settings';
32
+
33
+	const STATUS_CLOSED = 0;
34
+
35
+	const STATUS_OPEN = 1;
36
+
37
+	const SAVE_STATE_CLEAN = 'clean';
38
+	const SAVE_STATE_DIRTY = 'dirty';
39
+
40
+
41
+	/**
42
+	 * instance of the EE_Session object
43
+	 *
44
+	 * @var EE_Session
45
+	 */
46
+	private static $_instance;
47
+
48
+	/**
49
+	 * @var CacheStorageInterface $cache_storage
50
+	 */
51
+	protected $cache_storage;
52
+
53
+	/**
54
+	 * @var EE_Encryption $encryption
55
+	 */
56
+	protected $encryption;
57
+
58
+	/**
59
+	 * @var SessionStartHandler $session_start_handler
60
+	 */
61
+	protected $session_start_handler;
62
+
63
+	/**
64
+	 * the session id
65
+	 *
66
+	 * @var string
67
+	 */
68
+	private $_sid;
69
+
70
+	/**
71
+	 * session id salt
72
+	 *
73
+	 * @var string
74
+	 */
75
+	private $_sid_salt;
76
+
77
+	/**
78
+	 * session data
79
+	 *
80
+	 * @var array
81
+	 */
82
+	private $_session_data = array();
83
+
84
+	/**
85
+	 * how long an EE session lasts
86
+	 * default session lifespan of 1 hour (for not so instant IPNs)
87
+	 *
88
+	 * @var SessionLifespan $session_lifespan
89
+	 */
90
+	private $session_lifespan;
91
+
92
+	/**
93
+	 * session expiration time as Unix timestamp in GMT
94
+	 *
95
+	 * @var int
96
+	 */
97
+	private $_expiration;
98
+
99
+	/**
100
+	 * whether or not session has expired at some point
101
+	 *
102
+	 * @var boolean
103
+	 */
104
+	private $_expired = false;
105
+
106
+	/**
107
+	 * current time as Unix timestamp in GMT
108
+	 *
109
+	 * @var int
110
+	 */
111
+	private $_time;
112
+
113
+	/**
114
+	 * whether to encrypt session data
115
+	 *
116
+	 * @var bool
117
+	 */
118
+	private $_use_encryption;
119
+
120
+	/**
121
+	 * well... according to the server...
122
+	 *
123
+	 * @var null
124
+	 */
125
+	private $_user_agent;
126
+
127
+	/**
128
+	 * do you really trust the server ?
129
+	 *
130
+	 * @var null
131
+	 */
132
+	private $_ip_address;
133
+
134
+	/**
135
+	 * current WP user_id
136
+	 *
137
+	 * @var null
138
+	 */
139
+	private $_wp_user_id;
140
+
141
+	/**
142
+	 * array for defining default session vars
143
+	 *
144
+	 * @var array
145
+	 */
146
+	private $_default_session_vars = array(
147
+		'id'            => null,
148
+		'user_id'       => null,
149
+		'ip_address'    => null,
150
+		'user_agent'    => null,
151
+		'init_access'   => null,
152
+		'last_access'   => null,
153
+		'expiration'    => null,
154
+		'pages_visited' => array(),
155
+	);
156
+
157
+	/**
158
+	 * timestamp for when last garbage collection cycle was performed
159
+	 *
160
+	 * @var int $_last_gc
161
+	 */
162
+	private $_last_gc;
163
+
164
+	/**
165
+	 * @var RequestInterface $request
166
+	 */
167
+	protected $request;
168
+
169
+	/**
170
+	 * whether session is active or not
171
+	 *
172
+	 * @var int $status
173
+	 */
174
+	private $status = EE_Session::STATUS_CLOSED;
175
+
176
+	/**
177
+	 * whether session data has changed therefore requiring a session save
178
+	 *
179
+	 * @var string $save_state
180
+	 */
181
+	private $save_state = EE_Session::SAVE_STATE_CLEAN;
182
+
183
+
184
+	/**
185
+	 * @singleton method used to instantiate class object
186
+	 * @param CacheStorageInterface $cache_storage
187
+	 * @param SessionLifespan|null  $lifespan
188
+	 * @param RequestInterface      $request
189
+	 * @param SessionStartHandler   $session_start_handler
190
+	 * @param EE_Encryption         $encryption
191
+	 * @return EE_Session
192
+	 * @throws InvalidArgumentException
193
+	 * @throws InvalidDataTypeException
194
+	 * @throws InvalidInterfaceException
195
+	 */
196
+	public static function instance(
197
+		CacheStorageInterface $cache_storage = null,
198
+		SessionLifespan $lifespan = null,
199
+		RequestInterface $request = null,
200
+		SessionStartHandler $session_start_handler = null,
201
+		EE_Encryption $encryption = null
202
+	) {
203
+		// check if class object is instantiated
204
+		// session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
205
+		// add_filter( 'FHEE_load_EE_Session', '__return_false' );
206
+		if (! self::$_instance instanceof EE_Session
207
+			&& $cache_storage instanceof CacheStorageInterface
208
+			&& $lifespan instanceof SessionLifespan
209
+			&& $request instanceof RequestInterface
210
+			&& $session_start_handler instanceof SessionStartHandler
211
+			&& apply_filters('FHEE_load_EE_Session', true)
212
+		) {
213
+			self::$_instance = new self(
214
+				$cache_storage,
215
+				$lifespan,
216
+				$request,
217
+				$session_start_handler,
218
+				$encryption
219
+			);
220
+		}
221
+		return self::$_instance;
222
+	}
223
+
224
+
225
+	/**
226
+	 * protected constructor to prevent direct creation
227
+	 *
228
+	 * @param CacheStorageInterface $cache_storage
229
+	 * @param SessionLifespan       $lifespan
230
+	 * @param RequestInterface      $request
231
+	 * @param SessionStartHandler   $session_start_handler
232
+	 * @param EE_Encryption         $encryption
233
+	 * @throws InvalidArgumentException
234
+	 * @throws InvalidDataTypeException
235
+	 * @throws InvalidInterfaceException
236
+	 */
237
+	protected function __construct(
238
+		CacheStorageInterface $cache_storage,
239
+		SessionLifespan $lifespan,
240
+		RequestInterface $request,
241
+		SessionStartHandler $session_start_handler,
242
+		EE_Encryption $encryption = null
243
+	) {
244
+		// session loading is turned ON by default,
245
+		// but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
246
+		// (which currently fires on the init hook at priority 9),
247
+		// can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
248
+		if (! apply_filters('FHEE_load_EE_Session', true)) {
249
+			return;
250
+		}
251
+		$this->session_start_handler = $session_start_handler;
252
+		$this->session_lifespan = $lifespan;
253
+		$this->request = $request;
254
+		if (! defined('ESPRESSO_SESSION')) {
255
+			define('ESPRESSO_SESSION', true);
256
+		}
257
+		// retrieve session options from db
258
+		$session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
259
+		if (! empty($session_settings)) {
260
+			// cycle though existing session options
261
+			foreach ($session_settings as $var_name => $session_setting) {
262
+				// set values for class properties
263
+				$var_name = '_' . $var_name;
264
+				$this->{$var_name} = $session_setting;
265
+			}
266
+		}
267
+		$this->cache_storage = $cache_storage;
268
+		// are we using encryption?
269
+		$this->_use_encryption = $encryption instanceof EE_Encryption
270
+								 && EE_Registry::instance()->CFG->admin->encode_session_data();
271
+		// encrypt data via: $this->encryption->encrypt();
272
+		$this->encryption = $encryption;
273
+		// filter hook allows outside functions/classes/plugins to change default empty cart
274
+		$extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
275
+		array_merge($this->_default_session_vars, $extra_default_session_vars);
276
+		// apply default session vars
277
+		$this->_set_defaults();
278
+		add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
279
+		// check request for 'clear_session' param
280
+		add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
281
+		// once everything is all said and done,
282
+		add_action('shutdown', array($this, 'update'), 100);
283
+		add_action('shutdown', array($this, 'garbageCollection'), 1000);
284
+		$this->configure_garbage_collection_filters();
285
+	}
286
+
287
+
288
+	/**
289
+	 * @return bool
290
+	 * @throws InvalidArgumentException
291
+	 * @throws InvalidDataTypeException
292
+	 * @throws InvalidInterfaceException
293
+	 */
294
+	public static function isLoadedAndActive()
295
+	{
296
+		return did_action('AHEE__EE_System__core_loaded_and_ready')
297
+			   && EE_Session::instance() instanceof EE_Session
298
+			   && EE_Session::instance()->isActive();
299
+	}
300
+
301
+
302
+	/**
303
+	 * @return bool
304
+	 */
305
+	public function isActive()
306
+	{
307
+		return $this->status === EE_Session::STATUS_OPEN;
308
+	}
309
+
310
+
311
+	/**
312
+	 * @return void
313
+	 * @throws EE_Error
314
+	 * @throws InvalidArgumentException
315
+	 * @throws InvalidDataTypeException
316
+	 * @throws InvalidInterfaceException
317
+	 * @throws InvalidSessionDataException
318
+	 * @throws RuntimeException
319
+	 * @throws ReflectionException
320
+	 */
321
+	public function open_session()
322
+	{
323
+		// check for existing session and retrieve it from db
324
+		if (! $this->_espresso_session()) {
325
+			// or just start a new one
326
+			$this->_create_espresso_session();
327
+		}
328
+	}
329
+
330
+
331
+	/**
332
+	 * @return bool
333
+	 */
334
+	public function expired()
335
+	{
336
+		return $this->_expired;
337
+	}
338
+
339
+
340
+	/**
341
+	 * @return void
342
+	 */
343
+	public function reset_expired()
344
+	{
345
+		$this->_expired = false;
346
+	}
347
+
348
+
349
+	/**
350
+	 * @return int
351
+	 */
352
+	public function expiration()
353
+	{
354
+		return $this->_expiration;
355
+	}
356
+
357
+
358
+	/**
359
+	 * @return int
360
+	 */
361
+	public function extension()
362
+	{
363
+		return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
364
+	}
365
+
366
+
367
+	/**
368
+	 * @param int $time number of seconds to add to session expiration
369
+	 */
370
+	public function extend_expiration($time = 0)
371
+	{
372
+		$time = $time ? $time : $this->extension();
373
+		$this->_expiration += absint($time);
374
+	}
375
+
376
+
377
+	/**
378
+	 * @return int
379
+	 */
380
+	public function lifespan()
381
+	{
382
+		return $this->session_lifespan->inSeconds();
383
+	}
384
+
385
+
386
+	/**
387
+	 * Marks whether the session data has been updated or not.
388
+	 * Valid options are:
389
+	 *      EE_Session::SAVE_STATE_CLEAN - session data remains unchanged and updating is not necessary
390
+	 *      EE_Session::SAVE_STATE_DIRTY - session data has changed since last save and needs to be updated
391
+	 * default value is EE_Session::SAVE_STATE_DIRTY
392
+	 *
393
+	 * @param string $save_state
394
+	 */
395
+	public function setSaveState($save_state = EE_Session::SAVE_STATE_DIRTY)
396
+	{
397
+		$valid_save_states = [
398
+			EE_Session::SAVE_STATE_CLEAN,
399
+			EE_Session::SAVE_STATE_DIRTY,
400
+		];
401
+		if (! in_array($save_state, $valid_save_states, true)) {
402
+			$save_state = EE_Session::SAVE_STATE_DIRTY;
403
+		}
404
+		$this->save_state = $save_state;
405
+	}
406
+
407
+
408
+
409
+	/**
410
+	 * This just sets some defaults for the _session data property
411
+	 *
412
+	 * @return void
413
+	 */
414
+	private function _set_defaults()
415
+	{
416
+		// set some defaults
417
+		foreach ($this->_default_session_vars as $key => $default_var) {
418
+			if (is_array($default_var)) {
419
+				$this->_session_data[ $key ] = array();
420
+			} else {
421
+				$this->_session_data[ $key ] = '';
422
+			}
423
+		}
424
+	}
425
+
426
+
427
+	/**
428
+	 * @retrieve  session data
429
+	 * @return    string
430
+	 */
431
+	public function id()
432
+	{
433
+		return $this->_sid;
434
+	}
435
+
436
+
437
+	/**
438
+	 * @param \EE_Cart $cart
439
+	 * @return bool
440
+	 */
441
+	public function set_cart(EE_Cart $cart)
442
+	{
443
+		$this->_session_data['cart'] = $cart;
444
+		$this->setSaveState();
445
+		return true;
446
+	}
447
+
448
+
449
+	/**
450
+	 * reset_cart
451
+	 */
452
+	public function reset_cart()
453
+	{
454
+		do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
455
+		$this->_session_data['cart'] = null;
456
+		$this->setSaveState();
457
+	}
458
+
459
+
460
+	/**
461
+	 * @return \EE_Cart
462
+	 */
463
+	public function cart()
464
+	{
465
+		return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
466
+			? $this->_session_data['cart']
467
+			: null;
468
+	}
469
+
470
+
471
+	/**
472
+	 * @param \EE_Checkout $checkout
473
+	 * @return bool
474
+	 */
475
+	public function set_checkout(EE_Checkout $checkout)
476
+	{
477
+		$this->_session_data['checkout'] = $checkout;
478
+		$this->setSaveState();
479
+		return true;
480
+	}
481
+
482
+
483
+	/**
484
+	 * reset_checkout
485
+	 */
486
+	public function reset_checkout()
487
+	{
488
+		do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
489
+		$this->_session_data['checkout'] = null;
490
+		$this->setSaveState();
491
+	}
492
+
493
+
494
+	/**
495
+	 * @return \EE_Checkout
496
+	 */
497
+	public function checkout()
498
+	{
499
+		return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
500
+			? $this->_session_data['checkout']
501
+			: null;
502
+	}
503
+
504
+
505
+	/**
506
+	 * @param \EE_Transaction $transaction
507
+	 * @return bool
508
+	 * @throws EE_Error
509
+	 */
510
+	public function set_transaction(EE_Transaction $transaction)
511
+	{
512
+		// first remove the session from the transaction before we save the transaction in the session
513
+		$transaction->set_txn_session_data(null);
514
+		$this->_session_data['transaction'] = $transaction;
515
+		$this->setSaveState();
516
+		return true;
517
+	}
518
+
519
+
520
+	/**
521
+	 * reset_transaction
522
+	 */
523
+	public function reset_transaction()
524
+	{
525
+		do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
526
+		$this->_session_data['transaction'] = null;
527
+		$this->setSaveState();
528
+	}
529
+
530
+
531
+	/**
532
+	 * @return \EE_Transaction
533
+	 */
534
+	public function transaction()
535
+	{
536
+		return isset($this->_session_data['transaction'])
537
+			   && $this->_session_data['transaction'] instanceof EE_Transaction
538
+			? $this->_session_data['transaction']
539
+			: null;
540
+	}
541
+
542
+
543
+	/**
544
+	 * retrieve session data
545
+	 *
546
+	 * @param null $key
547
+	 * @param bool $reset_cache
548
+	 * @return array
549
+	 */
550
+	public function get_session_data($key = null, $reset_cache = false)
551
+	{
552
+		if ($reset_cache) {
553
+			$this->reset_cart();
554
+			$this->reset_checkout();
555
+			$this->reset_transaction();
556
+		}
557
+		if (! empty($key)) {
558
+			return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
559
+		}
560
+		return $this->_session_data;
561
+	}
562
+
563
+
564
+	/**
565
+	 * Returns TRUE on success, FALSE on fail
566
+	 *
567
+	 * @param array $data
568
+	 * @return bool
569
+	 */
570
+	public function set_session_data($data)
571
+	{
572
+		// nothing ??? bad data ??? go home!
573
+		if (empty($data) || ! is_array($data)) {
574
+			EE_Error::add_error(
575
+				esc_html__(
576
+					'No session data or invalid session data was provided.',
577
+					'event_espresso'
578
+				),
579
+				__FILE__,
580
+				__FUNCTION__,
581
+				__LINE__
582
+			);
583
+			return false;
584
+		}
585
+		foreach ($data as $key => $value) {
586
+			if (isset($this->_default_session_vars[ $key ])) {
587
+				EE_Error::add_error(
588
+					sprintf(
589
+						esc_html__(
590
+							'Sorry! %s is a default session datum and can not be reset.',
591
+							'event_espresso'
592
+						),
593
+						$key
594
+					),
595
+					__FILE__,
596
+					__FUNCTION__,
597
+					__LINE__
598
+				);
599
+				return false;
600
+			}
601
+			$this->_session_data[ $key ] = $value;
602
+			$this->setSaveState();
603
+		}
604
+		return true;
605
+	}
606
+
607
+
608
+	/**
609
+	 * @initiate session
610
+	 * @return bool TRUE on success, FALSE on fail
611
+	 * @throws EE_Error
612
+	 * @throws InvalidArgumentException
613
+	 * @throws InvalidDataTypeException
614
+	 * @throws InvalidInterfaceException
615
+	 * @throws InvalidSessionDataException
616
+	 * @throws RuntimeException
617
+	 * @throws ReflectionException
618
+	 */
619
+	private function _espresso_session()
620
+	{
621
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
622
+		$this->session_start_handler->startSession();
623
+		$this->status = EE_Session::STATUS_OPEN;
624
+		// get our modified session ID
625
+		$this->_sid = $this->_generate_session_id();
626
+		// and the visitors IP
627
+		$this->_ip_address = $this->request->ipAddress();
628
+		// set the "user agent"
629
+		$this->_user_agent = $this->request->userAgent();
630
+		// now let's retrieve what's in the db
631
+		$session_data = $this->_retrieve_session_data();
632
+		if (! empty($session_data)) {
633
+			// get the current time in UTC
634
+			$this->_time = $this->_time !== null ? $this->_time : time();
635
+			// and reset the session expiration
636
+			$this->_expiration = isset($session_data['expiration'])
637
+				? $session_data['expiration']
638
+				: $this->_time + $this->session_lifespan->inSeconds();
639
+		} else {
640
+			// set initial site access time and the session expiration
641
+			$this->_set_init_access_and_expiration();
642
+			// set referer
643
+			$this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
644
+				$this->request->getServerParam('HTTP_REFERER')
645
+			);
646
+			// no previous session = go back and create one (on top of the data above)
647
+			return false;
648
+		}
649
+		// now the user agent
650
+		if ($session_data['user_agent'] !== $this->_user_agent) {
651
+			return false;
652
+		}
653
+		// wait a minute... how old are you?
654
+		if ($this->_time > $this->_expiration) {
655
+			// yer too old fer me!
656
+			$this->_expired = true;
657
+			// wipe out everything that isn't a default session datum
658
+			$this->clear_session(__CLASS__, __FUNCTION__);
659
+		}
660
+		// make event espresso session data available to plugin
661
+		$this->_session_data = array_merge($this->_session_data, $session_data);
662
+		return true;
663
+	}
664
+
665
+
666
+	/**
667
+	 * _get_session_data
668
+	 * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
669
+	 * databases
670
+	 *
671
+	 * @return array
672
+	 * @throws EE_Error
673
+	 * @throws InvalidArgumentException
674
+	 * @throws InvalidSessionDataException
675
+	 * @throws InvalidDataTypeException
676
+	 * @throws InvalidInterfaceException
677
+	 * @throws RuntimeException
678
+	 */
679
+	protected function _retrieve_session_data()
680
+	{
681
+		$ssn_key = EE_Session::session_id_prefix . $this->_sid;
682
+		try {
683
+			// we're using WP's Transient API to store session data using the PHP session ID as the option name
684
+			$session_data = $this->cache_storage->get($ssn_key, false);
685
+			if (empty($session_data)) {
686
+				return array();
687
+			}
688
+			if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
689
+				$hash_check = $this->cache_storage->get(
690
+					EE_Session::hash_check_prefix . $this->_sid,
691
+					false
692
+				);
693
+				if ($hash_check && $hash_check !== md5($session_data)) {
694
+					EE_Error::add_error(
695
+						sprintf(
696
+							__(
697
+								'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
698
+								'event_espresso'
699
+							),
700
+							EE_Session::session_id_prefix . $this->_sid
701
+						),
702
+						__FILE__,
703
+						__FUNCTION__,
704
+						__LINE__
705
+					);
706
+				}
707
+			}
708
+		} catch (Exception $e) {
709
+			// let's just eat that error for now and attempt to correct any corrupted data
710
+			global $wpdb;
711
+			$row = $wpdb->get_row(
712
+				$wpdb->prepare(
713
+					"SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
714
+					'_transient_' . $ssn_key
715
+				)
716
+			);
717
+			$session_data = is_object($row) ? $row->option_value : null;
718
+			if ($session_data) {
719
+				$session_data = preg_replace_callback(
720
+					'!s:(d+):"(.*?)";!',
721
+					function ($match) {
722
+						return $match[1] === strlen($match[2])
723
+							? $match[0]
724
+							: 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
725
+					},
726
+					$session_data
727
+				);
728
+			}
729
+			$session_data = maybe_unserialize($session_data);
730
+		}
731
+		// in case the data is encoded... try to decode it
732
+		$session_data = $this->encryption instanceof EE_Encryption
733
+			? $this->encryption->base64_string_decode($session_data)
734
+			: $session_data;
735
+		if (! is_array($session_data)) {
736
+			try {
737
+				$session_data = maybe_unserialize($session_data);
738
+			} catch (Exception $e) {
739
+				$msg = esc_html__(
740
+					'An error occurred while attempting to unserialize the session data.',
741
+					'event_espresso'
742
+				);
743
+				$msg .= WP_DEBUG
744
+					? '<br><pre>'
745
+					  . print_r($session_data, true)
746
+					  . '</pre><br>'
747
+					  . $this->find_serialize_error($session_data)
748
+					: '';
749
+				$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
750
+				throw new InvalidSessionDataException($msg, 0, $e);
751
+			}
752
+		}
753
+		// just a check to make sure the session array is indeed an array
754
+		if (! is_array($session_data)) {
755
+			// no?!?! then something is wrong
756
+			$msg = esc_html__(
757
+				'The session data is missing, invalid, or corrupted.',
758
+				'event_espresso'
759
+			);
760
+			$msg .= WP_DEBUG
761
+				? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
762
+				: '';
763
+			$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
764
+			throw new InvalidSessionDataException($msg);
765
+		}
766
+		if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
767
+			$session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
768
+				$session_data['transaction']
769
+			);
770
+		}
771
+		return $session_data;
772
+	}
773
+
774
+
775
+	/**
776
+	 * _generate_session_id
777
+	 * Retrieves the PHP session id either directly from the PHP session,
778
+	 * or from the request array if it was passed in from an AJAX request.
779
+	 * The session id is then salted and hashed (mmm sounds tasty)
780
+	 * so that it can be safely used as a request param
781
+	 *
782
+	 * @return string
783
+	 */
784
+	protected function _generate_session_id()
785
+	{
786
+		// check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
787
+		$session_id = $this->request->requestParamIsSet('EESID')
788
+			? $this->request->getRequestParam('EESID')
789
+			: md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
790
+		return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
791
+	}
792
+
793
+
794
+	/**
795
+	 * _get_sid_salt
796
+	 *
797
+	 * @return string
798
+	 */
799
+	protected function _get_sid_salt()
800
+	{
801
+		// was session id salt already saved to db ?
802
+		if (empty($this->_sid_salt)) {
803
+			// no?  then maybe use WP defined constant
804
+			if (defined('AUTH_SALT')) {
805
+				$this->_sid_salt = AUTH_SALT;
806
+			}
807
+			// if salt doesn't exist or is too short
808
+			if (strlen($this->_sid_salt) < 32) {
809
+				// create a new one
810
+				$this->_sid_salt = wp_generate_password(64);
811
+			}
812
+			// and save it as a permanent session setting
813
+			$this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
814
+		}
815
+		return $this->_sid_salt;
816
+	}
817
+
818
+
819
+	/**
820
+	 * _set_init_access_and_expiration
821
+	 *
822
+	 * @return void
823
+	 */
824
+	protected function _set_init_access_and_expiration()
825
+	{
826
+		$this->_time = time();
827
+		$this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
828
+		// set initial site access time
829
+		$this->_session_data['init_access'] = $this->_time;
830
+		// and the session expiration
831
+		$this->_session_data['expiration'] = $this->_expiration;
832
+	}
833
+
834
+
835
+	/**
836
+	 * @update session data  prior to saving to the db
837
+	 * @param bool $new_session
838
+	 * @return TRUE on success, FALSE on fail
839
+	 * @throws EE_Error
840
+	 * @throws InvalidArgumentException
841
+	 * @throws InvalidDataTypeException
842
+	 * @throws InvalidInterfaceException
843
+	 * @throws ReflectionException
844
+	 */
845
+	public function update($new_session = false)
846
+	{
847
+		$this->_session_data = $this->_session_data !== null
848
+							   && is_array($this->_session_data)
849
+							   && isset($this->_session_data['id'])
850
+			? $this->_session_data
851
+			: array();
852
+		if (empty($this->_session_data)) {
853
+			$this->_set_defaults();
854
+		}
855
+		$session_data = array();
856
+		foreach ($this->_session_data as $key => $value) {
857
+			switch ($key) {
858
+				case 'id':
859
+					// session ID
860
+					$session_data['id'] = $this->_sid;
861
+					break;
862
+				case 'ip_address':
863
+					// visitor ip address
864
+					$session_data['ip_address'] = $this->request->ipAddress();
865
+					break;
866
+				case 'user_agent':
867
+					// visitor user_agent
868
+					$session_data['user_agent'] = $this->_user_agent;
869
+					break;
870
+				case 'init_access':
871
+					$session_data['init_access'] = absint($value);
872
+					break;
873
+				case 'last_access':
874
+					// current access time
875
+					$session_data['last_access'] = $this->_time;
876
+					break;
877
+				case 'expiration':
878
+					// when the session expires
879
+					$session_data['expiration'] = ! empty($this->_expiration)
880
+						? $this->_expiration
881
+						: $session_data['init_access'] + $this->session_lifespan->inSeconds();
882
+					break;
883
+				case 'user_id':
884
+					// current user if logged in
885
+					$session_data['user_id'] = $this->_wp_user_id();
886
+					break;
887
+				case 'pages_visited':
888
+					$page_visit = $this->_get_page_visit();
889
+					if ($page_visit) {
890
+						// set pages visited where the first will be the http referrer
891
+						$this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
892
+						// we'll only save the last 10 page visits.
893
+						$session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
894
+					}
895
+					break;
896
+				default:
897
+					// carry any other data over
898
+					$session_data[ $key ] = $this->_session_data[ $key ];
899
+			}
900
+		}
901
+		$this->_session_data = $session_data;
902
+		// creating a new session does not require saving to the db just yet
903
+		if (! $new_session) {
904
+			// ready? let's save
905
+			if ($this->_save_session_to_db()) {
906
+				return true;
907
+			}
908
+			return false;
909
+		}
910
+		// meh, why not?
911
+		return true;
912
+	}
913
+
914
+
915
+	/**
916
+	 * @create session data array
917
+	 * @return bool
918
+	 * @throws EE_Error
919
+	 * @throws InvalidArgumentException
920
+	 * @throws InvalidDataTypeException
921
+	 * @throws InvalidInterfaceException
922
+	 * @throws ReflectionException
923
+	 */
924
+	private function _create_espresso_session()
925
+	{
926
+		do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
927
+		// use the update function for now with $new_session arg set to TRUE
928
+		return $this->update(true) ? true : false;
929
+	}
930
+
931
+	/**
932
+	 * Detects if there is anything worth saving in the session (eg the cart is a good one, notices are pretty good
933
+	 * too). This is used when determining if we want to save the session or not.
934
+	 * @since 4.9.67.p
935
+	 * @return bool
936
+	 */
937
+	private function sessionHasStuffWorthSaving()
938
+	{
939
+		return $this->save_state === EE_Session::SAVE_STATE_DIRTY
940
+			   // we may want to eventually remove the following
941
+			   // on the assumption that the above check is enough
942
+			   || $this->cart() instanceof EE_Cart
943
+			   || (
944
+				   isset($this->_session_data['ee_notices'])
945
+				   && (
946
+					   ! empty($this->_session_data['ee_notices']['attention'])
947
+					   || ! empty($this->_session_data['ee_notices']['errors'])
948
+					   || ! empty($this->_session_data['ee_notices']['success'])
949
+				   )
950
+			   );
951
+	}
952
+
953
+
954
+	/**
955
+	 * _save_session_to_db
956
+	 *
957
+	 * @param bool $clear_session
958
+	 * @return string
959
+	 * @throws EE_Error
960
+	 * @throws InvalidArgumentException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws InvalidInterfaceException
963
+	 * @throws ReflectionException
964
+	 */
965
+	private function _save_session_to_db($clear_session = false)
966
+	{
967
+		// don't save sessions for crawlers
968
+		// and unless we're deleting the session data, don't save anything if there isn't a cart
969
+		if ($this->request->isBot()
970
+			|| (
971
+				! $clear_session
972
+				&& ! $this->sessionHasStuffWorthSaving()
973
+				&& apply_filters('FHEE__EE_Session___save_session_to_db__abort_session_save', true)
974
+			)
975
+		) {
976
+			return false;
977
+		}
978
+		$transaction = $this->transaction();
979
+		if ($transaction instanceof EE_Transaction) {
980
+			if (! $transaction->ID()) {
981
+				$transaction->save();
982
+			}
983
+			$this->_session_data['transaction'] = $transaction->ID();
984
+		}
985
+		// then serialize all of our session data
986
+		$session_data = serialize($this->_session_data);
987
+		// do we need to also encode it to avoid corrupted data when saved to the db?
988
+		$session_data = $this->_use_encryption
989
+			? $this->encryption->base64_string_encode($session_data)
990
+			: $session_data;
991
+		// maybe save hash check
992
+		if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
993
+			$this->cache_storage->add(
994
+				EE_Session::hash_check_prefix . $this->_sid,
995
+				md5($session_data),
996
+				$this->session_lifespan->inSeconds()
997
+			);
998
+		}
999
+		// we're using the Transient API for storing session data,
1000
+		$saved = $this->cache_storage->add(
1001
+			EE_Session::session_id_prefix . $this->_sid,
1002
+			$session_data,
1003
+			$this->session_lifespan->inSeconds()
1004
+		);
1005
+		$this->setSaveState(EE_Session::SAVE_STATE_CLEAN);
1006
+		return $saved;
1007
+	}
1008
+
1009
+
1010
+	/**
1011
+	 * @get    the full page request the visitor is accessing
1012
+	 * @return string
1013
+	 */
1014
+	public function _get_page_visit()
1015
+	{
1016
+		$page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1017
+		// check for request url
1018
+		if ($this->request->serverParamIsSet('REQUEST_URI')) {
1019
+			$page_id = '?';
1020
+			$e_reg = '';
1021
+			$request_uri = $this->request->getServerParam('REQUEST_URI');
1022
+			$ru_bits = explode('?', $request_uri);
1023
+			$request_uri = $ru_bits[0];
1024
+			$http_host = $this->request->getServerParam('HTTP_HOST');
1025
+			// check for page_id in SERVER REQUEST
1026
+			if ($this->request->requestParamIsSet('page_id')) {
1027
+				// rebuild $e_reg without any of the extra parameters
1028
+				$page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1029
+			}
1030
+			// check for $e_reg in SERVER REQUEST
1031
+			if ($this->request->requestParamIsSet('ee')) {
1032
+				// rebuild $e_reg without any of the extra parameters
1033
+				$e_reg = 'ee=' . $this->request->getRequestParam('ee');
1034
+			}
1035
+			$page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1036
+		}
1037
+		return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
1038
+	}
1039
+
1040
+
1041
+	/**
1042
+	 * @the    current wp user id
1043
+	 * @return int
1044
+	 */
1045
+	public function _wp_user_id()
1046
+	{
1047
+		// if I need to explain the following lines of code, then you shouldn't be looking at this!
1048
+		$this->_wp_user_id = get_current_user_id();
1049
+		return $this->_wp_user_id;
1050
+	}
1051
+
1052
+
1053
+	/**
1054
+	 * Clear EE_Session data
1055
+	 *
1056
+	 * @param string $class
1057
+	 * @param string $function
1058
+	 * @return void
1059
+	 * @throws EE_Error
1060
+	 * @throws InvalidArgumentException
1061
+	 * @throws InvalidDataTypeException
1062
+	 * @throws InvalidInterfaceException
1063
+	 * @throws ReflectionException
1064
+	 */
1065
+	public function clear_session($class = '', $function = '')
1066
+	{
1067 1067
 //         echo '
1068 1068
 // <h3 style="color:#999;line-height:.9em;">
1069 1069
 // <span style="color:#2EA2CC">' . __CLASS__ . '</span>::<span style="color:#E76700">' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )</span><br/>
1070 1070
 // <span style="font-size:9px;font-weight:normal;">' . __FILE__ . '</span>    <b style="font-size:10px;">  ' . __LINE__ . ' </b>
1071 1071
 // </h3>';
1072
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1073
-        $this->reset_cart();
1074
-        $this->reset_checkout();
1075
-        $this->reset_transaction();
1076
-        // wipe out everything that isn't a default session datum
1077
-        $this->reset_data(array_keys($this->_session_data));
1078
-        // reset initial site access time and the session expiration
1079
-        $this->_set_init_access_and_expiration();
1080
-        $this->setSaveState();
1081
-        $this->_save_session_to_db(true);
1082
-    }
1083
-
1084
-
1085
-    /**
1086
-     * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1087
-     *
1088
-     * @param array|mixed $data_to_reset
1089
-     * @param bool        $show_all_notices
1090
-     * @return bool
1091
-     */
1092
-    public function reset_data($data_to_reset = array(), $show_all_notices = false)
1093
-    {
1094
-        // if $data_to_reset is not in an array, then put it in one
1095
-        if (! is_array($data_to_reset)) {
1096
-            $data_to_reset = array($data_to_reset);
1097
-        }
1098
-        // nothing ??? go home!
1099
-        if (empty($data_to_reset)) {
1100
-            EE_Error::add_error(
1101
-                __(
1102
-                    'No session data could be reset, because no session var name was provided.',
1103
-                    'event_espresso'
1104
-                ),
1105
-                __FILE__,
1106
-                __FUNCTION__,
1107
-                __LINE__
1108
-            );
1109
-            return false;
1110
-        }
1111
-        $return_value = true;
1112
-        // since $data_to_reset is an array, cycle through the values
1113
-        foreach ($data_to_reset as $reset) {
1114
-            // first check to make sure it is a valid session var
1115
-            if (isset($this->_session_data[ $reset ])) {
1116
-                // then check to make sure it is not a default var
1117
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1118
-                    // remove session var
1119
-                    unset($this->_session_data[ $reset ]);
1120
-                    $this->setSaveState();
1121
-                    if ($show_all_notices) {
1122
-                        EE_Error::add_success(
1123
-                            sprintf(
1124
-                                __('The session variable %s was removed.', 'event_espresso'),
1125
-                                $reset
1126
-                            ),
1127
-                            __FILE__,
1128
-                            __FUNCTION__,
1129
-                            __LINE__
1130
-                        );
1131
-                    }
1132
-                } else {
1133
-                    // yeeeeeeeeerrrrrrrrrrr OUT !!!!
1134
-                    if ($show_all_notices) {
1135
-                        EE_Error::add_error(
1136
-                            sprintf(
1137
-                                __(
1138
-                                    'Sorry! %s is a default session datum and can not be reset.',
1139
-                                    'event_espresso'
1140
-                                ),
1141
-                                $reset
1142
-                            ),
1143
-                            __FILE__,
1144
-                            __FUNCTION__,
1145
-                            __LINE__
1146
-                        );
1147
-                    }
1148
-                    $return_value = false;
1149
-                }
1150
-            } elseif ($show_all_notices) {
1151
-                // oops! that session var does not exist!
1152
-                EE_Error::add_error(
1153
-                    sprintf(
1154
-                        __(
1155
-                            'The session item provided, %s, is invalid or does not exist.',
1156
-                            'event_espresso'
1157
-                        ),
1158
-                        $reset
1159
-                    ),
1160
-                    __FILE__,
1161
-                    __FUNCTION__,
1162
-                    __LINE__
1163
-                );
1164
-                $return_value = false;
1165
-            }
1166
-        } // end of foreach
1167
-        return $return_value;
1168
-    }
1169
-
1170
-
1171
-    /**
1172
-     *   wp_loaded
1173
-     *
1174
-     * @throws EE_Error
1175
-     * @throws InvalidDataTypeException
1176
-     * @throws InvalidInterfaceException
1177
-     * @throws InvalidArgumentException
1178
-     * @throws ReflectionException
1179
-     */
1180
-    public function wp_loaded()
1181
-    {
1182
-        if ($this->request->requestParamIsSet('clear_session')) {
1183
-            $this->clear_session(__CLASS__, __FUNCTION__);
1184
-        }
1185
-    }
1186
-
1187
-
1188
-    /**
1189
-     * Used to reset the entire object (for tests).
1190
-     *
1191
-     * @since 4.3.0
1192
-     * @throws EE_Error
1193
-     * @throws InvalidDataTypeException
1194
-     * @throws InvalidInterfaceException
1195
-     * @throws InvalidArgumentException
1196
-     * @throws ReflectionException
1197
-     */
1198
-    public function reset_instance()
1199
-    {
1200
-        $this->clear_session();
1201
-        self::$_instance = null;
1202
-    }
1203
-
1204
-
1205
-    public function configure_garbage_collection_filters()
1206
-    {
1207
-        // run old filter we had for controlling session cleanup
1208
-        $expired_session_transient_delete_query_limit = absint(
1209
-            apply_filters(
1210
-                'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1211
-                50
1212
-            )
1213
-        );
1214
-        // is there a value? or one that is different than the default 50 records?
1215
-        if ($expired_session_transient_delete_query_limit === 0) {
1216
-            // hook into TransientCacheStorage in case Session cleanup was turned off
1217
-            add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1218
-        } elseif ($expired_session_transient_delete_query_limit !== 50) {
1219
-            // or use that for the new transient cleanup query limit
1220
-            add_filter(
1221
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1222
-                function () use ($expired_session_transient_delete_query_limit) {
1223
-                    return $expired_session_transient_delete_query_limit;
1224
-                }
1225
-            );
1226
-        }
1227
-    }
1228
-
1229
-
1230
-    /**
1231
-     * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1232
-     * @param $data1
1233
-     * @return string
1234
-     */
1235
-    private function find_serialize_error($data1)
1236
-    {
1237
-        $error = '<pre>';
1238
-        $data2 = preg_replace_callback(
1239
-            '!s:(\d+):"(.*?)";!',
1240
-            function ($match) {
1241
-                return ($match[1] === strlen($match[2]))
1242
-                    ? $match[0]
1243
-                    : 's:'
1244
-                      . strlen($match[2])
1245
-                      . ':"'
1246
-                      . $match[2]
1247
-                      . '";';
1248
-            },
1249
-            $data1
1250
-        );
1251
-        $max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1252
-        $error .= $data1 . PHP_EOL;
1253
-        $error .= $data2 . PHP_EOL;
1254
-        for ($i = 0; $i < $max; $i++) {
1255
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1256
-                $error .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1257
-                $error .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1258
-                $error .= "\t-> Line Number = $i" . PHP_EOL;
1259
-                $start = ($i - 20);
1260
-                $start = ($start < 0) ? 0 : $start;
1261
-                $length = 40;
1262
-                $point = $max - $i;
1263
-                if ($point < 20) {
1264
-                    $rlength = 1;
1265
-                    $rpoint = -$point;
1266
-                } else {
1267
-                    $rpoint = $length - 20;
1268
-                    $rlength = 1;
1269
-                }
1270
-                $error .= "\t-> Section Data1  = ";
1271
-                $error .= substr_replace(
1272
-                    substr($data1, $start, $length),
1273
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1274
-                    $rpoint,
1275
-                    $rlength
1276
-                );
1277
-                $error .= PHP_EOL;
1278
-                $error .= "\t-> Section Data2  = ";
1279
-                $error .= substr_replace(
1280
-                    substr($data2, $start, $length),
1281
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1282
-                    $rpoint,
1283
-                    $rlength
1284
-                );
1285
-                $error .= PHP_EOL;
1286
-            }
1287
-        }
1288
-        $error .= '</pre>';
1289
-        return $error;
1290
-    }
1291
-
1292
-
1293
-    /**
1294
-     * Saves an  array of settings used for configuring aspects of session behaviour
1295
-     *
1296
-     * @param array $updated_settings
1297
-     */
1298
-    private function updateSessionSettings(array $updated_settings = array())
1299
-    {
1300
-        // add existing settings, but only if not included in incoming $updated_settings array
1301
-        $updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1302
-        update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1303
-    }
1304
-
1305
-
1306
-    /**
1307
-     * garbage_collection
1308
-     */
1309
-    public function garbageCollection()
1310
-    {
1311
-        // only perform during regular requests if last garbage collection was over an hour ago
1312
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1313
-            $this->_last_gc = time();
1314
-            $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1315
-            /** @type WPDB $wpdb */
1316
-            global $wpdb;
1317
-            // filter the query limit. Set to 0 to turn off garbage collection
1318
-            $expired_session_transient_delete_query_limit = absint(
1319
-                apply_filters(
1320
-                    'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1321
-                    50
1322
-                )
1323
-            );
1324
-            // non-zero LIMIT means take out the trash
1325
-            if ($expired_session_transient_delete_query_limit) {
1326
-                $session_key = str_replace('_', '\_', EE_Session::session_id_prefix);
1327
-                $hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1328
-                // since transient expiration timestamps are set in the future, we can compare against NOW
1329
-                // but we only want to pick up any trash that's been around for more than a day
1330
-                $expiration = time() - DAY_IN_SECONDS;
1331
-                $SQL = "
1072
+		do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1073
+		$this->reset_cart();
1074
+		$this->reset_checkout();
1075
+		$this->reset_transaction();
1076
+		// wipe out everything that isn't a default session datum
1077
+		$this->reset_data(array_keys($this->_session_data));
1078
+		// reset initial site access time and the session expiration
1079
+		$this->_set_init_access_and_expiration();
1080
+		$this->setSaveState();
1081
+		$this->_save_session_to_db(true);
1082
+	}
1083
+
1084
+
1085
+	/**
1086
+	 * resets all non-default session vars. Returns TRUE on success, FALSE on fail
1087
+	 *
1088
+	 * @param array|mixed $data_to_reset
1089
+	 * @param bool        $show_all_notices
1090
+	 * @return bool
1091
+	 */
1092
+	public function reset_data($data_to_reset = array(), $show_all_notices = false)
1093
+	{
1094
+		// if $data_to_reset is not in an array, then put it in one
1095
+		if (! is_array($data_to_reset)) {
1096
+			$data_to_reset = array($data_to_reset);
1097
+		}
1098
+		// nothing ??? go home!
1099
+		if (empty($data_to_reset)) {
1100
+			EE_Error::add_error(
1101
+				__(
1102
+					'No session data could be reset, because no session var name was provided.',
1103
+					'event_espresso'
1104
+				),
1105
+				__FILE__,
1106
+				__FUNCTION__,
1107
+				__LINE__
1108
+			);
1109
+			return false;
1110
+		}
1111
+		$return_value = true;
1112
+		// since $data_to_reset is an array, cycle through the values
1113
+		foreach ($data_to_reset as $reset) {
1114
+			// first check to make sure it is a valid session var
1115
+			if (isset($this->_session_data[ $reset ])) {
1116
+				// then check to make sure it is not a default var
1117
+				if (! array_key_exists($reset, $this->_default_session_vars)) {
1118
+					// remove session var
1119
+					unset($this->_session_data[ $reset ]);
1120
+					$this->setSaveState();
1121
+					if ($show_all_notices) {
1122
+						EE_Error::add_success(
1123
+							sprintf(
1124
+								__('The session variable %s was removed.', 'event_espresso'),
1125
+								$reset
1126
+							),
1127
+							__FILE__,
1128
+							__FUNCTION__,
1129
+							__LINE__
1130
+						);
1131
+					}
1132
+				} else {
1133
+					// yeeeeeeeeerrrrrrrrrrr OUT !!!!
1134
+					if ($show_all_notices) {
1135
+						EE_Error::add_error(
1136
+							sprintf(
1137
+								__(
1138
+									'Sorry! %s is a default session datum and can not be reset.',
1139
+									'event_espresso'
1140
+								),
1141
+								$reset
1142
+							),
1143
+							__FILE__,
1144
+							__FUNCTION__,
1145
+							__LINE__
1146
+						);
1147
+					}
1148
+					$return_value = false;
1149
+				}
1150
+			} elseif ($show_all_notices) {
1151
+				// oops! that session var does not exist!
1152
+				EE_Error::add_error(
1153
+					sprintf(
1154
+						__(
1155
+							'The session item provided, %s, is invalid or does not exist.',
1156
+							'event_espresso'
1157
+						),
1158
+						$reset
1159
+					),
1160
+					__FILE__,
1161
+					__FUNCTION__,
1162
+					__LINE__
1163
+				);
1164
+				$return_value = false;
1165
+			}
1166
+		} // end of foreach
1167
+		return $return_value;
1168
+	}
1169
+
1170
+
1171
+	/**
1172
+	 *   wp_loaded
1173
+	 *
1174
+	 * @throws EE_Error
1175
+	 * @throws InvalidDataTypeException
1176
+	 * @throws InvalidInterfaceException
1177
+	 * @throws InvalidArgumentException
1178
+	 * @throws ReflectionException
1179
+	 */
1180
+	public function wp_loaded()
1181
+	{
1182
+		if ($this->request->requestParamIsSet('clear_session')) {
1183
+			$this->clear_session(__CLASS__, __FUNCTION__);
1184
+		}
1185
+	}
1186
+
1187
+
1188
+	/**
1189
+	 * Used to reset the entire object (for tests).
1190
+	 *
1191
+	 * @since 4.3.0
1192
+	 * @throws EE_Error
1193
+	 * @throws InvalidDataTypeException
1194
+	 * @throws InvalidInterfaceException
1195
+	 * @throws InvalidArgumentException
1196
+	 * @throws ReflectionException
1197
+	 */
1198
+	public function reset_instance()
1199
+	{
1200
+		$this->clear_session();
1201
+		self::$_instance = null;
1202
+	}
1203
+
1204
+
1205
+	public function configure_garbage_collection_filters()
1206
+	{
1207
+		// run old filter we had for controlling session cleanup
1208
+		$expired_session_transient_delete_query_limit = absint(
1209
+			apply_filters(
1210
+				'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1211
+				50
1212
+			)
1213
+		);
1214
+		// is there a value? or one that is different than the default 50 records?
1215
+		if ($expired_session_transient_delete_query_limit === 0) {
1216
+			// hook into TransientCacheStorage in case Session cleanup was turned off
1217
+			add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1218
+		} elseif ($expired_session_transient_delete_query_limit !== 50) {
1219
+			// or use that for the new transient cleanup query limit
1220
+			add_filter(
1221
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1222
+				function () use ($expired_session_transient_delete_query_limit) {
1223
+					return $expired_session_transient_delete_query_limit;
1224
+				}
1225
+			);
1226
+		}
1227
+	}
1228
+
1229
+
1230
+	/**
1231
+	 * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1232
+	 * @param $data1
1233
+	 * @return string
1234
+	 */
1235
+	private function find_serialize_error($data1)
1236
+	{
1237
+		$error = '<pre>';
1238
+		$data2 = preg_replace_callback(
1239
+			'!s:(\d+):"(.*?)";!',
1240
+			function ($match) {
1241
+				return ($match[1] === strlen($match[2]))
1242
+					? $match[0]
1243
+					: 's:'
1244
+					  . strlen($match[2])
1245
+					  . ':"'
1246
+					  . $match[2]
1247
+					  . '";';
1248
+			},
1249
+			$data1
1250
+		);
1251
+		$max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1252
+		$error .= $data1 . PHP_EOL;
1253
+		$error .= $data2 . PHP_EOL;
1254
+		for ($i = 0; $i < $max; $i++) {
1255
+			if (@$data1[ $i ] !== @$data2[ $i ]) {
1256
+				$error .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1257
+				$error .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1258
+				$error .= "\t-> Line Number = $i" . PHP_EOL;
1259
+				$start = ($i - 20);
1260
+				$start = ($start < 0) ? 0 : $start;
1261
+				$length = 40;
1262
+				$point = $max - $i;
1263
+				if ($point < 20) {
1264
+					$rlength = 1;
1265
+					$rpoint = -$point;
1266
+				} else {
1267
+					$rpoint = $length - 20;
1268
+					$rlength = 1;
1269
+				}
1270
+				$error .= "\t-> Section Data1  = ";
1271
+				$error .= substr_replace(
1272
+					substr($data1, $start, $length),
1273
+					"<b style=\"color:green\">{$data1[ $i ]}</b>",
1274
+					$rpoint,
1275
+					$rlength
1276
+				);
1277
+				$error .= PHP_EOL;
1278
+				$error .= "\t-> Section Data2  = ";
1279
+				$error .= substr_replace(
1280
+					substr($data2, $start, $length),
1281
+					"<b style=\"color:red\">{$data2[ $i ]}</b>",
1282
+					$rpoint,
1283
+					$rlength
1284
+				);
1285
+				$error .= PHP_EOL;
1286
+			}
1287
+		}
1288
+		$error .= '</pre>';
1289
+		return $error;
1290
+	}
1291
+
1292
+
1293
+	/**
1294
+	 * Saves an  array of settings used for configuring aspects of session behaviour
1295
+	 *
1296
+	 * @param array $updated_settings
1297
+	 */
1298
+	private function updateSessionSettings(array $updated_settings = array())
1299
+	{
1300
+		// add existing settings, but only if not included in incoming $updated_settings array
1301
+		$updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1302
+		update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1303
+	}
1304
+
1305
+
1306
+	/**
1307
+	 * garbage_collection
1308
+	 */
1309
+	public function garbageCollection()
1310
+	{
1311
+		// only perform during regular requests if last garbage collection was over an hour ago
1312
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1313
+			$this->_last_gc = time();
1314
+			$this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1315
+			/** @type WPDB $wpdb */
1316
+			global $wpdb;
1317
+			// filter the query limit. Set to 0 to turn off garbage collection
1318
+			$expired_session_transient_delete_query_limit = absint(
1319
+				apply_filters(
1320
+					'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1321
+					50
1322
+				)
1323
+			);
1324
+			// non-zero LIMIT means take out the trash
1325
+			if ($expired_session_transient_delete_query_limit) {
1326
+				$session_key = str_replace('_', '\_', EE_Session::session_id_prefix);
1327
+				$hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1328
+				// since transient expiration timestamps are set in the future, we can compare against NOW
1329
+				// but we only want to pick up any trash that's been around for more than a day
1330
+				$expiration = time() - DAY_IN_SECONDS;
1331
+				$SQL = "
1332 1332
                     SELECT option_name
1333 1333
                     FROM {$wpdb->options}
1334 1334
                     WHERE
@@ -1337,17 +1337,17 @@  discard block
 block discarded – undo
1337 1337
                     AND option_value < {$expiration}
1338 1338
                     LIMIT {$expired_session_transient_delete_query_limit}
1339 1339
                 ";
1340
-                // produces something like:
1341
-                // SELECT option_name FROM wp_options
1342
-                // WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1343
-                // OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1344
-                // AND option_value < 1508368198 LIMIT 50
1345
-                $expired_sessions = $wpdb->get_col($SQL);
1346
-                // valid results?
1347
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1348
-                    $this->cache_storage->deleteMany($expired_sessions, true);
1349
-                }
1350
-            }
1351
-        }
1352
-    }
1340
+				// produces something like:
1341
+				// SELECT option_name FROM wp_options
1342
+				// WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1343
+				// OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1344
+				// AND option_value < 1508368198 LIMIT 50
1345
+				$expired_sessions = $wpdb->get_col($SQL);
1346
+				// valid results?
1347
+				if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1348
+					$this->cache_storage->deleteMany($expired_sessions, true);
1349
+				}
1350
+			}
1351
+		}
1352
+	}
1353 1353
 }
Please login to merge, or discard this patch.
Spacing   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
         // check if class object is instantiated
204 204
         // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
205 205
         // add_filter( 'FHEE_load_EE_Session', '__return_false' );
206
-        if (! self::$_instance instanceof EE_Session
206
+        if ( ! self::$_instance instanceof EE_Session
207 207
             && $cache_storage instanceof CacheStorageInterface
208 208
             && $lifespan instanceof SessionLifespan
209 209
             && $request instanceof RequestInterface
@@ -245,22 +245,22 @@  discard block
 block discarded – undo
245 245
         // but prior to the 'AHEE__EE_System__core_loaded_and_ready' hook
246 246
         // (which currently fires on the init hook at priority 9),
247 247
         // can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
248
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
248
+        if ( ! apply_filters('FHEE_load_EE_Session', true)) {
249 249
             return;
250 250
         }
251 251
         $this->session_start_handler = $session_start_handler;
252 252
         $this->session_lifespan = $lifespan;
253 253
         $this->request = $request;
254
-        if (! defined('ESPRESSO_SESSION')) {
254
+        if ( ! defined('ESPRESSO_SESSION')) {
255 255
             define('ESPRESSO_SESSION', true);
256 256
         }
257 257
         // retrieve session options from db
258 258
         $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
259
-        if (! empty($session_settings)) {
259
+        if ( ! empty($session_settings)) {
260 260
             // cycle though existing session options
261 261
             foreach ($session_settings as $var_name => $session_setting) {
262 262
                 // set values for class properties
263
-                $var_name = '_' . $var_name;
263
+                $var_name = '_'.$var_name;
264 264
                 $this->{$var_name} = $session_setting;
265 265
             }
266 266
         }
@@ -321,7 +321,7 @@  discard block
 block discarded – undo
321 321
     public function open_session()
322 322
     {
323 323
         // check for existing session and retrieve it from db
324
-        if (! $this->_espresso_session()) {
324
+        if ( ! $this->_espresso_session()) {
325 325
             // or just start a new one
326 326
             $this->_create_espresso_session();
327 327
         }
@@ -398,7 +398,7 @@  discard block
 block discarded – undo
398 398
             EE_Session::SAVE_STATE_CLEAN,
399 399
             EE_Session::SAVE_STATE_DIRTY,
400 400
         ];
401
-        if (! in_array($save_state, $valid_save_states, true)) {
401
+        if ( ! in_array($save_state, $valid_save_states, true)) {
402 402
             $save_state = EE_Session::SAVE_STATE_DIRTY;
403 403
         }
404 404
         $this->save_state = $save_state;
@@ -416,9 +416,9 @@  discard block
 block discarded – undo
416 416
         // set some defaults
417 417
         foreach ($this->_default_session_vars as $key => $default_var) {
418 418
             if (is_array($default_var)) {
419
-                $this->_session_data[ $key ] = array();
419
+                $this->_session_data[$key] = array();
420 420
             } else {
421
-                $this->_session_data[ $key ] = '';
421
+                $this->_session_data[$key] = '';
422 422
             }
423 423
         }
424 424
     }
@@ -554,8 +554,8 @@  discard block
 block discarded – undo
554 554
             $this->reset_checkout();
555 555
             $this->reset_transaction();
556 556
         }
557
-        if (! empty($key)) {
558
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
557
+        if ( ! empty($key)) {
558
+            return isset($this->_session_data[$key]) ? $this->_session_data[$key] : null;
559 559
         }
560 560
         return $this->_session_data;
561 561
     }
@@ -583,7 +583,7 @@  discard block
 block discarded – undo
583 583
             return false;
584 584
         }
585 585
         foreach ($data as $key => $value) {
586
-            if (isset($this->_default_session_vars[ $key ])) {
586
+            if (isset($this->_default_session_vars[$key])) {
587 587
                 EE_Error::add_error(
588 588
                     sprintf(
589 589
                         esc_html__(
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
                 );
599 599
                 return false;
600 600
             }
601
-            $this->_session_data[ $key ] = $value;
601
+            $this->_session_data[$key] = $value;
602 602
             $this->setSaveState();
603 603
         }
604 604
         return true;
@@ -629,7 +629,7 @@  discard block
 block discarded – undo
629 629
         $this->_user_agent = $this->request->userAgent();
630 630
         // now let's retrieve what's in the db
631 631
         $session_data = $this->_retrieve_session_data();
632
-        if (! empty($session_data)) {
632
+        if ( ! empty($session_data)) {
633 633
             // get the current time in UTC
634 634
             $this->_time = $this->_time !== null ? $this->_time : time();
635 635
             // and reset the session expiration
@@ -640,7 +640,7 @@  discard block
 block discarded – undo
640 640
             // set initial site access time and the session expiration
641 641
             $this->_set_init_access_and_expiration();
642 642
             // set referer
643
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = esc_attr(
643
+            $this->_session_data['pages_visited'][$this->_session_data['init_access']] = esc_attr(
644 644
                 $this->request->getServerParam('HTTP_REFERER')
645 645
             );
646 646
             // no previous session = go back and create one (on top of the data above)
@@ -678,7 +678,7 @@  discard block
 block discarded – undo
678 678
      */
679 679
     protected function _retrieve_session_data()
680 680
     {
681
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
681
+        $ssn_key = EE_Session::session_id_prefix.$this->_sid;
682 682
         try {
683 683
             // we're using WP's Transient API to store session data using the PHP session ID as the option name
684 684
             $session_data = $this->cache_storage->get($ssn_key, false);
@@ -687,7 +687,7 @@  discard block
 block discarded – undo
687 687
             }
688 688
             if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
689 689
                 $hash_check = $this->cache_storage->get(
690
-                    EE_Session::hash_check_prefix . $this->_sid,
690
+                    EE_Session::hash_check_prefix.$this->_sid,
691 691
                     false
692 692
                 );
693 693
                 if ($hash_check && $hash_check !== md5($session_data)) {
@@ -697,7 +697,7 @@  discard block
 block discarded – undo
697 697
                                 'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
698 698
                                 'event_espresso'
699 699
                             ),
700
-                            EE_Session::session_id_prefix . $this->_sid
700
+                            EE_Session::session_id_prefix.$this->_sid
701 701
                         ),
702 702
                         __FILE__,
703 703
                         __FUNCTION__,
@@ -711,17 +711,17 @@  discard block
 block discarded – undo
711 711
             $row = $wpdb->get_row(
712 712
                 $wpdb->prepare(
713 713
                     "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
714
-                    '_transient_' . $ssn_key
714
+                    '_transient_'.$ssn_key
715 715
                 )
716 716
             );
717 717
             $session_data = is_object($row) ? $row->option_value : null;
718 718
             if ($session_data) {
719 719
                 $session_data = preg_replace_callback(
720 720
                     '!s:(d+):"(.*?)";!',
721
-                    function ($match) {
721
+                    function($match) {
722 722
                         return $match[1] === strlen($match[2])
723 723
                             ? $match[0]
724
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
724
+                            : 's:'.strlen($match[2]).':"'.$match[2].'";';
725 725
                     },
726 726
                     $session_data
727 727
                 );
@@ -732,7 +732,7 @@  discard block
 block discarded – undo
732 732
         $session_data = $this->encryption instanceof EE_Encryption
733 733
             ? $this->encryption->base64_string_decode($session_data)
734 734
             : $session_data;
735
-        if (! is_array($session_data)) {
735
+        if ( ! is_array($session_data)) {
736 736
             try {
737 737
                 $session_data = maybe_unserialize($session_data);
738 738
             } catch (Exception $e) {
@@ -746,21 +746,21 @@  discard block
 block discarded – undo
746 746
                       . '</pre><br>'
747 747
                       . $this->find_serialize_error($session_data)
748 748
                     : '';
749
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
749
+                $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
750 750
                 throw new InvalidSessionDataException($msg, 0, $e);
751 751
             }
752 752
         }
753 753
         // just a check to make sure the session array is indeed an array
754
-        if (! is_array($session_data)) {
754
+        if ( ! is_array($session_data)) {
755 755
             // no?!?! then something is wrong
756 756
             $msg = esc_html__(
757 757
                 'The session data is missing, invalid, or corrupted.',
758 758
                 'event_espresso'
759 759
             );
760 760
             $msg .= WP_DEBUG
761
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
761
+                ? '<br><pre>'.print_r($session_data, true).'</pre><br>'.$this->find_serialize_error($session_data)
762 762
                 : '';
763
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
763
+            $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
764 764
             throw new InvalidSessionDataException($msg);
765 765
         }
766 766
         if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
@@ -786,7 +786,7 @@  discard block
 block discarded – undo
786 786
         // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
787 787
         $session_id = $this->request->requestParamIsSet('EESID')
788 788
             ? $this->request->getRequestParam('EESID')
789
-            : md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
789
+            : md5(session_id().get_current_blog_id().$this->_get_sid_salt());
790 790
         return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
791 791
     }
792 792
 
@@ -888,19 +888,19 @@  discard block
 block discarded – undo
888 888
                     $page_visit = $this->_get_page_visit();
889 889
                     if ($page_visit) {
890 890
                         // set pages visited where the first will be the http referrer
891
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
891
+                        $this->_session_data['pages_visited'][$this->_time] = $page_visit;
892 892
                         // we'll only save the last 10 page visits.
893 893
                         $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
894 894
                     }
895 895
                     break;
896 896
                 default:
897 897
                     // carry any other data over
898
-                    $session_data[ $key ] = $this->_session_data[ $key ];
898
+                    $session_data[$key] = $this->_session_data[$key];
899 899
             }
900 900
         }
901 901
         $this->_session_data = $session_data;
902 902
         // creating a new session does not require saving to the db just yet
903
-        if (! $new_session) {
903
+        if ( ! $new_session) {
904 904
             // ready? let's save
905 905
             if ($this->_save_session_to_db()) {
906 906
                 return true;
@@ -977,7 +977,7 @@  discard block
 block discarded – undo
977 977
         }
978 978
         $transaction = $this->transaction();
979 979
         if ($transaction instanceof EE_Transaction) {
980
-            if (! $transaction->ID()) {
980
+            if ( ! $transaction->ID()) {
981 981
                 $transaction->save();
982 982
             }
983 983
             $this->_session_data['transaction'] = $transaction->ID();
@@ -991,14 +991,14 @@  discard block
 block discarded – undo
991 991
         // maybe save hash check
992 992
         if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
993 993
             $this->cache_storage->add(
994
-                EE_Session::hash_check_prefix . $this->_sid,
994
+                EE_Session::hash_check_prefix.$this->_sid,
995 995
                 md5($session_data),
996 996
                 $this->session_lifespan->inSeconds()
997 997
             );
998 998
         }
999 999
         // we're using the Transient API for storing session data,
1000 1000
         $saved = $this->cache_storage->add(
1001
-            EE_Session::session_id_prefix . $this->_sid,
1001
+            EE_Session::session_id_prefix.$this->_sid,
1002 1002
             $session_data,
1003 1003
             $this->session_lifespan->inSeconds()
1004 1004
         );
@@ -1013,7 +1013,7 @@  discard block
 block discarded – undo
1013 1013
      */
1014 1014
     public function _get_page_visit()
1015 1015
     {
1016
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
1016
+        $page_visit = home_url('/').'wp-admin/admin-ajax.php';
1017 1017
         // check for request url
1018 1018
         if ($this->request->serverParamIsSet('REQUEST_URI')) {
1019 1019
             $page_id = '?';
@@ -1025,14 +1025,14 @@  discard block
 block discarded – undo
1025 1025
             // check for page_id in SERVER REQUEST
1026 1026
             if ($this->request->requestParamIsSet('page_id')) {
1027 1027
                 // rebuild $e_reg without any of the extra parameters
1028
-                $page_id .= 'page_id=' . $this->request->getRequestParam('page_id', 0, 'int') . '&amp;';
1028
+                $page_id .= 'page_id='.$this->request->getRequestParam('page_id', 0, 'int').'&amp;';
1029 1029
             }
1030 1030
             // check for $e_reg in SERVER REQUEST
1031 1031
             if ($this->request->requestParamIsSet('ee')) {
1032 1032
                 // rebuild $e_reg without any of the extra parameters
1033
-                $e_reg = 'ee=' . $this->request->getRequestParam('ee');
1033
+                $e_reg = 'ee='.$this->request->getRequestParam('ee');
1034 1034
             }
1035
-            $page_visit = esc_url(rtrim($http_host . $request_uri . $page_id . $e_reg, '?'));
1035
+            $page_visit = esc_url(rtrim($http_host.$request_uri.$page_id.$e_reg, '?'));
1036 1036
         }
1037 1037
         return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
1038 1038
     }
@@ -1069,7 +1069,7 @@  discard block
 block discarded – undo
1069 1069
 // <span style="color:#2EA2CC">' . __CLASS__ . '</span>::<span style="color:#E76700">' . __FUNCTION__ . '( ' . $class . '::' . $function . '() )</span><br/>
1070 1070
 // <span style="font-size:9px;font-weight:normal;">' . __FILE__ . '</span>    <b style="font-size:10px;">  ' . __LINE__ . ' </b>
1071 1071
 // </h3>';
1072
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
1072
+        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : '.$class.'::'.$function.'()');
1073 1073
         $this->reset_cart();
1074 1074
         $this->reset_checkout();
1075 1075
         $this->reset_transaction();
@@ -1092,7 +1092,7 @@  discard block
 block discarded – undo
1092 1092
     public function reset_data($data_to_reset = array(), $show_all_notices = false)
1093 1093
     {
1094 1094
         // if $data_to_reset is not in an array, then put it in one
1095
-        if (! is_array($data_to_reset)) {
1095
+        if ( ! is_array($data_to_reset)) {
1096 1096
             $data_to_reset = array($data_to_reset);
1097 1097
         }
1098 1098
         // nothing ??? go home!
@@ -1112,11 +1112,11 @@  discard block
 block discarded – undo
1112 1112
         // since $data_to_reset is an array, cycle through the values
1113 1113
         foreach ($data_to_reset as $reset) {
1114 1114
             // first check to make sure it is a valid session var
1115
-            if (isset($this->_session_data[ $reset ])) {
1115
+            if (isset($this->_session_data[$reset])) {
1116 1116
                 // then check to make sure it is not a default var
1117
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1117
+                if ( ! array_key_exists($reset, $this->_default_session_vars)) {
1118 1118
                     // remove session var
1119
-                    unset($this->_session_data[ $reset ]);
1119
+                    unset($this->_session_data[$reset]);
1120 1120
                     $this->setSaveState();
1121 1121
                     if ($show_all_notices) {
1122 1122
                         EE_Error::add_success(
@@ -1219,7 +1219,7 @@  discard block
 block discarded – undo
1219 1219
             // or use that for the new transient cleanup query limit
1220 1220
             add_filter(
1221 1221
                 'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1222
-                function () use ($expired_session_transient_delete_query_limit) {
1222
+                function() use ($expired_session_transient_delete_query_limit) {
1223 1223
                     return $expired_session_transient_delete_query_limit;
1224 1224
                 }
1225 1225
             );
@@ -1237,7 +1237,7 @@  discard block
 block discarded – undo
1237 1237
         $error = '<pre>';
1238 1238
         $data2 = preg_replace_callback(
1239 1239
             '!s:(\d+):"(.*?)";!',
1240
-            function ($match) {
1240
+            function($match) {
1241 1241
                 return ($match[1] === strlen($match[2]))
1242 1242
                     ? $match[0]
1243 1243
                     : 's:'
@@ -1249,13 +1249,13 @@  discard block
 block discarded – undo
1249 1249
             $data1
1250 1250
         );
1251 1251
         $max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1252
-        $error .= $data1 . PHP_EOL;
1253
-        $error .= $data2 . PHP_EOL;
1252
+        $error .= $data1.PHP_EOL;
1253
+        $error .= $data2.PHP_EOL;
1254 1254
         for ($i = 0; $i < $max; $i++) {
1255
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1256
-                $error .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1257
-                $error .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1258
-                $error .= "\t-> Line Number = $i" . PHP_EOL;
1255
+            if (@$data1[$i] !== @$data2[$i]) {
1256
+                $error .= 'Difference '.@$data1[$i].' != '.@$data2[$i].PHP_EOL;
1257
+                $error .= "\t-> ORD number ".ord(@$data1[$i]).' != '.ord(@$data2[$i]).PHP_EOL;
1258
+                $error .= "\t-> Line Number = $i".PHP_EOL;
1259 1259
                 $start = ($i - 20);
1260 1260
                 $start = ($start < 0) ? 0 : $start;
1261 1261
                 $length = 40;
@@ -1270,7 +1270,7 @@  discard block
 block discarded – undo
1270 1270
                 $error .= "\t-> Section Data1  = ";
1271 1271
                 $error .= substr_replace(
1272 1272
                     substr($data1, $start, $length),
1273
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1273
+                    "<b style=\"color:green\">{$data1[$i]}</b>",
1274 1274
                     $rpoint,
1275 1275
                     $rlength
1276 1276
                 );
@@ -1278,7 +1278,7 @@  discard block
 block discarded – undo
1278 1278
                 $error .= "\t-> Section Data2  = ";
1279 1279
                 $error .= substr_replace(
1280 1280
                     substr($data2, $start, $length),
1281
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1281
+                    "<b style=\"color:red\">{$data2[$i]}</b>",
1282 1282
                     $rpoint,
1283 1283
                     $rlength
1284 1284
                 );
@@ -1309,7 +1309,7 @@  discard block
 block discarded – undo
1309 1309
     public function garbageCollection()
1310 1310
     {
1311 1311
         // only perform during regular requests if last garbage collection was over an hour ago
1312
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1312
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1313 1313
             $this->_last_gc = time();
1314 1314
             $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1315 1315
             /** @type WPDB $wpdb */
@@ -1344,7 +1344,7 @@  discard block
 block discarded – undo
1344 1344
                 // AND option_value < 1508368198 LIMIT 50
1345 1345
                 $expired_sessions = $wpdb->get_col($SQL);
1346 1346
                 // valid results?
1347
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1347
+                if ( ! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1348 1348
                     $this->cache_storage->deleteMany($expired_sessions, true);
1349 1349
                 }
1350 1350
             }
Please login to merge, or discard this patch.
core/EE_Request_Handler.core.php 1 patch
Indentation   +262 added lines, -262 removed lines patch added patch discarded remove patch
@@ -16,266 +16,266 @@
 block discarded – undo
16 16
 final class EE_Request_Handler implements InterminableInterface
17 17
 {
18 18
 
19
-    /**
20
-     * @var CurrentPage
21
-     */
22
-    private $current_page;
23
-
24
-    /**
25
-     * @var RequestInterface
26
-     */
27
-    private $request;
28
-
29
-    /**
30
-     * @var ResponseInterface
31
-     */
32
-    private $response;
33
-
34
-    /**
35
-     * whether current request is via AJAX
36
-     *
37
-     * @var boolean
38
-     */
39
-    public $ajax = false;
40
-
41
-    /**
42
-     * whether current request is via AJAX from the frontend of the site
43
-     *
44
-     * @var boolean
45
-     */
46
-    public $front_ajax = false;
47
-
48
-
49
-    /**
50
-     * @param CurrentPage       $current_page
51
-     * @param RequestInterface  $request
52
-     * @param ResponseInterface $response
53
-     */
54
-    public function __construct(CurrentPage $current_page, RequestInterface $request, ResponseInterface $response)
55
-    {
56
-        $this->current_page = $current_page;
57
-        $this->request      = $request;
58
-        $this->response     = $response;
59
-        $this->ajax         = $this->request->isAjax();
60
-        $this->front_ajax   = $this->request->isFrontAjax();
61
-        do_action('AHEE__EE_Request_Handler__construct__complete');
62
-    }
63
-
64
-
65
-    /**
66
-     * @param WP $WP
67
-     * @return void
68
-     * @deprecated  $VID:$
69
-     */
70
-    public function parse_request($WP = null)
71
-    {
72
-    }
73
-
74
-
75
-    /**
76
-     * @param WP $WP
77
-     * @return void
78
-     * @deprecated  $VID:$
79
-     */
80
-    public function set_request_vars($WP = null)
81
-    {
82
-        $this->current_page->parseQueryVars($WP);
83
-    }
84
-
85
-
86
-    /**
87
-     * @param WP $WP
88
-     * @return int
89
-     * @deprecated  $VID:$
90
-     */
91
-    public function get_post_id_from_request($WP = null)
92
-    {
93
-        return $this->current_page->postId();
94
-    }
95
-
96
-
97
-    /**
98
-     * @param WP $WP
99
-     * @return string
100
-     * @deprecated  $VID:$
101
-     */
102
-    public function get_post_name_from_request($WP = null)
103
-    {
104
-        return $this->current_page->postName();
105
-    }
106
-
107
-
108
-    /**
109
-     * @param WP $WP
110
-     * @return array
111
-     * @deprecated  $VID:$
112
-     */
113
-    public function get_post_type_from_request($WP = null)
114
-    {
115
-        return $this->current_page->postType();
116
-    }
117
-
118
-
119
-    /**
120
-     * Just a helper method for getting the url for the displayed page.
121
-     *
122
-     * @param WP $WP
123
-     * @return string
124
-     * @deprecated  $VID:$
125
-     */
126
-    public function get_current_page_permalink($WP = null)
127
-    {
128
-        return $this->current_page->getPermalink($WP);
129
-    }
130
-
131
-
132
-    /**
133
-     * @return bool
134
-     * @deprecated  $VID:$
135
-     */
136
-    public function test_for_espresso_page()
137
-    {
138
-        return $this->current_page->isEspressoPage();
139
-    }
140
-
141
-
142
-    /**
143
-     * @param $key
144
-     * @param $value
145
-     * @return void
146
-     * @deprecated  $VID:$
147
-     */
148
-    public function set_notice($key, $value)
149
-    {
150
-        $this->response->setNotice($key, $value);
151
-    }
152
-
153
-
154
-    /**
155
-     * @param $key
156
-     * @return mixed
157
-     * @deprecated  $VID:$
158
-     */
159
-    public function get_notice($key)
160
-    {
161
-        return $this->response->getNotice($key);
162
-    }
163
-
164
-
165
-    /**
166
-     * @param $string
167
-     * @return void
168
-     * @deprecated  $VID:$
169
-     */
170
-    public function add_output($string)
171
-    {
172
-        $this->response->addOutput($string);
173
-    }
174
-
175
-
176
-    /**
177
-     * @return string
178
-     * @deprecated  $VID:$
179
-     */
180
-    public function get_output()
181
-    {
182
-        return $this->response->getOutput();
183
-    }
184
-
185
-
186
-    /**
187
-     * @param $item
188
-     * @param $key
189
-     * @deprecated  $VID:$
190
-     */
191
-    public function sanitize_text_field_for_array_walk(&$item, &$key)
192
-    {
193
-        $item = strpos($item, 'email') !== false
194
-            ? sanitize_email($item)
195
-            : sanitize_text_field($item);
196
-    }
197
-
198
-
199
-    /**
200
-     * @param null|bool $value
201
-     * @return void
202
-     * @deprecated  $VID:$
203
-     */
204
-    public function set_espresso_page($value = null)
205
-    {
206
-        $this->current_page->setEspressoPage($value);
207
-    }
208
-
209
-
210
-    /**
211
-     * @return bool
212
-     * @deprecated  $VID:$
213
-     */
214
-    public function is_espresso_page()
215
-    {
216
-        return $this->current_page->isEspressoPage();
217
-    }
218
-
219
-
220
-    /**
221
-     * returns sanitized contents of $_REQUEST
222
-     *
223
-     * @return array
224
-     * @deprecated  $VID:$
225
-     */
226
-    public function params()
227
-    {
228
-        return $this->request->requestParams();
229
-    }
230
-
231
-
232
-    /**
233
-     * @param      $key
234
-     * @param      $value
235
-     * @param bool $override_ee
236
-     * @return    void
237
-     * @deprecated  $VID:$
238
-     */
239
-    public function set($key, $value, $override_ee = false)
240
-    {
241
-        $this->request->setRequestParam($key, $value, $override_ee);
242
-    }
243
-
244
-
245
-    /**
246
-     * @param      $key
247
-     * @param null $default
248
-     * @return    mixed
249
-     * @deprecated  $VID:$
250
-     */
251
-    public function get($key, $default = null)
252
-    {
253
-        return $this->request->getRequestParam($key, $default);
254
-    }
255
-
256
-
257
-    /**
258
-     * check if param exists
259
-     *
260
-     * @param $key
261
-     * @return    boolean
262
-     * @deprecated  $VID:$
263
-     */
264
-    public function is_set($key)
265
-    {
266
-        return $this->request->requestParamIsSet($key);
267
-    }
268
-
269
-
270
-    /**
271
-     * remove param
272
-     *
273
-     * @param $key
274
-     * @return    void
275
-     * @deprecated  $VID:$
276
-     */
277
-    public function un_set($key)
278
-    {
279
-        $this->request->unSetRequestParam($key);
280
-    }
19
+	/**
20
+	 * @var CurrentPage
21
+	 */
22
+	private $current_page;
23
+
24
+	/**
25
+	 * @var RequestInterface
26
+	 */
27
+	private $request;
28
+
29
+	/**
30
+	 * @var ResponseInterface
31
+	 */
32
+	private $response;
33
+
34
+	/**
35
+	 * whether current request is via AJAX
36
+	 *
37
+	 * @var boolean
38
+	 */
39
+	public $ajax = false;
40
+
41
+	/**
42
+	 * whether current request is via AJAX from the frontend of the site
43
+	 *
44
+	 * @var boolean
45
+	 */
46
+	public $front_ajax = false;
47
+
48
+
49
+	/**
50
+	 * @param CurrentPage       $current_page
51
+	 * @param RequestInterface  $request
52
+	 * @param ResponseInterface $response
53
+	 */
54
+	public function __construct(CurrentPage $current_page, RequestInterface $request, ResponseInterface $response)
55
+	{
56
+		$this->current_page = $current_page;
57
+		$this->request      = $request;
58
+		$this->response     = $response;
59
+		$this->ajax         = $this->request->isAjax();
60
+		$this->front_ajax   = $this->request->isFrontAjax();
61
+		do_action('AHEE__EE_Request_Handler__construct__complete');
62
+	}
63
+
64
+
65
+	/**
66
+	 * @param WP $WP
67
+	 * @return void
68
+	 * @deprecated  $VID:$
69
+	 */
70
+	public function parse_request($WP = null)
71
+	{
72
+	}
73
+
74
+
75
+	/**
76
+	 * @param WP $WP
77
+	 * @return void
78
+	 * @deprecated  $VID:$
79
+	 */
80
+	public function set_request_vars($WP = null)
81
+	{
82
+		$this->current_page->parseQueryVars($WP);
83
+	}
84
+
85
+
86
+	/**
87
+	 * @param WP $WP
88
+	 * @return int
89
+	 * @deprecated  $VID:$
90
+	 */
91
+	public function get_post_id_from_request($WP = null)
92
+	{
93
+		return $this->current_page->postId();
94
+	}
95
+
96
+
97
+	/**
98
+	 * @param WP $WP
99
+	 * @return string
100
+	 * @deprecated  $VID:$
101
+	 */
102
+	public function get_post_name_from_request($WP = null)
103
+	{
104
+		return $this->current_page->postName();
105
+	}
106
+
107
+
108
+	/**
109
+	 * @param WP $WP
110
+	 * @return array
111
+	 * @deprecated  $VID:$
112
+	 */
113
+	public function get_post_type_from_request($WP = null)
114
+	{
115
+		return $this->current_page->postType();
116
+	}
117
+
118
+
119
+	/**
120
+	 * Just a helper method for getting the url for the displayed page.
121
+	 *
122
+	 * @param WP $WP
123
+	 * @return string
124
+	 * @deprecated  $VID:$
125
+	 */
126
+	public function get_current_page_permalink($WP = null)
127
+	{
128
+		return $this->current_page->getPermalink($WP);
129
+	}
130
+
131
+
132
+	/**
133
+	 * @return bool
134
+	 * @deprecated  $VID:$
135
+	 */
136
+	public function test_for_espresso_page()
137
+	{
138
+		return $this->current_page->isEspressoPage();
139
+	}
140
+
141
+
142
+	/**
143
+	 * @param $key
144
+	 * @param $value
145
+	 * @return void
146
+	 * @deprecated  $VID:$
147
+	 */
148
+	public function set_notice($key, $value)
149
+	{
150
+		$this->response->setNotice($key, $value);
151
+	}
152
+
153
+
154
+	/**
155
+	 * @param $key
156
+	 * @return mixed
157
+	 * @deprecated  $VID:$
158
+	 */
159
+	public function get_notice($key)
160
+	{
161
+		return $this->response->getNotice($key);
162
+	}
163
+
164
+
165
+	/**
166
+	 * @param $string
167
+	 * @return void
168
+	 * @deprecated  $VID:$
169
+	 */
170
+	public function add_output($string)
171
+	{
172
+		$this->response->addOutput($string);
173
+	}
174
+
175
+
176
+	/**
177
+	 * @return string
178
+	 * @deprecated  $VID:$
179
+	 */
180
+	public function get_output()
181
+	{
182
+		return $this->response->getOutput();
183
+	}
184
+
185
+
186
+	/**
187
+	 * @param $item
188
+	 * @param $key
189
+	 * @deprecated  $VID:$
190
+	 */
191
+	public function sanitize_text_field_for_array_walk(&$item, &$key)
192
+	{
193
+		$item = strpos($item, 'email') !== false
194
+			? sanitize_email($item)
195
+			: sanitize_text_field($item);
196
+	}
197
+
198
+
199
+	/**
200
+	 * @param null|bool $value
201
+	 * @return void
202
+	 * @deprecated  $VID:$
203
+	 */
204
+	public function set_espresso_page($value = null)
205
+	{
206
+		$this->current_page->setEspressoPage($value);
207
+	}
208
+
209
+
210
+	/**
211
+	 * @return bool
212
+	 * @deprecated  $VID:$
213
+	 */
214
+	public function is_espresso_page()
215
+	{
216
+		return $this->current_page->isEspressoPage();
217
+	}
218
+
219
+
220
+	/**
221
+	 * returns sanitized contents of $_REQUEST
222
+	 *
223
+	 * @return array
224
+	 * @deprecated  $VID:$
225
+	 */
226
+	public function params()
227
+	{
228
+		return $this->request->requestParams();
229
+	}
230
+
231
+
232
+	/**
233
+	 * @param      $key
234
+	 * @param      $value
235
+	 * @param bool $override_ee
236
+	 * @return    void
237
+	 * @deprecated  $VID:$
238
+	 */
239
+	public function set($key, $value, $override_ee = false)
240
+	{
241
+		$this->request->setRequestParam($key, $value, $override_ee);
242
+	}
243
+
244
+
245
+	/**
246
+	 * @param      $key
247
+	 * @param null $default
248
+	 * @return    mixed
249
+	 * @deprecated  $VID:$
250
+	 */
251
+	public function get($key, $default = null)
252
+	{
253
+		return $this->request->getRequestParam($key, $default);
254
+	}
255
+
256
+
257
+	/**
258
+	 * check if param exists
259
+	 *
260
+	 * @param $key
261
+	 * @return    boolean
262
+	 * @deprecated  $VID:$
263
+	 */
264
+	public function is_set($key)
265
+	{
266
+		return $this->request->requestParamIsSet($key);
267
+	}
268
+
269
+
270
+	/**
271
+	 * remove param
272
+	 *
273
+	 * @param $key
274
+	 * @return    void
275
+	 * @deprecated  $VID:$
276
+	 */
277
+	public function un_set($key)
278
+	{
279
+		$this->request->unSetRequestParam($key);
280
+	}
281 281
 }
Please login to merge, or discard this patch.