Completed
Branch BUG-10537-cart-ticket-reservat... (372129)
by
unknown
26:53 queued 15:32
created
core/libraries/rest_api/changes/Changes_In_4_8_36.php 1 patch
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -16,28 +16,28 @@  discard block
 block discarded – undo
16 16
 		//set a hook to remove the "calculate" query param
17 17
 		add_filter(
18 18
 			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
19
-			array( $this, 'remove_calculate_query_param' ),
19
+			array($this, 'remove_calculate_query_param'),
20 20
 			10,
21 21
 			3
22 22
 		);
23 23
 		//don't add the _calculated_fields either
24 24
 		add_filter(
25 25
 			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
26
-			array( $this, 'remove_calculated_fields_from_response' ),
26
+			array($this, 'remove_calculated_fields_from_response'),
27 27
 			10,
28 28
 			5
29 29
 		);
30 30
 		//and also don't add the count headers
31 31
 		add_filter(
32 32
 			'FHEE__EventEspresso\core\libraries\rest_api\controllers\Base___get_response_headers',
33
-			array( $this, 'remove_headers_new_in_this_version' ),
33
+			array($this, 'remove_headers_new_in_this_version'),
34 34
 			10,
35 35
 			3
36 36
 		);
37 37
 		//remove the old featured_image part of the response...
38 38
 		add_filter(
39 39
 			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
40
-			array( $this, 'add_old_featured_image_part_of_cpt_entities' ),
40
+			array($this, 'add_old_featured_image_part_of_cpt_entities'),
41 41
 			10,
42 42
 			5
43 43
 		);
@@ -47,7 +47,7 @@  discard block
 block discarded – undo
47 47
 		//before this, infinity was -1, now it's null
48 48
 		add_filter(
49 49
 			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
50
-			array( $this, 'use_negative_one_for_infinity_before_this_version' ),
50
+			array($this, 'use_negative_one_for_infinity_before_this_version'),
51 51
 			10,
52 52
 			4
53 53
 		);
@@ -60,9 +60,9 @@  discard block
 block discarded – undo
60 60
 	 * @param string $version
61 61
 	 * @return array
62 62
 	 */
63
-	public function remove_calculate_query_param( $query_params, \EEM_Base $model, $version ) {
64
-		if( $this->applies_to_version( $version ) ) {
65
-			unset( $query_params[ 'calculate' ] );
63
+	public function remove_calculate_query_param($query_params, \EEM_Base $model, $version) {
64
+		if ($this->applies_to_version($version)) {
65
+			unset($query_params['calculate']);
66 66
 		}
67 67
 		return $query_params;
68 68
 	}
@@ -83,8 +83,8 @@  discard block
 block discarded – undo
83 83
 		\WP_REST_Request $request,
84 84
 		Read $controller
85 85
 	) {
86
-		if( $this->applies_to_version( $controller->get_model_version_info()->requested_version() ) ) {
87
-			unset( $entity_response_array[ '_calculated_fields' ] );
86
+		if ($this->applies_to_version($controller->get_model_version_info()->requested_version())) {
87
+			unset($entity_response_array['_calculated_fields']);
88 88
 		}
89 89
 		return $entity_response_array;
90 90
 	}
@@ -101,14 +101,14 @@  discard block
 block discarded – undo
101 101
 		Controller_Base $controller,
102 102
 		$version
103 103
 	) {
104
-		if( $this->applies_to_version( $version ) ) {
104
+		if ($this->applies_to_version($version)) {
105 105
 			$headers = array_diff_key(
106 106
 				$headers,
107 107
 				array_flip(
108 108
 					array(
109
-						Base::header_prefix_for_wp . 'Total',
110
-						Base::header_prefix_for_wp . 'TotalPages',
111
-						Base::header_prefix_for_wp . 'PageSize'
109
+						Base::header_prefix_for_wp.'Total',
110
+						Base::header_prefix_for_wp.'TotalPages',
111
+						Base::header_prefix_for_wp.'PageSize'
112 112
 					)));
113 113
 		}
114 114
 		return $headers;
@@ -130,14 +130,14 @@  discard block
 block discarded – undo
130 130
 		\WP_REST_Request $request,
131 131
 		Read $controller
132 132
 	) {
133
-		if( $this->applies_to_version( $controller->get_model_version_info()->requested_version() )
133
+		if ($this->applies_to_version($controller->get_model_version_info()->requested_version())
134 134
 			&& $model instanceof \EEM_CPT_Base
135 135
 		) {
136 136
 			$attachment = wp_get_attachment_image_src(
137
-				get_post_thumbnail_id( $entity_response_array[ $model->primary_key_name() ] ),
137
+				get_post_thumbnail_id($entity_response_array[$model->primary_key_name()]),
138 138
 				'full'
139 139
 			);
140
-			$entity_response_array[ 'featured_image_url' ] = !empty( $attachment ) ? $attachment[ 0 ] : null;
140
+			$entity_response_array['featured_image_url'] = ! empty($attachment) ? $attachment[0] : null;
141 141
 		}
142 142
 		return $entity_response_array;
143 143
 	}
@@ -152,9 +152,9 @@  discard block
 block discarded – undo
152 152
 	 * @param string $requested_value
153 153
 	 * @return mixed
154 154
 	 */
155
-	public function use_negative_one_for_infinity_before_this_version( $new_value, $field_obj, $original_value, $requested_value ) {
156
-		if( $this->applies_to_version( $requested_value )
157
-			&& $original_value === EE_INF ) {
155
+	public function use_negative_one_for_infinity_before_this_version($new_value, $field_obj, $original_value, $requested_value) {
156
+		if ($this->applies_to_version($requested_value)
157
+			&& $original_value === EE_INF) {
158 158
 			//return the old representation of infinity in the JSON
159 159
 			return -1;
160 160
 		}
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Indentation   +1234 added lines, -1234 removed lines patch added patch discarded remove patch
@@ -9,7 +9,7 @@  discard block
 block discarded – undo
9 9
 use EE_Datetime_Field;
10 10
 
11 11
 if (! defined('EVENT_ESPRESSO_VERSION')) {
12
-    exit('No direct script access allowed');
12
+	exit('No direct script access allowed');
13 13
 }
14 14
 
15 15
 
@@ -27,1239 +27,1239 @@  discard block
 block discarded – undo
27 27
 
28 28
 
29 29
 
30
-    /**
31
-     * @var Calculated_Model_Fields
32
-     */
33
-    protected $_fields_calculator;
34
-
35
-
36
-
37
-    /**
38
-     * Read constructor.
39
-     */
40
-    public function __construct()
41
-    {
42
-        parent::__construct();
43
-        $this->_fields_calculator = new Calculated_Model_Fields();
44
-    }
45
-
46
-
47
-
48
-    /**
49
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
50
-     *
51
-     * @param \WP_REST_Request $request
52
-     * @return \WP_REST_Response|\WP_Error
53
-     */
54
-    public static function handle_request_get_all(\WP_REST_Request $request)
55
-    {
56
-        $controller = new Read();
57
-        try {
58
-            $matches = $controller->parse_route(
59
-                $request->get_route(),
60
-                '~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)~',
61
-                array('version', 'model')
62
-            );
63
-            $controller->set_requested_version($matches['version']);
64
-            $model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
65
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
66
-                return $controller->send_response(
67
-                    new \WP_Error(
68
-                        'endpoint_parsing_error',
69
-                        sprintf(
70
-                            __('There is no model for endpoint %s. Please contact event espresso support',
71
-                                'event_espresso'),
72
-                            $model_name_singular
73
-                        )
74
-                    )
75
-                );
76
-            }
77
-            return $controller->send_response(
78
-                $controller->get_entities_from_model(
79
-                    $controller->get_model_version_info()->load_model($model_name_singular),
80
-                    $request
81
-                )
82
-            );
83
-        } catch (\Exception $e) {
84
-            return $controller->send_response($e);
85
-        }
86
-    }
87
-
88
-
89
-    /**
90
-     * Prepares and returns schema for any OPTIONS request.
91
-     *
92
-     * @param string $model_name  Something like `Event` or `Registration`
93
-     * @param string $version     The API endpoint version being used.
94
-     * @return array
95
-     */
96
-    public static function handle_schema_request($model_name, $version)
97
-    {
98
-        $controller = new Read();
99
-        try {
100
-            $controller->set_requested_version($version);
101
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name)) {
102
-                return array();
103
-            }
104
-            //get the model for this version
105
-            $model = $controller->get_model_version_info()->load_model($model_name);
106
-            $model_schema = new JsonModelSchema($model);
107
-            return $model_schema->getModelSchemaForRelations(
108
-                $controller->get_model_version_info()->relation_settings($model),
109
-                $controller->_customize_schema_for_rest_response(
110
-                    $model,
111
-                    $model_schema->getModelSchemaForFields(
112
-                        $controller->get_model_version_info()->fields_on_model_in_this_version($model),
113
-                        $model_schema->getInitialSchemaStructure()
114
-                    )
115
-                )
116
-            );
117
-        } catch (\Exception $e) {
118
-            return array();
119
-        }
120
-    }
121
-
122
-
123
-    /**
124
-     * This loops through each field in the given schema for the model and does the following:
125
-     * - add any extra fields that are REST API specific and related to existing fields.
126
-     * - transform default values into the correct format for a REST API response.
127
-     *
128
-     * @param \EEM_Base $model
129
-     * @param array     $schema
130
-     * @return array  The final schema.
131
-     */
132
-    protected function _customize_schema_for_rest_response(\EEM_Base $model, array $schema)
133
-    {
134
-       foreach ($this->get_model_version_info()->fields_on_model_in_this_version($model) as $field_name => $field) {
135
-           $schema = $this->_translate_defaults_for_rest_response(
136
-               $field_name,
137
-               $field,
138
-               $this->_maybe_add_extra_fields_to_schema($field_name, $field, $schema)
139
-            );
140
-       }
141
-       return $schema;
142
-    }
143
-
144
-
145
-    /**
146
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
147
-     * response.
148
-     *
149
-     * @param                      $field_name
150
-     * @param \EE_Model_Field_Base $field
151
-     * @param array                $schema
152
-     * @return array
153
-     */
154
-    protected function _translate_defaults_for_rest_response($field_name, \EE_Model_Field_Base $field, array $schema)
155
-    {
156
-        if (isset($schema['properties'][$field_name]['default'])) {
157
-            if (is_array($schema['properties'][$field_name]['default'])) {
158
-                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
159
-                    if ($default_key === 'raw') {
160
-                        $schema['properties'][$field_name]['default'][$default_key] = Model_Data_Translator::prepare_field_value_for_json(
161
-                            $field,
162
-                            $default_value,
163
-                            $this->get_model_version_info()->requested_version()
164
-                        );
165
-                    }
166
-                }
167
-            } else {
168
-                $schema['properties'][$field_name]['default'] = Model_Data_Translator::prepare_field_value_for_json(
169
-                    $field,
170
-                    $schema['properties'][$field_name]['default'],
171
-                    $this->get_model_version_info()->requested_version()
172
-                );
173
-            }
174
-        }
175
-        return $schema;
176
-    }
177
-
178
-
179
-    /**
180
-     * Adds additional fields to the schema
181
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
182
-     * needs to be added to the schema.
183
-     *
184
-     * @param                      $field_name
185
-     * @param \EE_Model_Field_Base $field
186
-     * @param array                $schema
187
-     * @return array
188
-     */
189
-    protected function _maybe_add_extra_fields_to_schema($field_name, \EE_Model_Field_Base $field, array $schema)
190
-    {
191
-        if ($field instanceof EE_Datetime_Field) {
192
-            $schema['properties'][$field_name . '_gmt'] = $field->getSchema();
193
-            //modify the description
194
-            $schema['properties'][$field_name . '_gmt']['description'] = sprintf(
195
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
196
-                $field->get_nicename()
197
-            );
198
-        }
199
-        return $schema;
200
-    }
201
-
202
-
203
-
204
-
205
-    /**
206
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
207
-     * @return string
208
-     */
209
-    protected function get_route_from_request() {
210
-        if (isset($GLOBALS['wp'])
211
-            && $GLOBALS['wp'] instanceof \WP
212
-            && isset($GLOBALS['wp']->query_vars['rest_route'] )
213
-        ) {
214
-            return $GLOBALS['wp']->query_vars['rest_route'];
215
-        } else {
216
-            return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
217
-        }
218
-    }
219
-
220
-
221
-
222
-    /**
223
-     * Gets a single entity related to the model indicated in the path and its id
224
-     *
225
-     * @param \WP_REST_Request $request
226
-     * @return \WP_REST_Response|\WP_Error
227
-     */
228
-    public static function handle_request_get_one(\WP_REST_Request $request)
229
-    {
230
-        $controller = new Read();
231
-        try {
232
-            $matches = $controller->parse_route(
233
-                $request->get_route(),
234
-                '~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)~',
235
-                array('version', 'model', 'id'));
236
-            $controller->set_requested_version($matches['version']);
237
-            $model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
238
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
239
-                return $controller->send_response(
240
-                    new \WP_Error(
241
-                        'endpoint_parsing_error',
242
-                        sprintf(
243
-                            __('There is no model for endpoint %s. Please contact event espresso support',
244
-                                'event_espresso'),
245
-                            $model_name_singular
246
-                        )
247
-                    )
248
-                );
249
-            }
250
-            return $controller->send_response(
251
-                $controller->get_entity_from_model(
252
-                    $controller->get_model_version_info()->load_model($model_name_singular),
253
-                    $request
254
-                )
255
-            );
256
-        } catch (\Exception $e) {
257
-            return $controller->send_response($e);
258
-        }
259
-    }
260
-
261
-
262
-
263
-    /**
264
-     * Gets all the related entities (or if its a belongs-to relation just the one)
265
-     * to the item with the given id
266
-     *
267
-     * @param \WP_REST_Request $request
268
-     * @return \WP_REST_Response|\WP_Error
269
-     */
270
-    public static function handle_request_get_related(\WP_REST_Request $request)
271
-    {
272
-        $controller = new Read();
273
-        try {
274
-            $matches = $controller->parse_route(
275
-                $request->get_route(),
276
-                '~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)/(.*)~',
277
-                array('version', 'model', 'id', 'related_model')
278
-            );
279
-            $controller->set_requested_version($matches['version']);
280
-            $main_model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
281
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($main_model_name_singular)) {
282
-                return $controller->send_response(
283
-                    new \WP_Error(
284
-                        'endpoint_parsing_error',
285
-                        sprintf(
286
-                            __('There is no model for endpoint %s. Please contact event espresso support',
287
-                                'event_espresso'),
288
-                            $main_model_name_singular
289
-                        )
290
-                    )
291
-                );
292
-            }
293
-            $main_model = $controller->get_model_version_info()->load_model($main_model_name_singular);
294
-            //assume the related model name is plural and try to find the model's name
295
-            $related_model_name_singular = \EEH_Inflector::singularize_and_upper($matches['related_model']);
296
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
297
-                //so the word didn't singularize well. Maybe that's just because it's a singular word?
298
-                $related_model_name_singular = \EEH_Inflector::humanize($matches['related_model']);
299
-            }
300
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
301
-                return $controller->send_response(
302
-                    new \WP_Error(
303
-                        'endpoint_parsing_error',
304
-                        sprintf(
305
-                            __('There is no model for endpoint %s. Please contact event espresso support',
306
-                                'event_espresso'),
307
-                            $related_model_name_singular
308
-                        )
309
-                    )
310
-                );
311
-            }
312
-            return $controller->send_response(
313
-                $controller->get_entities_from_relation(
314
-                    $request->get_param('id'),
315
-                    $main_model->related_settings_for($related_model_name_singular),
316
-                    $request
317
-                )
318
-            );
319
-        } catch (\Exception $e) {
320
-            return $controller->send_response($e);
321
-        }
322
-    }
323
-
324
-
325
-
326
-    /**
327
-     * Gets a collection for the given model and filters
328
-     *
329
-     * @param \EEM_Base        $model
330
-     * @param \WP_REST_Request $request
331
-     * @return array|\WP_Error
332
-     */
333
-    public function get_entities_from_model($model, $request)
334
-    {
335
-        $query_params = $this->create_model_query_params($model, $request->get_params());
336
-        if (! Capabilities::current_user_has_partial_access_to($model, $query_params['caps'])) {
337
-            $model_name_plural = \EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
338
-            return new \WP_Error(
339
-                sprintf('rest_%s_cannot_list', $model_name_plural),
340
-                sprintf(
341
-                    __('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
342
-                    $model_name_plural,
343
-                    Capabilities::get_missing_permissions_string($model, $query_params['caps'])
344
-                ),
345
-                array('status' => 403)
346
-            );
347
-        }
348
-        if (! $request->get_header('no_rest_headers')) {
349
-            $this->_set_headers_from_query_params($model, $query_params);
350
-        }
351
-        /** @type array $results */
352
-        $results = $model->get_all_wpdb_results($query_params);
353
-        $nice_results = array();
354
-        foreach ($results as $result) {
355
-            $nice_results[] = $this->create_entity_from_wpdb_result(
356
-                $model,
357
-                $result,
358
-                $request
359
-            );
360
-        }
361
-        return $nice_results;
362
-    }
363
-
364
-
365
-
366
-    /**
367
-     * @param array                   $primary_model_query_params query params for finding the item from which
368
-     *                                                            relations will be based
369
-     * @param \EE_Model_Relation_Base $relation
370
-     * @param \WP_REST_Request        $request
371
-     * @return \WP_Error|array
372
-     */
373
-    protected function _get_entities_from_relation($primary_model_query_params, $relation, $request)
374
-    {
375
-        $context = $this->validate_context($request->get_param('caps'));
376
-        $model = $relation->get_this_model();
377
-        $related_model = $relation->get_other_model();
378
-        if (! isset($primary_model_query_params[0])) {
379
-            $primary_model_query_params[0] = array();
380
-        }
381
-        //check if they can access the 1st model object
382
-        $primary_model_query_params = array(
383
-            0       => $primary_model_query_params[0],
384
-            'limit' => 1,
385
-        );
386
-        if ($model instanceof \EEM_Soft_Delete_Base) {
387
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($primary_model_query_params);
388
-        }
389
-        $restricted_query_params = $primary_model_query_params;
390
-        $restricted_query_params['caps'] = $context;
391
-        $this->_set_debug_info('main model query params', $restricted_query_params);
392
-        $this->_set_debug_info('missing caps', Capabilities::get_missing_permissions_string($related_model, $context));
393
-        if (
394
-        ! (
395
-            Capabilities::current_user_has_partial_access_to($related_model, $context)
396
-            && $model->exists($restricted_query_params)
397
-        )
398
-        ) {
399
-            if ($relation instanceof \EE_Belongs_To_Relation) {
400
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
401
-            } else {
402
-                $related_model_name_maybe_plural = \EEH_Inflector::pluralize_and_lower($related_model->get_this_model_name());
403
-            }
404
-            return new \WP_Error(
405
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
406
-                sprintf(
407
-                    __('Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
408
-                        'event_espresso'),
409
-                    $related_model_name_maybe_plural,
410
-                    $relation->get_this_model()->get_this_model_name(),
411
-                    implode(
412
-                        ',',
413
-                        array_keys(
414
-                            Capabilities::get_missing_permissions($related_model, $context)
415
-                        )
416
-                    )
417
-                ),
418
-                array('status' => 403)
419
-            );
420
-        }
421
-        $query_params = $this->create_model_query_params($relation->get_other_model(), $request->get_params());
422
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
423
-            $query_params[0][$relation->get_this_model()->get_this_model_name()
424
-                             . '.'
425
-                             . $where_condition_key] = $where_condition_value;
426
-        }
427
-        $query_params['default_where_conditions'] = 'none';
428
-        $query_params['caps'] = $context;
429
-        if (! $request->get_header('no_rest_headers')) {
430
-            $this->_set_headers_from_query_params($relation->get_other_model(), $query_params);
431
-        }
432
-        /** @type array $results */
433
-        $results = $relation->get_other_model()->get_all_wpdb_results($query_params);
434
-        $nice_results = array();
435
-        foreach ($results as $result) {
436
-            $nice_result = $this->create_entity_from_wpdb_result(
437
-                $relation->get_other_model(),
438
-                $result,
439
-                $request
440
-            );
441
-            if ($relation instanceof \EE_HABTM_Relation) {
442
-                //put the unusual stuff (properties from the HABTM relation) first, and make sure
443
-                //if there are conflicts we prefer the properties from the main model
444
-                $join_model_result = $this->create_entity_from_wpdb_result(
445
-                    $relation->get_join_model(),
446
-                    $result,
447
-                    $request
448
-                );
449
-                $joined_result = array_merge($nice_result, $join_model_result);
450
-                //but keep the meta stuff from the main model
451
-                if (isset($nice_result['meta'])) {
452
-                    $joined_result['meta'] = $nice_result['meta'];
453
-                }
454
-                $nice_result = $joined_result;
455
-            }
456
-            $nice_results[] = $nice_result;
457
-        }
458
-        if ($relation instanceof \EE_Belongs_To_Relation) {
459
-            return array_shift($nice_results);
460
-        } else {
461
-            return $nice_results;
462
-        }
463
-    }
464
-
465
-
466
-
467
-    /**
468
-     * Gets the collection for given relation object
469
-     * The same as Read::get_entities_from_model(), except if the relation
470
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
471
-     * the join-model-object into the results
472
-     *
473
-     * @param string                  $id the ID of the thing we are fetching related stuff from
474
-     * @param \EE_Model_Relation_Base $relation
475
-     * @param \WP_REST_Request        $request
476
-     * @return array|\WP_Error
477
-     * @throws \EE_Error
478
-     */
479
-    public function get_entities_from_relation($id, $relation, $request)
480
-    {
481
-        if (! $relation->get_this_model()->has_primary_key_field()) {
482
-            throw new \EE_Error(
483
-                sprintf(
484
-                    __('Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
485
-                        'event_espresso'),
486
-                    $relation->get_this_model()->get_this_model_name()
487
-                )
488
-            );
489
-        }
490
-        return $this->_get_entities_from_relation(
491
-            array(
492
-                array(
493
-                    $relation->get_this_model()->primary_key_name() => $id,
494
-                ),
495
-            ),
496
-            $relation,
497
-            $request
498
-        );
499
-    }
500
-
501
-
502
-
503
-    /**
504
-     * Sets the headers that are based on the model and query params,
505
-     * like the total records. This should only be called on the original request
506
-     * from the client, not on subsequent internal
507
-     *
508
-     * @param \EEM_Base $model
509
-     * @param array     $query_params
510
-     * @return void
511
-     */
512
-    protected function _set_headers_from_query_params($model, $query_params)
513
-    {
514
-        $this->_set_debug_info('model query params', $query_params);
515
-        $this->_set_debug_info('missing caps',
516
-            Capabilities::get_missing_permissions_string($model, $query_params['caps']));
517
-        //normally the limit to a 2-part array, where the 2nd item is the limit
518
-        if (! isset($query_params['limit'])) {
519
-            $query_params['limit'] = \EED_Core_Rest_Api::get_default_query_limit();
520
-        }
521
-        if (is_array($query_params['limit'])) {
522
-            $limit_parts = $query_params['limit'];
523
-        } else {
524
-            $limit_parts = explode(',', $query_params['limit']);
525
-            if (count($limit_parts) == 1) {
526
-                $limit_parts = array(0, $limit_parts[0]);
527
-            }
528
-        }
529
-        //remove the group by and having parts of the query, as those will
530
-        //make the sql query return an array of values, instead of just a single value
531
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
532
-        $count = $model->count($query_params, null, true);
533
-        $pages = $count / $limit_parts[1];
534
-        $this->_set_response_header('Total', $count, false);
535
-        $this->_set_response_header('PageSize', $limit_parts[1], false);
536
-        $this->_set_response_header('TotalPages', ceil($pages), false);
537
-    }
538
-
539
-
540
-
541
-    /**
542
-     * Changes database results into REST API entities
543
-     *
544
-     * @param \EEM_Base        $model
545
-     * @param array            $db_row     like results from $wpdb->get_results()
546
-     * @param \WP_REST_Request $rest_request
547
-     * @param string           $deprecated no longer used
548
-     * @return array ready for being converted into json for sending to client
549
-     */
550
-    public function create_entity_from_wpdb_result($model, $db_row, $rest_request, $deprecated = null)
551
-    {
552
-        if (! $rest_request instanceof \WP_REST_Request) {
553
-            //ok so this was called in the old style, where the 3rd arg was
554
-            //$include, and the 4th arg was $context
555
-            //now setup the request just to avoid fatal errors, although we won't be able
556
-            //to truly make use of it because it's kinda devoid of info
557
-            $rest_request = new \WP_REST_Request();
558
-            $rest_request->set_param('include', $rest_request);
559
-            $rest_request->set_param('caps', $deprecated);
560
-        }
561
-        if ($rest_request->get_param('caps') == null) {
562
-            $rest_request->set_param('caps', \EEM_Base::caps_read);
563
-        }
564
-        $entity_array = $this->_create_bare_entity_from_wpdb_results($model, $db_row);
565
-        $entity_array = $this->_add_extra_fields($model, $db_row, $entity_array);
566
-        $entity_array['_links'] = $this->_get_entity_links($model, $db_row, $entity_array);
567
-        $entity_array['_calculated_fields'] = $this->_get_entity_calculations($model, $db_row, $rest_request);
568
-        $entity_array = apply_filters( 'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models', $entity_array, $model, $rest_request->get_param('caps'),$rest_request,$this);
569
-        $entity_array = $this->_include_requested_models($model, $rest_request, $entity_array, $db_row);
570
-        $entity_array = apply_filters(
571
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
572
-            $entity_array,
573
-            $model,
574
-            $rest_request->get_param('caps'),
575
-            $rest_request,
576
-            $this
577
-        );
578
-        $result_without_inaccessible_fields = Capabilities::filter_out_inaccessible_entity_fields(
579
-            $entity_array,
580
-            $model,
581
-            $rest_request->get_param('caps'),
582
-            $this->get_model_version_info(),
583
-            $model->get_index_primary_key_string(
584
-                $model->deduce_fields_n_values_from_cols_n_values($db_row)
585
-            )
586
-        );
587
-        $this->_set_debug_info(
588
-            'inaccessible fields',
589
-            array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
590
-        );
591
-        return apply_filters(
592
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
593
-            $result_without_inaccessible_fields,
594
-            $model,
595
-            $rest_request->get_param('caps')
596
-        );
597
-    }
598
-
599
-
600
-
601
-    /**
602
-     * Creates a REST entity array (JSON object we're going to return in the response, but
603
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
604
-     * from $wpdb->get_row( $sql, ARRAY_A)
605
-     *
606
-     * @param \EEM_Base $model
607
-     * @param array     $db_row
608
-     * @return array entity mostly ready for converting to JSON and sending in the response
609
-     */
610
-    protected function _create_bare_entity_from_wpdb_results(\EEM_Base $model, $db_row)
611
-    {
612
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
613
-        $result = array_intersect_key($result,
614
-            $this->get_model_version_info()->fields_on_model_in_this_version($model));
615
-        foreach ($result as $field_name => $raw_field_value) {
616
-            $field_obj = $model->field_settings_for($field_name);
617
-            $field_value = $field_obj->prepare_for_set_from_db($raw_field_value);
618
-            if ($this->is_subclass_of_one($field_obj, $this->get_model_version_info()->fields_ignored())) {
619
-                unset($result[$field_name]);
620
-            } elseif (
621
-            $this->is_subclass_of_one($field_obj, $this->get_model_version_info()->fields_that_have_rendered_format())
622
-            ) {
623
-                $result[$field_name] = array(
624
-                    'raw'      => $field_obj->prepare_for_get($field_value),
625
-                    'rendered' => $field_obj->prepare_for_pretty_echoing($field_value),
626
-                );
627
-            } elseif (
628
-            $this->is_subclass_of_one($field_obj, $this->get_model_version_info()->fields_that_have_pretty_format())
629
-            ) {
630
-                $result[$field_name] = array(
631
-                    'raw'    => $field_obj->prepare_for_get($field_value),
632
-                    'pretty' => $field_obj->prepare_for_pretty_echoing($field_value),
633
-                );
634
-            } elseif ($field_obj instanceof \EE_Datetime_Field) {
635
-                if ($field_value instanceof \DateTime) {
636
-                    $timezone = $field_value->getTimezone();
637
-                    $field_value->setTimezone(new \DateTimeZone('UTC'));
638
-                    $result[$field_name . '_gmt'] = Model_Data_Translator::prepare_field_value_for_json(
639
-                        $field_obj,
640
-                        $field_value,
641
-                        $this->get_model_version_info()->requested_version()
642
-                    );
643
-                    $field_value->setTimezone($timezone);
644
-                    $result[$field_name] = Model_Data_Translator::prepare_field_value_for_json(
645
-                        $field_obj,
646
-                        $field_value,
647
-                        $this->get_model_version_info()->requested_version()
648
-                    );
649
-                }
650
-            } else {
651
-                $result[$field_name] = Model_Data_Translator::prepare_field_value_for_json(
652
-                    $field_obj,
653
-                    $field_obj->prepare_for_get($field_value),
654
-                    $this->get_model_version_info()->requested_version()
655
-                );
656
-            }
657
-        }
658
-        return $result;
659
-    }
660
-
661
-
662
-
663
-    /**
664
-     * Adds a few extra fields to the entity response
665
-     *
666
-     * @param \EEM_Base $model
667
-     * @param array     $db_row
668
-     * @param array     $entity_array
669
-     * @return array modified entity
670
-     */
671
-    protected function _add_extra_fields(\EEM_Base $model, $db_row, $entity_array)
672
-    {
673
-        if ($model instanceof \EEM_CPT_Base) {
674
-            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
675
-        }
676
-        return $entity_array;
677
-    }
678
-
679
-
680
-
681
-    /**
682
-     * Gets links we want to add to the response
683
-     *
684
-     * @global \WP_REST_Server $wp_rest_server
685
-     * @param \EEM_Base        $model
686
-     * @param array            $db_row
687
-     * @param array            $entity_array
688
-     * @return array the _links item in the entity
689
-     */
690
-    protected function _get_entity_links($model, $db_row, $entity_array)
691
-    {
692
-        //add basic links
693
-        $links = array();
694
-        if ($model->has_primary_key_field()) {
695
-            $links['self'] = array(
696
-                array(
697
-                    'href' => $this->get_versioned_link_to(
698
-                        \EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
699
-                        . '/'
700
-                        . $entity_array[$model->primary_key_name()]
701
-                    ),
702
-                ),
703
-            );
704
-        }
705
-        $links['collection'] = array(
706
-            array(
707
-                'href' => $this->get_versioned_link_to(
708
-                    \EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
709
-                ),
710
-            ),
711
-        );
712
-        //add links to related models
713
-        if ($model->has_primary_key_field()) {
714
-            foreach ($this->get_model_version_info()->relation_settings($model) as $relation_name => $relation_obj) {
715
-                $related_model_part = Read::get_related_entity_name($relation_name, $relation_obj);
716
-                $links[\EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part] = array(
717
-                    array(
718
-                        'href'   => $this->get_versioned_link_to(
719
-                            \EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
720
-                            . '/'
721
-                            . $entity_array[$model->primary_key_name()]
722
-                            . '/'
723
-                            . $related_model_part
724
-                        ),
725
-                        'single' => $relation_obj instanceof \EE_Belongs_To_Relation ? true : false,
726
-                    ),
727
-                );
728
-            }
729
-        }
730
-        return $links;
731
-    }
732
-
733
-
734
-
735
-    /**
736
-     * Adds the included models indicated in the request to the entity provided
737
-     *
738
-     * @param \EEM_Base        $model
739
-     * @param \WP_REST_Request $rest_request
740
-     * @param array            $entity_array
741
-     * @param array            $db_row
742
-     * @return array the modified entity
743
-     */
744
-    protected function _include_requested_models(
745
-        \EEM_Base $model,
746
-        \WP_REST_Request $rest_request,
747
-        $entity_array,
748
-        $db_row = array()
749
-    ) {
750
-        //if $db_row not included, hope the entity array has what we need
751
-        if (! $db_row) {
752
-            $db_row = $entity_array;
753
-        }
754
-        $includes_for_this_model = $this->explode_and_get_items_prefixed_with($rest_request->get_param('include'), '');
755
-        $includes_for_this_model = $this->_remove_model_names_from_array($includes_for_this_model);
756
-        //if they passed in * or didn't specify any includes, return everything
757
-        if (! in_array('*', $includes_for_this_model)
758
-            && ! empty($includes_for_this_model)
759
-        ) {
760
-            if ($model->has_primary_key_field()) {
761
-                //always include the primary key. ya just gotta know that at least
762
-                $includes_for_this_model[] = $model->primary_key_name();
763
-            }
764
-            if ($this->explode_and_get_items_prefixed_with($rest_request->get_param('calculate'), '')) {
765
-                $includes_for_this_model[] = '_calculated_fields';
766
-            }
767
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
768
-        }
769
-        $relation_settings = $this->get_model_version_info()->relation_settings($model);
770
-        foreach ($relation_settings as $relation_name => $relation_obj) {
771
-            $related_fields_to_include = $this->explode_and_get_items_prefixed_with(
772
-                $rest_request->get_param('include'),
773
-                $relation_name
774
-            );
775
-            $related_fields_to_calculate = $this->explode_and_get_items_prefixed_with(
776
-                $rest_request->get_param('calculate'),
777
-                $relation_name
778
-            );
779
-            //did they specify they wanted to include a related model, or
780
-            //specific fields from a related model?
781
-            //or did they specify to calculate a field from a related model?
782
-            if ($related_fields_to_include || $related_fields_to_calculate) {
783
-                //if so, we should include at least some part of the related model
784
-                $pretend_related_request = new \WP_REST_Request();
785
-                $pretend_related_request->set_query_params(
786
-                    array(
787
-                        'caps'      => $rest_request->get_param('caps'),
788
-                        'include'   => $related_fields_to_include,
789
-                        'calculate' => $related_fields_to_calculate,
790
-                    )
791
-                );
792
-                $pretend_related_request->add_header('no_rest_headers', true);
793
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
794
-                    $model->get_index_primary_key_string(
795
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
796
-                    )
797
-                );
798
-                $related_results = $this->_get_entities_from_relation(
799
-                    $primary_model_query_params,
800
-                    $relation_obj,
801
-                    $pretend_related_request
802
-                );
803
-                $entity_array[Read::get_related_entity_name($relation_name, $relation_obj)] = $related_results
804
-                                                                                              instanceof
805
-                                                                                              \WP_Error
806
-                    ? null
807
-                    : $related_results;
808
-            }
809
-        }
810
-        return $entity_array;
811
-    }
812
-
813
-
814
-
815
-    /**
816
-     * Returns a new array with all the names of models removed. Eg
817
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
818
-     *
819
-     * @param array $arr
820
-     * @return array
821
-     */
822
-    private function _remove_model_names_from_array($arr)
823
-    {
824
-        return array_diff($arr, array_keys(\EE_Registry::instance()->non_abstract_db_models));
825
-    }
826
-
827
-
828
-
829
-    /**
830
-     * Gets the calculated fields for the response
831
-     *
832
-     * @param \EEM_Base        $model
833
-     * @param array            $wpdb_row
834
-     * @param \WP_REST_Request $rest_request
835
-     * @return \stdClass the _calculations item in the entity
836
-     */
837
-    protected function _get_entity_calculations($model, $wpdb_row, $rest_request)
838
-    {
839
-        $calculated_fields = $this->explode_and_get_items_prefixed_with(
840
-            $rest_request->get_param('calculate'),
841
-            ''
842
-        );
843
-        //note: setting calculate=* doesn't do anything
844
-        $calculated_fields_to_return = new \stdClass();
845
-        foreach ($calculated_fields as $field_to_calculate) {
846
-            try {
847
-                $calculated_fields_to_return->$field_to_calculate = Model_Data_Translator::prepare_field_value_for_json(
848
-                    null,
849
-                    $this->_fields_calculator->retrieve_calculated_field_value(
850
-                        $model,
851
-                        $field_to_calculate,
852
-                        $wpdb_row,
853
-                        $rest_request,
854
-                        $this
855
-                    ),
856
-                    $this->get_model_version_info()->requested_version()
857
-                );
858
-            } catch (Rest_Exception $e) {
859
-                //if we don't have permission to read it, just leave it out. but let devs know about the problem
860
-                $this->_set_response_header(
861
-                    'Notices-Field-Calculation-Errors['
862
-                    . $e->get_string_code()
863
-                    . ']['
864
-                    . $model->get_this_model_name()
865
-                    . ']['
866
-                    . $field_to_calculate
867
-                    . ']',
868
-                    $e->getMessage(),
869
-                    true
870
-                );
871
-            }
872
-        }
873
-        return $calculated_fields_to_return;
874
-    }
875
-
876
-
877
-
878
-    /**
879
-     * Gets the full URL to the resource, taking the requested version into account
880
-     *
881
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
882
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
883
-     */
884
-    public function get_versioned_link_to($link_part_after_version_and_slash)
885
-    {
886
-        return rest_url(
887
-            \EED_Core_Rest_Api::ee_api_namespace
888
-            . $this->get_model_version_info()->requested_version()
889
-            . '/'
890
-            . $link_part_after_version_and_slash
891
-        );
892
-    }
893
-
894
-
895
-
896
-    /**
897
-     * Gets the correct lowercase name for the relation in the API according
898
-     * to the relation's type
899
-     *
900
-     * @param string                  $relation_name
901
-     * @param \EE_Model_Relation_Base $relation_obj
902
-     * @return string
903
-     */
904
-    public static function get_related_entity_name($relation_name, $relation_obj)
905
-    {
906
-        if ($relation_obj instanceof \EE_Belongs_To_Relation) {
907
-            return strtolower($relation_name);
908
-        } else {
909
-            return \EEH_Inflector::pluralize_and_lower($relation_name);
910
-        }
911
-    }
912
-
913
-
914
-
915
-    /**
916
-     * Gets the one model object with the specified id for the specified model
917
-     *
918
-     * @param \EEM_Base        $model
919
-     * @param \WP_REST_Request $request
920
-     * @return array|\WP_Error
921
-     */
922
-    public function get_entity_from_model($model, $request)
923
-    {
924
-        $query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
925
-        if ($model instanceof \EEM_Soft_Delete_Base) {
926
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
927
-        }
928
-        $restricted_query_params = $query_params;
929
-        $restricted_query_params['caps'] = $this->validate_context($request->get_param('caps'));
930
-        $this->_set_debug_info('model query params', $restricted_query_params);
931
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
932
-        if (! empty ($model_rows)) {
933
-            return $this->create_entity_from_wpdb_result(
934
-                $model,
935
-                array_shift($model_rows),
936
-                $request);
937
-        } else {
938
-            //ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
939
-            $lowercase_model_name = strtolower($model->get_this_model_name());
940
-            $model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
941
-            if (! empty($model_rows_found_sans_restrictions)) {
942
-                //you got shafted- it existed but we didn't want to tell you!
943
-                return new \WP_Error(
944
-                    'rest_user_cannot_read',
945
-                    sprintf(
946
-                        __('Sorry, you cannot read this %1$s. Missing permissions are: %2$s', 'event_espresso'),
947
-                        strtolower($model->get_this_model_name()),
948
-                        Capabilities::get_missing_permissions_string(
949
-                            $model,
950
-                            $this->validate_context($request->get_param('caps')))
951
-                    ),
952
-                    array('status' => 403)
953
-                );
954
-            } else {
955
-                //it's not you. It just doesn't exist
956
-                return new \WP_Error(
957
-                    sprintf('rest_%s_invalid_id', $lowercase_model_name),
958
-                    sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
959
-                    array('status' => 404)
960
-                );
961
-            }
962
-        }
963
-    }
964
-
965
-
966
-
967
-    /**
968
-     * If a context is provided which isn't valid, maybe it was added in a future
969
-     * version so just treat it as a default read
970
-     *
971
-     * @param string $context
972
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
973
-     */
974
-    public function validate_context($context)
975
-    {
976
-        if (! $context) {
977
-            $context = \EEM_Base::caps_read;
978
-        }
979
-        $valid_contexts = \EEM_Base::valid_cap_contexts();
980
-        if (in_array($context, $valid_contexts)) {
981
-            return $context;
982
-        } else {
983
-            return \EEM_Base::caps_read;
984
-        }
985
-    }
986
-
987
-
988
-
989
-    /**
990
-     * Verifies the passed in value is an allowable default where conditions value.
991
-     *
992
-     * @param $default_query_params
993
-     * @return string
994
-     */
995
-    public function validate_default_query_params($default_query_params)
996
-    {
997
-        $valid_default_where_conditions_for_api_calls = array(
998
-            \EEM_Base::default_where_conditions_all,
999
-            \EEM_Base::default_where_conditions_minimum_all,
1000
-            \EEM_Base::default_where_conditions_minimum_others,
1001
-        );
1002
-        if (! $default_query_params) {
1003
-            $default_query_params = \EEM_Base::default_where_conditions_all;
1004
-        }
1005
-        if (
1006
-        in_array(
1007
-            $default_query_params,
1008
-            $valid_default_where_conditions_for_api_calls,
1009
-            true
1010
-        )
1011
-        ) {
1012
-            return $default_query_params;
1013
-        } else {
1014
-            return \EEM_Base::default_where_conditions_all;
1015
-        }
1016
-    }
1017
-
1018
-
1019
-
1020
-    /**
1021
-     * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1022
-     * Note: right now the query parameter keys for fields (and related fields)
1023
-     * can be left as-is, but it's quite possible this will change someday.
1024
-     * Also, this method's contents might be candidate for moving to Model_Data_Translator
1025
-     *
1026
-     * @param \EEM_Base $model
1027
-     * @param array     $query_parameters from $_GET parameter @see Read:handle_request_get_all
1028
-     * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1029
-     *                                    that absolutely no results should be returned
1030
-     * @throws \EE_Error
1031
-     */
1032
-    public function create_model_query_params($model, $query_parameters)
1033
-    {
1034
-        $model_query_params = array();
1035
-        if (isset($query_parameters['where'])) {
1036
-            $model_query_params[0] = Model_Data_Translator::prepare_conditions_query_params_for_models(
1037
-                $query_parameters['where'],
1038
-                $model,
1039
-                $this->get_model_version_info()->requested_version()
1040
-            );
1041
-        }
1042
-        if (isset($query_parameters['order_by'])) {
1043
-            $order_by = $query_parameters['order_by'];
1044
-        } elseif (isset($query_parameters['orderby'])) {
1045
-            $order_by = $query_parameters['orderby'];
1046
-        } else {
1047
-            $order_by = null;
1048
-        }
1049
-        if ($order_by !== null) {
1050
-            if (is_array($order_by)) {
1051
-                $order_by = Model_Data_Translator::prepare_field_names_in_array_keys_from_json($order_by);
1052
-            } else {
1053
-                //it's a single item
1054
-                $order_by = Model_Data_Translator::prepare_field_name_from_json($order_by);
1055
-            }
1056
-            $model_query_params['order_by'] = $order_by;
1057
-        }
1058
-        if (isset($query_parameters['group_by'])) {
1059
-            $group_by = $query_parameters['group_by'];
1060
-        } elseif (isset($query_parameters['groupby'])) {
1061
-            $group_by = $query_parameters['groupby'];
1062
-        } else {
1063
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1064
-        }
1065
-        //make sure they're all real names
1066
-        if (is_array($group_by)) {
1067
-            $group_by = Model_Data_Translator::prepare_field_names_from_json($group_by);
1068
-        }
1069
-        if ($group_by !== null) {
1070
-            $model_query_params['group_by'] = $group_by;
1071
-        }
1072
-        if (isset($query_parameters['having'])) {
1073
-            $model_query_params['having'] = Model_Data_Translator::prepare_conditions_query_params_for_models(
1074
-                $query_parameters['having'],
1075
-                $model,
1076
-                $this->get_model_version_info()->requested_version()
1077
-            );
1078
-        }
1079
-        if (isset($query_parameters['order'])) {
1080
-            $model_query_params['order'] = $query_parameters['order'];
1081
-        }
1082
-        if (isset($query_parameters['mine'])) {
1083
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1084
-        }
1085
-        if (isset($query_parameters['limit'])) {
1086
-            //limit should be either a string like '23' or '23,43', or an array with two items in it
1087
-            if (! is_array($query_parameters['limit'])) {
1088
-                $limit_array = explode(',', (string)$query_parameters['limit']);
1089
-            } else {
1090
-                $limit_array = $query_parameters['limit'];
1091
-            }
1092
-            $sanitized_limit = array();
1093
-            foreach ($limit_array as $key => $limit_part) {
1094
-                if ($this->_debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1095
-                    throw new \EE_Error(
1096
-                        sprintf(
1097
-                            __('An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1098
-                                'event_espresso'),
1099
-                            wp_json_encode($query_parameters['limit'])
1100
-                        )
1101
-                    );
1102
-                }
1103
-                $sanitized_limit[] = (int)$limit_part;
1104
-            }
1105
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1106
-        } else {
1107
-            $model_query_params['limit'] = \EED_Core_Rest_Api::get_default_query_limit();
1108
-        }
1109
-        if (isset($query_parameters['caps'])) {
1110
-            $model_query_params['caps'] = $this->validate_context($query_parameters['caps']);
1111
-        } else {
1112
-            $model_query_params['caps'] = \EEM_Base::caps_read;
1113
-        }
1114
-        if (isset($query_parameters['default_where_conditions'])) {
1115
-            $model_query_params['default_where_conditions'] = $this->validate_default_query_params($query_parameters['default_where_conditions']);
1116
-        }
1117
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1118
-    }
1119
-
1120
-
1121
-
1122
-    /**
1123
-     * Changes the REST-style query params for use in the models
1124
-     *
1125
-     * @deprecated
1126
-     * @param \EEM_Base $model
1127
-     * @param array     $query_params sub-array from @see EEM_Base::get_all()
1128
-     * @return array
1129
-     */
1130
-    public function prepare_rest_query_params_key_for_models($model, $query_params)
1131
-    {
1132
-        $model_ready_query_params = array();
1133
-        foreach ($query_params as $key => $value) {
1134
-            if (is_array($value)) {
1135
-                $model_ready_query_params[$key] = $this->prepare_rest_query_params_key_for_models($model, $value);
1136
-            } else {
1137
-                $model_ready_query_params[$key] = $value;
1138
-            }
1139
-        }
1140
-        return $model_ready_query_params;
1141
-    }
1142
-
1143
-
1144
-
1145
-    /**
1146
-     * @deprecated
1147
-     * @param $model
1148
-     * @param $query_params
1149
-     * @return array
1150
-     */
1151
-    public function prepare_rest_query_params_values_for_models($model, $query_params)
1152
-    {
1153
-        $model_ready_query_params = array();
1154
-        foreach ($query_params as $key => $value) {
1155
-            if (is_array($value)) {
1156
-                $model_ready_query_params[$key] = $this->prepare_rest_query_params_values_for_models($model, $value);
1157
-            } else {
1158
-                $model_ready_query_params[$key] = $value;
1159
-            }
1160
-        }
1161
-        return $model_ready_query_params;
1162
-    }
1163
-
1164
-
1165
-
1166
-    /**
1167
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1168
-     * If no prefix is specified, returns items with no period.
1169
-     *
1170
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blaabla" or array('jibba', 'jabba' )
1171
-     * @param string       $prefix            "Event" or "foobar"
1172
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1173
-     *                                        we only return strings starting with that and a period; if no prefix was
1174
-     *                                        specified we return all items containing NO periods
1175
-     */
1176
-    public function explode_and_get_items_prefixed_with($string_to_explode, $prefix)
1177
-    {
1178
-        if (is_string($string_to_explode)) {
1179
-            $exploded_contents = explode(',', $string_to_explode);
1180
-        } else if (is_array($string_to_explode)) {
1181
-            $exploded_contents = $string_to_explode;
1182
-        } else {
1183
-            $exploded_contents = array();
1184
-        }
1185
-        //if the string was empty, we want an empty array
1186
-        $exploded_contents = array_filter($exploded_contents);
1187
-        $contents_with_prefix = array();
1188
-        foreach ($exploded_contents as $item) {
1189
-            $item = trim($item);
1190
-            //if no prefix was provided, so we look for items with no "." in them
1191
-            if (! $prefix) {
1192
-                //does this item have a period?
1193
-                if (strpos($item, '.') === false) {
1194
-                    //if not, then its what we're looking for
1195
-                    $contents_with_prefix[] = $item;
1196
-                }
1197
-            } else if (strpos($item, $prefix . '.') === 0) {
1198
-                //this item has the prefix and a period, grab it
1199
-                $contents_with_prefix[] = substr(
1200
-                    $item,
1201
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1202
-                );
1203
-            } else if ($item === $prefix) {
1204
-                //this item is JUST the prefix
1205
-                //so let's grab everything after, which is a blank string
1206
-                $contents_with_prefix[] = '';
1207
-            }
1208
-        }
1209
-        return $contents_with_prefix;
1210
-    }
1211
-
1212
-
1213
-
1214
-    /**
1215
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1216
-     * Deprecated because its return values were really quite confusing- sometimes it returned
1217
-     * an empty array (when the include string was blank or '*') or sometimes it returned
1218
-     * array('*') (when you provided a model and a model of that kind was found).
1219
-     * Parses the $include_string so we fetch all the field names relating to THIS model
1220
-     * (ie have NO period in them), or for the provided model (ie start with the model
1221
-     * name and then a period).
1222
-     * @param string $include_string @see Read:handle_request_get_all
1223
-     * @param string $model_name
1224
-     * @return array of fields for this model. If $model_name is provided, then
1225
-     *                               the fields for that model, with the model's name removed from each.
1226
-     *                               If $include_string was blank or '*' returns an empty array
1227
-     */
1228
-    public function extract_includes_for_this_model($include_string, $model_name = null)
1229
-    {
1230
-        if (is_array($include_string)) {
1231
-            $include_string = implode(',', $include_string);
1232
-        }
1233
-        if ($include_string === '*' || $include_string === '') {
1234
-            return array();
1235
-        }
1236
-        $includes = explode(',', $include_string);
1237
-        $extracted_fields_to_include = array();
1238
-        if ($model_name) {
1239
-            foreach ($includes as $field_to_include) {
1240
-                $field_to_include = trim($field_to_include);
1241
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1242
-                    //found the model name at the exact start
1243
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1244
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1245
-                } elseif ($field_to_include == $model_name) {
1246
-                    $extracted_fields_to_include[] = '*';
1247
-                }
1248
-            }
1249
-        } else {
1250
-            //look for ones with no period
1251
-            foreach ($includes as $field_to_include) {
1252
-                $field_to_include = trim($field_to_include);
1253
-                if (
1254
-                    strpos($field_to_include, '.') === false
1255
-                    && ! $this->get_model_version_info()->is_model_name_in_this_version($field_to_include)
1256
-                ) {
1257
-                    $extracted_fields_to_include[] = $field_to_include;
1258
-                }
1259
-            }
1260
-        }
1261
-        return $extracted_fields_to_include;
1262
-    }
30
+	/**
31
+	 * @var Calculated_Model_Fields
32
+	 */
33
+	protected $_fields_calculator;
34
+
35
+
36
+
37
+	/**
38
+	 * Read constructor.
39
+	 */
40
+	public function __construct()
41
+	{
42
+		parent::__construct();
43
+		$this->_fields_calculator = new Calculated_Model_Fields();
44
+	}
45
+
46
+
47
+
48
+	/**
49
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
50
+	 *
51
+	 * @param \WP_REST_Request $request
52
+	 * @return \WP_REST_Response|\WP_Error
53
+	 */
54
+	public static function handle_request_get_all(\WP_REST_Request $request)
55
+	{
56
+		$controller = new Read();
57
+		try {
58
+			$matches = $controller->parse_route(
59
+				$request->get_route(),
60
+				'~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)~',
61
+				array('version', 'model')
62
+			);
63
+			$controller->set_requested_version($matches['version']);
64
+			$model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
65
+			if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
66
+				return $controller->send_response(
67
+					new \WP_Error(
68
+						'endpoint_parsing_error',
69
+						sprintf(
70
+							__('There is no model for endpoint %s. Please contact event espresso support',
71
+								'event_espresso'),
72
+							$model_name_singular
73
+						)
74
+					)
75
+				);
76
+			}
77
+			return $controller->send_response(
78
+				$controller->get_entities_from_model(
79
+					$controller->get_model_version_info()->load_model($model_name_singular),
80
+					$request
81
+				)
82
+			);
83
+		} catch (\Exception $e) {
84
+			return $controller->send_response($e);
85
+		}
86
+	}
87
+
88
+
89
+	/**
90
+	 * Prepares and returns schema for any OPTIONS request.
91
+	 *
92
+	 * @param string $model_name  Something like `Event` or `Registration`
93
+	 * @param string $version     The API endpoint version being used.
94
+	 * @return array
95
+	 */
96
+	public static function handle_schema_request($model_name, $version)
97
+	{
98
+		$controller = new Read();
99
+		try {
100
+			$controller->set_requested_version($version);
101
+			if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name)) {
102
+				return array();
103
+			}
104
+			//get the model for this version
105
+			$model = $controller->get_model_version_info()->load_model($model_name);
106
+			$model_schema = new JsonModelSchema($model);
107
+			return $model_schema->getModelSchemaForRelations(
108
+				$controller->get_model_version_info()->relation_settings($model),
109
+				$controller->_customize_schema_for_rest_response(
110
+					$model,
111
+					$model_schema->getModelSchemaForFields(
112
+						$controller->get_model_version_info()->fields_on_model_in_this_version($model),
113
+						$model_schema->getInitialSchemaStructure()
114
+					)
115
+				)
116
+			);
117
+		} catch (\Exception $e) {
118
+			return array();
119
+		}
120
+	}
121
+
122
+
123
+	/**
124
+	 * This loops through each field in the given schema for the model and does the following:
125
+	 * - add any extra fields that are REST API specific and related to existing fields.
126
+	 * - transform default values into the correct format for a REST API response.
127
+	 *
128
+	 * @param \EEM_Base $model
129
+	 * @param array     $schema
130
+	 * @return array  The final schema.
131
+	 */
132
+	protected function _customize_schema_for_rest_response(\EEM_Base $model, array $schema)
133
+	{
134
+	   foreach ($this->get_model_version_info()->fields_on_model_in_this_version($model) as $field_name => $field) {
135
+		   $schema = $this->_translate_defaults_for_rest_response(
136
+			   $field_name,
137
+			   $field,
138
+			   $this->_maybe_add_extra_fields_to_schema($field_name, $field, $schema)
139
+			);
140
+	   }
141
+	   return $schema;
142
+	}
143
+
144
+
145
+	/**
146
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
147
+	 * response.
148
+	 *
149
+	 * @param                      $field_name
150
+	 * @param \EE_Model_Field_Base $field
151
+	 * @param array                $schema
152
+	 * @return array
153
+	 */
154
+	protected function _translate_defaults_for_rest_response($field_name, \EE_Model_Field_Base $field, array $schema)
155
+	{
156
+		if (isset($schema['properties'][$field_name]['default'])) {
157
+			if (is_array($schema['properties'][$field_name]['default'])) {
158
+				foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
159
+					if ($default_key === 'raw') {
160
+						$schema['properties'][$field_name]['default'][$default_key] = Model_Data_Translator::prepare_field_value_for_json(
161
+							$field,
162
+							$default_value,
163
+							$this->get_model_version_info()->requested_version()
164
+						);
165
+					}
166
+				}
167
+			} else {
168
+				$schema['properties'][$field_name]['default'] = Model_Data_Translator::prepare_field_value_for_json(
169
+					$field,
170
+					$schema['properties'][$field_name]['default'],
171
+					$this->get_model_version_info()->requested_version()
172
+				);
173
+			}
174
+		}
175
+		return $schema;
176
+	}
177
+
178
+
179
+	/**
180
+	 * Adds additional fields to the schema
181
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
182
+	 * needs to be added to the schema.
183
+	 *
184
+	 * @param                      $field_name
185
+	 * @param \EE_Model_Field_Base $field
186
+	 * @param array                $schema
187
+	 * @return array
188
+	 */
189
+	protected function _maybe_add_extra_fields_to_schema($field_name, \EE_Model_Field_Base $field, array $schema)
190
+	{
191
+		if ($field instanceof EE_Datetime_Field) {
192
+			$schema['properties'][$field_name . '_gmt'] = $field->getSchema();
193
+			//modify the description
194
+			$schema['properties'][$field_name . '_gmt']['description'] = sprintf(
195
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
196
+				$field->get_nicename()
197
+			);
198
+		}
199
+		return $schema;
200
+	}
201
+
202
+
203
+
204
+
205
+	/**
206
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
207
+	 * @return string
208
+	 */
209
+	protected function get_route_from_request() {
210
+		if (isset($GLOBALS['wp'])
211
+			&& $GLOBALS['wp'] instanceof \WP
212
+			&& isset($GLOBALS['wp']->query_vars['rest_route'] )
213
+		) {
214
+			return $GLOBALS['wp']->query_vars['rest_route'];
215
+		} else {
216
+			return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
217
+		}
218
+	}
219
+
220
+
221
+
222
+	/**
223
+	 * Gets a single entity related to the model indicated in the path and its id
224
+	 *
225
+	 * @param \WP_REST_Request $request
226
+	 * @return \WP_REST_Response|\WP_Error
227
+	 */
228
+	public static function handle_request_get_one(\WP_REST_Request $request)
229
+	{
230
+		$controller = new Read();
231
+		try {
232
+			$matches = $controller->parse_route(
233
+				$request->get_route(),
234
+				'~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)~',
235
+				array('version', 'model', 'id'));
236
+			$controller->set_requested_version($matches['version']);
237
+			$model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
238
+			if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
239
+				return $controller->send_response(
240
+					new \WP_Error(
241
+						'endpoint_parsing_error',
242
+						sprintf(
243
+							__('There is no model for endpoint %s. Please contact event espresso support',
244
+								'event_espresso'),
245
+							$model_name_singular
246
+						)
247
+					)
248
+				);
249
+			}
250
+			return $controller->send_response(
251
+				$controller->get_entity_from_model(
252
+					$controller->get_model_version_info()->load_model($model_name_singular),
253
+					$request
254
+				)
255
+			);
256
+		} catch (\Exception $e) {
257
+			return $controller->send_response($e);
258
+		}
259
+	}
260
+
261
+
262
+
263
+	/**
264
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
265
+	 * to the item with the given id
266
+	 *
267
+	 * @param \WP_REST_Request $request
268
+	 * @return \WP_REST_Response|\WP_Error
269
+	 */
270
+	public static function handle_request_get_related(\WP_REST_Request $request)
271
+	{
272
+		$controller = new Read();
273
+		try {
274
+			$matches = $controller->parse_route(
275
+				$request->get_route(),
276
+				'~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)/(.*)~',
277
+				array('version', 'model', 'id', 'related_model')
278
+			);
279
+			$controller->set_requested_version($matches['version']);
280
+			$main_model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
281
+			if (! $controller->get_model_version_info()->is_model_name_in_this_version($main_model_name_singular)) {
282
+				return $controller->send_response(
283
+					new \WP_Error(
284
+						'endpoint_parsing_error',
285
+						sprintf(
286
+							__('There is no model for endpoint %s. Please contact event espresso support',
287
+								'event_espresso'),
288
+							$main_model_name_singular
289
+						)
290
+					)
291
+				);
292
+			}
293
+			$main_model = $controller->get_model_version_info()->load_model($main_model_name_singular);
294
+			//assume the related model name is plural and try to find the model's name
295
+			$related_model_name_singular = \EEH_Inflector::singularize_and_upper($matches['related_model']);
296
+			if (! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
297
+				//so the word didn't singularize well. Maybe that's just because it's a singular word?
298
+				$related_model_name_singular = \EEH_Inflector::humanize($matches['related_model']);
299
+			}
300
+			if (! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
301
+				return $controller->send_response(
302
+					new \WP_Error(
303
+						'endpoint_parsing_error',
304
+						sprintf(
305
+							__('There is no model for endpoint %s. Please contact event espresso support',
306
+								'event_espresso'),
307
+							$related_model_name_singular
308
+						)
309
+					)
310
+				);
311
+			}
312
+			return $controller->send_response(
313
+				$controller->get_entities_from_relation(
314
+					$request->get_param('id'),
315
+					$main_model->related_settings_for($related_model_name_singular),
316
+					$request
317
+				)
318
+			);
319
+		} catch (\Exception $e) {
320
+			return $controller->send_response($e);
321
+		}
322
+	}
323
+
324
+
325
+
326
+	/**
327
+	 * Gets a collection for the given model and filters
328
+	 *
329
+	 * @param \EEM_Base        $model
330
+	 * @param \WP_REST_Request $request
331
+	 * @return array|\WP_Error
332
+	 */
333
+	public function get_entities_from_model($model, $request)
334
+	{
335
+		$query_params = $this->create_model_query_params($model, $request->get_params());
336
+		if (! Capabilities::current_user_has_partial_access_to($model, $query_params['caps'])) {
337
+			$model_name_plural = \EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
338
+			return new \WP_Error(
339
+				sprintf('rest_%s_cannot_list', $model_name_plural),
340
+				sprintf(
341
+					__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
342
+					$model_name_plural,
343
+					Capabilities::get_missing_permissions_string($model, $query_params['caps'])
344
+				),
345
+				array('status' => 403)
346
+			);
347
+		}
348
+		if (! $request->get_header('no_rest_headers')) {
349
+			$this->_set_headers_from_query_params($model, $query_params);
350
+		}
351
+		/** @type array $results */
352
+		$results = $model->get_all_wpdb_results($query_params);
353
+		$nice_results = array();
354
+		foreach ($results as $result) {
355
+			$nice_results[] = $this->create_entity_from_wpdb_result(
356
+				$model,
357
+				$result,
358
+				$request
359
+			);
360
+		}
361
+		return $nice_results;
362
+	}
363
+
364
+
365
+
366
+	/**
367
+	 * @param array                   $primary_model_query_params query params for finding the item from which
368
+	 *                                                            relations will be based
369
+	 * @param \EE_Model_Relation_Base $relation
370
+	 * @param \WP_REST_Request        $request
371
+	 * @return \WP_Error|array
372
+	 */
373
+	protected function _get_entities_from_relation($primary_model_query_params, $relation, $request)
374
+	{
375
+		$context = $this->validate_context($request->get_param('caps'));
376
+		$model = $relation->get_this_model();
377
+		$related_model = $relation->get_other_model();
378
+		if (! isset($primary_model_query_params[0])) {
379
+			$primary_model_query_params[0] = array();
380
+		}
381
+		//check if they can access the 1st model object
382
+		$primary_model_query_params = array(
383
+			0       => $primary_model_query_params[0],
384
+			'limit' => 1,
385
+		);
386
+		if ($model instanceof \EEM_Soft_Delete_Base) {
387
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($primary_model_query_params);
388
+		}
389
+		$restricted_query_params = $primary_model_query_params;
390
+		$restricted_query_params['caps'] = $context;
391
+		$this->_set_debug_info('main model query params', $restricted_query_params);
392
+		$this->_set_debug_info('missing caps', Capabilities::get_missing_permissions_string($related_model, $context));
393
+		if (
394
+		! (
395
+			Capabilities::current_user_has_partial_access_to($related_model, $context)
396
+			&& $model->exists($restricted_query_params)
397
+		)
398
+		) {
399
+			if ($relation instanceof \EE_Belongs_To_Relation) {
400
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
401
+			} else {
402
+				$related_model_name_maybe_plural = \EEH_Inflector::pluralize_and_lower($related_model->get_this_model_name());
403
+			}
404
+			return new \WP_Error(
405
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
406
+				sprintf(
407
+					__('Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
408
+						'event_espresso'),
409
+					$related_model_name_maybe_plural,
410
+					$relation->get_this_model()->get_this_model_name(),
411
+					implode(
412
+						',',
413
+						array_keys(
414
+							Capabilities::get_missing_permissions($related_model, $context)
415
+						)
416
+					)
417
+				),
418
+				array('status' => 403)
419
+			);
420
+		}
421
+		$query_params = $this->create_model_query_params($relation->get_other_model(), $request->get_params());
422
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
423
+			$query_params[0][$relation->get_this_model()->get_this_model_name()
424
+							 . '.'
425
+							 . $where_condition_key] = $where_condition_value;
426
+		}
427
+		$query_params['default_where_conditions'] = 'none';
428
+		$query_params['caps'] = $context;
429
+		if (! $request->get_header('no_rest_headers')) {
430
+			$this->_set_headers_from_query_params($relation->get_other_model(), $query_params);
431
+		}
432
+		/** @type array $results */
433
+		$results = $relation->get_other_model()->get_all_wpdb_results($query_params);
434
+		$nice_results = array();
435
+		foreach ($results as $result) {
436
+			$nice_result = $this->create_entity_from_wpdb_result(
437
+				$relation->get_other_model(),
438
+				$result,
439
+				$request
440
+			);
441
+			if ($relation instanceof \EE_HABTM_Relation) {
442
+				//put the unusual stuff (properties from the HABTM relation) first, and make sure
443
+				//if there are conflicts we prefer the properties from the main model
444
+				$join_model_result = $this->create_entity_from_wpdb_result(
445
+					$relation->get_join_model(),
446
+					$result,
447
+					$request
448
+				);
449
+				$joined_result = array_merge($nice_result, $join_model_result);
450
+				//but keep the meta stuff from the main model
451
+				if (isset($nice_result['meta'])) {
452
+					$joined_result['meta'] = $nice_result['meta'];
453
+				}
454
+				$nice_result = $joined_result;
455
+			}
456
+			$nice_results[] = $nice_result;
457
+		}
458
+		if ($relation instanceof \EE_Belongs_To_Relation) {
459
+			return array_shift($nice_results);
460
+		} else {
461
+			return $nice_results;
462
+		}
463
+	}
464
+
465
+
466
+
467
+	/**
468
+	 * Gets the collection for given relation object
469
+	 * The same as Read::get_entities_from_model(), except if the relation
470
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
471
+	 * the join-model-object into the results
472
+	 *
473
+	 * @param string                  $id the ID of the thing we are fetching related stuff from
474
+	 * @param \EE_Model_Relation_Base $relation
475
+	 * @param \WP_REST_Request        $request
476
+	 * @return array|\WP_Error
477
+	 * @throws \EE_Error
478
+	 */
479
+	public function get_entities_from_relation($id, $relation, $request)
480
+	{
481
+		if (! $relation->get_this_model()->has_primary_key_field()) {
482
+			throw new \EE_Error(
483
+				sprintf(
484
+					__('Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
485
+						'event_espresso'),
486
+					$relation->get_this_model()->get_this_model_name()
487
+				)
488
+			);
489
+		}
490
+		return $this->_get_entities_from_relation(
491
+			array(
492
+				array(
493
+					$relation->get_this_model()->primary_key_name() => $id,
494
+				),
495
+			),
496
+			$relation,
497
+			$request
498
+		);
499
+	}
500
+
501
+
502
+
503
+	/**
504
+	 * Sets the headers that are based on the model and query params,
505
+	 * like the total records. This should only be called on the original request
506
+	 * from the client, not on subsequent internal
507
+	 *
508
+	 * @param \EEM_Base $model
509
+	 * @param array     $query_params
510
+	 * @return void
511
+	 */
512
+	protected function _set_headers_from_query_params($model, $query_params)
513
+	{
514
+		$this->_set_debug_info('model query params', $query_params);
515
+		$this->_set_debug_info('missing caps',
516
+			Capabilities::get_missing_permissions_string($model, $query_params['caps']));
517
+		//normally the limit to a 2-part array, where the 2nd item is the limit
518
+		if (! isset($query_params['limit'])) {
519
+			$query_params['limit'] = \EED_Core_Rest_Api::get_default_query_limit();
520
+		}
521
+		if (is_array($query_params['limit'])) {
522
+			$limit_parts = $query_params['limit'];
523
+		} else {
524
+			$limit_parts = explode(',', $query_params['limit']);
525
+			if (count($limit_parts) == 1) {
526
+				$limit_parts = array(0, $limit_parts[0]);
527
+			}
528
+		}
529
+		//remove the group by and having parts of the query, as those will
530
+		//make the sql query return an array of values, instead of just a single value
531
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
532
+		$count = $model->count($query_params, null, true);
533
+		$pages = $count / $limit_parts[1];
534
+		$this->_set_response_header('Total', $count, false);
535
+		$this->_set_response_header('PageSize', $limit_parts[1], false);
536
+		$this->_set_response_header('TotalPages', ceil($pages), false);
537
+	}
538
+
539
+
540
+
541
+	/**
542
+	 * Changes database results into REST API entities
543
+	 *
544
+	 * @param \EEM_Base        $model
545
+	 * @param array            $db_row     like results from $wpdb->get_results()
546
+	 * @param \WP_REST_Request $rest_request
547
+	 * @param string           $deprecated no longer used
548
+	 * @return array ready for being converted into json for sending to client
549
+	 */
550
+	public function create_entity_from_wpdb_result($model, $db_row, $rest_request, $deprecated = null)
551
+	{
552
+		if (! $rest_request instanceof \WP_REST_Request) {
553
+			//ok so this was called in the old style, where the 3rd arg was
554
+			//$include, and the 4th arg was $context
555
+			//now setup the request just to avoid fatal errors, although we won't be able
556
+			//to truly make use of it because it's kinda devoid of info
557
+			$rest_request = new \WP_REST_Request();
558
+			$rest_request->set_param('include', $rest_request);
559
+			$rest_request->set_param('caps', $deprecated);
560
+		}
561
+		if ($rest_request->get_param('caps') == null) {
562
+			$rest_request->set_param('caps', \EEM_Base::caps_read);
563
+		}
564
+		$entity_array = $this->_create_bare_entity_from_wpdb_results($model, $db_row);
565
+		$entity_array = $this->_add_extra_fields($model, $db_row, $entity_array);
566
+		$entity_array['_links'] = $this->_get_entity_links($model, $db_row, $entity_array);
567
+		$entity_array['_calculated_fields'] = $this->_get_entity_calculations($model, $db_row, $rest_request);
568
+		$entity_array = apply_filters( 'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models', $entity_array, $model, $rest_request->get_param('caps'),$rest_request,$this);
569
+		$entity_array = $this->_include_requested_models($model, $rest_request, $entity_array, $db_row);
570
+		$entity_array = apply_filters(
571
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
572
+			$entity_array,
573
+			$model,
574
+			$rest_request->get_param('caps'),
575
+			$rest_request,
576
+			$this
577
+		);
578
+		$result_without_inaccessible_fields = Capabilities::filter_out_inaccessible_entity_fields(
579
+			$entity_array,
580
+			$model,
581
+			$rest_request->get_param('caps'),
582
+			$this->get_model_version_info(),
583
+			$model->get_index_primary_key_string(
584
+				$model->deduce_fields_n_values_from_cols_n_values($db_row)
585
+			)
586
+		);
587
+		$this->_set_debug_info(
588
+			'inaccessible fields',
589
+			array_keys(array_diff_key($entity_array, $result_without_inaccessible_fields))
590
+		);
591
+		return apply_filters(
592
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
593
+			$result_without_inaccessible_fields,
594
+			$model,
595
+			$rest_request->get_param('caps')
596
+		);
597
+	}
598
+
599
+
600
+
601
+	/**
602
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
603
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
604
+	 * from $wpdb->get_row( $sql, ARRAY_A)
605
+	 *
606
+	 * @param \EEM_Base $model
607
+	 * @param array     $db_row
608
+	 * @return array entity mostly ready for converting to JSON and sending in the response
609
+	 */
610
+	protected function _create_bare_entity_from_wpdb_results(\EEM_Base $model, $db_row)
611
+	{
612
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
613
+		$result = array_intersect_key($result,
614
+			$this->get_model_version_info()->fields_on_model_in_this_version($model));
615
+		foreach ($result as $field_name => $raw_field_value) {
616
+			$field_obj = $model->field_settings_for($field_name);
617
+			$field_value = $field_obj->prepare_for_set_from_db($raw_field_value);
618
+			if ($this->is_subclass_of_one($field_obj, $this->get_model_version_info()->fields_ignored())) {
619
+				unset($result[$field_name]);
620
+			} elseif (
621
+			$this->is_subclass_of_one($field_obj, $this->get_model_version_info()->fields_that_have_rendered_format())
622
+			) {
623
+				$result[$field_name] = array(
624
+					'raw'      => $field_obj->prepare_for_get($field_value),
625
+					'rendered' => $field_obj->prepare_for_pretty_echoing($field_value),
626
+				);
627
+			} elseif (
628
+			$this->is_subclass_of_one($field_obj, $this->get_model_version_info()->fields_that_have_pretty_format())
629
+			) {
630
+				$result[$field_name] = array(
631
+					'raw'    => $field_obj->prepare_for_get($field_value),
632
+					'pretty' => $field_obj->prepare_for_pretty_echoing($field_value),
633
+				);
634
+			} elseif ($field_obj instanceof \EE_Datetime_Field) {
635
+				if ($field_value instanceof \DateTime) {
636
+					$timezone = $field_value->getTimezone();
637
+					$field_value->setTimezone(new \DateTimeZone('UTC'));
638
+					$result[$field_name . '_gmt'] = Model_Data_Translator::prepare_field_value_for_json(
639
+						$field_obj,
640
+						$field_value,
641
+						$this->get_model_version_info()->requested_version()
642
+					);
643
+					$field_value->setTimezone($timezone);
644
+					$result[$field_name] = Model_Data_Translator::prepare_field_value_for_json(
645
+						$field_obj,
646
+						$field_value,
647
+						$this->get_model_version_info()->requested_version()
648
+					);
649
+				}
650
+			} else {
651
+				$result[$field_name] = Model_Data_Translator::prepare_field_value_for_json(
652
+					$field_obj,
653
+					$field_obj->prepare_for_get($field_value),
654
+					$this->get_model_version_info()->requested_version()
655
+				);
656
+			}
657
+		}
658
+		return $result;
659
+	}
660
+
661
+
662
+
663
+	/**
664
+	 * Adds a few extra fields to the entity response
665
+	 *
666
+	 * @param \EEM_Base $model
667
+	 * @param array     $db_row
668
+	 * @param array     $entity_array
669
+	 * @return array modified entity
670
+	 */
671
+	protected function _add_extra_fields(\EEM_Base $model, $db_row, $entity_array)
672
+	{
673
+		if ($model instanceof \EEM_CPT_Base) {
674
+			$entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
675
+		}
676
+		return $entity_array;
677
+	}
678
+
679
+
680
+
681
+	/**
682
+	 * Gets links we want to add to the response
683
+	 *
684
+	 * @global \WP_REST_Server $wp_rest_server
685
+	 * @param \EEM_Base        $model
686
+	 * @param array            $db_row
687
+	 * @param array            $entity_array
688
+	 * @return array the _links item in the entity
689
+	 */
690
+	protected function _get_entity_links($model, $db_row, $entity_array)
691
+	{
692
+		//add basic links
693
+		$links = array();
694
+		if ($model->has_primary_key_field()) {
695
+			$links['self'] = array(
696
+				array(
697
+					'href' => $this->get_versioned_link_to(
698
+						\EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
699
+						. '/'
700
+						. $entity_array[$model->primary_key_name()]
701
+					),
702
+				),
703
+			);
704
+		}
705
+		$links['collection'] = array(
706
+			array(
707
+				'href' => $this->get_versioned_link_to(
708
+					\EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
709
+				),
710
+			),
711
+		);
712
+		//add links to related models
713
+		if ($model->has_primary_key_field()) {
714
+			foreach ($this->get_model_version_info()->relation_settings($model) as $relation_name => $relation_obj) {
715
+				$related_model_part = Read::get_related_entity_name($relation_name, $relation_obj);
716
+				$links[\EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part] = array(
717
+					array(
718
+						'href'   => $this->get_versioned_link_to(
719
+							\EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
720
+							. '/'
721
+							. $entity_array[$model->primary_key_name()]
722
+							. '/'
723
+							. $related_model_part
724
+						),
725
+						'single' => $relation_obj instanceof \EE_Belongs_To_Relation ? true : false,
726
+					),
727
+				);
728
+			}
729
+		}
730
+		return $links;
731
+	}
732
+
733
+
734
+
735
+	/**
736
+	 * Adds the included models indicated in the request to the entity provided
737
+	 *
738
+	 * @param \EEM_Base        $model
739
+	 * @param \WP_REST_Request $rest_request
740
+	 * @param array            $entity_array
741
+	 * @param array            $db_row
742
+	 * @return array the modified entity
743
+	 */
744
+	protected function _include_requested_models(
745
+		\EEM_Base $model,
746
+		\WP_REST_Request $rest_request,
747
+		$entity_array,
748
+		$db_row = array()
749
+	) {
750
+		//if $db_row not included, hope the entity array has what we need
751
+		if (! $db_row) {
752
+			$db_row = $entity_array;
753
+		}
754
+		$includes_for_this_model = $this->explode_and_get_items_prefixed_with($rest_request->get_param('include'), '');
755
+		$includes_for_this_model = $this->_remove_model_names_from_array($includes_for_this_model);
756
+		//if they passed in * or didn't specify any includes, return everything
757
+		if (! in_array('*', $includes_for_this_model)
758
+			&& ! empty($includes_for_this_model)
759
+		) {
760
+			if ($model->has_primary_key_field()) {
761
+				//always include the primary key. ya just gotta know that at least
762
+				$includes_for_this_model[] = $model->primary_key_name();
763
+			}
764
+			if ($this->explode_and_get_items_prefixed_with($rest_request->get_param('calculate'), '')) {
765
+				$includes_for_this_model[] = '_calculated_fields';
766
+			}
767
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
768
+		}
769
+		$relation_settings = $this->get_model_version_info()->relation_settings($model);
770
+		foreach ($relation_settings as $relation_name => $relation_obj) {
771
+			$related_fields_to_include = $this->explode_and_get_items_prefixed_with(
772
+				$rest_request->get_param('include'),
773
+				$relation_name
774
+			);
775
+			$related_fields_to_calculate = $this->explode_and_get_items_prefixed_with(
776
+				$rest_request->get_param('calculate'),
777
+				$relation_name
778
+			);
779
+			//did they specify they wanted to include a related model, or
780
+			//specific fields from a related model?
781
+			//or did they specify to calculate a field from a related model?
782
+			if ($related_fields_to_include || $related_fields_to_calculate) {
783
+				//if so, we should include at least some part of the related model
784
+				$pretend_related_request = new \WP_REST_Request();
785
+				$pretend_related_request->set_query_params(
786
+					array(
787
+						'caps'      => $rest_request->get_param('caps'),
788
+						'include'   => $related_fields_to_include,
789
+						'calculate' => $related_fields_to_calculate,
790
+					)
791
+				);
792
+				$pretend_related_request->add_header('no_rest_headers', true);
793
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
794
+					$model->get_index_primary_key_string(
795
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
796
+					)
797
+				);
798
+				$related_results = $this->_get_entities_from_relation(
799
+					$primary_model_query_params,
800
+					$relation_obj,
801
+					$pretend_related_request
802
+				);
803
+				$entity_array[Read::get_related_entity_name($relation_name, $relation_obj)] = $related_results
804
+																							  instanceof
805
+																							  \WP_Error
806
+					? null
807
+					: $related_results;
808
+			}
809
+		}
810
+		return $entity_array;
811
+	}
812
+
813
+
814
+
815
+	/**
816
+	 * Returns a new array with all the names of models removed. Eg
817
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
818
+	 *
819
+	 * @param array $arr
820
+	 * @return array
821
+	 */
822
+	private function _remove_model_names_from_array($arr)
823
+	{
824
+		return array_diff($arr, array_keys(\EE_Registry::instance()->non_abstract_db_models));
825
+	}
826
+
827
+
828
+
829
+	/**
830
+	 * Gets the calculated fields for the response
831
+	 *
832
+	 * @param \EEM_Base        $model
833
+	 * @param array            $wpdb_row
834
+	 * @param \WP_REST_Request $rest_request
835
+	 * @return \stdClass the _calculations item in the entity
836
+	 */
837
+	protected function _get_entity_calculations($model, $wpdb_row, $rest_request)
838
+	{
839
+		$calculated_fields = $this->explode_and_get_items_prefixed_with(
840
+			$rest_request->get_param('calculate'),
841
+			''
842
+		);
843
+		//note: setting calculate=* doesn't do anything
844
+		$calculated_fields_to_return = new \stdClass();
845
+		foreach ($calculated_fields as $field_to_calculate) {
846
+			try {
847
+				$calculated_fields_to_return->$field_to_calculate = Model_Data_Translator::prepare_field_value_for_json(
848
+					null,
849
+					$this->_fields_calculator->retrieve_calculated_field_value(
850
+						$model,
851
+						$field_to_calculate,
852
+						$wpdb_row,
853
+						$rest_request,
854
+						$this
855
+					),
856
+					$this->get_model_version_info()->requested_version()
857
+				);
858
+			} catch (Rest_Exception $e) {
859
+				//if we don't have permission to read it, just leave it out. but let devs know about the problem
860
+				$this->_set_response_header(
861
+					'Notices-Field-Calculation-Errors['
862
+					. $e->get_string_code()
863
+					. ']['
864
+					. $model->get_this_model_name()
865
+					. ']['
866
+					. $field_to_calculate
867
+					. ']',
868
+					$e->getMessage(),
869
+					true
870
+				);
871
+			}
872
+		}
873
+		return $calculated_fields_to_return;
874
+	}
875
+
876
+
877
+
878
+	/**
879
+	 * Gets the full URL to the resource, taking the requested version into account
880
+	 *
881
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
882
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
883
+	 */
884
+	public function get_versioned_link_to($link_part_after_version_and_slash)
885
+	{
886
+		return rest_url(
887
+			\EED_Core_Rest_Api::ee_api_namespace
888
+			. $this->get_model_version_info()->requested_version()
889
+			. '/'
890
+			. $link_part_after_version_and_slash
891
+		);
892
+	}
893
+
894
+
895
+
896
+	/**
897
+	 * Gets the correct lowercase name for the relation in the API according
898
+	 * to the relation's type
899
+	 *
900
+	 * @param string                  $relation_name
901
+	 * @param \EE_Model_Relation_Base $relation_obj
902
+	 * @return string
903
+	 */
904
+	public static function get_related_entity_name($relation_name, $relation_obj)
905
+	{
906
+		if ($relation_obj instanceof \EE_Belongs_To_Relation) {
907
+			return strtolower($relation_name);
908
+		} else {
909
+			return \EEH_Inflector::pluralize_and_lower($relation_name);
910
+		}
911
+	}
912
+
913
+
914
+
915
+	/**
916
+	 * Gets the one model object with the specified id for the specified model
917
+	 *
918
+	 * @param \EEM_Base        $model
919
+	 * @param \WP_REST_Request $request
920
+	 * @return array|\WP_Error
921
+	 */
922
+	public function get_entity_from_model($model, $request)
923
+	{
924
+		$query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
925
+		if ($model instanceof \EEM_Soft_Delete_Base) {
926
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
927
+		}
928
+		$restricted_query_params = $query_params;
929
+		$restricted_query_params['caps'] = $this->validate_context($request->get_param('caps'));
930
+		$this->_set_debug_info('model query params', $restricted_query_params);
931
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
932
+		if (! empty ($model_rows)) {
933
+			return $this->create_entity_from_wpdb_result(
934
+				$model,
935
+				array_shift($model_rows),
936
+				$request);
937
+		} else {
938
+			//ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
939
+			$lowercase_model_name = strtolower($model->get_this_model_name());
940
+			$model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
941
+			if (! empty($model_rows_found_sans_restrictions)) {
942
+				//you got shafted- it existed but we didn't want to tell you!
943
+				return new \WP_Error(
944
+					'rest_user_cannot_read',
945
+					sprintf(
946
+						__('Sorry, you cannot read this %1$s. Missing permissions are: %2$s', 'event_espresso'),
947
+						strtolower($model->get_this_model_name()),
948
+						Capabilities::get_missing_permissions_string(
949
+							$model,
950
+							$this->validate_context($request->get_param('caps')))
951
+					),
952
+					array('status' => 403)
953
+				);
954
+			} else {
955
+				//it's not you. It just doesn't exist
956
+				return new \WP_Error(
957
+					sprintf('rest_%s_invalid_id', $lowercase_model_name),
958
+					sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
959
+					array('status' => 404)
960
+				);
961
+			}
962
+		}
963
+	}
964
+
965
+
966
+
967
+	/**
968
+	 * If a context is provided which isn't valid, maybe it was added in a future
969
+	 * version so just treat it as a default read
970
+	 *
971
+	 * @param string $context
972
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
973
+	 */
974
+	public function validate_context($context)
975
+	{
976
+		if (! $context) {
977
+			$context = \EEM_Base::caps_read;
978
+		}
979
+		$valid_contexts = \EEM_Base::valid_cap_contexts();
980
+		if (in_array($context, $valid_contexts)) {
981
+			return $context;
982
+		} else {
983
+			return \EEM_Base::caps_read;
984
+		}
985
+	}
986
+
987
+
988
+
989
+	/**
990
+	 * Verifies the passed in value is an allowable default where conditions value.
991
+	 *
992
+	 * @param $default_query_params
993
+	 * @return string
994
+	 */
995
+	public function validate_default_query_params($default_query_params)
996
+	{
997
+		$valid_default_where_conditions_for_api_calls = array(
998
+			\EEM_Base::default_where_conditions_all,
999
+			\EEM_Base::default_where_conditions_minimum_all,
1000
+			\EEM_Base::default_where_conditions_minimum_others,
1001
+		);
1002
+		if (! $default_query_params) {
1003
+			$default_query_params = \EEM_Base::default_where_conditions_all;
1004
+		}
1005
+		if (
1006
+		in_array(
1007
+			$default_query_params,
1008
+			$valid_default_where_conditions_for_api_calls,
1009
+			true
1010
+		)
1011
+		) {
1012
+			return $default_query_params;
1013
+		} else {
1014
+			return \EEM_Base::default_where_conditions_all;
1015
+		}
1016
+	}
1017
+
1018
+
1019
+
1020
+	/**
1021
+	 * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
1022
+	 * Note: right now the query parameter keys for fields (and related fields)
1023
+	 * can be left as-is, but it's quite possible this will change someday.
1024
+	 * Also, this method's contents might be candidate for moving to Model_Data_Translator
1025
+	 *
1026
+	 * @param \EEM_Base $model
1027
+	 * @param array     $query_parameters from $_GET parameter @see Read:handle_request_get_all
1028
+	 * @return array like what EEM_Base::get_all() expects or FALSE to indicate
1029
+	 *                                    that absolutely no results should be returned
1030
+	 * @throws \EE_Error
1031
+	 */
1032
+	public function create_model_query_params($model, $query_parameters)
1033
+	{
1034
+		$model_query_params = array();
1035
+		if (isset($query_parameters['where'])) {
1036
+			$model_query_params[0] = Model_Data_Translator::prepare_conditions_query_params_for_models(
1037
+				$query_parameters['where'],
1038
+				$model,
1039
+				$this->get_model_version_info()->requested_version()
1040
+			);
1041
+		}
1042
+		if (isset($query_parameters['order_by'])) {
1043
+			$order_by = $query_parameters['order_by'];
1044
+		} elseif (isset($query_parameters['orderby'])) {
1045
+			$order_by = $query_parameters['orderby'];
1046
+		} else {
1047
+			$order_by = null;
1048
+		}
1049
+		if ($order_by !== null) {
1050
+			if (is_array($order_by)) {
1051
+				$order_by = Model_Data_Translator::prepare_field_names_in_array_keys_from_json($order_by);
1052
+			} else {
1053
+				//it's a single item
1054
+				$order_by = Model_Data_Translator::prepare_field_name_from_json($order_by);
1055
+			}
1056
+			$model_query_params['order_by'] = $order_by;
1057
+		}
1058
+		if (isset($query_parameters['group_by'])) {
1059
+			$group_by = $query_parameters['group_by'];
1060
+		} elseif (isset($query_parameters['groupby'])) {
1061
+			$group_by = $query_parameters['groupby'];
1062
+		} else {
1063
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1064
+		}
1065
+		//make sure they're all real names
1066
+		if (is_array($group_by)) {
1067
+			$group_by = Model_Data_Translator::prepare_field_names_from_json($group_by);
1068
+		}
1069
+		if ($group_by !== null) {
1070
+			$model_query_params['group_by'] = $group_by;
1071
+		}
1072
+		if (isset($query_parameters['having'])) {
1073
+			$model_query_params['having'] = Model_Data_Translator::prepare_conditions_query_params_for_models(
1074
+				$query_parameters['having'],
1075
+				$model,
1076
+				$this->get_model_version_info()->requested_version()
1077
+			);
1078
+		}
1079
+		if (isset($query_parameters['order'])) {
1080
+			$model_query_params['order'] = $query_parameters['order'];
1081
+		}
1082
+		if (isset($query_parameters['mine'])) {
1083
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1084
+		}
1085
+		if (isset($query_parameters['limit'])) {
1086
+			//limit should be either a string like '23' or '23,43', or an array with two items in it
1087
+			if (! is_array($query_parameters['limit'])) {
1088
+				$limit_array = explode(',', (string)$query_parameters['limit']);
1089
+			} else {
1090
+				$limit_array = $query_parameters['limit'];
1091
+			}
1092
+			$sanitized_limit = array();
1093
+			foreach ($limit_array as $key => $limit_part) {
1094
+				if ($this->_debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1095
+					throw new \EE_Error(
1096
+						sprintf(
1097
+							__('An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1098
+								'event_espresso'),
1099
+							wp_json_encode($query_parameters['limit'])
1100
+						)
1101
+					);
1102
+				}
1103
+				$sanitized_limit[] = (int)$limit_part;
1104
+			}
1105
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1106
+		} else {
1107
+			$model_query_params['limit'] = \EED_Core_Rest_Api::get_default_query_limit();
1108
+		}
1109
+		if (isset($query_parameters['caps'])) {
1110
+			$model_query_params['caps'] = $this->validate_context($query_parameters['caps']);
1111
+		} else {
1112
+			$model_query_params['caps'] = \EEM_Base::caps_read;
1113
+		}
1114
+		if (isset($query_parameters['default_where_conditions'])) {
1115
+			$model_query_params['default_where_conditions'] = $this->validate_default_query_params($query_parameters['default_where_conditions']);
1116
+		}
1117
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model);
1118
+	}
1119
+
1120
+
1121
+
1122
+	/**
1123
+	 * Changes the REST-style query params for use in the models
1124
+	 *
1125
+	 * @deprecated
1126
+	 * @param \EEM_Base $model
1127
+	 * @param array     $query_params sub-array from @see EEM_Base::get_all()
1128
+	 * @return array
1129
+	 */
1130
+	public function prepare_rest_query_params_key_for_models($model, $query_params)
1131
+	{
1132
+		$model_ready_query_params = array();
1133
+		foreach ($query_params as $key => $value) {
1134
+			if (is_array($value)) {
1135
+				$model_ready_query_params[$key] = $this->prepare_rest_query_params_key_for_models($model, $value);
1136
+			} else {
1137
+				$model_ready_query_params[$key] = $value;
1138
+			}
1139
+		}
1140
+		return $model_ready_query_params;
1141
+	}
1142
+
1143
+
1144
+
1145
+	/**
1146
+	 * @deprecated
1147
+	 * @param $model
1148
+	 * @param $query_params
1149
+	 * @return array
1150
+	 */
1151
+	public function prepare_rest_query_params_values_for_models($model, $query_params)
1152
+	{
1153
+		$model_ready_query_params = array();
1154
+		foreach ($query_params as $key => $value) {
1155
+			if (is_array($value)) {
1156
+				$model_ready_query_params[$key] = $this->prepare_rest_query_params_values_for_models($model, $value);
1157
+			} else {
1158
+				$model_ready_query_params[$key] = $value;
1159
+			}
1160
+		}
1161
+		return $model_ready_query_params;
1162
+	}
1163
+
1164
+
1165
+
1166
+	/**
1167
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1168
+	 * If no prefix is specified, returns items with no period.
1169
+	 *
1170
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blaabla" or array('jibba', 'jabba' )
1171
+	 * @param string       $prefix            "Event" or "foobar"
1172
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1173
+	 *                                        we only return strings starting with that and a period; if no prefix was
1174
+	 *                                        specified we return all items containing NO periods
1175
+	 */
1176
+	public function explode_and_get_items_prefixed_with($string_to_explode, $prefix)
1177
+	{
1178
+		if (is_string($string_to_explode)) {
1179
+			$exploded_contents = explode(',', $string_to_explode);
1180
+		} else if (is_array($string_to_explode)) {
1181
+			$exploded_contents = $string_to_explode;
1182
+		} else {
1183
+			$exploded_contents = array();
1184
+		}
1185
+		//if the string was empty, we want an empty array
1186
+		$exploded_contents = array_filter($exploded_contents);
1187
+		$contents_with_prefix = array();
1188
+		foreach ($exploded_contents as $item) {
1189
+			$item = trim($item);
1190
+			//if no prefix was provided, so we look for items with no "." in them
1191
+			if (! $prefix) {
1192
+				//does this item have a period?
1193
+				if (strpos($item, '.') === false) {
1194
+					//if not, then its what we're looking for
1195
+					$contents_with_prefix[] = $item;
1196
+				}
1197
+			} else if (strpos($item, $prefix . '.') === 0) {
1198
+				//this item has the prefix and a period, grab it
1199
+				$contents_with_prefix[] = substr(
1200
+					$item,
1201
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1202
+				);
1203
+			} else if ($item === $prefix) {
1204
+				//this item is JUST the prefix
1205
+				//so let's grab everything after, which is a blank string
1206
+				$contents_with_prefix[] = '';
1207
+			}
1208
+		}
1209
+		return $contents_with_prefix;
1210
+	}
1211
+
1212
+
1213
+
1214
+	/**
1215
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1216
+	 * Deprecated because its return values were really quite confusing- sometimes it returned
1217
+	 * an empty array (when the include string was blank or '*') or sometimes it returned
1218
+	 * array('*') (when you provided a model and a model of that kind was found).
1219
+	 * Parses the $include_string so we fetch all the field names relating to THIS model
1220
+	 * (ie have NO period in them), or for the provided model (ie start with the model
1221
+	 * name and then a period).
1222
+	 * @param string $include_string @see Read:handle_request_get_all
1223
+	 * @param string $model_name
1224
+	 * @return array of fields for this model. If $model_name is provided, then
1225
+	 *                               the fields for that model, with the model's name removed from each.
1226
+	 *                               If $include_string was blank or '*' returns an empty array
1227
+	 */
1228
+	public function extract_includes_for_this_model($include_string, $model_name = null)
1229
+	{
1230
+		if (is_array($include_string)) {
1231
+			$include_string = implode(',', $include_string);
1232
+		}
1233
+		if ($include_string === '*' || $include_string === '') {
1234
+			return array();
1235
+		}
1236
+		$includes = explode(',', $include_string);
1237
+		$extracted_fields_to_include = array();
1238
+		if ($model_name) {
1239
+			foreach ($includes as $field_to_include) {
1240
+				$field_to_include = trim($field_to_include);
1241
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1242
+					//found the model name at the exact start
1243
+					$field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1244
+					$extracted_fields_to_include[] = $field_sans_model_name;
1245
+				} elseif ($field_to_include == $model_name) {
1246
+					$extracted_fields_to_include[] = '*';
1247
+				}
1248
+			}
1249
+		} else {
1250
+			//look for ones with no period
1251
+			foreach ($includes as $field_to_include) {
1252
+				$field_to_include = trim($field_to_include);
1253
+				if (
1254
+					strpos($field_to_include, '.') === false
1255
+					&& ! $this->get_model_version_info()->is_model_name_in_this_version($field_to_include)
1256
+				) {
1257
+					$extracted_fields_to_include[] = $field_to_include;
1258
+				}
1259
+			}
1260
+		}
1261
+		return $extracted_fields_to_include;
1262
+	}
1263 1263
 }
1264 1264
 
1265 1265
 
Please login to merge, or discard this patch.
Spacing   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -8,7 +8,7 @@  discard block
 block discarded – undo
8 8
 use EventEspresso\core\entities\models\JsonModelSchema;
9 9
 use EE_Datetime_Field;
10 10
 
11
-if (! defined('EVENT_ESPRESSO_VERSION')) {
11
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
12 12
     exit('No direct script access allowed');
13 13
 }
14 14
 
@@ -57,12 +57,12 @@  discard block
 block discarded – undo
57 57
         try {
58 58
             $matches = $controller->parse_route(
59 59
                 $request->get_route(),
60
-                '~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)~',
60
+                '~'.\EED_Core_Rest_Api::ee_api_namespace_for_regex.'(.*)~',
61 61
                 array('version', 'model')
62 62
             );
63 63
             $controller->set_requested_version($matches['version']);
64 64
             $model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
65
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
65
+            if ( ! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
66 66
                 return $controller->send_response(
67 67
                     new \WP_Error(
68 68
                         'endpoint_parsing_error',
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
         $controller = new Read();
99 99
         try {
100 100
             $controller->set_requested_version($version);
101
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name)) {
101
+            if ( ! $controller->get_model_version_info()->is_model_name_in_this_version($model_name)) {
102 102
                 return array();
103 103
             }
104 104
             //get the model for this version
@@ -189,9 +189,9 @@  discard block
 block discarded – undo
189 189
     protected function _maybe_add_extra_fields_to_schema($field_name, \EE_Model_Field_Base $field, array $schema)
190 190
     {
191 191
         if ($field instanceof EE_Datetime_Field) {
192
-            $schema['properties'][$field_name . '_gmt'] = $field->getSchema();
192
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
193 193
             //modify the description
194
-            $schema['properties'][$field_name . '_gmt']['description'] = sprintf(
194
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
195 195
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
196 196
                 $field->get_nicename()
197 197
             );
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
     protected function get_route_from_request() {
210 210
         if (isset($GLOBALS['wp'])
211 211
             && $GLOBALS['wp'] instanceof \WP
212
-            && isset($GLOBALS['wp']->query_vars['rest_route'] )
212
+            && isset($GLOBALS['wp']->query_vars['rest_route'])
213 213
         ) {
214 214
             return $GLOBALS['wp']->query_vars['rest_route'];
215 215
         } else {
@@ -231,11 +231,11 @@  discard block
 block discarded – undo
231 231
         try {
232 232
             $matches = $controller->parse_route(
233 233
                 $request->get_route(),
234
-                '~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)~',
234
+                '~'.\EED_Core_Rest_Api::ee_api_namespace_for_regex.'(.*)/(.*)~',
235 235
                 array('version', 'model', 'id'));
236 236
             $controller->set_requested_version($matches['version']);
237 237
             $model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
238
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
238
+            if ( ! $controller->get_model_version_info()->is_model_name_in_this_version($model_name_singular)) {
239 239
                 return $controller->send_response(
240 240
                     new \WP_Error(
241 241
                         'endpoint_parsing_error',
@@ -273,12 +273,12 @@  discard block
 block discarded – undo
273 273
         try {
274 274
             $matches = $controller->parse_route(
275 275
                 $request->get_route(),
276
-                '~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)/(.*)~',
276
+                '~'.\EED_Core_Rest_Api::ee_api_namespace_for_regex.'(.*)/(.*)/(.*)~',
277 277
                 array('version', 'model', 'id', 'related_model')
278 278
             );
279 279
             $controller->set_requested_version($matches['version']);
280 280
             $main_model_name_singular = \EEH_Inflector::singularize_and_upper($matches['model']);
281
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($main_model_name_singular)) {
281
+            if ( ! $controller->get_model_version_info()->is_model_name_in_this_version($main_model_name_singular)) {
282 282
                 return $controller->send_response(
283 283
                     new \WP_Error(
284 284
                         'endpoint_parsing_error',
@@ -293,11 +293,11 @@  discard block
 block discarded – undo
293 293
             $main_model = $controller->get_model_version_info()->load_model($main_model_name_singular);
294 294
             //assume the related model name is plural and try to find the model's name
295 295
             $related_model_name_singular = \EEH_Inflector::singularize_and_upper($matches['related_model']);
296
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
296
+            if ( ! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
297 297
                 //so the word didn't singularize well. Maybe that's just because it's a singular word?
298 298
                 $related_model_name_singular = \EEH_Inflector::humanize($matches['related_model']);
299 299
             }
300
-            if (! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
300
+            if ( ! $controller->get_model_version_info()->is_model_name_in_this_version($related_model_name_singular)) {
301 301
                 return $controller->send_response(
302 302
                     new \WP_Error(
303 303
                         'endpoint_parsing_error',
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
     public function get_entities_from_model($model, $request)
334 334
     {
335 335
         $query_params = $this->create_model_query_params($model, $request->get_params());
336
-        if (! Capabilities::current_user_has_partial_access_to($model, $query_params['caps'])) {
336
+        if ( ! Capabilities::current_user_has_partial_access_to($model, $query_params['caps'])) {
337 337
             $model_name_plural = \EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
338 338
             return new \WP_Error(
339 339
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -345,7 +345,7 @@  discard block
 block discarded – undo
345 345
                 array('status' => 403)
346 346
             );
347 347
         }
348
-        if (! $request->get_header('no_rest_headers')) {
348
+        if ( ! $request->get_header('no_rest_headers')) {
349 349
             $this->_set_headers_from_query_params($model, $query_params);
350 350
         }
351 351
         /** @type array $results */
@@ -375,7 +375,7 @@  discard block
 block discarded – undo
375 375
         $context = $this->validate_context($request->get_param('caps'));
376 376
         $model = $relation->get_this_model();
377 377
         $related_model = $relation->get_other_model();
378
-        if (! isset($primary_model_query_params[0])) {
378
+        if ( ! isset($primary_model_query_params[0])) {
379 379
             $primary_model_query_params[0] = array();
380 380
         }
381 381
         //check if they can access the 1st model object
@@ -426,7 +426,7 @@  discard block
 block discarded – undo
426 426
         }
427 427
         $query_params['default_where_conditions'] = 'none';
428 428
         $query_params['caps'] = $context;
429
-        if (! $request->get_header('no_rest_headers')) {
429
+        if ( ! $request->get_header('no_rest_headers')) {
430 430
             $this->_set_headers_from_query_params($relation->get_other_model(), $query_params);
431 431
         }
432 432
         /** @type array $results */
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
      */
479 479
     public function get_entities_from_relation($id, $relation, $request)
480 480
     {
481
-        if (! $relation->get_this_model()->has_primary_key_field()) {
481
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
482 482
             throw new \EE_Error(
483 483
                 sprintf(
484 484
                     __('Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
         $this->_set_debug_info('missing caps',
516 516
             Capabilities::get_missing_permissions_string($model, $query_params['caps']));
517 517
         //normally the limit to a 2-part array, where the 2nd item is the limit
518
-        if (! isset($query_params['limit'])) {
518
+        if ( ! isset($query_params['limit'])) {
519 519
             $query_params['limit'] = \EED_Core_Rest_Api::get_default_query_limit();
520 520
         }
521 521
         if (is_array($query_params['limit'])) {
@@ -549,7 +549,7 @@  discard block
 block discarded – undo
549 549
      */
550 550
     public function create_entity_from_wpdb_result($model, $db_row, $rest_request, $deprecated = null)
551 551
     {
552
-        if (! $rest_request instanceof \WP_REST_Request) {
552
+        if ( ! $rest_request instanceof \WP_REST_Request) {
553 553
             //ok so this was called in the old style, where the 3rd arg was
554 554
             //$include, and the 4th arg was $context
555 555
             //now setup the request just to avoid fatal errors, although we won't be able
@@ -565,7 +565,7 @@  discard block
 block discarded – undo
565 565
         $entity_array = $this->_add_extra_fields($model, $db_row, $entity_array);
566 566
         $entity_array['_links'] = $this->_get_entity_links($model, $db_row, $entity_array);
567 567
         $entity_array['_calculated_fields'] = $this->_get_entity_calculations($model, $db_row, $rest_request);
568
-        $entity_array = apply_filters( 'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models', $entity_array, $model, $rest_request->get_param('caps'),$rest_request,$this);
568
+        $entity_array = apply_filters('FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models', $entity_array, $model, $rest_request->get_param('caps'), $rest_request, $this);
569 569
         $entity_array = $this->_include_requested_models($model, $rest_request, $entity_array, $db_row);
570 570
         $entity_array = apply_filters(
571 571
             'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
@@ -635,7 +635,7 @@  discard block
 block discarded – undo
635 635
                 if ($field_value instanceof \DateTime) {
636 636
                     $timezone = $field_value->getTimezone();
637 637
                     $field_value->setTimezone(new \DateTimeZone('UTC'));
638
-                    $result[$field_name . '_gmt'] = Model_Data_Translator::prepare_field_value_for_json(
638
+                    $result[$field_name.'_gmt'] = Model_Data_Translator::prepare_field_value_for_json(
639 639
                         $field_obj,
640 640
                         $field_value,
641 641
                         $this->get_model_version_info()->requested_version()
@@ -713,7 +713,7 @@  discard block
 block discarded – undo
713 713
         if ($model->has_primary_key_field()) {
714 714
             foreach ($this->get_model_version_info()->relation_settings($model) as $relation_name => $relation_obj) {
715 715
                 $related_model_part = Read::get_related_entity_name($relation_name, $relation_obj);
716
-                $links[\EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part] = array(
716
+                $links[\EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = array(
717 717
                     array(
718 718
                         'href'   => $this->get_versioned_link_to(
719 719
                             \EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
@@ -748,13 +748,13 @@  discard block
 block discarded – undo
748 748
         $db_row = array()
749 749
     ) {
750 750
         //if $db_row not included, hope the entity array has what we need
751
-        if (! $db_row) {
751
+        if ( ! $db_row) {
752 752
             $db_row = $entity_array;
753 753
         }
754 754
         $includes_for_this_model = $this->explode_and_get_items_prefixed_with($rest_request->get_param('include'), '');
755 755
         $includes_for_this_model = $this->_remove_model_names_from_array($includes_for_this_model);
756 756
         //if they passed in * or didn't specify any includes, return everything
757
-        if (! in_array('*', $includes_for_this_model)
757
+        if ( ! in_array('*', $includes_for_this_model)
758 758
             && ! empty($includes_for_this_model)
759 759
         ) {
760 760
             if ($model->has_primary_key_field()) {
@@ -929,7 +929,7 @@  discard block
 block discarded – undo
929 929
         $restricted_query_params['caps'] = $this->validate_context($request->get_param('caps'));
930 930
         $this->_set_debug_info('model query params', $restricted_query_params);
931 931
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
932
-        if (! empty ($model_rows)) {
932
+        if ( ! empty ($model_rows)) {
933 933
             return $this->create_entity_from_wpdb_result(
934 934
                 $model,
935 935
                 array_shift($model_rows),
@@ -938,7 +938,7 @@  discard block
 block discarded – undo
938 938
             //ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
939 939
             $lowercase_model_name = strtolower($model->get_this_model_name());
940 940
             $model_rows_found_sans_restrictions = $model->get_all_wpdb_results($query_params);
941
-            if (! empty($model_rows_found_sans_restrictions)) {
941
+            if ( ! empty($model_rows_found_sans_restrictions)) {
942 942
                 //you got shafted- it existed but we didn't want to tell you!
943 943
                 return new \WP_Error(
944 944
                     'rest_user_cannot_read',
@@ -973,7 +973,7 @@  discard block
 block discarded – undo
973 973
      */
974 974
     public function validate_context($context)
975 975
     {
976
-        if (! $context) {
976
+        if ( ! $context) {
977 977
             $context = \EEM_Base::caps_read;
978 978
         }
979 979
         $valid_contexts = \EEM_Base::valid_cap_contexts();
@@ -999,7 +999,7 @@  discard block
 block discarded – undo
999 999
             \EEM_Base::default_where_conditions_minimum_all,
1000 1000
             \EEM_Base::default_where_conditions_minimum_others,
1001 1001
         );
1002
-        if (! $default_query_params) {
1002
+        if ( ! $default_query_params) {
1003 1003
             $default_query_params = \EEM_Base::default_where_conditions_all;
1004 1004
         }
1005 1005
         if (
@@ -1084,14 +1084,14 @@  discard block
 block discarded – undo
1084 1084
         }
1085 1085
         if (isset($query_parameters['limit'])) {
1086 1086
             //limit should be either a string like '23' or '23,43', or an array with two items in it
1087
-            if (! is_array($query_parameters['limit'])) {
1088
-                $limit_array = explode(',', (string)$query_parameters['limit']);
1087
+            if ( ! is_array($query_parameters['limit'])) {
1088
+                $limit_array = explode(',', (string) $query_parameters['limit']);
1089 1089
             } else {
1090 1090
                 $limit_array = $query_parameters['limit'];
1091 1091
             }
1092 1092
             $sanitized_limit = array();
1093 1093
             foreach ($limit_array as $key => $limit_part) {
1094
-                if ($this->_debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1094
+                if ($this->_debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1095 1095
                     throw new \EE_Error(
1096 1096
                         sprintf(
1097 1097
                             __('An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
@@ -1100,7 +1100,7 @@  discard block
 block discarded – undo
1100 1100
                         )
1101 1101
                     );
1102 1102
                 }
1103
-                $sanitized_limit[] = (int)$limit_part;
1103
+                $sanitized_limit[] = (int) $limit_part;
1104 1104
             }
1105 1105
             $model_query_params['limit'] = implode(',', $sanitized_limit);
1106 1106
         } else {
@@ -1188,17 +1188,17 @@  discard block
 block discarded – undo
1188 1188
         foreach ($exploded_contents as $item) {
1189 1189
             $item = trim($item);
1190 1190
             //if no prefix was provided, so we look for items with no "." in them
1191
-            if (! $prefix) {
1191
+            if ( ! $prefix) {
1192 1192
                 //does this item have a period?
1193 1193
                 if (strpos($item, '.') === false) {
1194 1194
                     //if not, then its what we're looking for
1195 1195
                     $contents_with_prefix[] = $item;
1196 1196
                 }
1197
-            } else if (strpos($item, $prefix . '.') === 0) {
1197
+            } else if (strpos($item, $prefix.'.') === 0) {
1198 1198
                 //this item has the prefix and a period, grab it
1199 1199
                 $contents_with_prefix[] = substr(
1200 1200
                     $item,
1201
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1201
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1202 1202
                 );
1203 1203
             } else if ($item === $prefix) {
1204 1204
                 //this item is JUST the prefix
@@ -1238,9 +1238,9 @@  discard block
 block discarded – undo
1238 1238
         if ($model_name) {
1239 1239
             foreach ($includes as $field_to_include) {
1240 1240
                 $field_to_include = trim($field_to_include);
1241
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1241
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1242 1242
                     //found the model name at the exact start
1243
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1243
+                    $field_sans_model_name = str_replace($model_name.'.', '', $field_to_include);
1244 1244
                     $extracted_fields_to_include[] = $field_sans_model_name;
1245 1245
                 } elseif ($field_to_include == $model_name) {
1246 1246
                     $extracted_fields_to_include[] = '*';
Please login to merge, or discard this patch.
core/libraries/form_sections/base/EE_Form_Section_Proper.form.php 1 patch
Indentation   +1380 added lines, -1380 removed lines patch added patch discarded remove patch
@@ -13,1386 +13,1386 @@
 block discarded – undo
13 13
 class EE_Form_Section_Proper extends EE_Form_Section_Validatable
14 14
 {
15 15
 
16
-    const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
17
-
18
-    /**
19
-     * Subsections
20
-     *
21
-     * @var EE_Form_Section_Validatable[]
22
-     */
23
-    protected $_subsections = array();
24
-
25
-    /**
26
-     * Strategy for laying out the form
27
-     *
28
-     * @var EE_Form_Section_Layout_Base
29
-     */
30
-    protected $_layout_strategy;
31
-
32
-    /**
33
-     * Whether or not this form has received and validated a form submission yet
34
-     *
35
-     * @var boolean
36
-     */
37
-    protected $_received_submission = false;
38
-
39
-    /**
40
-     * message displayed to users upon successful form submission
41
-     *
42
-     * @var string
43
-     */
44
-    protected $_form_submission_success_message = '';
45
-
46
-    /**
47
-     * message displayed to users upon unsuccessful form submission
48
-     *
49
-     * @var string
50
-     */
51
-    protected $_form_submission_error_message = '';
52
-
53
-    /**
54
-     * Stores all the data that will localized for form validation
55
-     *
56
-     * @var array
57
-     */
58
-    static protected $_js_localization = array();
59
-
60
-    /**
61
-     * whether or not the form's localized validation JS vars have been set
62
-     *
63
-     * @type boolean
64
-     */
65
-    static protected $_scripts_localized = false;
66
-
67
-
68
-
69
-    /**
70
-     * when constructing a proper form section, calls _construct_finalize on children
71
-     * so that they know who their parent is, and what name they've been given.
72
-     *
73
-     * @param array $options_array   {
74
-     * @type        $subsections     EE_Form_Section_Validatable[] where keys are the section's name
75
-     * @type        $include         string[] numerically-indexed where values are section names to be included,
76
-     *                               and in that order. This is handy if you want
77
-     *                               the subsections to be ordered differently than the default, and if you override
78
-     *                               which fields are shown
79
-     * @type        $exclude         string[] values are subsections to be excluded. This is handy if you want
80
-     *                               to remove certain default subsections (note: if you specify BOTH 'include' AND
81
-     *                               'exclude', the inclusions will be applied first, and the exclusions will exclude
82
-     *                               items from that list of inclusions)
83
-     * @type        $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
84
-     *                               } @see EE_Form_Section_Validatable::__construct()
85
-     * @throws \EE_Error
86
-     */
87
-    public function __construct($options_array = array())
88
-    {
89
-        $options_array = (array)apply_filters('FHEE__EE_Form_Section_Proper___construct__options_array', $options_array,
90
-            $this);
91
-        //call parent first, as it may be setting the name
92
-        parent::__construct($options_array);
93
-        //if they've included subsections in the constructor, add them now
94
-        if (isset($options_array['include'])) {
95
-            //we are going to make sure we ONLY have those subsections to include
96
-            //AND we are going to make sure they're in that specified order
97
-            $reordered_subsections = array();
98
-            foreach ($options_array['include'] as $input_name) {
99
-                if (isset($this->_subsections[$input_name])) {
100
-                    $reordered_subsections[$input_name] = $this->_subsections[$input_name];
101
-                }
102
-            }
103
-            $this->_subsections = $reordered_subsections;
104
-        }
105
-        if (isset($options_array['exclude'])) {
106
-            $exclude = $options_array['exclude'];
107
-            $this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
108
-        }
109
-        if (isset($options_array['layout_strategy'])) {
110
-            $this->_layout_strategy = $options_array['layout_strategy'];
111
-        }
112
-        if (! $this->_layout_strategy) {
113
-            $this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
114
-        }
115
-        $this->_layout_strategy->_construct_finalize($this);
116
-        //ok so we are definitely going to want the forms JS,
117
-        //so enqueue it or remember to enqueue it during wp_enqueue_scripts
118
-        if (did_action('wp_enqueue_scripts')
119
-            || did_action('admin_enqueue_scripts')
120
-        ) {
121
-            //ok so they've constructed this object after when they should have.
122
-            //just enqueue the generic form scripts and initialize the form immediately in the JS
123
-            \EE_Form_Section_Proper::wp_enqueue_scripts(true);
124
-        } else {
125
-            add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
126
-            add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
127
-        }
128
-        add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
129
-
130
-        /**
131
-         * Gives other plugins a chance to hook in before construct finalize is called. The form probably doesn't
132
-         * yet have a parent form section. Since 4.9.32, when this action was introduced, this is the best place to
133
-         * add a subsection onto a form, assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
134
-         * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
135
-         * @since 4.9.32
136
-         * @param EE_Form_Section_Proper $this before __construct is done, but all of its logic, except maybe calling
137
-         *                                      _construct_finalize has been done
138
-         * @param array $options_array options passed into the constructor
139
-         */
140
-        do_action('AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called', $this, $options_array);
141
-
142
-        if (isset($options_array['name'])) {
143
-            $this->_construct_finalize(null, $options_array['name']);
144
-        }
145
-    }
146
-
147
-
148
-
149
-    /**
150
-     * Finishes construction given the parent form section and this form section's name
151
-     *
152
-     * @param EE_Form_Section_Proper $parent_form_section
153
-     * @param string                 $name
154
-     * @throws \EE_Error
155
-     */
156
-    public function _construct_finalize($parent_form_section, $name)
157
-    {
158
-        parent::_construct_finalize($parent_form_section, $name);
159
-        $this->_set_default_name_if_empty();
160
-        $this->_set_default_html_id_if_empty();
161
-        foreach ($this->_subsections as $subsection_name => $subsection) {
162
-            if ($subsection instanceof EE_Form_Section_Base) {
163
-                $subsection->_construct_finalize($this, $subsection_name);
164
-            } else {
165
-                throw new EE_Error(
166
-                    sprintf(
167
-                        __('Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
168
-                            'event_espresso'),
169
-                        $subsection_name,
170
-                        get_class($this),
171
-                        $subsection ? get_class($subsection) : __('NULL', 'event_espresso')
172
-                    )
173
-                );
174
-            }
175
-        }
176
-        /**
177
-         * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
178
-         * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID (or other attributes derived
179
-         * from the name like the HTML label id, etc), this is where it should be done.
180
-         * This might only happen just before displaying the form, or just before it receives form submission data.
181
-         * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
182
-         * ensured it has a name, HTML IDs, etc
183
-         * @param EE_Form_Section_Proper $this
184
-         * @param EE_Form_Section_Proper|null $parent_form_section
185
-         * @param string $name
186
-         */
187
-        do_action('AHEE__EE_Form_Section_Proper___construct_finalize__end', $this, $parent_form_section, $name);
188
-    }
189
-
190
-
191
-
192
-    /**
193
-     * Gets the layout strategy for this form section
194
-     *
195
-     * @return EE_Form_Section_Layout_Base
196
-     */
197
-    public function get_layout_strategy()
198
-    {
199
-        return $this->_layout_strategy;
200
-    }
201
-
202
-
203
-
204
-    /**
205
-     * Gets the HTML for a single input for this form section according
206
-     * to the layout strategy
207
-     *
208
-     * @param EE_Form_Input_Base $input
209
-     * @return string
210
-     */
211
-    public function get_html_for_input($input)
212
-    {
213
-        return $this->_layout_strategy->layout_input($input);
214
-    }
215
-
216
-
217
-
218
-    /**
219
-     * was_submitted - checks if form inputs are present in request data
220
-     * Basically an alias for form_data_present_in() (which is used by both
221
-     * proper form sections and form inputs)
222
-     *
223
-     * @param null $form_data
224
-     * @return boolean
225
-     */
226
-    public function was_submitted($form_data = null)
227
-    {
228
-        return $this->form_data_present_in($form_data);
229
-    }
230
-
231
-
232
-
233
-    /**
234
-     * After the form section is initially created, call this to sanitize the data in the submission
235
-     * which relates to this form section, validate it, and set it as properties on the form.
236
-     *
237
-     * @param array|null $req_data should usually be $_POST (the default).
238
-     *                             However, you CAN supply a different array.
239
-     *                             Consider using set_defaults() instead however.
240
-     *                             (If you rendered the form in the page using echo $form_x->get_html()
241
-     *                             the inputs will have the correct name in the request data for this function
242
-     *                             to find them and populate the form with them.
243
-     *                             If you have a flat form (with only input subsections),
244
-     *                             you can supply a flat array where keys
245
-     *                             are the form input names and values are their values)
246
-     * @param boolean    $validate whether or not to perform validation on this data. Default is,
247
-     *                             of course, to validate that data, and set errors on the invalid values.
248
-     *                             But if the data has already been validated
249
-     *                             (eg you validated the data then stored it in the DB)
250
-     *                             you may want to skip this step.
251
-     */
252
-    public function receive_form_submission($req_data = null, $validate = true)
253
-    {
254
-        $req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__req_data', $req_data, $this,
255
-            $validate);
256
-        if ($req_data === null) {
257
-            $req_data = array_merge($_GET, $_POST);
258
-        }
259
-        $req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__request_data', $req_data,
260
-            $this);
261
-        $this->_normalize($req_data);
262
-        if ($validate) {
263
-            $this->_validate();
264
-            //if it's invalid, we're going to want to re-display so remember what they submitted
265
-            if (! $this->is_valid()) {
266
-                $this->store_submitted_form_data_in_session();
267
-            }
268
-        }
269
-        do_action('AHEE__EE_Form_Section_Proper__receive_form_submission__end', $req_data, $this, $validate);
270
-    }
271
-
272
-
273
-
274
-    /**
275
-     * caches the originally submitted input values in the session
276
-     * so that they can be used to repopulate the form if it failed validation
277
-     *
278
-     * @return boolean whether or not the data was successfully stored in the session
279
-     */
280
-    protected function store_submitted_form_data_in_session()
281
-    {
282
-        return EE_Registry::instance()->SSN->set_session_data(
283
-            array(
284
-                \EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
285
-            )
286
-        );
287
-    }
288
-
289
-
290
-
291
-    /**
292
-     * retrieves the originally submitted input values in the session
293
-     * so that they can be used to repopulate the form if it failed validation
294
-     *
295
-     * @return array
296
-     */
297
-    protected function get_submitted_form_data_from_session()
298
-    {
299
-        $session = EE_Registry::instance()->SSN;
300
-        if ($session instanceof EE_Session) {
301
-            return $session->get_session_data(
302
-                \EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
303
-            );
304
-        } else {
305
-            return array();
306
-        }
307
-    }
308
-
309
-
310
-
311
-    /**
312
-     * flushed the originally submitted input values from the session
313
-     *
314
-     * @return boolean whether or not the data was successfully removed from the session
315
-     */
316
-    protected function flush_submitted_form_data_from_session()
317
-    {
318
-        return EE_Registry::instance()->SSN->reset_data(
319
-            array(\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
320
-        );
321
-    }
322
-
323
-
324
-
325
-    /**
326
-     * Populates this form and its subsections with data from the session.
327
-     * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
328
-     * validation errors when displaying too)
329
-     * Returns true if the form was populated from the session, false otherwise
330
-     *
331
-     * @return boolean
332
-     */
333
-    public function populate_from_session()
334
-    {
335
-        $form_data_in_session = $this->get_submitted_form_data_from_session();
336
-        if (empty($form_data_in_session)) {
337
-            return false;
338
-        }
339
-        $this->receive_form_submission($form_data_in_session);
340
-        $this->flush_submitted_form_data_from_session();
341
-        if ($this->form_data_present_in($form_data_in_session)) {
342
-            return true;
343
-        } else {
344
-            return false;
345
-        }
346
-    }
347
-
348
-
349
-
350
-    /**
351
-     * Populates the default data for the form, given an array where keys are
352
-     * the input names, and values are their values (preferably normalized to be their
353
-     * proper PHP types, not all strings... although that should be ok too).
354
-     * Proper subsections are sub-arrays, the key being the subsection's name, and
355
-     * the value being an array formatted in teh same way
356
-     *
357
-     * @param array $default_data
358
-     */
359
-    public function populate_defaults($default_data)
360
-    {
361
-        foreach ($this->subsections(false) as $subsection_name => $subsection) {
362
-            if (isset($default_data[$subsection_name])) {
363
-                if ($subsection instanceof EE_Form_Input_Base) {
364
-                    $subsection->set_default($default_data[$subsection_name]);
365
-                } elseif ($subsection instanceof EE_Form_Section_Proper) {
366
-                    $subsection->populate_defaults($default_data[$subsection_name]);
367
-                }
368
-            }
369
-        }
370
-    }
371
-
372
-
373
-
374
-    /**
375
-     * returns true if subsection exists
376
-     *
377
-     * @param string $name
378
-     * @return boolean
379
-     */
380
-    public function subsection_exists($name)
381
-    {
382
-        return isset($this->_subsections[$name]) ? true : false;
383
-    }
384
-
385
-
386
-
387
-    /**
388
-     * Gets the subsection specified by its name
389
-     *
390
-     * @param string  $name
391
-     * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
392
-     *                                                      so that the inputs will be properly configured.
393
-     *                                                      However, some client code may be ok
394
-     *                                                      with construction finalize being called later
395
-     *                                                      (realizing that the subsections' html names
396
-     *                                                      might not be set yet, etc.)
397
-     * @return EE_Form_Section_Base
398
-     * @throws \EE_Error
399
-     */
400
-    public function get_subsection($name, $require_construction_to_be_finalized = true)
401
-    {
402
-        if ($require_construction_to_be_finalized) {
403
-            $this->ensure_construct_finalized_called();
404
-        }
405
-        return $this->subsection_exists($name) ? $this->_subsections[$name] : null;
406
-    }
407
-
408
-
409
-
410
-    /**
411
-     * Gets all the validatable subsections of this form section
412
-     *
413
-     * @return EE_Form_Section_Validatable[]
414
-     */
415
-    public function get_validatable_subsections()
416
-    {
417
-        $validatable_subsections = array();
418
-        foreach ($this->subsections() as $name => $obj) {
419
-            if ($obj instanceof EE_Form_Section_Validatable) {
420
-                $validatable_subsections[$name] = $obj;
421
-            }
422
-        }
423
-        return $validatable_subsections;
424
-    }
425
-
426
-
427
-
428
-    /**
429
-     * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
430
-     * throw an EE_Error.
431
-     *
432
-     * @param string  $name
433
-     * @param boolean $require_construction_to_be_finalized most client code should
434
-     *                                                      leave this as TRUE so that the inputs will be properly
435
-     *                                                      configured. However, some client code may be ok with
436
-     *                                                      construction finalize being called later
437
-     *                                                      (realizing that the subsections' html names might not be
438
-     *                                                      set yet, etc.)
439
-     * @return EE_Form_Input_Base
440
-     * @throws EE_Error
441
-     */
442
-    public function get_input($name, $require_construction_to_be_finalized = true)
443
-    {
444
-        $subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
445
-        if (! $subsection instanceof EE_Form_Input_Base) {
446
-            throw new EE_Error(
447
-                sprintf(
448
-                    __(
449
-                        "Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
450
-                        'event_espresso'
451
-                    ),
452
-                    $name,
453
-                    get_class($this),
454
-                    $subsection ? get_class($subsection) : __("NULL", 'event_espresso')
455
-                )
456
-            );
457
-        }
458
-        return $subsection;
459
-    }
460
-
461
-
462
-
463
-    /**
464
-     * Like get_input(), gets the proper subsection of the form given the name,
465
-     * otherwise throws an EE_Error
466
-     *
467
-     * @param string  $name
468
-     * @param boolean $require_construction_to_be_finalized most client code should
469
-     *                                                      leave this as TRUE so that the inputs will be properly
470
-     *                                                      configured. However, some client code may be ok with
471
-     *                                                      construction finalize being called later
472
-     *                                                      (realizing that the subsections' html names might not be
473
-     *                                                      set yet, etc.)
474
-     * @return EE_Form_Section_Proper
475
-     * @throws EE_Error
476
-     */
477
-    public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
478
-    {
479
-        $subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
480
-        if (! $subsection instanceof EE_Form_Section_Proper) {
481
-            throw new EE_Error(
482
-                sprintf(
483
-                    __("Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'", 'event_espresso'),
484
-                    $name,
485
-                    get_class($this)
486
-                )
487
-            );
488
-        }
489
-        return $subsection;
490
-    }
491
-
492
-
493
-
494
-    /**
495
-     * Gets the value of the specified input. Should be called after receive_form_submission()
496
-     * or populate_defaults() on the form, where the normalized value on the input is set.
497
-     *
498
-     * @param string $name
499
-     * @return mixed depending on the input's type and its normalization strategy
500
-     * @throws \EE_Error
501
-     */
502
-    public function get_input_value($name)
503
-    {
504
-        $input = $this->get_input($name);
505
-        return $input->normalized_value();
506
-    }
507
-
508
-
509
-
510
-    /**
511
-     * Checks if this form section itself is valid, and then checks its subsections
512
-     *
513
-     * @throws EE_Error
514
-     * @return boolean
515
-     */
516
-    public function is_valid()
517
-    {
518
-        if (! $this->has_received_submission()) {
519
-            throw new EE_Error(
520
-                sprintf(
521
-                    __(
522
-                        "You cannot check if a form is valid before receiving the form submission using receive_form_submission",
523
-                        "event_espresso"
524
-                    )
525
-                )
526
-            );
527
-        }
528
-        if (! parent::is_valid()) {
529
-            return false;
530
-        }
531
-        // ok so no general errors to this entire form section.
532
-        // so let's check the subsections, but only set errors if that hasn't been done yet
533
-        $set_submission_errors = $this->submission_error_message() === '' ? true : false;
534
-        foreach ($this->get_validatable_subsections() as $subsection) {
535
-            if (! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
536
-                if ($set_submission_errors) {
537
-                    $this->set_submission_error_message($subsection->get_validation_error_string());
538
-                }
539
-                return false;
540
-            }
541
-        }
542
-        return true;
543
-    }
544
-
545
-
546
-
547
-    /**
548
-     * gets teh default name of this form section if none is specified
549
-     *
550
-     * @return string
551
-     */
552
-    protected function _set_default_name_if_empty()
553
-    {
554
-        if (! $this->_name) {
555
-            $classname = get_class($this);
556
-            $default_name = str_replace("EE_", "", $classname);
557
-            $this->_name = $default_name;
558
-        }
559
-    }
560
-
561
-
562
-
563
-    /**
564
-     * Returns the HTML for the form, except for the form opening and closing tags
565
-     * (as the form section doesn't know where you necessarily want to send the information to),
566
-     * and except for a submit button. Enqueus JS and CSS; if called early enough we will
567
-     * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
568
-     * Not doing_it_wrong because theoretically this CAN be used properly,
569
-     * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
570
-     * any CSS.
571
-     *
572
-     * @throws \EE_Error
573
-     */
574
-    public function get_html_and_js()
575
-    {
576
-        $this->enqueue_js();
577
-        return $this->get_html();
578
-    }
579
-
580
-
581
-
582
-    /**
583
-     * returns HTML for displaying this form section. recursively calls display_section() on all subsections
584
-     *
585
-     * @param bool $display_previously_submitted_data
586
-     * @return string
587
-     */
588
-    public function get_html($display_previously_submitted_data = true)
589
-    {
590
-        $this->ensure_construct_finalized_called();
591
-        if ($display_previously_submitted_data) {
592
-            $this->populate_from_session();
593
-        }
594
-        return $this->_layout_strategy->layout_form();
595
-    }
596
-
597
-
598
-
599
-    /**
600
-     * enqueues JS and CSS for the form.
601
-     * It is preferred to call this before wp_enqueue_scripts so the
602
-     * scripts and styles can be put in the header, but if called later
603
-     * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
604
-     * only be in the header; but in HTML5 its ok in the body.
605
-     * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
606
-     * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
607
-     *
608
-     * @return string
609
-     * @throws \EE_Error
610
-     */
611
-    public function enqueue_js()
612
-    {
613
-        $this->_enqueue_and_localize_form_js();
614
-        foreach ($this->subsections() as $subsection) {
615
-            $subsection->enqueue_js();
616
-        }
617
-    }
618
-
619
-
620
-
621
-    /**
622
-     * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
623
-     * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
624
-     * the wp_enqueue_scripts hook.
625
-     * However, registering the form js and localizing it can happen when we
626
-     * actually output the form (which is preferred, seeing how teh form's fields
627
-     * could change until it's actually outputted)
628
-     *
629
-     * @param boolean $init_form_validation_automatically whether or not we want the form validation
630
-     *                                                    to be triggered automatically or not
631
-     * @return void
632
-     */
633
-    public static function wp_enqueue_scripts($init_form_validation_automatically = true)
634
-    {
635
-        add_filter('FHEE_load_jquery_validate', '__return_true');
636
-        wp_register_script(
637
-            'ee_form_section_validation',
638
-            EE_GLOBAL_ASSETS_URL . 'scripts' . DS . 'form_section_validation.js',
639
-            array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
640
-            EVENT_ESPRESSO_VERSION,
641
-            true
642
-        );
643
-        wp_localize_script(
644
-            'ee_form_section_validation',
645
-            'ee_form_section_validation_init',
646
-            array('init' => $init_form_validation_automatically ? true : false)
647
-        );
648
-    }
649
-
650
-
651
-
652
-    /**
653
-     * gets the variables used by form_section_validation.js.
654
-     * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
655
-     * but before the wordpress hook wp_loaded
656
-     *
657
-     * @throws \EE_Error
658
-     */
659
-    public function _enqueue_and_localize_form_js()
660
-    {
661
-        $this->ensure_construct_finalized_called();
662
-        //actually, we don't want to localize just yet. There may be other forms on the page.
663
-        //so we need to add our form section data to a static variable accessible by all form sections
664
-        //and localize it just before the footer
665
-        $this->localize_validation_rules();
666
-        add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
667
-        add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
668
-    }
669
-
670
-
671
-
672
-    /**
673
-     * add our form section data to a static variable accessible by all form sections
674
-     *
675
-     * @param bool $return_for_subsection
676
-     * @return void
677
-     * @throws \EE_Error
678
-     */
679
-    public function localize_validation_rules($return_for_subsection = false)
680
-    {
681
-        // we only want to localize vars ONCE for the entire form,
682
-        // so if the form section doesn't have a parent, then it must be the top dog
683
-        if ($return_for_subsection || ! $this->parent_section()) {
684
-            EE_Form_Section_Proper::$_js_localization['form_data'][$this->html_id()] = array(
685
-                'form_section_id'  => $this->html_id(true),
686
-                'validation_rules' => $this->get_jquery_validation_rules(),
687
-                'other_data'       => $this->get_other_js_data(),
688
-                'errors'           => $this->subsection_validation_errors_by_html_name(),
689
-            );
690
-            EE_Form_Section_Proper::$_scripts_localized = true;
691
-        }
692
-    }
693
-
694
-
695
-
696
-    /**
697
-     * Gets an array of extra data that will be useful for client-side javascript.
698
-     * This is primarily data added by inputs and forms in addition to any
699
-     * scripts they might enqueue
700
-     *
701
-     * @param array $form_other_js_data
702
-     * @return array
703
-     */
704
-    public function get_other_js_data($form_other_js_data = array())
705
-    {
706
-        foreach ($this->subsections() as $subsection) {
707
-            $form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
708
-        }
709
-        return $form_other_js_data;
710
-    }
711
-
712
-
713
-
714
-    /**
715
-     * Gets a flat array of inputs for this form section and its subsections.
716
-     * Keys are their form names, and values are the inputs themselves
717
-     *
718
-     * @return EE_Form_Input_Base
719
-     */
720
-    public function inputs_in_subsections()
721
-    {
722
-        $inputs = array();
723
-        foreach ($this->subsections() as $subsection) {
724
-            if ($subsection instanceof EE_Form_Input_Base) {
725
-                $inputs[$subsection->html_name()] = $subsection;
726
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
727
-                $inputs += $subsection->inputs_in_subsections();
728
-            }
729
-        }
730
-        return $inputs;
731
-    }
732
-
733
-
734
-
735
-    /**
736
-     * Gets a flat array of all the validation errors.
737
-     * Keys are html names (because those should be unique)
738
-     * and values are a string of all their validation errors
739
-     *
740
-     * @return string[]
741
-     */
742
-    public function subsection_validation_errors_by_html_name()
743
-    {
744
-        $inputs = $this->inputs();
745
-        $errors = array();
746
-        foreach ($inputs as $form_input) {
747
-            if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
748
-                $errors[$form_input->html_name()] = $form_input->get_validation_error_string();
749
-            }
750
-        }
751
-        return $errors;
752
-    }
753
-
754
-
755
-
756
-    /**
757
-     * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
758
-     * Should be setup by each form during the _enqueues_and_localize_form_js
759
-     */
760
-    public static function localize_script_for_all_forms()
761
-    {
762
-        //allow inputs and stuff to hook in their JS and stuff here
763
-        do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
764
-        EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
765
-        $email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
766
-            ? EE_Registry::instance()->CFG->registration->email_validation_level
767
-            : 'wp_default';
768
-        EE_Form_Section_Proper::$_js_localization['email_validation_level'] = $email_validation_level;
769
-        wp_enqueue_script('ee_form_section_validation');
770
-        wp_localize_script(
771
-            'ee_form_section_validation',
772
-            'ee_form_section_vars',
773
-            EE_Form_Section_Proper::$_js_localization
774
-        );
775
-    }
776
-
777
-
778
-
779
-    /**
780
-     * ensure_scripts_localized
781
-     */
782
-    public function ensure_scripts_localized()
783
-    {
784
-        if (! EE_Form_Section_Proper::$_scripts_localized) {
785
-            $this->_enqueue_and_localize_form_js();
786
-        }
787
-    }
788
-
789
-
790
-
791
-    /**
792
-     * Gets the hard-coded validation error messages to be used in the JS. The convention
793
-     * is that the key here should be the same as the custom validation rule put in the JS file
794
-     *
795
-     * @return array keys are custom validation rules, and values are internationalized strings
796
-     */
797
-    private static function _get_localized_error_messages()
798
-    {
799
-        return array(
800
-            'validUrl' => __("This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg", "event_espresso"),
801
-            'regex'    => __('Please check your input', 'event_espresso'),
802
-        );
803
-    }
804
-
805
-
806
-
807
-    /**
808
-     * @return array
809
-     */
810
-    public static function js_localization()
811
-    {
812
-        return self::$_js_localization;
813
-    }
814
-
815
-
816
-
817
-    /**
818
-     * @return array
819
-     */
820
-    public static function reset_js_localization()
821
-    {
822
-        self::$_js_localization = array();
823
-    }
824
-
825
-
826
-
827
-    /**
828
-     * Gets the JS to put inside the jquery validation rules for subsection of this form section.
829
-     * See parent function for more...
830
-     *
831
-     * @return array
832
-     */
833
-    public function get_jquery_validation_rules()
834
-    {
835
-        $jquery_validation_rules = array();
836
-        foreach ($this->get_validatable_subsections() as $subsection) {
837
-            $jquery_validation_rules = array_merge(
838
-                $jquery_validation_rules,
839
-                $subsection->get_jquery_validation_rules()
840
-            );
841
-        }
842
-        return $jquery_validation_rules;
843
-    }
844
-
845
-
846
-
847
-    /**
848
-     * Sanitizes all the data and sets the sanitized value of each field
849
-     *
850
-     * @param array $req_data like $_POST
851
-     * @return void
852
-     */
853
-    protected function _normalize($req_data)
854
-    {
855
-        $this->_received_submission = true;
856
-        $this->_validation_errors = array();
857
-        foreach ($this->get_validatable_subsections() as $subsection) {
858
-            try {
859
-                $subsection->_normalize($req_data);
860
-            } catch (EE_Validation_Error $e) {
861
-                $subsection->add_validation_error($e);
862
-            }
863
-        }
864
-    }
865
-
866
-
867
-
868
-    /**
869
-     * Performs validation on this form section and its subsections.
870
-     * For each subsection,
871
-     * calls _validate_{subsection_name} on THIS form (if the function exists)
872
-     * and passes it the subsection, then calls _validate on that subsection.
873
-     * If you need to perform validation on the form as a whole (considering multiple)
874
-     * you would be best to override this _validate method,
875
-     * calling parent::_validate() first.
876
-     */
877
-    protected function _validate()
878
-    {
879
-        foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
880
-            if (method_exists($this, '_validate_' . $subsection_name)) {
881
-                call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
882
-            }
883
-            $subsection->_validate();
884
-        }
885
-    }
886
-
887
-
888
-
889
-    /**
890
-     * Gets all the validated inputs for the form section
891
-     *
892
-     * @return array
893
-     */
894
-    public function valid_data()
895
-    {
896
-        $inputs = array();
897
-        foreach ($this->subsections() as $subsection_name => $subsection) {
898
-            if ($subsection instanceof EE_Form_Section_Proper) {
899
-                $inputs[$subsection_name] = $subsection->valid_data();
900
-            } else if ($subsection instanceof EE_Form_Input_Base) {
901
-                $inputs[$subsection_name] = $subsection->normalized_value();
902
-            }
903
-        }
904
-        return $inputs;
905
-    }
906
-
907
-
908
-
909
-    /**
910
-     * Gets all the inputs on this form section
911
-     *
912
-     * @return EE_Form_Input_Base[]
913
-     */
914
-    public function inputs()
915
-    {
916
-        $inputs = array();
917
-        foreach ($this->subsections() as $subsection_name => $subsection) {
918
-            if ($subsection instanceof EE_Form_Input_Base) {
919
-                $inputs[$subsection_name] = $subsection;
920
-            }
921
-        }
922
-        return $inputs;
923
-    }
924
-
925
-
926
-
927
-    /**
928
-     * Gets all the subsections which are a proper form
929
-     *
930
-     * @return EE_Form_Section_Proper[]
931
-     */
932
-    public function subforms()
933
-    {
934
-        $form_sections = array();
935
-        foreach ($this->subsections() as $name => $obj) {
936
-            if ($obj instanceof EE_Form_Section_Proper) {
937
-                $form_sections[$name] = $obj;
938
-            }
939
-        }
940
-        return $form_sections;
941
-    }
942
-
943
-
944
-
945
-    /**
946
-     * Gets all the subsections (inputs, proper subsections, or html-only sections).
947
-     * Consider using inputs() or subforms()
948
-     * if you only want form inputs or proper form sections.
949
-     *
950
-     * @param boolean $require_construction_to_be_finalized most client code should
951
-     *                                                      leave this as TRUE so that the inputs will be properly
952
-     *                                                      configured. However, some client code may be ok with
953
-     *                                                      construction finalize being called later
954
-     *                                                      (realizing that the subsections' html names might not be
955
-     *                                                      set yet, etc.)
956
-     * @return EE_Form_Section_Proper[]
957
-     */
958
-    public function subsections($require_construction_to_be_finalized = true)
959
-    {
960
-        if ($require_construction_to_be_finalized) {
961
-            $this->ensure_construct_finalized_called();
962
-        }
963
-        return $this->_subsections;
964
-    }
965
-
966
-
967
-
968
-    /**
969
-     * Returns a simple array where keys are input names, and values are their normalized
970
-     * values. (Similar to calling get_input_value on inputs)
971
-     *
972
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
973
-     *                                        or just this forms' direct children inputs
974
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
975
-     *                                        or allow multidimensional array
976
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
977
-     *                                        with array keys being input names
978
-     *                                        (regardless of whether they are from a subsection or not),
979
-     *                                        and if $flatten is FALSE it can be a multidimensional array
980
-     *                                        where keys are always subsection names and values are either
981
-     *                                        the input's normalized value, or an array like the top-level array
982
-     */
983
-    public function input_values($include_subform_inputs = false, $flatten = false)
984
-    {
985
-        return $this->_input_values(false, $include_subform_inputs, $flatten);
986
-    }
987
-
988
-
989
-
990
-    /**
991
-     * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
992
-     * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
993
-     * is not necessarily the value we want to display to users. This creates an array
994
-     * where keys are the input names, and values are their display values
995
-     *
996
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
997
-     *                                        or just this forms' direct children inputs
998
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
999
-     *                                        or allow multidimensional array
1000
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
1001
-     *                                        with array keys being input names
1002
-     *                                        (regardless of whether they are from a subsection or not),
1003
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1004
-     *                                        where keys are always subsection names and values are either
1005
-     *                                        the input's normalized value, or an array like the top-level array
1006
-     */
1007
-    public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1008
-    {
1009
-        return $this->_input_values(true, $include_subform_inputs, $flatten);
1010
-    }
1011
-
1012
-
1013
-
1014
-    /**
1015
-     * Gets the input values from the form
1016
-     *
1017
-     * @param boolean $pretty                 Whether to retrieve the pretty value,
1018
-     *                                        or just the normalized value
1019
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1020
-     *                                        or just this forms' direct children inputs
1021
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1022
-     *                                        or allow multidimensional array
1023
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1024
-     *                                        input names (regardless of whether they are from a subsection or not),
1025
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1026
-     *                                        where keys are always subsection names and values are either
1027
-     *                                        the input's normalized value, or an array like the top-level array
1028
-     */
1029
-    public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1030
-    {
1031
-        $input_values = array();
1032
-        foreach ($this->subsections() as $subsection_name => $subsection) {
1033
-            if ($subsection instanceof EE_Form_Input_Base) {
1034
-                $input_values[$subsection_name] = $pretty
1035
-                    ? $subsection->pretty_value()
1036
-                    : $subsection->normalized_value();
1037
-            } else if ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1038
-                $subform_input_values = $subsection->_input_values($pretty, $include_subform_inputs, $flatten);
1039
-                if ($flatten) {
1040
-                    $input_values = array_merge($input_values, $subform_input_values);
1041
-                } else {
1042
-                    $input_values[$subsection_name] = $subform_input_values;
1043
-                }
1044
-            }
1045
-        }
1046
-        return $input_values;
1047
-    }
1048
-
1049
-
1050
-
1051
-    /**
1052
-     * Gets the originally submitted input values from the form
1053
-     *
1054
-     * @param boolean $include_subforms  Whether to include inputs from subforms,
1055
-     *                                   or just this forms' direct children inputs
1056
-     * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1057
-     *                                   with array keys being input names
1058
-     *                                   (regardless of whether they are from a subsection or not),
1059
-     *                                   and if $flatten is FALSE it can be a multidimensional array
1060
-     *                                   where keys are always subsection names and values are either
1061
-     *                                   the input's normalized value, or an array like the top-level array
1062
-     */
1063
-    public function submitted_values($include_subforms = false)
1064
-    {
1065
-        $submitted_values = array();
1066
-        foreach ($this->subsections() as $subsection) {
1067
-            if ($subsection instanceof EE_Form_Input_Base) {
1068
-                // is this input part of an array of inputs?
1069
-                if (strpos($subsection->html_name(), '[') !== false) {
1070
-                    $full_input_name = \EEH_Array::convert_array_values_to_keys(
1071
-                        explode('[', str_replace(']', '', $subsection->html_name())),
1072
-                        $subsection->raw_value()
1073
-                    );
1074
-                    $submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1075
-                } else {
1076
-                    $submitted_values[$subsection->html_name()] = $subsection->raw_value();
1077
-                }
1078
-            } else if ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1079
-                $subform_input_values = $subsection->submitted_values($include_subforms);
1080
-                $submitted_values = array_replace_recursive($submitted_values, $subform_input_values);
1081
-            }
1082
-        }
1083
-        return $submitted_values;
1084
-    }
1085
-
1086
-
1087
-
1088
-    /**
1089
-     * Indicates whether or not this form has received a submission yet
1090
-     * (ie, had receive_form_submission called on it yet)
1091
-     *
1092
-     * @return boolean
1093
-     * @throws \EE_Error
1094
-     */
1095
-    public function has_received_submission()
1096
-    {
1097
-        $this->ensure_construct_finalized_called();
1098
-        return $this->_received_submission;
1099
-    }
1100
-
1101
-
1102
-
1103
-    /**
1104
-     * Equivalent to passing 'exclude' in the constructor's options array.
1105
-     * Removes the listed inputs from the form
1106
-     *
1107
-     * @param array $inputs_to_exclude values are the input names
1108
-     * @return void
1109
-     */
1110
-    public function exclude(array $inputs_to_exclude = array())
1111
-    {
1112
-        foreach ($inputs_to_exclude as $input_to_exclude_name) {
1113
-            unset($this->_subsections[$input_to_exclude_name]);
1114
-        }
1115
-    }
1116
-
1117
-
1118
-
1119
-    /**
1120
-     * @param array $inputs_to_hide
1121
-     * @throws \EE_Error
1122
-     */
1123
-    public function hide(array $inputs_to_hide = array())
1124
-    {
1125
-        foreach ($inputs_to_hide as $input_to_hide) {
1126
-            $input = $this->get_input($input_to_hide);
1127
-            $input->set_display_strategy(new EE_Hidden_Display_Strategy());
1128
-        }
1129
-    }
1130
-
1131
-
1132
-
1133
-    /**
1134
-     * add_subsections
1135
-     * Adds the listed subsections to the form section.
1136
-     * If $subsection_name_to_target is provided,
1137
-     * then new subsections are added before or after that subsection,
1138
-     * otherwise to the start or end of the entire subsections array.
1139
-     *
1140
-     * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1141
-     *                                                          where keys are their names
1142
-     * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1143
-     *                                                          should be added before or after
1144
-     *                                                          IF $subsection_name_to_target is null,
1145
-     *                                                          then $new_subsections will be added to
1146
-     *                                                          the beginning or end of the entire subsections array
1147
-     * @param boolean                $add_before                whether to add $new_subsections, before or after
1148
-     *                                                          $subsection_name_to_target,
1149
-     *                                                          or if $subsection_name_to_target is null,
1150
-     *                                                          before or after entire subsections array
1151
-     * @return void
1152
-     * @throws \EE_Error
1153
-     */
1154
-    public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1155
-    {
1156
-        foreach ($new_subsections as $subsection_name => $subsection) {
1157
-            if (! $subsection instanceof EE_Form_Section_Base) {
1158
-                EE_Error::add_error(
1159
-                    sprintf(
1160
-                        __(
1161
-                            "Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1162
-                            "event_espresso"
1163
-                        ),
1164
-                        get_class($subsection),
1165
-                        $subsection_name,
1166
-                        $this->name()
1167
-                    )
1168
-                );
1169
-                unset($new_subsections[$subsection_name]);
1170
-            }
1171
-        }
1172
-        $this->_subsections = EEH_Array::insert_into_array(
1173
-            $this->_subsections,
1174
-            $new_subsections,
1175
-            $subsection_name_to_target,
1176
-            $add_before
1177
-        );
1178
-        if ($this->_construction_finalized) {
1179
-            foreach ($this->_subsections as $name => $subsection) {
1180
-                $subsection->_construct_finalize($this, $name);
1181
-            }
1182
-        }
1183
-    }
1184
-
1185
-
1186
-
1187
-    /**
1188
-     * Just gets all validatable subsections to clean their sensitive data
1189
-     */
1190
-    public function clean_sensitive_data()
1191
-    {
1192
-        foreach ($this->get_validatable_subsections() as $subsection) {
1193
-            $subsection->clean_sensitive_data();
1194
-        }
1195
-    }
1196
-
1197
-
1198
-
1199
-    /**
1200
-     * @param string $form_submission_error_message
1201
-     */
1202
-    public function set_submission_error_message($form_submission_error_message = '')
1203
-    {
1204
-        $this->_form_submission_error_message .= ! empty($form_submission_error_message)
1205
-            ? $form_submission_error_message
1206
-            : __('Form submission failed due to errors', 'event_espresso');
1207
-    }
1208
-
1209
-
1210
-
1211
-    /**
1212
-     * @return string
1213
-     */
1214
-    public function submission_error_message()
1215
-    {
1216
-        return $this->_form_submission_error_message;
1217
-    }
1218
-
1219
-
1220
-
1221
-    /**
1222
-     * @param string $form_submission_success_message
1223
-     */
1224
-    public function set_submission_success_message($form_submission_success_message)
1225
-    {
1226
-        $this->_form_submission_success_message .= ! empty($form_submission_success_message)
1227
-            ? $form_submission_success_message
1228
-            : __('Form submitted successfully', 'event_espresso');
1229
-    }
1230
-
1231
-
1232
-
1233
-    /**
1234
-     * @return string
1235
-     */
1236
-    public function submission_success_message()
1237
-    {
1238
-        return $this->_form_submission_success_message;
1239
-    }
1240
-
1241
-
1242
-
1243
-    /**
1244
-     * Returns the prefix that should be used on child of this form section for
1245
-     * their html names. If this form section itself has a parent, prepends ITS
1246
-     * prefix onto this form section's prefix. Used primarily by
1247
-     * EE_Form_Input_Base::_set_default_html_name_if_empty
1248
-     *
1249
-     * @return string
1250
-     * @throws \EE_Error
1251
-     */
1252
-    public function html_name_prefix()
1253
-    {
1254
-        if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1255
-            return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1256
-        } else {
1257
-            return $this->name();
1258
-        }
1259
-    }
1260
-
1261
-
1262
-
1263
-    /**
1264
-     * Gets the name, but first checks _construct_finalize has been called. If not,
1265
-     * calls it (assumes there is no parent and that we want the name to be whatever
1266
-     * was set, which is probably nothing, or the classname)
1267
-     *
1268
-     * @return string
1269
-     * @throws \EE_Error
1270
-     */
1271
-    public function name()
1272
-    {
1273
-        $this->ensure_construct_finalized_called();
1274
-        return parent::name();
1275
-    }
1276
-
1277
-
1278
-
1279
-    /**
1280
-     * @return EE_Form_Section_Proper
1281
-     * @throws \EE_Error
1282
-     */
1283
-    public function parent_section()
1284
-    {
1285
-        $this->ensure_construct_finalized_called();
1286
-        return parent::parent_section();
1287
-    }
1288
-
1289
-
1290
-
1291
-    /**
1292
-     * make sure construction finalized was called, otherwise children might not be ready
1293
-     *
1294
-     * @return void
1295
-     * @throws \EE_Error
1296
-     */
1297
-    public function ensure_construct_finalized_called()
1298
-    {
1299
-        if (! $this->_construction_finalized) {
1300
-            $this->_construct_finalize($this->_parent_section, $this->_name);
1301
-        }
1302
-    }
1303
-
1304
-
1305
-
1306
-    /**
1307
-     * Checks if any of this form section's inputs, or any of its children's inputs,
1308
-     * are in teh form data. If any are found, returns true. Else false
1309
-     *
1310
-     * @param array $req_data
1311
-     * @return boolean
1312
-     */
1313
-    public function form_data_present_in($req_data = null)
1314
-    {
1315
-        if ($req_data === null) {
1316
-            $req_data = $_POST;
1317
-        }
1318
-        foreach ($this->subsections() as $subsection) {
1319
-            if ($subsection instanceof EE_Form_Input_Base) {
1320
-                if ($subsection->form_data_present_in($req_data)) {
1321
-                    return true;
1322
-                }
1323
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
1324
-                if ($subsection->form_data_present_in($req_data)) {
1325
-                    return true;
1326
-                }
1327
-            }
1328
-        }
1329
-        return false;
1330
-    }
1331
-
1332
-
1333
-
1334
-    /**
1335
-     * Gets validation errors for this form section and subsections
1336
-     * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1337
-     * gets the validation errors for ALL subsection
1338
-     *
1339
-     * @return EE_Validation_Error[]
1340
-     */
1341
-    public function get_validation_errors_accumulated()
1342
-    {
1343
-        $validation_errors = $this->get_validation_errors();
1344
-        foreach ($this->get_validatable_subsections() as $subsection) {
1345
-            if ($subsection instanceof EE_Form_Section_Proper) {
1346
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1347
-            } else {
1348
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors();
1349
-            }
1350
-            if ($validation_errors_on_this_subsection) {
1351
-                $validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1352
-            }
1353
-        }
1354
-        return $validation_errors;
1355
-    }
1356
-
1357
-
1358
-
1359
-    /**
1360
-     * This isn't just the name of an input, it's a path pointing to an input. The
1361
-     * path is similar to a folder path: slash (/) means to descend into a subsection,
1362
-     * dot-dot-slash (../) means to ascend into the parent section.
1363
-     * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1364
-     * which will be returned.
1365
-     * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1366
-     * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1367
-     * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1368
-     * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1369
-     * Etc
1370
-     *
1371
-     * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1372
-     * @return EE_Form_Section_Base
1373
-     */
1374
-    public function find_section_from_path($form_section_path)
1375
-    {
1376
-        //check if we can find the input from purely going straight up the tree
1377
-        $input = parent::find_section_from_path($form_section_path);
1378
-        if ($input instanceof EE_Form_Section_Base) {
1379
-            return $input;
1380
-        }
1381
-        $next_slash_pos = strpos($form_section_path, '/');
1382
-        if ($next_slash_pos !== false) {
1383
-            $child_section_name = substr($form_section_path, 0, $next_slash_pos);
1384
-            $subpath = substr($form_section_path, $next_slash_pos + 1);
1385
-        } else {
1386
-            $child_section_name = $form_section_path;
1387
-            $subpath = '';
1388
-        }
1389
-        $child_section = $this->get_subsection($child_section_name);
1390
-        if ($child_section instanceof EE_Form_Section_Base) {
1391
-            return $child_section->find_section_from_path($subpath);
1392
-        } else {
1393
-            return null;
1394
-        }
1395
-    }
16
+	const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
17
+
18
+	/**
19
+	 * Subsections
20
+	 *
21
+	 * @var EE_Form_Section_Validatable[]
22
+	 */
23
+	protected $_subsections = array();
24
+
25
+	/**
26
+	 * Strategy for laying out the form
27
+	 *
28
+	 * @var EE_Form_Section_Layout_Base
29
+	 */
30
+	protected $_layout_strategy;
31
+
32
+	/**
33
+	 * Whether or not this form has received and validated a form submission yet
34
+	 *
35
+	 * @var boolean
36
+	 */
37
+	protected $_received_submission = false;
38
+
39
+	/**
40
+	 * message displayed to users upon successful form submission
41
+	 *
42
+	 * @var string
43
+	 */
44
+	protected $_form_submission_success_message = '';
45
+
46
+	/**
47
+	 * message displayed to users upon unsuccessful form submission
48
+	 *
49
+	 * @var string
50
+	 */
51
+	protected $_form_submission_error_message = '';
52
+
53
+	/**
54
+	 * Stores all the data that will localized for form validation
55
+	 *
56
+	 * @var array
57
+	 */
58
+	static protected $_js_localization = array();
59
+
60
+	/**
61
+	 * whether or not the form's localized validation JS vars have been set
62
+	 *
63
+	 * @type boolean
64
+	 */
65
+	static protected $_scripts_localized = false;
66
+
67
+
68
+
69
+	/**
70
+	 * when constructing a proper form section, calls _construct_finalize on children
71
+	 * so that they know who their parent is, and what name they've been given.
72
+	 *
73
+	 * @param array $options_array   {
74
+	 * @type        $subsections     EE_Form_Section_Validatable[] where keys are the section's name
75
+	 * @type        $include         string[] numerically-indexed where values are section names to be included,
76
+	 *                               and in that order. This is handy if you want
77
+	 *                               the subsections to be ordered differently than the default, and if you override
78
+	 *                               which fields are shown
79
+	 * @type        $exclude         string[] values are subsections to be excluded. This is handy if you want
80
+	 *                               to remove certain default subsections (note: if you specify BOTH 'include' AND
81
+	 *                               'exclude', the inclusions will be applied first, and the exclusions will exclude
82
+	 *                               items from that list of inclusions)
83
+	 * @type        $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
84
+	 *                               } @see EE_Form_Section_Validatable::__construct()
85
+	 * @throws \EE_Error
86
+	 */
87
+	public function __construct($options_array = array())
88
+	{
89
+		$options_array = (array)apply_filters('FHEE__EE_Form_Section_Proper___construct__options_array', $options_array,
90
+			$this);
91
+		//call parent first, as it may be setting the name
92
+		parent::__construct($options_array);
93
+		//if they've included subsections in the constructor, add them now
94
+		if (isset($options_array['include'])) {
95
+			//we are going to make sure we ONLY have those subsections to include
96
+			//AND we are going to make sure they're in that specified order
97
+			$reordered_subsections = array();
98
+			foreach ($options_array['include'] as $input_name) {
99
+				if (isset($this->_subsections[$input_name])) {
100
+					$reordered_subsections[$input_name] = $this->_subsections[$input_name];
101
+				}
102
+			}
103
+			$this->_subsections = $reordered_subsections;
104
+		}
105
+		if (isset($options_array['exclude'])) {
106
+			$exclude = $options_array['exclude'];
107
+			$this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
108
+		}
109
+		if (isset($options_array['layout_strategy'])) {
110
+			$this->_layout_strategy = $options_array['layout_strategy'];
111
+		}
112
+		if (! $this->_layout_strategy) {
113
+			$this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
114
+		}
115
+		$this->_layout_strategy->_construct_finalize($this);
116
+		//ok so we are definitely going to want the forms JS,
117
+		//so enqueue it or remember to enqueue it during wp_enqueue_scripts
118
+		if (did_action('wp_enqueue_scripts')
119
+			|| did_action('admin_enqueue_scripts')
120
+		) {
121
+			//ok so they've constructed this object after when they should have.
122
+			//just enqueue the generic form scripts and initialize the form immediately in the JS
123
+			\EE_Form_Section_Proper::wp_enqueue_scripts(true);
124
+		} else {
125
+			add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
126
+			add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
127
+		}
128
+		add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
129
+
130
+		/**
131
+		 * Gives other plugins a chance to hook in before construct finalize is called. The form probably doesn't
132
+		 * yet have a parent form section. Since 4.9.32, when this action was introduced, this is the best place to
133
+		 * add a subsection onto a form, assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
134
+		 * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
135
+		 * @since 4.9.32
136
+		 * @param EE_Form_Section_Proper $this before __construct is done, but all of its logic, except maybe calling
137
+		 *                                      _construct_finalize has been done
138
+		 * @param array $options_array options passed into the constructor
139
+		 */
140
+		do_action('AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called', $this, $options_array);
141
+
142
+		if (isset($options_array['name'])) {
143
+			$this->_construct_finalize(null, $options_array['name']);
144
+		}
145
+	}
146
+
147
+
148
+
149
+	/**
150
+	 * Finishes construction given the parent form section and this form section's name
151
+	 *
152
+	 * @param EE_Form_Section_Proper $parent_form_section
153
+	 * @param string                 $name
154
+	 * @throws \EE_Error
155
+	 */
156
+	public function _construct_finalize($parent_form_section, $name)
157
+	{
158
+		parent::_construct_finalize($parent_form_section, $name);
159
+		$this->_set_default_name_if_empty();
160
+		$this->_set_default_html_id_if_empty();
161
+		foreach ($this->_subsections as $subsection_name => $subsection) {
162
+			if ($subsection instanceof EE_Form_Section_Base) {
163
+				$subsection->_construct_finalize($this, $subsection_name);
164
+			} else {
165
+				throw new EE_Error(
166
+					sprintf(
167
+						__('Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
168
+							'event_espresso'),
169
+						$subsection_name,
170
+						get_class($this),
171
+						$subsection ? get_class($subsection) : __('NULL', 'event_espresso')
172
+					)
173
+				);
174
+			}
175
+		}
176
+		/**
177
+		 * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
178
+		 * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID (or other attributes derived
179
+		 * from the name like the HTML label id, etc), this is where it should be done.
180
+		 * This might only happen just before displaying the form, or just before it receives form submission data.
181
+		 * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
182
+		 * ensured it has a name, HTML IDs, etc
183
+		 * @param EE_Form_Section_Proper $this
184
+		 * @param EE_Form_Section_Proper|null $parent_form_section
185
+		 * @param string $name
186
+		 */
187
+		do_action('AHEE__EE_Form_Section_Proper___construct_finalize__end', $this, $parent_form_section, $name);
188
+	}
189
+
190
+
191
+
192
+	/**
193
+	 * Gets the layout strategy for this form section
194
+	 *
195
+	 * @return EE_Form_Section_Layout_Base
196
+	 */
197
+	public function get_layout_strategy()
198
+	{
199
+		return $this->_layout_strategy;
200
+	}
201
+
202
+
203
+
204
+	/**
205
+	 * Gets the HTML for a single input for this form section according
206
+	 * to the layout strategy
207
+	 *
208
+	 * @param EE_Form_Input_Base $input
209
+	 * @return string
210
+	 */
211
+	public function get_html_for_input($input)
212
+	{
213
+		return $this->_layout_strategy->layout_input($input);
214
+	}
215
+
216
+
217
+
218
+	/**
219
+	 * was_submitted - checks if form inputs are present in request data
220
+	 * Basically an alias for form_data_present_in() (which is used by both
221
+	 * proper form sections and form inputs)
222
+	 *
223
+	 * @param null $form_data
224
+	 * @return boolean
225
+	 */
226
+	public function was_submitted($form_data = null)
227
+	{
228
+		return $this->form_data_present_in($form_data);
229
+	}
230
+
231
+
232
+
233
+	/**
234
+	 * After the form section is initially created, call this to sanitize the data in the submission
235
+	 * which relates to this form section, validate it, and set it as properties on the form.
236
+	 *
237
+	 * @param array|null $req_data should usually be $_POST (the default).
238
+	 *                             However, you CAN supply a different array.
239
+	 *                             Consider using set_defaults() instead however.
240
+	 *                             (If you rendered the form in the page using echo $form_x->get_html()
241
+	 *                             the inputs will have the correct name in the request data for this function
242
+	 *                             to find them and populate the form with them.
243
+	 *                             If you have a flat form (with only input subsections),
244
+	 *                             you can supply a flat array where keys
245
+	 *                             are the form input names and values are their values)
246
+	 * @param boolean    $validate whether or not to perform validation on this data. Default is,
247
+	 *                             of course, to validate that data, and set errors on the invalid values.
248
+	 *                             But if the data has already been validated
249
+	 *                             (eg you validated the data then stored it in the DB)
250
+	 *                             you may want to skip this step.
251
+	 */
252
+	public function receive_form_submission($req_data = null, $validate = true)
253
+	{
254
+		$req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__req_data', $req_data, $this,
255
+			$validate);
256
+		if ($req_data === null) {
257
+			$req_data = array_merge($_GET, $_POST);
258
+		}
259
+		$req_data = apply_filters('FHEE__EE_Form_Section_Proper__receive_form_submission__request_data', $req_data,
260
+			$this);
261
+		$this->_normalize($req_data);
262
+		if ($validate) {
263
+			$this->_validate();
264
+			//if it's invalid, we're going to want to re-display so remember what they submitted
265
+			if (! $this->is_valid()) {
266
+				$this->store_submitted_form_data_in_session();
267
+			}
268
+		}
269
+		do_action('AHEE__EE_Form_Section_Proper__receive_form_submission__end', $req_data, $this, $validate);
270
+	}
271
+
272
+
273
+
274
+	/**
275
+	 * caches the originally submitted input values in the session
276
+	 * so that they can be used to repopulate the form if it failed validation
277
+	 *
278
+	 * @return boolean whether or not the data was successfully stored in the session
279
+	 */
280
+	protected function store_submitted_form_data_in_session()
281
+	{
282
+		return EE_Registry::instance()->SSN->set_session_data(
283
+			array(
284
+				\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
285
+			)
286
+		);
287
+	}
288
+
289
+
290
+
291
+	/**
292
+	 * retrieves the originally submitted input values in the session
293
+	 * so that they can be used to repopulate the form if it failed validation
294
+	 *
295
+	 * @return array
296
+	 */
297
+	protected function get_submitted_form_data_from_session()
298
+	{
299
+		$session = EE_Registry::instance()->SSN;
300
+		if ($session instanceof EE_Session) {
301
+			return $session->get_session_data(
302
+				\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
303
+			);
304
+		} else {
305
+			return array();
306
+		}
307
+	}
308
+
309
+
310
+
311
+	/**
312
+	 * flushed the originally submitted input values from the session
313
+	 *
314
+	 * @return boolean whether or not the data was successfully removed from the session
315
+	 */
316
+	protected function flush_submitted_form_data_from_session()
317
+	{
318
+		return EE_Registry::instance()->SSN->reset_data(
319
+			array(\EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
320
+		);
321
+	}
322
+
323
+
324
+
325
+	/**
326
+	 * Populates this form and its subsections with data from the session.
327
+	 * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
328
+	 * validation errors when displaying too)
329
+	 * Returns true if the form was populated from the session, false otherwise
330
+	 *
331
+	 * @return boolean
332
+	 */
333
+	public function populate_from_session()
334
+	{
335
+		$form_data_in_session = $this->get_submitted_form_data_from_session();
336
+		if (empty($form_data_in_session)) {
337
+			return false;
338
+		}
339
+		$this->receive_form_submission($form_data_in_session);
340
+		$this->flush_submitted_form_data_from_session();
341
+		if ($this->form_data_present_in($form_data_in_session)) {
342
+			return true;
343
+		} else {
344
+			return false;
345
+		}
346
+	}
347
+
348
+
349
+
350
+	/**
351
+	 * Populates the default data for the form, given an array where keys are
352
+	 * the input names, and values are their values (preferably normalized to be their
353
+	 * proper PHP types, not all strings... although that should be ok too).
354
+	 * Proper subsections are sub-arrays, the key being the subsection's name, and
355
+	 * the value being an array formatted in teh same way
356
+	 *
357
+	 * @param array $default_data
358
+	 */
359
+	public function populate_defaults($default_data)
360
+	{
361
+		foreach ($this->subsections(false) as $subsection_name => $subsection) {
362
+			if (isset($default_data[$subsection_name])) {
363
+				if ($subsection instanceof EE_Form_Input_Base) {
364
+					$subsection->set_default($default_data[$subsection_name]);
365
+				} elseif ($subsection instanceof EE_Form_Section_Proper) {
366
+					$subsection->populate_defaults($default_data[$subsection_name]);
367
+				}
368
+			}
369
+		}
370
+	}
371
+
372
+
373
+
374
+	/**
375
+	 * returns true if subsection exists
376
+	 *
377
+	 * @param string $name
378
+	 * @return boolean
379
+	 */
380
+	public function subsection_exists($name)
381
+	{
382
+		return isset($this->_subsections[$name]) ? true : false;
383
+	}
384
+
385
+
386
+
387
+	/**
388
+	 * Gets the subsection specified by its name
389
+	 *
390
+	 * @param string  $name
391
+	 * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
392
+	 *                                                      so that the inputs will be properly configured.
393
+	 *                                                      However, some client code may be ok
394
+	 *                                                      with construction finalize being called later
395
+	 *                                                      (realizing that the subsections' html names
396
+	 *                                                      might not be set yet, etc.)
397
+	 * @return EE_Form_Section_Base
398
+	 * @throws \EE_Error
399
+	 */
400
+	public function get_subsection($name, $require_construction_to_be_finalized = true)
401
+	{
402
+		if ($require_construction_to_be_finalized) {
403
+			$this->ensure_construct_finalized_called();
404
+		}
405
+		return $this->subsection_exists($name) ? $this->_subsections[$name] : null;
406
+	}
407
+
408
+
409
+
410
+	/**
411
+	 * Gets all the validatable subsections of this form section
412
+	 *
413
+	 * @return EE_Form_Section_Validatable[]
414
+	 */
415
+	public function get_validatable_subsections()
416
+	{
417
+		$validatable_subsections = array();
418
+		foreach ($this->subsections() as $name => $obj) {
419
+			if ($obj instanceof EE_Form_Section_Validatable) {
420
+				$validatable_subsections[$name] = $obj;
421
+			}
422
+		}
423
+		return $validatable_subsections;
424
+	}
425
+
426
+
427
+
428
+	/**
429
+	 * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
430
+	 * throw an EE_Error.
431
+	 *
432
+	 * @param string  $name
433
+	 * @param boolean $require_construction_to_be_finalized most client code should
434
+	 *                                                      leave this as TRUE so that the inputs will be properly
435
+	 *                                                      configured. However, some client code may be ok with
436
+	 *                                                      construction finalize being called later
437
+	 *                                                      (realizing that the subsections' html names might not be
438
+	 *                                                      set yet, etc.)
439
+	 * @return EE_Form_Input_Base
440
+	 * @throws EE_Error
441
+	 */
442
+	public function get_input($name, $require_construction_to_be_finalized = true)
443
+	{
444
+		$subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
445
+		if (! $subsection instanceof EE_Form_Input_Base) {
446
+			throw new EE_Error(
447
+				sprintf(
448
+					__(
449
+						"Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
450
+						'event_espresso'
451
+					),
452
+					$name,
453
+					get_class($this),
454
+					$subsection ? get_class($subsection) : __("NULL", 'event_espresso')
455
+				)
456
+			);
457
+		}
458
+		return $subsection;
459
+	}
460
+
461
+
462
+
463
+	/**
464
+	 * Like get_input(), gets the proper subsection of the form given the name,
465
+	 * otherwise throws an EE_Error
466
+	 *
467
+	 * @param string  $name
468
+	 * @param boolean $require_construction_to_be_finalized most client code should
469
+	 *                                                      leave this as TRUE so that the inputs will be properly
470
+	 *                                                      configured. However, some client code may be ok with
471
+	 *                                                      construction finalize being called later
472
+	 *                                                      (realizing that the subsections' html names might not be
473
+	 *                                                      set yet, etc.)
474
+	 * @return EE_Form_Section_Proper
475
+	 * @throws EE_Error
476
+	 */
477
+	public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
478
+	{
479
+		$subsection = $this->get_subsection($name, $require_construction_to_be_finalized);
480
+		if (! $subsection instanceof EE_Form_Section_Proper) {
481
+			throw new EE_Error(
482
+				sprintf(
483
+					__("Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'", 'event_espresso'),
484
+					$name,
485
+					get_class($this)
486
+				)
487
+			);
488
+		}
489
+		return $subsection;
490
+	}
491
+
492
+
493
+
494
+	/**
495
+	 * Gets the value of the specified input. Should be called after receive_form_submission()
496
+	 * or populate_defaults() on the form, where the normalized value on the input is set.
497
+	 *
498
+	 * @param string $name
499
+	 * @return mixed depending on the input's type and its normalization strategy
500
+	 * @throws \EE_Error
501
+	 */
502
+	public function get_input_value($name)
503
+	{
504
+		$input = $this->get_input($name);
505
+		return $input->normalized_value();
506
+	}
507
+
508
+
509
+
510
+	/**
511
+	 * Checks if this form section itself is valid, and then checks its subsections
512
+	 *
513
+	 * @throws EE_Error
514
+	 * @return boolean
515
+	 */
516
+	public function is_valid()
517
+	{
518
+		if (! $this->has_received_submission()) {
519
+			throw new EE_Error(
520
+				sprintf(
521
+					__(
522
+						"You cannot check if a form is valid before receiving the form submission using receive_form_submission",
523
+						"event_espresso"
524
+					)
525
+				)
526
+			);
527
+		}
528
+		if (! parent::is_valid()) {
529
+			return false;
530
+		}
531
+		// ok so no general errors to this entire form section.
532
+		// so let's check the subsections, but only set errors if that hasn't been done yet
533
+		$set_submission_errors = $this->submission_error_message() === '' ? true : false;
534
+		foreach ($this->get_validatable_subsections() as $subsection) {
535
+			if (! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
536
+				if ($set_submission_errors) {
537
+					$this->set_submission_error_message($subsection->get_validation_error_string());
538
+				}
539
+				return false;
540
+			}
541
+		}
542
+		return true;
543
+	}
544
+
545
+
546
+
547
+	/**
548
+	 * gets teh default name of this form section if none is specified
549
+	 *
550
+	 * @return string
551
+	 */
552
+	protected function _set_default_name_if_empty()
553
+	{
554
+		if (! $this->_name) {
555
+			$classname = get_class($this);
556
+			$default_name = str_replace("EE_", "", $classname);
557
+			$this->_name = $default_name;
558
+		}
559
+	}
560
+
561
+
562
+
563
+	/**
564
+	 * Returns the HTML for the form, except for the form opening and closing tags
565
+	 * (as the form section doesn't know where you necessarily want to send the information to),
566
+	 * and except for a submit button. Enqueus JS and CSS; if called early enough we will
567
+	 * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
568
+	 * Not doing_it_wrong because theoretically this CAN be used properly,
569
+	 * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
570
+	 * any CSS.
571
+	 *
572
+	 * @throws \EE_Error
573
+	 */
574
+	public function get_html_and_js()
575
+	{
576
+		$this->enqueue_js();
577
+		return $this->get_html();
578
+	}
579
+
580
+
581
+
582
+	/**
583
+	 * returns HTML for displaying this form section. recursively calls display_section() on all subsections
584
+	 *
585
+	 * @param bool $display_previously_submitted_data
586
+	 * @return string
587
+	 */
588
+	public function get_html($display_previously_submitted_data = true)
589
+	{
590
+		$this->ensure_construct_finalized_called();
591
+		if ($display_previously_submitted_data) {
592
+			$this->populate_from_session();
593
+		}
594
+		return $this->_layout_strategy->layout_form();
595
+	}
596
+
597
+
598
+
599
+	/**
600
+	 * enqueues JS and CSS for the form.
601
+	 * It is preferred to call this before wp_enqueue_scripts so the
602
+	 * scripts and styles can be put in the header, but if called later
603
+	 * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
604
+	 * only be in the header; but in HTML5 its ok in the body.
605
+	 * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
606
+	 * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
607
+	 *
608
+	 * @return string
609
+	 * @throws \EE_Error
610
+	 */
611
+	public function enqueue_js()
612
+	{
613
+		$this->_enqueue_and_localize_form_js();
614
+		foreach ($this->subsections() as $subsection) {
615
+			$subsection->enqueue_js();
616
+		}
617
+	}
618
+
619
+
620
+
621
+	/**
622
+	 * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
623
+	 * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
624
+	 * the wp_enqueue_scripts hook.
625
+	 * However, registering the form js and localizing it can happen when we
626
+	 * actually output the form (which is preferred, seeing how teh form's fields
627
+	 * could change until it's actually outputted)
628
+	 *
629
+	 * @param boolean $init_form_validation_automatically whether or not we want the form validation
630
+	 *                                                    to be triggered automatically or not
631
+	 * @return void
632
+	 */
633
+	public static function wp_enqueue_scripts($init_form_validation_automatically = true)
634
+	{
635
+		add_filter('FHEE_load_jquery_validate', '__return_true');
636
+		wp_register_script(
637
+			'ee_form_section_validation',
638
+			EE_GLOBAL_ASSETS_URL . 'scripts' . DS . 'form_section_validation.js',
639
+			array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
640
+			EVENT_ESPRESSO_VERSION,
641
+			true
642
+		);
643
+		wp_localize_script(
644
+			'ee_form_section_validation',
645
+			'ee_form_section_validation_init',
646
+			array('init' => $init_form_validation_automatically ? true : false)
647
+		);
648
+	}
649
+
650
+
651
+
652
+	/**
653
+	 * gets the variables used by form_section_validation.js.
654
+	 * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
655
+	 * but before the wordpress hook wp_loaded
656
+	 *
657
+	 * @throws \EE_Error
658
+	 */
659
+	public function _enqueue_and_localize_form_js()
660
+	{
661
+		$this->ensure_construct_finalized_called();
662
+		//actually, we don't want to localize just yet. There may be other forms on the page.
663
+		//so we need to add our form section data to a static variable accessible by all form sections
664
+		//and localize it just before the footer
665
+		$this->localize_validation_rules();
666
+		add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
667
+		add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
668
+	}
669
+
670
+
671
+
672
+	/**
673
+	 * add our form section data to a static variable accessible by all form sections
674
+	 *
675
+	 * @param bool $return_for_subsection
676
+	 * @return void
677
+	 * @throws \EE_Error
678
+	 */
679
+	public function localize_validation_rules($return_for_subsection = false)
680
+	{
681
+		// we only want to localize vars ONCE for the entire form,
682
+		// so if the form section doesn't have a parent, then it must be the top dog
683
+		if ($return_for_subsection || ! $this->parent_section()) {
684
+			EE_Form_Section_Proper::$_js_localization['form_data'][$this->html_id()] = array(
685
+				'form_section_id'  => $this->html_id(true),
686
+				'validation_rules' => $this->get_jquery_validation_rules(),
687
+				'other_data'       => $this->get_other_js_data(),
688
+				'errors'           => $this->subsection_validation_errors_by_html_name(),
689
+			);
690
+			EE_Form_Section_Proper::$_scripts_localized = true;
691
+		}
692
+	}
693
+
694
+
695
+
696
+	/**
697
+	 * Gets an array of extra data that will be useful for client-side javascript.
698
+	 * This is primarily data added by inputs and forms in addition to any
699
+	 * scripts they might enqueue
700
+	 *
701
+	 * @param array $form_other_js_data
702
+	 * @return array
703
+	 */
704
+	public function get_other_js_data($form_other_js_data = array())
705
+	{
706
+		foreach ($this->subsections() as $subsection) {
707
+			$form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
708
+		}
709
+		return $form_other_js_data;
710
+	}
711
+
712
+
713
+
714
+	/**
715
+	 * Gets a flat array of inputs for this form section and its subsections.
716
+	 * Keys are their form names, and values are the inputs themselves
717
+	 *
718
+	 * @return EE_Form_Input_Base
719
+	 */
720
+	public function inputs_in_subsections()
721
+	{
722
+		$inputs = array();
723
+		foreach ($this->subsections() as $subsection) {
724
+			if ($subsection instanceof EE_Form_Input_Base) {
725
+				$inputs[$subsection->html_name()] = $subsection;
726
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
727
+				$inputs += $subsection->inputs_in_subsections();
728
+			}
729
+		}
730
+		return $inputs;
731
+	}
732
+
733
+
734
+
735
+	/**
736
+	 * Gets a flat array of all the validation errors.
737
+	 * Keys are html names (because those should be unique)
738
+	 * and values are a string of all their validation errors
739
+	 *
740
+	 * @return string[]
741
+	 */
742
+	public function subsection_validation_errors_by_html_name()
743
+	{
744
+		$inputs = $this->inputs();
745
+		$errors = array();
746
+		foreach ($inputs as $form_input) {
747
+			if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
748
+				$errors[$form_input->html_name()] = $form_input->get_validation_error_string();
749
+			}
750
+		}
751
+		return $errors;
752
+	}
753
+
754
+
755
+
756
+	/**
757
+	 * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
758
+	 * Should be setup by each form during the _enqueues_and_localize_form_js
759
+	 */
760
+	public static function localize_script_for_all_forms()
761
+	{
762
+		//allow inputs and stuff to hook in their JS and stuff here
763
+		do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
764
+		EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
765
+		$email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
766
+			? EE_Registry::instance()->CFG->registration->email_validation_level
767
+			: 'wp_default';
768
+		EE_Form_Section_Proper::$_js_localization['email_validation_level'] = $email_validation_level;
769
+		wp_enqueue_script('ee_form_section_validation');
770
+		wp_localize_script(
771
+			'ee_form_section_validation',
772
+			'ee_form_section_vars',
773
+			EE_Form_Section_Proper::$_js_localization
774
+		);
775
+	}
776
+
777
+
778
+
779
+	/**
780
+	 * ensure_scripts_localized
781
+	 */
782
+	public function ensure_scripts_localized()
783
+	{
784
+		if (! EE_Form_Section_Proper::$_scripts_localized) {
785
+			$this->_enqueue_and_localize_form_js();
786
+		}
787
+	}
788
+
789
+
790
+
791
+	/**
792
+	 * Gets the hard-coded validation error messages to be used in the JS. The convention
793
+	 * is that the key here should be the same as the custom validation rule put in the JS file
794
+	 *
795
+	 * @return array keys are custom validation rules, and values are internationalized strings
796
+	 */
797
+	private static function _get_localized_error_messages()
798
+	{
799
+		return array(
800
+			'validUrl' => __("This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg", "event_espresso"),
801
+			'regex'    => __('Please check your input', 'event_espresso'),
802
+		);
803
+	}
804
+
805
+
806
+
807
+	/**
808
+	 * @return array
809
+	 */
810
+	public static function js_localization()
811
+	{
812
+		return self::$_js_localization;
813
+	}
814
+
815
+
816
+
817
+	/**
818
+	 * @return array
819
+	 */
820
+	public static function reset_js_localization()
821
+	{
822
+		self::$_js_localization = array();
823
+	}
824
+
825
+
826
+
827
+	/**
828
+	 * Gets the JS to put inside the jquery validation rules for subsection of this form section.
829
+	 * See parent function for more...
830
+	 *
831
+	 * @return array
832
+	 */
833
+	public function get_jquery_validation_rules()
834
+	{
835
+		$jquery_validation_rules = array();
836
+		foreach ($this->get_validatable_subsections() as $subsection) {
837
+			$jquery_validation_rules = array_merge(
838
+				$jquery_validation_rules,
839
+				$subsection->get_jquery_validation_rules()
840
+			);
841
+		}
842
+		return $jquery_validation_rules;
843
+	}
844
+
845
+
846
+
847
+	/**
848
+	 * Sanitizes all the data and sets the sanitized value of each field
849
+	 *
850
+	 * @param array $req_data like $_POST
851
+	 * @return void
852
+	 */
853
+	protected function _normalize($req_data)
854
+	{
855
+		$this->_received_submission = true;
856
+		$this->_validation_errors = array();
857
+		foreach ($this->get_validatable_subsections() as $subsection) {
858
+			try {
859
+				$subsection->_normalize($req_data);
860
+			} catch (EE_Validation_Error $e) {
861
+				$subsection->add_validation_error($e);
862
+			}
863
+		}
864
+	}
865
+
866
+
867
+
868
+	/**
869
+	 * Performs validation on this form section and its subsections.
870
+	 * For each subsection,
871
+	 * calls _validate_{subsection_name} on THIS form (if the function exists)
872
+	 * and passes it the subsection, then calls _validate on that subsection.
873
+	 * If you need to perform validation on the form as a whole (considering multiple)
874
+	 * you would be best to override this _validate method,
875
+	 * calling parent::_validate() first.
876
+	 */
877
+	protected function _validate()
878
+	{
879
+		foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
880
+			if (method_exists($this, '_validate_' . $subsection_name)) {
881
+				call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
882
+			}
883
+			$subsection->_validate();
884
+		}
885
+	}
886
+
887
+
888
+
889
+	/**
890
+	 * Gets all the validated inputs for the form section
891
+	 *
892
+	 * @return array
893
+	 */
894
+	public function valid_data()
895
+	{
896
+		$inputs = array();
897
+		foreach ($this->subsections() as $subsection_name => $subsection) {
898
+			if ($subsection instanceof EE_Form_Section_Proper) {
899
+				$inputs[$subsection_name] = $subsection->valid_data();
900
+			} else if ($subsection instanceof EE_Form_Input_Base) {
901
+				$inputs[$subsection_name] = $subsection->normalized_value();
902
+			}
903
+		}
904
+		return $inputs;
905
+	}
906
+
907
+
908
+
909
+	/**
910
+	 * Gets all the inputs on this form section
911
+	 *
912
+	 * @return EE_Form_Input_Base[]
913
+	 */
914
+	public function inputs()
915
+	{
916
+		$inputs = array();
917
+		foreach ($this->subsections() as $subsection_name => $subsection) {
918
+			if ($subsection instanceof EE_Form_Input_Base) {
919
+				$inputs[$subsection_name] = $subsection;
920
+			}
921
+		}
922
+		return $inputs;
923
+	}
924
+
925
+
926
+
927
+	/**
928
+	 * Gets all the subsections which are a proper form
929
+	 *
930
+	 * @return EE_Form_Section_Proper[]
931
+	 */
932
+	public function subforms()
933
+	{
934
+		$form_sections = array();
935
+		foreach ($this->subsections() as $name => $obj) {
936
+			if ($obj instanceof EE_Form_Section_Proper) {
937
+				$form_sections[$name] = $obj;
938
+			}
939
+		}
940
+		return $form_sections;
941
+	}
942
+
943
+
944
+
945
+	/**
946
+	 * Gets all the subsections (inputs, proper subsections, or html-only sections).
947
+	 * Consider using inputs() or subforms()
948
+	 * if you only want form inputs or proper form sections.
949
+	 *
950
+	 * @param boolean $require_construction_to_be_finalized most client code should
951
+	 *                                                      leave this as TRUE so that the inputs will be properly
952
+	 *                                                      configured. However, some client code may be ok with
953
+	 *                                                      construction finalize being called later
954
+	 *                                                      (realizing that the subsections' html names might not be
955
+	 *                                                      set yet, etc.)
956
+	 * @return EE_Form_Section_Proper[]
957
+	 */
958
+	public function subsections($require_construction_to_be_finalized = true)
959
+	{
960
+		if ($require_construction_to_be_finalized) {
961
+			$this->ensure_construct_finalized_called();
962
+		}
963
+		return $this->_subsections;
964
+	}
965
+
966
+
967
+
968
+	/**
969
+	 * Returns a simple array where keys are input names, and values are their normalized
970
+	 * values. (Similar to calling get_input_value on inputs)
971
+	 *
972
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
973
+	 *                                        or just this forms' direct children inputs
974
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
975
+	 *                                        or allow multidimensional array
976
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
977
+	 *                                        with array keys being input names
978
+	 *                                        (regardless of whether they are from a subsection or not),
979
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
980
+	 *                                        where keys are always subsection names and values are either
981
+	 *                                        the input's normalized value, or an array like the top-level array
982
+	 */
983
+	public function input_values($include_subform_inputs = false, $flatten = false)
984
+	{
985
+		return $this->_input_values(false, $include_subform_inputs, $flatten);
986
+	}
987
+
988
+
989
+
990
+	/**
991
+	 * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
992
+	 * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
993
+	 * is not necessarily the value we want to display to users. This creates an array
994
+	 * where keys are the input names, and values are their display values
995
+	 *
996
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
997
+	 *                                        or just this forms' direct children inputs
998
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
999
+	 *                                        or allow multidimensional array
1000
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
1001
+	 *                                        with array keys being input names
1002
+	 *                                        (regardless of whether they are from a subsection or not),
1003
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1004
+	 *                                        where keys are always subsection names and values are either
1005
+	 *                                        the input's normalized value, or an array like the top-level array
1006
+	 */
1007
+	public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1008
+	{
1009
+		return $this->_input_values(true, $include_subform_inputs, $flatten);
1010
+	}
1011
+
1012
+
1013
+
1014
+	/**
1015
+	 * Gets the input values from the form
1016
+	 *
1017
+	 * @param boolean $pretty                 Whether to retrieve the pretty value,
1018
+	 *                                        or just the normalized value
1019
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1020
+	 *                                        or just this forms' direct children inputs
1021
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1022
+	 *                                        or allow multidimensional array
1023
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1024
+	 *                                        input names (regardless of whether they are from a subsection or not),
1025
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1026
+	 *                                        where keys are always subsection names and values are either
1027
+	 *                                        the input's normalized value, or an array like the top-level array
1028
+	 */
1029
+	public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1030
+	{
1031
+		$input_values = array();
1032
+		foreach ($this->subsections() as $subsection_name => $subsection) {
1033
+			if ($subsection instanceof EE_Form_Input_Base) {
1034
+				$input_values[$subsection_name] = $pretty
1035
+					? $subsection->pretty_value()
1036
+					: $subsection->normalized_value();
1037
+			} else if ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1038
+				$subform_input_values = $subsection->_input_values($pretty, $include_subform_inputs, $flatten);
1039
+				if ($flatten) {
1040
+					$input_values = array_merge($input_values, $subform_input_values);
1041
+				} else {
1042
+					$input_values[$subsection_name] = $subform_input_values;
1043
+				}
1044
+			}
1045
+		}
1046
+		return $input_values;
1047
+	}
1048
+
1049
+
1050
+
1051
+	/**
1052
+	 * Gets the originally submitted input values from the form
1053
+	 *
1054
+	 * @param boolean $include_subforms  Whether to include inputs from subforms,
1055
+	 *                                   or just this forms' direct children inputs
1056
+	 * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1057
+	 *                                   with array keys being input names
1058
+	 *                                   (regardless of whether they are from a subsection or not),
1059
+	 *                                   and if $flatten is FALSE it can be a multidimensional array
1060
+	 *                                   where keys are always subsection names and values are either
1061
+	 *                                   the input's normalized value, or an array like the top-level array
1062
+	 */
1063
+	public function submitted_values($include_subforms = false)
1064
+	{
1065
+		$submitted_values = array();
1066
+		foreach ($this->subsections() as $subsection) {
1067
+			if ($subsection instanceof EE_Form_Input_Base) {
1068
+				// is this input part of an array of inputs?
1069
+				if (strpos($subsection->html_name(), '[') !== false) {
1070
+					$full_input_name = \EEH_Array::convert_array_values_to_keys(
1071
+						explode('[', str_replace(']', '', $subsection->html_name())),
1072
+						$subsection->raw_value()
1073
+					);
1074
+					$submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1075
+				} else {
1076
+					$submitted_values[$subsection->html_name()] = $subsection->raw_value();
1077
+				}
1078
+			} else if ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1079
+				$subform_input_values = $subsection->submitted_values($include_subforms);
1080
+				$submitted_values = array_replace_recursive($submitted_values, $subform_input_values);
1081
+			}
1082
+		}
1083
+		return $submitted_values;
1084
+	}
1085
+
1086
+
1087
+
1088
+	/**
1089
+	 * Indicates whether or not this form has received a submission yet
1090
+	 * (ie, had receive_form_submission called on it yet)
1091
+	 *
1092
+	 * @return boolean
1093
+	 * @throws \EE_Error
1094
+	 */
1095
+	public function has_received_submission()
1096
+	{
1097
+		$this->ensure_construct_finalized_called();
1098
+		return $this->_received_submission;
1099
+	}
1100
+
1101
+
1102
+
1103
+	/**
1104
+	 * Equivalent to passing 'exclude' in the constructor's options array.
1105
+	 * Removes the listed inputs from the form
1106
+	 *
1107
+	 * @param array $inputs_to_exclude values are the input names
1108
+	 * @return void
1109
+	 */
1110
+	public function exclude(array $inputs_to_exclude = array())
1111
+	{
1112
+		foreach ($inputs_to_exclude as $input_to_exclude_name) {
1113
+			unset($this->_subsections[$input_to_exclude_name]);
1114
+		}
1115
+	}
1116
+
1117
+
1118
+
1119
+	/**
1120
+	 * @param array $inputs_to_hide
1121
+	 * @throws \EE_Error
1122
+	 */
1123
+	public function hide(array $inputs_to_hide = array())
1124
+	{
1125
+		foreach ($inputs_to_hide as $input_to_hide) {
1126
+			$input = $this->get_input($input_to_hide);
1127
+			$input->set_display_strategy(new EE_Hidden_Display_Strategy());
1128
+		}
1129
+	}
1130
+
1131
+
1132
+
1133
+	/**
1134
+	 * add_subsections
1135
+	 * Adds the listed subsections to the form section.
1136
+	 * If $subsection_name_to_target is provided,
1137
+	 * then new subsections are added before or after that subsection,
1138
+	 * otherwise to the start or end of the entire subsections array.
1139
+	 *
1140
+	 * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1141
+	 *                                                          where keys are their names
1142
+	 * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1143
+	 *                                                          should be added before or after
1144
+	 *                                                          IF $subsection_name_to_target is null,
1145
+	 *                                                          then $new_subsections will be added to
1146
+	 *                                                          the beginning or end of the entire subsections array
1147
+	 * @param boolean                $add_before                whether to add $new_subsections, before or after
1148
+	 *                                                          $subsection_name_to_target,
1149
+	 *                                                          or if $subsection_name_to_target is null,
1150
+	 *                                                          before or after entire subsections array
1151
+	 * @return void
1152
+	 * @throws \EE_Error
1153
+	 */
1154
+	public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1155
+	{
1156
+		foreach ($new_subsections as $subsection_name => $subsection) {
1157
+			if (! $subsection instanceof EE_Form_Section_Base) {
1158
+				EE_Error::add_error(
1159
+					sprintf(
1160
+						__(
1161
+							"Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1162
+							"event_espresso"
1163
+						),
1164
+						get_class($subsection),
1165
+						$subsection_name,
1166
+						$this->name()
1167
+					)
1168
+				);
1169
+				unset($new_subsections[$subsection_name]);
1170
+			}
1171
+		}
1172
+		$this->_subsections = EEH_Array::insert_into_array(
1173
+			$this->_subsections,
1174
+			$new_subsections,
1175
+			$subsection_name_to_target,
1176
+			$add_before
1177
+		);
1178
+		if ($this->_construction_finalized) {
1179
+			foreach ($this->_subsections as $name => $subsection) {
1180
+				$subsection->_construct_finalize($this, $name);
1181
+			}
1182
+		}
1183
+	}
1184
+
1185
+
1186
+
1187
+	/**
1188
+	 * Just gets all validatable subsections to clean their sensitive data
1189
+	 */
1190
+	public function clean_sensitive_data()
1191
+	{
1192
+		foreach ($this->get_validatable_subsections() as $subsection) {
1193
+			$subsection->clean_sensitive_data();
1194
+		}
1195
+	}
1196
+
1197
+
1198
+
1199
+	/**
1200
+	 * @param string $form_submission_error_message
1201
+	 */
1202
+	public function set_submission_error_message($form_submission_error_message = '')
1203
+	{
1204
+		$this->_form_submission_error_message .= ! empty($form_submission_error_message)
1205
+			? $form_submission_error_message
1206
+			: __('Form submission failed due to errors', 'event_espresso');
1207
+	}
1208
+
1209
+
1210
+
1211
+	/**
1212
+	 * @return string
1213
+	 */
1214
+	public function submission_error_message()
1215
+	{
1216
+		return $this->_form_submission_error_message;
1217
+	}
1218
+
1219
+
1220
+
1221
+	/**
1222
+	 * @param string $form_submission_success_message
1223
+	 */
1224
+	public function set_submission_success_message($form_submission_success_message)
1225
+	{
1226
+		$this->_form_submission_success_message .= ! empty($form_submission_success_message)
1227
+			? $form_submission_success_message
1228
+			: __('Form submitted successfully', 'event_espresso');
1229
+	}
1230
+
1231
+
1232
+
1233
+	/**
1234
+	 * @return string
1235
+	 */
1236
+	public function submission_success_message()
1237
+	{
1238
+		return $this->_form_submission_success_message;
1239
+	}
1240
+
1241
+
1242
+
1243
+	/**
1244
+	 * Returns the prefix that should be used on child of this form section for
1245
+	 * their html names. If this form section itself has a parent, prepends ITS
1246
+	 * prefix onto this form section's prefix. Used primarily by
1247
+	 * EE_Form_Input_Base::_set_default_html_name_if_empty
1248
+	 *
1249
+	 * @return string
1250
+	 * @throws \EE_Error
1251
+	 */
1252
+	public function html_name_prefix()
1253
+	{
1254
+		if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1255
+			return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1256
+		} else {
1257
+			return $this->name();
1258
+		}
1259
+	}
1260
+
1261
+
1262
+
1263
+	/**
1264
+	 * Gets the name, but first checks _construct_finalize has been called. If not,
1265
+	 * calls it (assumes there is no parent and that we want the name to be whatever
1266
+	 * was set, which is probably nothing, or the classname)
1267
+	 *
1268
+	 * @return string
1269
+	 * @throws \EE_Error
1270
+	 */
1271
+	public function name()
1272
+	{
1273
+		$this->ensure_construct_finalized_called();
1274
+		return parent::name();
1275
+	}
1276
+
1277
+
1278
+
1279
+	/**
1280
+	 * @return EE_Form_Section_Proper
1281
+	 * @throws \EE_Error
1282
+	 */
1283
+	public function parent_section()
1284
+	{
1285
+		$this->ensure_construct_finalized_called();
1286
+		return parent::parent_section();
1287
+	}
1288
+
1289
+
1290
+
1291
+	/**
1292
+	 * make sure construction finalized was called, otherwise children might not be ready
1293
+	 *
1294
+	 * @return void
1295
+	 * @throws \EE_Error
1296
+	 */
1297
+	public function ensure_construct_finalized_called()
1298
+	{
1299
+		if (! $this->_construction_finalized) {
1300
+			$this->_construct_finalize($this->_parent_section, $this->_name);
1301
+		}
1302
+	}
1303
+
1304
+
1305
+
1306
+	/**
1307
+	 * Checks if any of this form section's inputs, or any of its children's inputs,
1308
+	 * are in teh form data. If any are found, returns true. Else false
1309
+	 *
1310
+	 * @param array $req_data
1311
+	 * @return boolean
1312
+	 */
1313
+	public function form_data_present_in($req_data = null)
1314
+	{
1315
+		if ($req_data === null) {
1316
+			$req_data = $_POST;
1317
+		}
1318
+		foreach ($this->subsections() as $subsection) {
1319
+			if ($subsection instanceof EE_Form_Input_Base) {
1320
+				if ($subsection->form_data_present_in($req_data)) {
1321
+					return true;
1322
+				}
1323
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
1324
+				if ($subsection->form_data_present_in($req_data)) {
1325
+					return true;
1326
+				}
1327
+			}
1328
+		}
1329
+		return false;
1330
+	}
1331
+
1332
+
1333
+
1334
+	/**
1335
+	 * Gets validation errors for this form section and subsections
1336
+	 * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1337
+	 * gets the validation errors for ALL subsection
1338
+	 *
1339
+	 * @return EE_Validation_Error[]
1340
+	 */
1341
+	public function get_validation_errors_accumulated()
1342
+	{
1343
+		$validation_errors = $this->get_validation_errors();
1344
+		foreach ($this->get_validatable_subsections() as $subsection) {
1345
+			if ($subsection instanceof EE_Form_Section_Proper) {
1346
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1347
+			} else {
1348
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors();
1349
+			}
1350
+			if ($validation_errors_on_this_subsection) {
1351
+				$validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1352
+			}
1353
+		}
1354
+		return $validation_errors;
1355
+	}
1356
+
1357
+
1358
+
1359
+	/**
1360
+	 * This isn't just the name of an input, it's a path pointing to an input. The
1361
+	 * path is similar to a folder path: slash (/) means to descend into a subsection,
1362
+	 * dot-dot-slash (../) means to ascend into the parent section.
1363
+	 * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1364
+	 * which will be returned.
1365
+	 * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1366
+	 * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1367
+	 * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1368
+	 * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1369
+	 * Etc
1370
+	 *
1371
+	 * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1372
+	 * @return EE_Form_Section_Base
1373
+	 */
1374
+	public function find_section_from_path($form_section_path)
1375
+	{
1376
+		//check if we can find the input from purely going straight up the tree
1377
+		$input = parent::find_section_from_path($form_section_path);
1378
+		if ($input instanceof EE_Form_Section_Base) {
1379
+			return $input;
1380
+		}
1381
+		$next_slash_pos = strpos($form_section_path, '/');
1382
+		if ($next_slash_pos !== false) {
1383
+			$child_section_name = substr($form_section_path, 0, $next_slash_pos);
1384
+			$subpath = substr($form_section_path, $next_slash_pos + 1);
1385
+		} else {
1386
+			$child_section_name = $form_section_path;
1387
+			$subpath = '';
1388
+		}
1389
+		$child_section = $this->get_subsection($child_section_name);
1390
+		if ($child_section instanceof EE_Form_Section_Base) {
1391
+			return $child_section->find_section_from_path($subpath);
1392
+		} else {
1393
+			return null;
1394
+		}
1395
+	}
1396 1396
 
1397 1397
 }
1398 1398
 
Please login to merge, or discard this patch.
messages/data_class/EE_Messages_Registrations_incoming_data.class.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-if (! defined('EVENT_ESPRESSO_VERSION')) {
2
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
3 3
     exit('No direct script access allowed');
4 4
 }
5 5
 
@@ -27,7 +27,7 @@  discard block
 block discarded – undo
27 27
     {
28 28
 
29 29
         //validate that the first element in the array is an EE_Registration object.
30
-        if (! reset($data) instanceof EE_Registration) {
30
+        if ( ! reset($data) instanceof EE_Registration) {
31 31
             throw new EE_Error(__('The EE_Message_Registrations_incoming_data class expects an array of EE_Registration objects.',
32 32
                 'event_espresso'));
33 33
         }
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 
95 95
         $registration_ids = array_filter(
96 96
             array_map(
97
-                function ($registration) {
97
+                function($registration) {
98 98
                     if ($registration instanceof EE_Registration) {
99 99
                         return $registration->ID();
100 100
                     }
Please login to merge, or discard this patch.
Indentation   +81 added lines, -81 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if (! defined('EVENT_ESPRESSO_VERSION')) {
3
-    exit('No direct script access allowed');
3
+	exit('No direct script access allowed');
4 4
 }
5 5
 
6 6
 /**
@@ -16,96 +16,96 @@  discard block
 block discarded – undo
16 16
 {
17 17
 
18 18
 
19
-    /**
20
-     * Constructor.
21
-     *
22
-     * @param  EE_Registration[] $data expecting an array of EE_Registration objects.
23
-     * @throws EE_Error
24
-     * @access protected
25
-     */
26
-    public function __construct($data = array())
27
-    {
19
+	/**
20
+	 * Constructor.
21
+	 *
22
+	 * @param  EE_Registration[] $data expecting an array of EE_Registration objects.
23
+	 * @throws EE_Error
24
+	 * @access protected
25
+	 */
26
+	public function __construct($data = array())
27
+	{
28 28
 
29
-        //validate that the first element in the array is an EE_Registration object.
30
-        if (! reset($data) instanceof EE_Registration) {
31
-            throw new EE_Error(__('The EE_Message_Registrations_incoming_data class expects an array of EE_Registration objects.',
32
-                'event_espresso'));
33
-        }
34
-        parent::__construct($data);
35
-    }
29
+		//validate that the first element in the array is an EE_Registration object.
30
+		if (! reset($data) instanceof EE_Registration) {
31
+			throw new EE_Error(__('The EE_Message_Registrations_incoming_data class expects an array of EE_Registration objects.',
32
+				'event_espresso'));
33
+		}
34
+		parent::__construct($data);
35
+	}
36 36
 
37 37
 
38
-    /**
39
-     * setup the data.
40
-     * Sets up the expected data object for the messages prep using incoming registration objects.
41
-     *
42
-     * @return void
43
-     * @access protected
44
-     */
45
-    protected function _setup_data()
46
-    {
47
-        //we'll loop through each contact and setup the data needed.  Note that many properties will just be set as empty
48
-        //because this data handler is for a very specific set of data (i.e. just what's related to the registration).
38
+	/**
39
+	 * setup the data.
40
+	 * Sets up the expected data object for the messages prep using incoming registration objects.
41
+	 *
42
+	 * @return void
43
+	 * @access protected
44
+	 */
45
+	protected function _setup_data()
46
+	{
47
+		//we'll loop through each contact and setup the data needed.  Note that many properties will just be set as empty
48
+		//because this data handler is for a very specific set of data (i.e. just what's related to the registration).
49 49
 
50
-        //there could be multiple transactions represented so we leave at null.
51
-        $this->txn      = null;
52
-        $this->reg_objs = $this->data();
53
-        $this->_assemble_data();
54
-    }
50
+		//there could be multiple transactions represented so we leave at null.
51
+		$this->txn      = null;
52
+		$this->reg_objs = $this->data();
53
+		$this->_assemble_data();
54
+	}
55 55
 
56 56
 
57
-    /**
58
-     * Returns database safe representation of the data later used to when instantiating this object.
59
-     *
60
-     * @param array $registrations The incoming data to be prepped.
61
-     * @return EE_Registration[]   The data being prepared for the db
62
-     */
63
-    static public function convert_data_for_persistent_storage($registrations)
64
-    {
65
-        if (
66
-            ! is_array($registrations)
67
-            || ! reset($registrations) instanceof EE_Registration
68
-        ) {
69
-            return array();
70
-        }
57
+	/**
58
+	 * Returns database safe representation of the data later used to when instantiating this object.
59
+	 *
60
+	 * @param array $registrations The incoming data to be prepped.
61
+	 * @return EE_Registration[]   The data being prepared for the db
62
+	 */
63
+	static public function convert_data_for_persistent_storage($registrations)
64
+	{
65
+		if (
66
+			! is_array($registrations)
67
+			|| ! reset($registrations) instanceof EE_Registration
68
+		) {
69
+			return array();
70
+		}
71 71
 
72
-        $registration_ids = array();
72
+		$registration_ids = array();
73 73
 
74
-        $registration_ids = array_filter(
75
-            array_map(
76
-                function ($registration) {
77
-                    if ($registration instanceof EE_Registration) {
78
-                        return $registration->ID();
79
-                    }
80
-                    return false;
81
-                },
82
-                $registrations
83
-            )
84
-        );
74
+		$registration_ids = array_filter(
75
+			array_map(
76
+				function ($registration) {
77
+					if ($registration instanceof EE_Registration) {
78
+						return $registration->ID();
79
+					}
80
+					return false;
81
+				},
82
+				$registrations
83
+			)
84
+		);
85 85
 
86
-        return $registration_ids;
87
-    }
86
+		return $registration_ids;
87
+	}
88 88
 
89 89
 
90
-    /**
91
-     * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage
92
-     * can be sent into this method and converted back into the format used for instantiating with this data handler.
93
-     *
94
-     * @param array $data
95
-     * @return EE_Registration[]
96
-     */
97
-    static public function convert_data_from_persistent_storage($data)
98
-    {
99
-        //since this was added later, we need to account of possible back compat issues where data already queued for generation
100
-        //is in the old format, which is an array of EE_Registration objects.  So if that's the case, then let's just return them
101
-        //@see https://events.codebasehq.com/projects/event-espresso/tickets/10127
102
-        if (is_array($data) && reset($data) instanceof EE_Registration) {
103
-            return $data;
104
-        }
90
+	/**
91
+	 * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage
92
+	 * can be sent into this method and converted back into the format used for instantiating with this data handler.
93
+	 *
94
+	 * @param array $data
95
+	 * @return EE_Registration[]
96
+	 */
97
+	static public function convert_data_from_persistent_storage($data)
98
+	{
99
+		//since this was added later, we need to account of possible back compat issues where data already queued for generation
100
+		//is in the old format, which is an array of EE_Registration objects.  So if that's the case, then let's just return them
101
+		//@see https://events.codebasehq.com/projects/event-espresso/tickets/10127
102
+		if (is_array($data) && reset($data) instanceof EE_Registration) {
103
+			return $data;
104
+		}
105 105
 
106
-        $registrations = is_array($data)
107
-            ? EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $data))))
108
-            : array();
109
-        return $registrations;
110
-    }
106
+		$registrations = is_array($data)
107
+			? EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $data))))
108
+			: array();
109
+		return $registrations;
110
+	}
111 111
 }
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +219 added lines, -219 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if ( ! defined('ABSPATH')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 /*
5 5
   Plugin Name:		Event Espresso
@@ -40,243 +40,243 @@  discard block
 block discarded – undo
40 40
  * @since            4.0
41 41
  */
42 42
 if (function_exists('espresso_version')) {
43
-    /**
44
-     *    espresso_duplicate_plugin_error
45
-     *    displays if more than one version of EE is activated at the same time
46
-     */
47
-    function espresso_duplicate_plugin_error()
48
-    {
49
-        ?>
43
+	/**
44
+	 *    espresso_duplicate_plugin_error
45
+	 *    displays if more than one version of EE is activated at the same time
46
+	 */
47
+	function espresso_duplicate_plugin_error()
48
+	{
49
+		?>
50 50
         <div class="error">
51 51
             <p>
52 52
                 <?php echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                ); ?>
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+				); ?>
56 56
             </p>
57 57
         </div>
58 58
         <?php
59
-        espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-    }
59
+		espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+	}
61 61
 
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 } else {
64
-    define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
65
-    if ( ! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
-        /**
67
-         * espresso_minimum_php_version_error
68
-         *
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
64
+	define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
65
+	if ( ! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+		/**
67
+		 * espresso_minimum_php_version_error
68
+		 *
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                            esc_html__(
79
-                                    'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                                    'event_espresso'
81
-                            ),
82
-                            EE_MIN_PHP_VER_REQUIRED,
83
-                            PHP_VERSION,
84
-                            '<br/>',
85
-                            '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+							esc_html__(
79
+									'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+									'event_espresso'
81
+							),
82
+							EE_MIN_PHP_VER_REQUIRED,
83
+							PHP_VERSION,
84
+							'<br/>',
85
+							'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        /**
97
-         * espresso_version
98
-         * Returns the plugin version
99
-         *
100
-         * @return string
101
-         */
102
-        function espresso_version()
103
-        {
104
-            return apply_filters('FHEE__espresso__espresso_version', '4.9.32.rc.019');
105
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		/**
97
+		 * espresso_version
98
+		 * Returns the plugin version
99
+		 *
100
+		 * @return string
101
+		 */
102
+		function espresso_version()
103
+		{
104
+			return apply_filters('FHEE__espresso__espresso_version', '4.9.32.rc.019');
105
+		}
106 106
 
107
-        // define versions
108
-        define('EVENT_ESPRESSO_VERSION', espresso_version());
109
-        define('EE_MIN_WP_VER_REQUIRED', '4.1');
110
-        define('EE_MIN_WP_VER_RECOMMENDED', '4.4.2');
111
-        define('EE_MIN_PHP_VER_RECOMMENDED', '5.4.44');
112
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
113
-        //used to be DIRECTORY_SEPARATOR, but that caused issues on windows
114
-        if ( ! defined('DS')) {
115
-            define('DS', '/');
116
-        }
117
-        if ( ! defined('PS')) {
118
-            define('PS', PATH_SEPARATOR);
119
-        }
120
-        if ( ! defined('SP')) {
121
-            define('SP', ' ');
122
-        }
123
-        if ( ! defined('EENL')) {
124
-            define('EENL', "\n");
125
-        }
126
-        define('EE_SUPPORT_EMAIL', '[email protected]');
127
-        // define the plugin directory and URL
128
-        define('EE_PLUGIN_BASENAME', plugin_basename(EVENT_ESPRESSO_MAIN_FILE));
129
-        define('EE_PLUGIN_DIR_PATH', plugin_dir_path(EVENT_ESPRESSO_MAIN_FILE));
130
-        define('EE_PLUGIN_DIR_URL', plugin_dir_url(EVENT_ESPRESSO_MAIN_FILE));
131
-        // main root folder paths
132
-        define('EE_ADMIN_PAGES', EE_PLUGIN_DIR_PATH . 'admin_pages' . DS);
133
-        define('EE_CORE', EE_PLUGIN_DIR_PATH . 'core' . DS);
134
-        define('EE_MODULES', EE_PLUGIN_DIR_PATH . 'modules' . DS);
135
-        define('EE_PUBLIC', EE_PLUGIN_DIR_PATH . 'public' . DS);
136
-        define('EE_SHORTCODES', EE_PLUGIN_DIR_PATH . 'shortcodes' . DS);
137
-        define('EE_WIDGETS', EE_PLUGIN_DIR_PATH . 'widgets' . DS);
138
-        define('EE_PAYMENT_METHODS', EE_PLUGIN_DIR_PATH . 'payment_methods' . DS);
139
-        define('EE_CAFF_PATH', EE_PLUGIN_DIR_PATH . 'caffeinated' . DS);
140
-        // core system paths
141
-        define('EE_ADMIN', EE_CORE . 'admin' . DS);
142
-        define('EE_CPTS', EE_CORE . 'CPTs' . DS);
143
-        define('EE_CLASSES', EE_CORE . 'db_classes' . DS);
144
-        define('EE_INTERFACES', EE_CORE . 'interfaces' . DS);
145
-        define('EE_BUSINESS', EE_CORE . 'business' . DS);
146
-        define('EE_MODELS', EE_CORE . 'db_models' . DS);
147
-        define('EE_HELPERS', EE_CORE . 'helpers' . DS);
148
-        define('EE_LIBRARIES', EE_CORE . 'libraries' . DS);
149
-        define('EE_TEMPLATES', EE_CORE . 'templates' . DS);
150
-        define('EE_THIRD_PARTY', EE_CORE . 'third_party_libs' . DS);
151
-        define('EE_GLOBAL_ASSETS', EE_TEMPLATES . 'global_assets' . DS);
152
-        define('EE_FORM_SECTIONS', EE_LIBRARIES . 'form_sections' . DS);
153
-        // gateways
154
-        define('EE_GATEWAYS', EE_MODULES . 'gateways' . DS);
155
-        define('EE_GATEWAYS_URL', EE_PLUGIN_DIR_URL . 'modules' . DS . 'gateways' . DS);
156
-        // asset URL paths
157
-        define('EE_TEMPLATES_URL', EE_PLUGIN_DIR_URL . 'core' . DS . 'templates' . DS);
158
-        define('EE_GLOBAL_ASSETS_URL', EE_TEMPLATES_URL . 'global_assets' . DS);
159
-        define('EE_IMAGES_URL', EE_GLOBAL_ASSETS_URL . 'images' . DS);
160
-        define('EE_THIRD_PARTY_URL', EE_PLUGIN_DIR_URL . 'core' . DS . 'third_party_libs' . DS);
161
-        define('EE_HELPERS_ASSETS', EE_PLUGIN_DIR_URL . 'core/helpers/assets/');
162
-        define('EE_LIBRARIES_URL', EE_PLUGIN_DIR_URL . 'core/libraries/');
163
-        // define upload paths
164
-        $uploads = wp_upload_dir();
165
-        // define the uploads directory and URL
166
-        define('EVENT_ESPRESSO_UPLOAD_DIR', $uploads['basedir'] . DS . 'espresso' . DS);
167
-        define('EVENT_ESPRESSO_UPLOAD_URL', $uploads['baseurl'] . DS . 'espresso' . DS);
168
-        // define the templates directory and URL
169
-        define('EVENT_ESPRESSO_TEMPLATE_DIR', $uploads['basedir'] . DS . 'espresso' . DS . 'templates' . DS);
170
-        define('EVENT_ESPRESSO_TEMPLATE_URL', $uploads['baseurl'] . DS . 'espresso' . DS . 'templates' . DS);
171
-        // define the gateway directory and URL
172
-        define('EVENT_ESPRESSO_GATEWAY_DIR', $uploads['basedir'] . DS . 'espresso' . DS . 'gateways' . DS);
173
-        define('EVENT_ESPRESSO_GATEWAY_URL', $uploads['baseurl'] . DS . 'espresso' . DS . 'gateways' . DS);
174
-        // languages folder/path
175
-        define('EE_LANGUAGES_SAFE_LOC', '..' . DS . 'uploads' . DS . 'espresso' . DS . 'languages' . DS);
176
-        define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'languages' . DS);
177
-        //check for dompdf fonts in uploads
178
-        if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS)) {
179
-            define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS);
180
-        }
181
-        //ajax constants
182
-        define(
183
-                'EE_FRONT_AJAX',
184
-                isset($_REQUEST['ee_front_ajax']) || isset($_REQUEST['data']['ee_front_ajax']) ? true : false
185
-        );
186
-        define(
187
-                'EE_ADMIN_AJAX',
188
-                isset($_REQUEST['ee_admin_ajax']) || isset($_REQUEST['data']['ee_admin_ajax']) ? true : false
189
-        );
190
-        //just a handy constant occasionally needed for finding values representing infinity in the DB
191
-        //you're better to use this than its straight value (currently -1) in case you ever
192
-        //want to change its default value! or find when -1 means infinity
193
-        define('EE_INF_IN_DB', -1);
194
-        define('EE_INF', INF > (float)PHP_INT_MAX ? INF : PHP_INT_MAX);
195
-        define('EE_DEBUG', false);
196
-        // for older WP versions
197
-        if ( ! defined('MONTH_IN_SECONDS')) {
198
-            define('MONTH_IN_SECONDS', DAY_IN_SECONDS * 30);
199
-        }
200
-        /**
201
-         *    espresso_plugin_activation
202
-         *    adds a wp-option to indicate that EE has been activated via the WP admin plugins page
203
-         */
204
-        function espresso_plugin_activation()
205
-        {
206
-            update_option('ee_espresso_activation', true);
207
-        }
107
+		// define versions
108
+		define('EVENT_ESPRESSO_VERSION', espresso_version());
109
+		define('EE_MIN_WP_VER_REQUIRED', '4.1');
110
+		define('EE_MIN_WP_VER_RECOMMENDED', '4.4.2');
111
+		define('EE_MIN_PHP_VER_RECOMMENDED', '5.4.44');
112
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
113
+		//used to be DIRECTORY_SEPARATOR, but that caused issues on windows
114
+		if ( ! defined('DS')) {
115
+			define('DS', '/');
116
+		}
117
+		if ( ! defined('PS')) {
118
+			define('PS', PATH_SEPARATOR);
119
+		}
120
+		if ( ! defined('SP')) {
121
+			define('SP', ' ');
122
+		}
123
+		if ( ! defined('EENL')) {
124
+			define('EENL', "\n");
125
+		}
126
+		define('EE_SUPPORT_EMAIL', '[email protected]');
127
+		// define the plugin directory and URL
128
+		define('EE_PLUGIN_BASENAME', plugin_basename(EVENT_ESPRESSO_MAIN_FILE));
129
+		define('EE_PLUGIN_DIR_PATH', plugin_dir_path(EVENT_ESPRESSO_MAIN_FILE));
130
+		define('EE_PLUGIN_DIR_URL', plugin_dir_url(EVENT_ESPRESSO_MAIN_FILE));
131
+		// main root folder paths
132
+		define('EE_ADMIN_PAGES', EE_PLUGIN_DIR_PATH . 'admin_pages' . DS);
133
+		define('EE_CORE', EE_PLUGIN_DIR_PATH . 'core' . DS);
134
+		define('EE_MODULES', EE_PLUGIN_DIR_PATH . 'modules' . DS);
135
+		define('EE_PUBLIC', EE_PLUGIN_DIR_PATH . 'public' . DS);
136
+		define('EE_SHORTCODES', EE_PLUGIN_DIR_PATH . 'shortcodes' . DS);
137
+		define('EE_WIDGETS', EE_PLUGIN_DIR_PATH . 'widgets' . DS);
138
+		define('EE_PAYMENT_METHODS', EE_PLUGIN_DIR_PATH . 'payment_methods' . DS);
139
+		define('EE_CAFF_PATH', EE_PLUGIN_DIR_PATH . 'caffeinated' . DS);
140
+		// core system paths
141
+		define('EE_ADMIN', EE_CORE . 'admin' . DS);
142
+		define('EE_CPTS', EE_CORE . 'CPTs' . DS);
143
+		define('EE_CLASSES', EE_CORE . 'db_classes' . DS);
144
+		define('EE_INTERFACES', EE_CORE . 'interfaces' . DS);
145
+		define('EE_BUSINESS', EE_CORE . 'business' . DS);
146
+		define('EE_MODELS', EE_CORE . 'db_models' . DS);
147
+		define('EE_HELPERS', EE_CORE . 'helpers' . DS);
148
+		define('EE_LIBRARIES', EE_CORE . 'libraries' . DS);
149
+		define('EE_TEMPLATES', EE_CORE . 'templates' . DS);
150
+		define('EE_THIRD_PARTY', EE_CORE . 'third_party_libs' . DS);
151
+		define('EE_GLOBAL_ASSETS', EE_TEMPLATES . 'global_assets' . DS);
152
+		define('EE_FORM_SECTIONS', EE_LIBRARIES . 'form_sections' . DS);
153
+		// gateways
154
+		define('EE_GATEWAYS', EE_MODULES . 'gateways' . DS);
155
+		define('EE_GATEWAYS_URL', EE_PLUGIN_DIR_URL . 'modules' . DS . 'gateways' . DS);
156
+		// asset URL paths
157
+		define('EE_TEMPLATES_URL', EE_PLUGIN_DIR_URL . 'core' . DS . 'templates' . DS);
158
+		define('EE_GLOBAL_ASSETS_URL', EE_TEMPLATES_URL . 'global_assets' . DS);
159
+		define('EE_IMAGES_URL', EE_GLOBAL_ASSETS_URL . 'images' . DS);
160
+		define('EE_THIRD_PARTY_URL', EE_PLUGIN_DIR_URL . 'core' . DS . 'third_party_libs' . DS);
161
+		define('EE_HELPERS_ASSETS', EE_PLUGIN_DIR_URL . 'core/helpers/assets/');
162
+		define('EE_LIBRARIES_URL', EE_PLUGIN_DIR_URL . 'core/libraries/');
163
+		// define upload paths
164
+		$uploads = wp_upload_dir();
165
+		// define the uploads directory and URL
166
+		define('EVENT_ESPRESSO_UPLOAD_DIR', $uploads['basedir'] . DS . 'espresso' . DS);
167
+		define('EVENT_ESPRESSO_UPLOAD_URL', $uploads['baseurl'] . DS . 'espresso' . DS);
168
+		// define the templates directory and URL
169
+		define('EVENT_ESPRESSO_TEMPLATE_DIR', $uploads['basedir'] . DS . 'espresso' . DS . 'templates' . DS);
170
+		define('EVENT_ESPRESSO_TEMPLATE_URL', $uploads['baseurl'] . DS . 'espresso' . DS . 'templates' . DS);
171
+		// define the gateway directory and URL
172
+		define('EVENT_ESPRESSO_GATEWAY_DIR', $uploads['basedir'] . DS . 'espresso' . DS . 'gateways' . DS);
173
+		define('EVENT_ESPRESSO_GATEWAY_URL', $uploads['baseurl'] . DS . 'espresso' . DS . 'gateways' . DS);
174
+		// languages folder/path
175
+		define('EE_LANGUAGES_SAFE_LOC', '..' . DS . 'uploads' . DS . 'espresso' . DS . 'languages' . DS);
176
+		define('EE_LANGUAGES_SAFE_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'languages' . DS);
177
+		//check for dompdf fonts in uploads
178
+		if (file_exists(EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS)) {
179
+			define('DOMPDF_FONT_DIR', EVENT_ESPRESSO_UPLOAD_DIR . 'fonts' . DS);
180
+		}
181
+		//ajax constants
182
+		define(
183
+				'EE_FRONT_AJAX',
184
+				isset($_REQUEST['ee_front_ajax']) || isset($_REQUEST['data']['ee_front_ajax']) ? true : false
185
+		);
186
+		define(
187
+				'EE_ADMIN_AJAX',
188
+				isset($_REQUEST['ee_admin_ajax']) || isset($_REQUEST['data']['ee_admin_ajax']) ? true : false
189
+		);
190
+		//just a handy constant occasionally needed for finding values representing infinity in the DB
191
+		//you're better to use this than its straight value (currently -1) in case you ever
192
+		//want to change its default value! or find when -1 means infinity
193
+		define('EE_INF_IN_DB', -1);
194
+		define('EE_INF', INF > (float)PHP_INT_MAX ? INF : PHP_INT_MAX);
195
+		define('EE_DEBUG', false);
196
+		// for older WP versions
197
+		if ( ! defined('MONTH_IN_SECONDS')) {
198
+			define('MONTH_IN_SECONDS', DAY_IN_SECONDS * 30);
199
+		}
200
+		/**
201
+		 *    espresso_plugin_activation
202
+		 *    adds a wp-option to indicate that EE has been activated via the WP admin plugins page
203
+		 */
204
+		function espresso_plugin_activation()
205
+		{
206
+			update_option('ee_espresso_activation', true);
207
+		}
208 208
 
209
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
210
-        /**
211
-         *    espresso_load_error_handling
212
-         *    this function loads EE's class for handling exceptions and errors
213
-         */
214
-        function espresso_load_error_handling()
215
-        {
216
-            // load debugging tools
217
-            if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
218
-                require_once(EE_HELPERS . 'EEH_Debug_Tools.helper.php');
219
-                EEH_Debug_Tools::instance();
220
-            }
221
-            // load error handling
222
-            if (is_readable(EE_CORE . 'EE_Error.core.php')) {
223
-                require_once(EE_CORE . 'EE_Error.core.php');
224
-            } else {
225
-                wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
226
-            }
227
-        }
209
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
210
+		/**
211
+		 *    espresso_load_error_handling
212
+		 *    this function loads EE's class for handling exceptions and errors
213
+		 */
214
+		function espresso_load_error_handling()
215
+		{
216
+			// load debugging tools
217
+			if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
218
+				require_once(EE_HELPERS . 'EEH_Debug_Tools.helper.php');
219
+				EEH_Debug_Tools::instance();
220
+			}
221
+			// load error handling
222
+			if (is_readable(EE_CORE . 'EE_Error.core.php')) {
223
+				require_once(EE_CORE . 'EE_Error.core.php');
224
+			} else {
225
+				wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
226
+			}
227
+		}
228 228
 
229
-        /**
230
-         *    espresso_load_required
231
-         *    given a class name and path, this function will load that file or throw an exception
232
-         *
233
-         * @param    string $classname
234
-         * @param    string $full_path_to_file
235
-         * @throws    EE_Error
236
-         */
237
-        function espresso_load_required($classname, $full_path_to_file)
238
-        {
239
-            static $error_handling_loaded = false;
240
-            if ( ! $error_handling_loaded) {
241
-                espresso_load_error_handling();
242
-                $error_handling_loaded = true;
243
-            }
244
-            if (is_readable($full_path_to_file)) {
245
-                require_once($full_path_to_file);
246
-            } else {
247
-                throw new EE_Error (
248
-                        sprintf(
249
-                                esc_html__(
250
-                                        'The %s class file could not be located or is not readable due to file permissions.',
251
-                                        'event_espresso'
252
-                                ),
253
-                                $classname
254
-                        )
255
-                );
256
-            }
257
-        }
229
+		/**
230
+		 *    espresso_load_required
231
+		 *    given a class name and path, this function will load that file or throw an exception
232
+		 *
233
+		 * @param    string $classname
234
+		 * @param    string $full_path_to_file
235
+		 * @throws    EE_Error
236
+		 */
237
+		function espresso_load_required($classname, $full_path_to_file)
238
+		{
239
+			static $error_handling_loaded = false;
240
+			if ( ! $error_handling_loaded) {
241
+				espresso_load_error_handling();
242
+				$error_handling_loaded = true;
243
+			}
244
+			if (is_readable($full_path_to_file)) {
245
+				require_once($full_path_to_file);
246
+			} else {
247
+				throw new EE_Error (
248
+						sprintf(
249
+								esc_html__(
250
+										'The %s class file could not be located or is not readable due to file permissions.',
251
+										'event_espresso'
252
+								),
253
+								$classname
254
+						)
255
+				);
256
+			}
257
+		}
258 258
 
259
-        espresso_load_required('EEH_Base', EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php');
260
-        espresso_load_required('EEH_File', EE_CORE . 'helpers' . DS . 'EEH_File.helper.php');
261
-        espresso_load_required('EE_Bootstrap', EE_CORE . 'EE_Bootstrap.core.php');
262
-        new EE_Bootstrap();
263
-    }
259
+		espresso_load_required('EEH_Base', EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php');
260
+		espresso_load_required('EEH_File', EE_CORE . 'helpers' . DS . 'EEH_File.helper.php');
261
+		espresso_load_required('EE_Bootstrap', EE_CORE . 'EE_Bootstrap.core.php');
262
+		new EE_Bootstrap();
263
+	}
264 264
 }
265 265
 if ( ! function_exists('espresso_deactivate_plugin')) {
266
-    /**
267
-     *    deactivate_plugin
268
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
269
-     *
270
-     * @access public
271
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
272
-     * @return    void
273
-     */
274
-    function espresso_deactivate_plugin($plugin_basename = '')
275
-    {
276
-        if ( ! function_exists('deactivate_plugins')) {
277
-            require_once(ABSPATH . 'wp-admin/includes/plugin.php');
278
-        }
279
-        unset($_GET['activate'], $_REQUEST['activate']);
280
-        deactivate_plugins($plugin_basename);
281
-    }
266
+	/**
267
+	 *    deactivate_plugin
268
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
269
+	 *
270
+	 * @access public
271
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
272
+	 * @return    void
273
+	 */
274
+	function espresso_deactivate_plugin($plugin_basename = '')
275
+	{
276
+		if ( ! function_exists('deactivate_plugins')) {
277
+			require_once(ABSPATH . 'wp-admin/includes/plugin.php');
278
+		}
279
+		unset($_GET['activate'], $_REQUEST['activate']);
280
+		deactivate_plugins($plugin_basename);
281
+	}
282 282
 }
283 283
\ No newline at end of file
Please login to merge, or discard this patch.
core/helpers/EEH_Parse_Shortcodes.helper.php 2 patches
Indentation   +242 added lines, -242 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (! defined('EVENT_ESPRESSO_VERSION')) {
4
-    exit('NO direct script access allowed');
4
+	exit('NO direct script access allowed');
5 5
 }
6 6
 
7 7
 /**
@@ -26,247 +26,247 @@  discard block
 block discarded – undo
26 26
 {
27 27
 
28 28
 
29
-    /**
30
-     * holds the template
31
-     *
32
-     * @access private
33
-     * @var mixed (string|array)
34
-     */
35
-    private $_template;
36
-
37
-
38
-    /**
39
-     * holds the incoming data object
40
-     *
41
-     * @access private
42
-     * @var object
43
-     */
44
-    private $_data;
45
-
46
-
47
-    /**
48
-     * will hold an array of EE_Shortcodes library objects.
49
-     *
50
-     * @access private
51
-     * @var EE_Shortcodes[]
52
-     */
53
-    private $_shortcode_objs = array();
54
-
55
-
56
-    public function __construct()
57
-    {
58
-    }
59
-
60
-
61
-    /**
62
-     * This kicks off the parsing of shortcodes in message templates
63
-     *
64
-     * @param  string                $template         This is the incoming string to be parsed
65
-     * @param  EE_Messages_Addressee $data             This is the incoming data object
66
-     * @param  array                 $valid_shortcodes An array of strings that correspond to EE_Shortcode libraries
67
-     * @param EE_message_type        $message_type     The message type that called the parser
68
-     * @param EE_messenger           $messenger        The active messenger for this parsing session.
69
-     * @param EE_Message             $message
70
-     * @return string                   The parsed template string
71
-     */
72
-    public function parse_message_template(
73
-        $template,
74
-        EE_Messages_Addressee $data,
75
-        $valid_shortcodes,
76
-        EE_message_type $message_type,
77
-        EE_messenger $messenger,
78
-        EE_Message $message
79
-    ) {
80
-        $extra_data = array(
81
-            'messenger'    => $messenger,
82
-            'message_type' => $message_type,
83
-            'message'      => $message,
84
-        );
85
-        $this->_init_data($template, $data, $valid_shortcodes, $extra_data);
86
-        $this->_template = is_array($template) ? $template['main'] : $template;
87
-        return $this->_parse_message_template();
88
-    }
89
-
90
-
91
-    public function parse_attendee_list_template(
92
-        $template,
93
-        EE_Registration $registration,
94
-        $valid_shortcodes,
95
-        $extra_data = array()
96
-    ) {
97
-        $this->_init_data($template, $registration, $valid_shortcodes, $extra_data);
98
-        $this->_template = is_array($template) ? $template['attendee_list'] : $template;
99
-        return $this->_parse_message_template();
100
-    }
101
-
102
-    public function parse_event_list_template($template, EE_Event $event, $valid_shortcodes, $extra_data = array())
103
-    {
104
-        $this->_init_data($template, $event, $valid_shortcodes, $extra_data);
105
-        $this->_template = is_array($template) ? $template['event_list'] : $template;
106
-        return $this->_parse_message_template();
107
-    }
108
-
109
-
110
-    public function parse_ticket_list_template($template, EE_Ticket $ticket, $valid_shortcodes, $extra_data = array())
111
-    {
112
-        $this->_init_data($template, $ticket, $valid_shortcodes, $extra_data);
113
-        $this->_template = is_array($template) ? $template['ticket_list'] : $template;
114
-        return $this->_parse_message_template();
115
-    }
116
-
117
-
118
-    public function parse_line_item_list_template(
119
-        $template,
120
-        EE_Line_Item $line_item,
121
-        $valid_shortcodes,
122
-        $extra_data = array()
123
-    ) {
124
-        $this->_init_data($template, $line_item, $valid_shortcodes, $extra_data);
125
-        $this->_template = is_array($template) ? $template['ticket_line_item_no_pms'] : $template;
126
-        return $this->_parse_message_template();
127
-    }
128
-
129
-
130
-    public function parse_payment_list_template(
131
-        $template,
132
-        EE_Payment $payment_item,
133
-        $valid_shortcodes,
134
-        $extra_data = array()
135
-    ) {
136
-        $this->_init_data($template, $payment_item, $valid_shortcodes, $extra_data);
137
-        $this->_template = is_array($template) ? $template['payment_list'] : $template;
138
-        return $this->_parse_message_template();
139
-    }
140
-
141
-
142
-    public function parse_datetime_list_template(
143
-        $template,
144
-        EE_Datetime $datetime,
145
-        $valid_shortcodes,
146
-        $extra_data = array()
147
-    ) {
148
-        $this->_init_data($template, $datetime, $valid_shortcodes, $extra_data);
149
-        $this->_template = is_array($template) ? $template['datetime_list'] : $template;
150
-        return $this->_parse_message_template();
151
-    }
152
-
153
-
154
-    public function parse_question_list_template($template, EE_Answer $answer, $valid_shortcodes, $extra_data = array())
155
-    {
156
-        $this->_init_data($template, $answer, $valid_shortcodes, $extra_data);
157
-        $this->_template = is_array($template) ? $template['question_list'] : $template;
158
-        return $this->_parse_message_template();
159
-    }
160
-
161
-
162
-    private function _init_data($template, $data, $valid_shortcodes, $extra_data = array())
163
-    {
164
-        $this->_reset_props();
165
-        $this->_data['template']   = $template;
166
-        $this->_data['data']       = $data;
167
-        $this->_data['extra_data'] = $extra_data;
168
-        $this->_set_shortcodes($valid_shortcodes);
169
-    }
170
-
171
-
172
-    private function _reset_props()
173
-    {
174
-        $this->_template       = $this->_data = null;
175
-        $this->_shortcode_objs = array();
176
-    }
177
-
178
-
179
-    /**
180
-     * takes the given template and parses it with the $_shortcodes property
181
-     *
182
-     * @access private
183
-     * @return string
184
-     */
185
-    private function _parse_message_template()
186
-    {
187
-        //now let's get a list of shortcodes that are found in the given template
188
-        preg_match_all('/(\[.+?\])/', $this->_template, $matches);
189
-        $shortcodes = (array)$matches[0]; //this should be an array of shortcodes in the template string.
190
-
191
-        $matched_code = array();
192
-        $sc_values    = array();
193
-
194
-        $list_type_shortcodes = array(
195
-            '[ATTENDEE_LIST]',
196
-            '[EVENT_LIST]',
197
-            '[TICKET_LIST]',
198
-            '[DATETIME_LIST]',
199
-            '[QUESTION_LIST]',
200
-            '[RECIPIENT_QUESTION_LIST]',
201
-            '[PRIMARY_REGISTRANT_QUESTION_LIST]',
202
-            '[RECIPIENT_TICKET_LIST]',
203
-            '[PRIMARY_REGISTRANT_TICKET_LIST]',
204
-            '[RECIPIENT_DATETIME_LIST]',
205
-            '[PRIMARY_REGISTRANT_DATETIME_LIST]',
206
-            '[TICKET_LINE_ITEM_LIST]',
207
-            '[TAX_LINE_ITEM_LIST]',
208
-            '[ADDITIONAL_LINE_ITEM_LIST]',
209
-            '[PRICE_MODIFIER_LINE_ITEM_LIST]',
210
-            '[PAYMENT_LIST_*]',
211
-        );
212
-
213
-        $list_type_shortcodes = apply_filters('FHEE__EEH_Parse_Shortcodes___parse_message_template__list_type_shortcodes',
214
-            $list_type_shortcodes);
215
-
216
-        //now lets go ahead and loop through our parsers for each shortcode and setup the values
217
-        foreach ($shortcodes as $shortcode) {
218
-
219
-            foreach ($this->_shortcode_objs as $sc_obj) {
220
-                if ($sc_obj instanceof EE_Shortcodes) {
221
-                    //we need to setup any dynamic shortcodes so that they work with the array_key_exists
222
-                    preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
223
-                    $sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
224
-
225
-                    if (! array_key_exists($sc_to_verify, $sc_obj->get_shortcodes())) {
226
-                        continue; //the given shortcode isn't in this object
227
-                    }
228
-
229
-                    //if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
230
-                    if (! in_array($sc_to_verify, $list_type_shortcodes)) {
231
-                        $data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
232
-                    } else {
233
-                        $data_send = $this->_data;
234
-                    }
235
-
236
-
237
-                    $parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
238
-
239
-                    $matched_code[] = $shortcode;
240
-                    $sc_values[]    = $parsed;
241
-                }
242
-            }
243
-        }
244
-
245
-        //now we've got parsed values for all the shortcodes in the template so we can go ahead and swap the shortcodes out.
246
-        $parsed = str_replace(array_values($matched_code), array_values($sc_values), $this->_template);
247
-        return $parsed;
248
-    }
249
-
250
-
251
-    /**
252
-     * This sets the shortcodes property from the incoming array of valid shortcodes that corresponds to names of
253
-     * various EE_Shortcode library objects
254
-     *
255
-     * @access private
256
-     * @param array $valid_shortcodes an array of strings corresponding to EE_Shortcode Library objects
257
-     * @return void
258
-     */
259
-    private function _set_shortcodes($valid_shortcodes)
260
-    {
261
-        foreach ($valid_shortcodes as $shortcode_ref) {
262
-            $ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
263
-            $ref       = str_replace(' ', '_', $ref);
264
-            $classname = 'EE_' . $ref . '_Shortcodes';
265
-            if (class_exists($classname)) {
266
-                $this->_shortcode_objs[] = new $classname;
267
-            }
268
-        }
269
-    }
29
+	/**
30
+	 * holds the template
31
+	 *
32
+	 * @access private
33
+	 * @var mixed (string|array)
34
+	 */
35
+	private $_template;
36
+
37
+
38
+	/**
39
+	 * holds the incoming data object
40
+	 *
41
+	 * @access private
42
+	 * @var object
43
+	 */
44
+	private $_data;
45
+
46
+
47
+	/**
48
+	 * will hold an array of EE_Shortcodes library objects.
49
+	 *
50
+	 * @access private
51
+	 * @var EE_Shortcodes[]
52
+	 */
53
+	private $_shortcode_objs = array();
54
+
55
+
56
+	public function __construct()
57
+	{
58
+	}
59
+
60
+
61
+	/**
62
+	 * This kicks off the parsing of shortcodes in message templates
63
+	 *
64
+	 * @param  string                $template         This is the incoming string to be parsed
65
+	 * @param  EE_Messages_Addressee $data             This is the incoming data object
66
+	 * @param  array                 $valid_shortcodes An array of strings that correspond to EE_Shortcode libraries
67
+	 * @param EE_message_type        $message_type     The message type that called the parser
68
+	 * @param EE_messenger           $messenger        The active messenger for this parsing session.
69
+	 * @param EE_Message             $message
70
+	 * @return string                   The parsed template string
71
+	 */
72
+	public function parse_message_template(
73
+		$template,
74
+		EE_Messages_Addressee $data,
75
+		$valid_shortcodes,
76
+		EE_message_type $message_type,
77
+		EE_messenger $messenger,
78
+		EE_Message $message
79
+	) {
80
+		$extra_data = array(
81
+			'messenger'    => $messenger,
82
+			'message_type' => $message_type,
83
+			'message'      => $message,
84
+		);
85
+		$this->_init_data($template, $data, $valid_shortcodes, $extra_data);
86
+		$this->_template = is_array($template) ? $template['main'] : $template;
87
+		return $this->_parse_message_template();
88
+	}
89
+
90
+
91
+	public function parse_attendee_list_template(
92
+		$template,
93
+		EE_Registration $registration,
94
+		$valid_shortcodes,
95
+		$extra_data = array()
96
+	) {
97
+		$this->_init_data($template, $registration, $valid_shortcodes, $extra_data);
98
+		$this->_template = is_array($template) ? $template['attendee_list'] : $template;
99
+		return $this->_parse_message_template();
100
+	}
101
+
102
+	public function parse_event_list_template($template, EE_Event $event, $valid_shortcodes, $extra_data = array())
103
+	{
104
+		$this->_init_data($template, $event, $valid_shortcodes, $extra_data);
105
+		$this->_template = is_array($template) ? $template['event_list'] : $template;
106
+		return $this->_parse_message_template();
107
+	}
108
+
109
+
110
+	public function parse_ticket_list_template($template, EE_Ticket $ticket, $valid_shortcodes, $extra_data = array())
111
+	{
112
+		$this->_init_data($template, $ticket, $valid_shortcodes, $extra_data);
113
+		$this->_template = is_array($template) ? $template['ticket_list'] : $template;
114
+		return $this->_parse_message_template();
115
+	}
116
+
117
+
118
+	public function parse_line_item_list_template(
119
+		$template,
120
+		EE_Line_Item $line_item,
121
+		$valid_shortcodes,
122
+		$extra_data = array()
123
+	) {
124
+		$this->_init_data($template, $line_item, $valid_shortcodes, $extra_data);
125
+		$this->_template = is_array($template) ? $template['ticket_line_item_no_pms'] : $template;
126
+		return $this->_parse_message_template();
127
+	}
128
+
129
+
130
+	public function parse_payment_list_template(
131
+		$template,
132
+		EE_Payment $payment_item,
133
+		$valid_shortcodes,
134
+		$extra_data = array()
135
+	) {
136
+		$this->_init_data($template, $payment_item, $valid_shortcodes, $extra_data);
137
+		$this->_template = is_array($template) ? $template['payment_list'] : $template;
138
+		return $this->_parse_message_template();
139
+	}
140
+
141
+
142
+	public function parse_datetime_list_template(
143
+		$template,
144
+		EE_Datetime $datetime,
145
+		$valid_shortcodes,
146
+		$extra_data = array()
147
+	) {
148
+		$this->_init_data($template, $datetime, $valid_shortcodes, $extra_data);
149
+		$this->_template = is_array($template) ? $template['datetime_list'] : $template;
150
+		return $this->_parse_message_template();
151
+	}
152
+
153
+
154
+	public function parse_question_list_template($template, EE_Answer $answer, $valid_shortcodes, $extra_data = array())
155
+	{
156
+		$this->_init_data($template, $answer, $valid_shortcodes, $extra_data);
157
+		$this->_template = is_array($template) ? $template['question_list'] : $template;
158
+		return $this->_parse_message_template();
159
+	}
160
+
161
+
162
+	private function _init_data($template, $data, $valid_shortcodes, $extra_data = array())
163
+	{
164
+		$this->_reset_props();
165
+		$this->_data['template']   = $template;
166
+		$this->_data['data']       = $data;
167
+		$this->_data['extra_data'] = $extra_data;
168
+		$this->_set_shortcodes($valid_shortcodes);
169
+	}
170
+
171
+
172
+	private function _reset_props()
173
+	{
174
+		$this->_template       = $this->_data = null;
175
+		$this->_shortcode_objs = array();
176
+	}
177
+
178
+
179
+	/**
180
+	 * takes the given template and parses it with the $_shortcodes property
181
+	 *
182
+	 * @access private
183
+	 * @return string
184
+	 */
185
+	private function _parse_message_template()
186
+	{
187
+		//now let's get a list of shortcodes that are found in the given template
188
+		preg_match_all('/(\[.+?\])/', $this->_template, $matches);
189
+		$shortcodes = (array)$matches[0]; //this should be an array of shortcodes in the template string.
190
+
191
+		$matched_code = array();
192
+		$sc_values    = array();
193
+
194
+		$list_type_shortcodes = array(
195
+			'[ATTENDEE_LIST]',
196
+			'[EVENT_LIST]',
197
+			'[TICKET_LIST]',
198
+			'[DATETIME_LIST]',
199
+			'[QUESTION_LIST]',
200
+			'[RECIPIENT_QUESTION_LIST]',
201
+			'[PRIMARY_REGISTRANT_QUESTION_LIST]',
202
+			'[RECIPIENT_TICKET_LIST]',
203
+			'[PRIMARY_REGISTRANT_TICKET_LIST]',
204
+			'[RECIPIENT_DATETIME_LIST]',
205
+			'[PRIMARY_REGISTRANT_DATETIME_LIST]',
206
+			'[TICKET_LINE_ITEM_LIST]',
207
+			'[TAX_LINE_ITEM_LIST]',
208
+			'[ADDITIONAL_LINE_ITEM_LIST]',
209
+			'[PRICE_MODIFIER_LINE_ITEM_LIST]',
210
+			'[PAYMENT_LIST_*]',
211
+		);
212
+
213
+		$list_type_shortcodes = apply_filters('FHEE__EEH_Parse_Shortcodes___parse_message_template__list_type_shortcodes',
214
+			$list_type_shortcodes);
215
+
216
+		//now lets go ahead and loop through our parsers for each shortcode and setup the values
217
+		foreach ($shortcodes as $shortcode) {
218
+
219
+			foreach ($this->_shortcode_objs as $sc_obj) {
220
+				if ($sc_obj instanceof EE_Shortcodes) {
221
+					//we need to setup any dynamic shortcodes so that they work with the array_key_exists
222
+					preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
223
+					$sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
224
+
225
+					if (! array_key_exists($sc_to_verify, $sc_obj->get_shortcodes())) {
226
+						continue; //the given shortcode isn't in this object
227
+					}
228
+
229
+					//if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
230
+					if (! in_array($sc_to_verify, $list_type_shortcodes)) {
231
+						$data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
232
+					} else {
233
+						$data_send = $this->_data;
234
+					}
235
+
236
+
237
+					$parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
238
+
239
+					$matched_code[] = $shortcode;
240
+					$sc_values[]    = $parsed;
241
+				}
242
+			}
243
+		}
244
+
245
+		//now we've got parsed values for all the shortcodes in the template so we can go ahead and swap the shortcodes out.
246
+		$parsed = str_replace(array_values($matched_code), array_values($sc_values), $this->_template);
247
+		return $parsed;
248
+	}
249
+
250
+
251
+	/**
252
+	 * This sets the shortcodes property from the incoming array of valid shortcodes that corresponds to names of
253
+	 * various EE_Shortcode library objects
254
+	 *
255
+	 * @access private
256
+	 * @param array $valid_shortcodes an array of strings corresponding to EE_Shortcode Library objects
257
+	 * @return void
258
+	 */
259
+	private function _set_shortcodes($valid_shortcodes)
260
+	{
261
+		foreach ($valid_shortcodes as $shortcode_ref) {
262
+			$ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
263
+			$ref       = str_replace(' ', '_', $ref);
264
+			$classname = 'EE_' . $ref . '_Shortcodes';
265
+			if (class_exists($classname)) {
266
+				$this->_shortcode_objs[] = new $classname;
267
+			}
268
+		}
269
+	}
270 270
 
271 271
 
272 272
 } //end EEH_Parse_Shortcodes
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-if (! defined('EVENT_ESPRESSO_VERSION')) {
3
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
4 4
     exit('NO direct script access allowed');
5 5
 }
6 6
 
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
     {
187 187
         //now let's get a list of shortcodes that are found in the given template
188 188
         preg_match_all('/(\[.+?\])/', $this->_template, $matches);
189
-        $shortcodes = (array)$matches[0]; //this should be an array of shortcodes in the template string.
189
+        $shortcodes = (array) $matches[0]; //this should be an array of shortcodes in the template string.
190 190
 
191 191
         $matched_code = array();
192 192
         $sc_values    = array();
@@ -220,14 +220,14 @@  discard block
 block discarded – undo
220 220
                 if ($sc_obj instanceof EE_Shortcodes) {
221 221
                     //we need to setup any dynamic shortcodes so that they work with the array_key_exists
222 222
                     preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
223
-                    $sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
223
+                    $sc_to_verify = ! empty($matches[0]) ? $matches[0][0].']' : $shortcode;
224 224
 
225
-                    if (! array_key_exists($sc_to_verify, $sc_obj->get_shortcodes())) {
225
+                    if ( ! array_key_exists($sc_to_verify, $sc_obj->get_shortcodes())) {
226 226
                         continue; //the given shortcode isn't in this object
227 227
                     }
228 228
 
229 229
                     //if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
230
-                    if (! in_array($sc_to_verify, $list_type_shortcodes)) {
230
+                    if ( ! in_array($sc_to_verify, $list_type_shortcodes)) {
231 231
                         $data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
232 232
                     } else {
233 233
                         $data_send = $this->_data;
@@ -261,7 +261,7 @@  discard block
 block discarded – undo
261 261
         foreach ($valid_shortcodes as $shortcode_ref) {
262 262
             $ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
263 263
             $ref       = str_replace(' ', '_', $ref);
264
-            $classname = 'EE_' . $ref . '_Shortcodes';
264
+            $classname = 'EE_'.$ref.'_Shortcodes';
265 265
             if (class_exists($classname)) {
266 266
                 $this->_shortcode_objs[] = new $classname;
267 267
             }
Please login to merge, or discard this patch.
core/libraries/shortcodes/EE_Shortcodes.lib.php 2 patches
Indentation   +340 added lines, -340 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (! defined('EVENT_ESPRESSO_VERSION')) {
4
-    exit('NO direct script access allowed');
4
+	exit('NO direct script access allowed');
5 5
 }
6 6
 
7 7
 /**
@@ -30,345 +30,345 @@  discard block
 block discarded – undo
30 30
 abstract class EE_Shortcodes extends EE_Base
31 31
 {
32 32
 
33
-    /**
34
-     * holds label for library
35
-     * This is used for referencing the library label
36
-     *
37
-     * @access public
38
-     * @var string
39
-     */
40
-    public $label;
41
-
42
-
43
-    /**
44
-     * This property is used for referencing a short description of the library
45
-     *
46
-     * @access public
47
-     * @var string
48
-     */
49
-    public $description;
50
-
51
-
52
-    /**
53
-     * This will hold an array of shortcodes with the key as the shortcode ([shortcode]) and the value as a
54
-     * label/description for the shortcode.
55
-     *
56
-     * @access protected
57
-     * @var array
58
-     */
59
-    protected $_shortcodes;
60
-
61
-
62
-    /**
63
-     * This will hold the incoming data item sent to the parser method
64
-     *
65
-     * @access protected
66
-     * @var mixed (array|object)
67
-     */
68
-    protected $_data;
69
-
70
-
71
-    /**
72
-     * some shortcodes may require extra data to parse.  This property is provided for that.
73
-     *
74
-     * @var array
75
-     */
76
-    protected $_extra_data;
77
-
78
-
79
-    /**
80
-     * EE_messenger used to generate the template being parsed.
81
-     *
82
-     * @since 4.5.0
83
-     * @var EE_messenger
84
-     */
85
-    protected $_messenger;
86
-
87
-
88
-    /**
89
-     * message type used to generate the template being parsed.
90
-     *
91
-     * @since 4.5.0
92
-     * @var EE_message_type
93
-     */
94
-    protected $_message_type;
95
-
96
-
97
-    /**
98
-     * context used for the template being parsed
99
-     *
100
-     * @since 4.5.0
101
-     * @var string
102
-     */
103
-    protected $_context;
104
-
105
-
106
-    /**
107
-     * Specific Message Template Group ID
108
-     *
109
-     * @since 4.5.0
110
-     * @var int
111
-     */
112
-    protected $_GRP_ID;
113
-
114
-
115
-    /**
116
-     * @since 4.9.0
117
-     * @type EE_Message
118
-     */
119
-    protected $_message;
120
-
121
-
122
-    /**
123
-     * This will hold an instance of the EEH_Parse_Shortcodes helper that will be used when handling list type
124
-     * shortcodes
125
-     *
126
-     * @var EEH_Parse_Shortcodes
127
-     */
128
-    protected $_shortcode_helper;
129
-
130
-
131
-    public function __construct()
132
-    {
133
-        $this->_set_defaults();
134
-        $this->_init_props();
135
-    }
136
-
137
-
138
-    /**
139
-     * This sets the defaults for the properties.  Child classes will override these properties in their _init_props
140
-     * method
141
-     */
142
-    private function _set_defaults()
143
-    {
144
-        $this->name        = $this->description = '';
145
-        $this->_shortcodes = array();
146
-        $this->_set_shortcode_helper();
147
-    }
148
-
149
-
150
-    /**
151
-     * loads an instance of the EE_Shortcode_Parser helper when requested
152
-     */
153
-    protected function _set_shortcode_helper()
154
-    {
155
-        //get shortcode_replace instance- set when _get_messages is called in child...
156
-        $this->_shortcode_helper = new EEH_Parse_Shortcodes();
157
-    }
158
-
159
-
160
-    public function get_shortcode_helper()
161
-    {
162
-        if (! $this->_shortcode_helper instanceof EEH_Parse_Shortcodes) {
163
-            $this->_set_shortcode_helper();
164
-        }
165
-        return $this->_shortcode_helper;
166
-    }
167
-
168
-
169
-    /**
170
-     * This is the public method for kicking of the parser included with each child.  It can be overridden by child
171
-     * classes if necessary (see EE_Questions_Answers for example)
172
-     *
173
-     * @param  string               $shortcode  incoming shortcode to be parsed
174
-     * @param  mixed (object|array) $data       incoming data to be be used for parsing
175
-     * @param  mixed (object|array) $extra_data extra incoming data (usually EE_Messages_Addressee)
176
-     * @return string            parsed shortcode.
177
-     */
178
-    public function parser($shortcode, $data, $extra_data = array())
179
-    {
180
-
181
-        //filter setup shortcodes
182
-        $this->_shortcodes = $this->get_shortcodes();
183
-
184
-        //we need to setup any dynamic shortcodes so that they work with the array_key_exists
185
-        $sc           = preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
186
-        $sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
187
-
188
-        //first we want to make sure this is a valid shortcode
189
-        if (! array_key_exists($sc_to_verify, $this->_shortcodes)) {
190
-            return false;
191
-        } //get out, this parser doesn't handle the incoming shortcode.
192
-        $this->_data       = $data;
193
-        $this->_extra_data = $extra_data;
194
-        $this->_set_messages_properties();
195
-        $parsed = apply_filters('FHEE__' . get_class($this) . '__parser_after', $this->_parser($shortcode), $shortcode,
196
-            $data, $extra_data, $this);
197
-
198
-        //note the below filter applies to ALL shortcode parsers... be careful!
199
-        $parsed = apply_filters('FHEE__EE_Shortcodes__parser_after', $parsed, $shortcode, $data, $extra_data, $this);
200
-        return $parsed;
201
-    }
202
-
203
-
204
-    /**
205
-     * This method just returns the shortcodes in the $_shortcodes array property.
206
-     *
207
-     * @access public
208
-     * @return array array of shortcodes => description pairs
209
-     */
210
-    public function get_shortcodes()
211
-    {
212
-        $this->_shortcodes = apply_filters('FHEE__' . get_class($this) . '__shortcodes', $this->_shortcodes, $this);
213
-
214
-        //note the below filter applies to ALL shortcode parsers... be careful!
215
-        $this->_shortcodes = apply_filters('FHEE__EE_Shortcodes__shortcodes', $this->_shortcodes, $this);
216
-
217
-        return $this->_shortcodes;
218
-    }
219
-
220
-
221
-    /**
222
-     * Child classes use this method to set the $name, $description, and $_shortcodes properties.
223
-     *
224
-     * @abstract
225
-     * @access protected
226
-     * @return void
227
-     */
228
-    abstract protected function _init_props();
229
-
230
-
231
-    /**
232
-     * This method will give parsing instructions for each shortcode defined in the _shortcodes array.  Child methods
233
-     * will have to take care of handling.
234
-     *
235
-     * @abstract
236
-     * @access protected
237
-     * @param string               $shortcode the shortcode to be parsed.
238
-     * @param mixed (object|array) $data      incoming data for the parser.  The data could be either an object or
239
-     *                             array because there are some shortcodes that might be replaced by prepared data that
240
-     *                             has multiple items in a list (i.e. list of attendees in an event and we're showing
241
-     *                             fname/lname for each attendee).  In this case data will be in an array.  Otherwise
242
-     *                             the data shoudl be in a properly formatted object.  The
243
-     *                             EEH_Parse_Shortcodes.helper.php describes the data object we're expecting.
244
-     * @return string parsed shortcode
245
-     */
246
-    abstract protected function _parser($shortcode);
247
-
248
-
249
-    /**
250
-     * This just validates incoming data for list type shortcode parsers (and they call this method) to make sure it
251
-     * meets their requirements
252
-     *
253
-     * @return mixed (void|exception) If validation fails we'll throw an exception.
254
-     */
255
-    protected function _validate_list_requirements()
256
-    {
257
-
258
-        //first test to make sure we've got an array!
259
-        if (! is_array($this->_data)) {
260
-            throw new EE_Error(sprintf(__('Expecting an array for the data sent to %s. Instead it was %s',
261
-                'event_espresso'), get_class($this), gettype($this->_data)));
262
-        }
263
-
264
-        //next test to make sure we've got the required template in the index!
265
-        if (! isset($this->_data['template'])) {
266
-            throw new EE_Error(sprintf(__('The incoming data does not have the required template index in its array',
267
-                'event_espresso')));
268
-        }
269
-
270
-        //next test to make sure we've got got a data index in the incoming data array
271
-        if (! isset($this->_data['data'])) {
272
-            throw new EE_Error(__('The incoming data does not have the required data index in its array',
273
-                'event_espresso'));
274
-        }
275
-
276
-        //all is well let's make sure _extra_data always has the values needed.
277
-        //let's make sure that extra_data includes all templates (for later parsing if necessary)
278
-        if (empty($this->_extra_data) || (empty($this->_extra_data['data']) && empty($this->_extra_data['template']))) {
279
-            $this->_extra_data['data']     = $this->_data['data'];
280
-            $this->_extra_data['template'] = $this->_data['template'];
281
-        }
282
-
283
-    }
284
-
285
-
286
-    /**
287
-     * This returns any attributes that may be existing on an EE_Shortcode
288
-     *
289
-     * @since 4.5.0
290
-     * @param string $shortcode incoming shortcode
291
-     * @return array An array with the attributes
292
-     */
293
-    protected function _get_shortcode_attrs($shortcode)
294
-    {
295
-        //make sure the required wp helper function is present
296
-        //require the shortcode file if necessary
297
-        if (! function_exists('shortcode_parse_atts')) {
298
-            require_once(ABSPATH . WPINC . '/shortcodes.php');
299
-        }
300
-
301
-        //let's get any attributes that may be present and set the defaults.
302
-        $shortcode_to_parse = str_replace('[', '', str_replace(']', '', $shortcode));
303
-        return shortcode_parse_atts($shortcode_to_parse);
304
-    }
305
-
306
-
307
-    /**
308
-     * This sets the properties related to the messages system
309
-     *
310
-     * @since 4.5.0
311
-     * @return void
312
-     */
313
-    protected function _set_messages_properties()
314
-    {
315
-        //should be in _extra_data
316
-        if (isset($this->_extra_data['messenger'])) {
317
-            $this->_messenger    = $this->_extra_data['messenger'];
318
-            $this->_message_type = $this->_extra_data['message_type'];
319
-            $this->_context      = $this->_extra_data['message'] instanceof EE_Message ? $this->_extra_data['message']->context() : '';
320
-            $this->_GRP_ID       = $this->_extra_data['message'] instanceof EE_Message ? $this->_extra_data['message']->GRP_ID() : 0;
321
-            $this->_message      = $this->_extra_data['message'] instanceof EE_Message ? $this->_extra_data['message'] : null;
322
-        }
323
-    }
324
-
325
-
326
-    /**
327
-     * This returns whatever the set message type object is that was set on this shortcode parser.
328
-     *
329
-     * @since 4.5.0
330
-     * @return EE_message_type
331
-     */
332
-    public function get_set_message_type()
333
-    {
334
-        return $this->_message_type;
335
-    }
336
-
337
-
338
-    /**
339
-     * This returns whatever the set messenger object is that was set on this shortcode parser
340
-     *
341
-     * @since 4.5.0
342
-     * @return EE_messenger
343
-     */
344
-    public function get_set_messenger()
345
-    {
346
-        return $this->_messenger;
347
-    }
348
-
349
-
350
-    /**
351
-     * This returns whatever the set context string is on this shortcode parser.
352
-     *
353
-     * @since 4.5.0
354
-     * @return string
355
-     */
356
-    public function get_set_context()
357
-    {
358
-        return $this->_context;
359
-    }
360
-
361
-
362
-    /**
363
-     * This returns whatever the set EE_Message object is on this shortcode.
364
-     *
365
-     * @since 4.9.0
366
-     * @return EE_Message
367
-     */
368
-    public function get_set_message()
369
-    {
370
-        return $this->_message;
371
-    }
33
+	/**
34
+	 * holds label for library
35
+	 * This is used for referencing the library label
36
+	 *
37
+	 * @access public
38
+	 * @var string
39
+	 */
40
+	public $label;
41
+
42
+
43
+	/**
44
+	 * This property is used for referencing a short description of the library
45
+	 *
46
+	 * @access public
47
+	 * @var string
48
+	 */
49
+	public $description;
50
+
51
+
52
+	/**
53
+	 * This will hold an array of shortcodes with the key as the shortcode ([shortcode]) and the value as a
54
+	 * label/description for the shortcode.
55
+	 *
56
+	 * @access protected
57
+	 * @var array
58
+	 */
59
+	protected $_shortcodes;
60
+
61
+
62
+	/**
63
+	 * This will hold the incoming data item sent to the parser method
64
+	 *
65
+	 * @access protected
66
+	 * @var mixed (array|object)
67
+	 */
68
+	protected $_data;
69
+
70
+
71
+	/**
72
+	 * some shortcodes may require extra data to parse.  This property is provided for that.
73
+	 *
74
+	 * @var array
75
+	 */
76
+	protected $_extra_data;
77
+
78
+
79
+	/**
80
+	 * EE_messenger used to generate the template being parsed.
81
+	 *
82
+	 * @since 4.5.0
83
+	 * @var EE_messenger
84
+	 */
85
+	protected $_messenger;
86
+
87
+
88
+	/**
89
+	 * message type used to generate the template being parsed.
90
+	 *
91
+	 * @since 4.5.0
92
+	 * @var EE_message_type
93
+	 */
94
+	protected $_message_type;
95
+
96
+
97
+	/**
98
+	 * context used for the template being parsed
99
+	 *
100
+	 * @since 4.5.0
101
+	 * @var string
102
+	 */
103
+	protected $_context;
104
+
105
+
106
+	/**
107
+	 * Specific Message Template Group ID
108
+	 *
109
+	 * @since 4.5.0
110
+	 * @var int
111
+	 */
112
+	protected $_GRP_ID;
113
+
114
+
115
+	/**
116
+	 * @since 4.9.0
117
+	 * @type EE_Message
118
+	 */
119
+	protected $_message;
120
+
121
+
122
+	/**
123
+	 * This will hold an instance of the EEH_Parse_Shortcodes helper that will be used when handling list type
124
+	 * shortcodes
125
+	 *
126
+	 * @var EEH_Parse_Shortcodes
127
+	 */
128
+	protected $_shortcode_helper;
129
+
130
+
131
+	public function __construct()
132
+	{
133
+		$this->_set_defaults();
134
+		$this->_init_props();
135
+	}
136
+
137
+
138
+	/**
139
+	 * This sets the defaults for the properties.  Child classes will override these properties in their _init_props
140
+	 * method
141
+	 */
142
+	private function _set_defaults()
143
+	{
144
+		$this->name        = $this->description = '';
145
+		$this->_shortcodes = array();
146
+		$this->_set_shortcode_helper();
147
+	}
148
+
149
+
150
+	/**
151
+	 * loads an instance of the EE_Shortcode_Parser helper when requested
152
+	 */
153
+	protected function _set_shortcode_helper()
154
+	{
155
+		//get shortcode_replace instance- set when _get_messages is called in child...
156
+		$this->_shortcode_helper = new EEH_Parse_Shortcodes();
157
+	}
158
+
159
+
160
+	public function get_shortcode_helper()
161
+	{
162
+		if (! $this->_shortcode_helper instanceof EEH_Parse_Shortcodes) {
163
+			$this->_set_shortcode_helper();
164
+		}
165
+		return $this->_shortcode_helper;
166
+	}
167
+
168
+
169
+	/**
170
+	 * This is the public method for kicking of the parser included with each child.  It can be overridden by child
171
+	 * classes if necessary (see EE_Questions_Answers for example)
172
+	 *
173
+	 * @param  string               $shortcode  incoming shortcode to be parsed
174
+	 * @param  mixed (object|array) $data       incoming data to be be used for parsing
175
+	 * @param  mixed (object|array) $extra_data extra incoming data (usually EE_Messages_Addressee)
176
+	 * @return string            parsed shortcode.
177
+	 */
178
+	public function parser($shortcode, $data, $extra_data = array())
179
+	{
180
+
181
+		//filter setup shortcodes
182
+		$this->_shortcodes = $this->get_shortcodes();
183
+
184
+		//we need to setup any dynamic shortcodes so that they work with the array_key_exists
185
+		$sc           = preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
186
+		$sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
187
+
188
+		//first we want to make sure this is a valid shortcode
189
+		if (! array_key_exists($sc_to_verify, $this->_shortcodes)) {
190
+			return false;
191
+		} //get out, this parser doesn't handle the incoming shortcode.
192
+		$this->_data       = $data;
193
+		$this->_extra_data = $extra_data;
194
+		$this->_set_messages_properties();
195
+		$parsed = apply_filters('FHEE__' . get_class($this) . '__parser_after', $this->_parser($shortcode), $shortcode,
196
+			$data, $extra_data, $this);
197
+
198
+		//note the below filter applies to ALL shortcode parsers... be careful!
199
+		$parsed = apply_filters('FHEE__EE_Shortcodes__parser_after', $parsed, $shortcode, $data, $extra_data, $this);
200
+		return $parsed;
201
+	}
202
+
203
+
204
+	/**
205
+	 * This method just returns the shortcodes in the $_shortcodes array property.
206
+	 *
207
+	 * @access public
208
+	 * @return array array of shortcodes => description pairs
209
+	 */
210
+	public function get_shortcodes()
211
+	{
212
+		$this->_shortcodes = apply_filters('FHEE__' . get_class($this) . '__shortcodes', $this->_shortcodes, $this);
213
+
214
+		//note the below filter applies to ALL shortcode parsers... be careful!
215
+		$this->_shortcodes = apply_filters('FHEE__EE_Shortcodes__shortcodes', $this->_shortcodes, $this);
216
+
217
+		return $this->_shortcodes;
218
+	}
219
+
220
+
221
+	/**
222
+	 * Child classes use this method to set the $name, $description, and $_shortcodes properties.
223
+	 *
224
+	 * @abstract
225
+	 * @access protected
226
+	 * @return void
227
+	 */
228
+	abstract protected function _init_props();
229
+
230
+
231
+	/**
232
+	 * This method will give parsing instructions for each shortcode defined in the _shortcodes array.  Child methods
233
+	 * will have to take care of handling.
234
+	 *
235
+	 * @abstract
236
+	 * @access protected
237
+	 * @param string               $shortcode the shortcode to be parsed.
238
+	 * @param mixed (object|array) $data      incoming data for the parser.  The data could be either an object or
239
+	 *                             array because there are some shortcodes that might be replaced by prepared data that
240
+	 *                             has multiple items in a list (i.e. list of attendees in an event and we're showing
241
+	 *                             fname/lname for each attendee).  In this case data will be in an array.  Otherwise
242
+	 *                             the data shoudl be in a properly formatted object.  The
243
+	 *                             EEH_Parse_Shortcodes.helper.php describes the data object we're expecting.
244
+	 * @return string parsed shortcode
245
+	 */
246
+	abstract protected function _parser($shortcode);
247
+
248
+
249
+	/**
250
+	 * This just validates incoming data for list type shortcode parsers (and they call this method) to make sure it
251
+	 * meets their requirements
252
+	 *
253
+	 * @return mixed (void|exception) If validation fails we'll throw an exception.
254
+	 */
255
+	protected function _validate_list_requirements()
256
+	{
257
+
258
+		//first test to make sure we've got an array!
259
+		if (! is_array($this->_data)) {
260
+			throw new EE_Error(sprintf(__('Expecting an array for the data sent to %s. Instead it was %s',
261
+				'event_espresso'), get_class($this), gettype($this->_data)));
262
+		}
263
+
264
+		//next test to make sure we've got the required template in the index!
265
+		if (! isset($this->_data['template'])) {
266
+			throw new EE_Error(sprintf(__('The incoming data does not have the required template index in its array',
267
+				'event_espresso')));
268
+		}
269
+
270
+		//next test to make sure we've got got a data index in the incoming data array
271
+		if (! isset($this->_data['data'])) {
272
+			throw new EE_Error(__('The incoming data does not have the required data index in its array',
273
+				'event_espresso'));
274
+		}
275
+
276
+		//all is well let's make sure _extra_data always has the values needed.
277
+		//let's make sure that extra_data includes all templates (for later parsing if necessary)
278
+		if (empty($this->_extra_data) || (empty($this->_extra_data['data']) && empty($this->_extra_data['template']))) {
279
+			$this->_extra_data['data']     = $this->_data['data'];
280
+			$this->_extra_data['template'] = $this->_data['template'];
281
+		}
282
+
283
+	}
284
+
285
+
286
+	/**
287
+	 * This returns any attributes that may be existing on an EE_Shortcode
288
+	 *
289
+	 * @since 4.5.0
290
+	 * @param string $shortcode incoming shortcode
291
+	 * @return array An array with the attributes
292
+	 */
293
+	protected function _get_shortcode_attrs($shortcode)
294
+	{
295
+		//make sure the required wp helper function is present
296
+		//require the shortcode file if necessary
297
+		if (! function_exists('shortcode_parse_atts')) {
298
+			require_once(ABSPATH . WPINC . '/shortcodes.php');
299
+		}
300
+
301
+		//let's get any attributes that may be present and set the defaults.
302
+		$shortcode_to_parse = str_replace('[', '', str_replace(']', '', $shortcode));
303
+		return shortcode_parse_atts($shortcode_to_parse);
304
+	}
305
+
306
+
307
+	/**
308
+	 * This sets the properties related to the messages system
309
+	 *
310
+	 * @since 4.5.0
311
+	 * @return void
312
+	 */
313
+	protected function _set_messages_properties()
314
+	{
315
+		//should be in _extra_data
316
+		if (isset($this->_extra_data['messenger'])) {
317
+			$this->_messenger    = $this->_extra_data['messenger'];
318
+			$this->_message_type = $this->_extra_data['message_type'];
319
+			$this->_context      = $this->_extra_data['message'] instanceof EE_Message ? $this->_extra_data['message']->context() : '';
320
+			$this->_GRP_ID       = $this->_extra_data['message'] instanceof EE_Message ? $this->_extra_data['message']->GRP_ID() : 0;
321
+			$this->_message      = $this->_extra_data['message'] instanceof EE_Message ? $this->_extra_data['message'] : null;
322
+		}
323
+	}
324
+
325
+
326
+	/**
327
+	 * This returns whatever the set message type object is that was set on this shortcode parser.
328
+	 *
329
+	 * @since 4.5.0
330
+	 * @return EE_message_type
331
+	 */
332
+	public function get_set_message_type()
333
+	{
334
+		return $this->_message_type;
335
+	}
336
+
337
+
338
+	/**
339
+	 * This returns whatever the set messenger object is that was set on this shortcode parser
340
+	 *
341
+	 * @since 4.5.0
342
+	 * @return EE_messenger
343
+	 */
344
+	public function get_set_messenger()
345
+	{
346
+		return $this->_messenger;
347
+	}
348
+
349
+
350
+	/**
351
+	 * This returns whatever the set context string is on this shortcode parser.
352
+	 *
353
+	 * @since 4.5.0
354
+	 * @return string
355
+	 */
356
+	public function get_set_context()
357
+	{
358
+		return $this->_context;
359
+	}
360
+
361
+
362
+	/**
363
+	 * This returns whatever the set EE_Message object is on this shortcode.
364
+	 *
365
+	 * @since 4.9.0
366
+	 * @return EE_Message
367
+	 */
368
+	public function get_set_message()
369
+	{
370
+		return $this->_message;
371
+	}
372 372
 
373 373
 
374 374
 } //end EE_Shortcodes
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-if (! defined('EVENT_ESPRESSO_VERSION')) {
3
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
4 4
     exit('NO direct script access allowed');
5 5
 }
6 6
 
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
 
160 160
     public function get_shortcode_helper()
161 161
     {
162
-        if (! $this->_shortcode_helper instanceof EEH_Parse_Shortcodes) {
162
+        if ( ! $this->_shortcode_helper instanceof EEH_Parse_Shortcodes) {
163 163
             $this->_set_shortcode_helper();
164 164
         }
165 165
         return $this->_shortcode_helper;
@@ -183,16 +183,16 @@  discard block
 block discarded – undo
183 183
 
184 184
         //we need to setup any dynamic shortcodes so that they work with the array_key_exists
185 185
         $sc           = preg_match_all('/(\[[A-Za-z0-9\_]+_\*)/', $shortcode, $matches);
186
-        $sc_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
186
+        $sc_to_verify = ! empty($matches[0]) ? $matches[0][0].']' : $shortcode;
187 187
 
188 188
         //first we want to make sure this is a valid shortcode
189
-        if (! array_key_exists($sc_to_verify, $this->_shortcodes)) {
189
+        if ( ! array_key_exists($sc_to_verify, $this->_shortcodes)) {
190 190
             return false;
191 191
         } //get out, this parser doesn't handle the incoming shortcode.
192 192
         $this->_data       = $data;
193 193
         $this->_extra_data = $extra_data;
194 194
         $this->_set_messages_properties();
195
-        $parsed = apply_filters('FHEE__' . get_class($this) . '__parser_after', $this->_parser($shortcode), $shortcode,
195
+        $parsed = apply_filters('FHEE__'.get_class($this).'__parser_after', $this->_parser($shortcode), $shortcode,
196 196
             $data, $extra_data, $this);
197 197
 
198 198
         //note the below filter applies to ALL shortcode parsers... be careful!
@@ -209,7 +209,7 @@  discard block
 block discarded – undo
209 209
      */
210 210
     public function get_shortcodes()
211 211
     {
212
-        $this->_shortcodes = apply_filters('FHEE__' . get_class($this) . '__shortcodes', $this->_shortcodes, $this);
212
+        $this->_shortcodes = apply_filters('FHEE__'.get_class($this).'__shortcodes', $this->_shortcodes, $this);
213 213
 
214 214
         //note the below filter applies to ALL shortcode parsers... be careful!
215 215
         $this->_shortcodes = apply_filters('FHEE__EE_Shortcodes__shortcodes', $this->_shortcodes, $this);
@@ -256,19 +256,19 @@  discard block
 block discarded – undo
256 256
     {
257 257
 
258 258
         //first test to make sure we've got an array!
259
-        if (! is_array($this->_data)) {
259
+        if ( ! is_array($this->_data)) {
260 260
             throw new EE_Error(sprintf(__('Expecting an array for the data sent to %s. Instead it was %s',
261 261
                 'event_espresso'), get_class($this), gettype($this->_data)));
262 262
         }
263 263
 
264 264
         //next test to make sure we've got the required template in the index!
265
-        if (! isset($this->_data['template'])) {
265
+        if ( ! isset($this->_data['template'])) {
266 266
             throw new EE_Error(sprintf(__('The incoming data does not have the required template index in its array',
267 267
                 'event_espresso')));
268 268
         }
269 269
 
270 270
         //next test to make sure we've got got a data index in the incoming data array
271
-        if (! isset($this->_data['data'])) {
271
+        if ( ! isset($this->_data['data'])) {
272 272
             throw new EE_Error(__('The incoming data does not have the required data index in its array',
273 273
                 'event_espresso'));
274 274
         }
@@ -294,8 +294,8 @@  discard block
 block discarded – undo
294 294
     {
295 295
         //make sure the required wp helper function is present
296 296
         //require the shortcode file if necessary
297
-        if (! function_exists('shortcode_parse_atts')) {
298
-            require_once(ABSPATH . WPINC . '/shortcodes.php');
297
+        if ( ! function_exists('shortcode_parse_atts')) {
298
+            require_once(ABSPATH.WPINC.'/shortcodes.php');
299 299
         }
300 300
 
301 301
         //let's get any attributes that may be present and set the defaults.
Please login to merge, or discard this patch.