Completed
Branch BUG/reg-status-change-recursio... (fbd515)
by
unknown
09:28 queued 36s
created
core/db_models/EEM_Payment_Method.model.php 1 patch
Indentation   +376 added lines, -376 removed lines patch added patch discarded remove patch
@@ -20,380 +20,380 @@
 block discarded – undo
20 20
 class EEM_Payment_Method extends EEM_Base
21 21
 {
22 22
 
23
-    const scope_cart = 'CART';
24
-
25
-    const scope_admin = 'ADMIN';
26
-
27
-    const scope_api = 'API';
28
-
29
-    /**
30
-     *
31
-     * @type EEM_Payment_Method
32
-     */
33
-    protected static $_instance = null;
34
-
35
-
36
-
37
-    /**
38
-     * private constructor to prevent direct creation
39
-     * @Constructor
40
-     * @access   protected
41
-     * @return EEM_Payment_Method
42
-     */
43
-    protected function __construct($timezone = null)
44
-    {
45
-        $this->singlular_item = __('Payment Method', 'event_espresso');
46
-        $this->plural_item = __('Payment Methods', 'event_espresso');
47
-        $this->_tables = array( 'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID') );
48
-        $this->_fields = array(
49
-            'Payment_Method' => array(
50
-                'PMD_ID' => new EE_Primary_Key_Int_Field('PMD_ID', __("ID", 'event_espresso')),
51
-                'PMD_type' => new EE_Plain_Text_Field('PMD_type', __("Payment Method Type", 'event_espresso'), false, 'Admin_Only'),
52
-                'PMD_name' => new EE_Plain_Text_Field('PMD_name', __("Name", 'event_espresso'), false),
53
-                'PMD_desc' => new EE_Post_Content_Field('PMD_desc', __("Description", 'event_espresso'), false, ''),
54
-                'PMD_admin_name' => new EE_Plain_Text_Field('PMD_admin_name', __("Admin-Only Name", 'event_espresso'), true),
55
-                'PMD_admin_desc' => new EE_Post_Content_Field('PMD_admin_desc', __("Admin-Only Description", 'event_espresso'), true),
56
-                'PMD_slug' => new EE_Slug_Field('PMD_slug', __("Slug", 'event_espresso'), false),
57
-                'PMD_order' => new EE_Integer_Field('PMD_order', __("Order", 'event_espresso'), false, 0),
58
-                'PMD_debug_mode' => new EE_Boolean_Field('PMD_debug_mode', __("Debug Mode On?", 'event_espresso'), false, false),
59
-                'PMD_wp_user' => new EE_WP_User_Field('PMD_wp_user', __("Payment Method Creator ID", 'event_espresso'), false),
60
-                'PMD_open_by_default' => new EE_Boolean_Field('PMD_open_by_default', __("Open by Default?", 'event_espresso'), false, false), 'PMD_button_url' => new EE_Plain_Text_Field('PMD_button_url', __("Button URL", 'event_espresso'), true, ''),
61
-                'PMD_scope' => new EE_Serialized_Text_Field('PMD_scope', __("Usable From?", 'event_espresso'), false, array()), // possible values currently are 'CART','ADMIN','API'
62
-        ) );
63
-        $this->_model_relations = array(
64
-            'Payment' => new EE_Has_Many_Relation(),
65
-            'Currency' => new EE_HABTM_Relation('Currency_Payment_Method'),
66
-            'Transaction' => new EE_Has_Many_Relation(),
67
-            'WP_User' => new EE_Belongs_To_Relation(),
68
-        );
69
-        parent::__construct($timezone);
70
-    }
71
-
72
-
73
-
74
-    /**
75
-     * Gets one by the slug provided
76
-     * @param string $slug
77
-     * @return EE_Payment_Method
78
-     */
79
-    public function get_one_by_slug($slug)
80
-    {
81
-        return $this->get_one(array( array( 'PMD_slug' => $slug ) ));
82
-    }
83
-
84
-
85
-
86
-    /**
87
-     * Gets all the acceptable scopes for payment methods.
88
-     * Keys are their names as store din the DB, and values are nice names for displaying them
89
-     * @return array
90
-     */
91
-    public function scopes()
92
-    {
93
-        return apply_filters(
94
-            'FHEE__EEM_Payment_Method__scopes',
95
-            array(
96
-                self::scope_cart        => __("Front-end Registration Page", 'event_espresso'),
97
-                self::scope_admin   => __("Admin Registration Page (no online processing)", 'event_espresso')
98
-            )
99
-        );
100
-    }
101
-
102
-
103
-
104
-    /**
105
-     * Determines if this is an valid scope
106
-     * @param string $scope like one of EEM_Payment_Method::instance()->scopes()
107
-     * @return boolean
108
-     */
109
-    public function is_valid_scope($scope)
110
-    {
111
-        $scopes = $this->scopes();
112
-        if (isset($scopes[ $scope ])) {
113
-            return true;
114
-        } else {
115
-            return false;
116
-        }
117
-    }
118
-
119
-
120
-
121
-    /**
122
-     * Gets all active payment methods
123
-     * @param string $scope one of
124
-     * @param array  $query_params
125
-     * @throws EE_Error
126
-     * @return EE_Payment_Method[]
127
-     */
128
-    public function get_all_active($scope = null, $query_params = array())
129
-    {
130
-        if (! isset($query_params['order_by']) && ! isset($query_params['order'])) {
131
-            $query_params['order_by'] = array( 'PMD_order' => 'ASC', 'PMD_ID' => 'ASC' );
132
-        }
133
-        return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params));
134
-    }
135
-
136
-    /**
137
-     * Counts all active gateways in the specified scope
138
-     * @param string $scope one of EEM_Payment_Method::scope_*
139
-     * @param array $query_params
140
-     * @return int
141
-     */
142
-    public function count_active($scope = null, $query_params = array())
143
-    {
144
-        return $this->count($this->_get_query_params_for_all_active($scope, $query_params));
145
-    }
146
-
147
-    /**
148
-     * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
149
-     * argument to get all active for a given scope
150
-     * @param string $scope one of the constants EEM_Payment_Method::scope_*
151
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
152
-     * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
153
-     * @throws EE_Error
154
-     */
155
-    protected function _get_query_params_for_all_active($scope = null, $query_params = array())
156
-    {
157
-        if ($scope) {
158
-            if ($this->is_valid_scope($scope)) {
159
-                return array_replace_recursive(array( array( 'PMD_scope' => array( 'LIKE', "%$scope%" ) ) ), $query_params);
160
-            } else {
161
-                throw new EE_Error(sprintf(__("'%s' is not a valid scope for a payment method", "event_espresso"), $scope));
162
-            }
163
-        } else {
164
-            $acceptable_scopes = array();
165
-            $count = 0;
166
-            foreach ($this->scopes() as $scope_name => $desc) {
167
-                $count++;
168
-                $acceptable_scopes[ 'PMD_scope*' . $count ] = array( 'LIKE', '%' . $scope_name . '%' );
169
-            }
170
-            return array_replace_recursive(array( array( 'OR*active_scope' => $acceptable_scopes ) ), $query_params);
171
-        }
172
-    }
173
-
174
-    /**
175
-     * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
176
-     * argument to get all active for a given scope
177
-     * @param string $scope one of the constants EEM_Payment_Method::scope_*
178
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
179
-     * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
180
-     * @throws EE_Error
181
-     */
182
-    public function get_query_params_for_all_active($scope = null, $query_params = array())
183
-    {
184
-        return $this->_get_query_params_for_all_active($scope, $query_params);
185
-    }
186
-
187
-
188
-    /**
189
-     * Gets one active payment method. see @get_all_active for documentation
190
-     * @param string $scope
191
-     * @param array  $query_params
192
-     * @return EE_Payment_Method
193
-     */
194
-    public function get_one_active($scope = null, $query_params = array())
195
-    {
196
-        return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params));
197
-    }
198
-
199
-
200
-
201
-    /**
202
-     * Gets one payment method of that type, regardless of whether its active or not
203
-     * @param string $type
204
-     * @return EE_Payment_Method
205
-     */
206
-    public function get_one_of_type($type)
207
-    {
208
-        return $this->get_one(array( array( 'PMD_type' => $type ) ));
209
-    }
210
-
211
-
212
-
213
-    /**
214
-     * Overrides parent ot also check by the slug
215
-     * @see EEM_Base::ensure_is_obj()
216
-     * @param string|int|EE_Payment_Method $base_class_obj_or_id
217
-     * @param boolean                      $ensure_is_in_db
218
-     * @return EE_Payment_Method
219
-     * @throws EE_Error
220
-     */
221
-    public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
222
-    {
223
-        // first: check if it's a slug
224
-        if (is_string($base_class_obj_or_id)) {
225
-            $obj = $this->get_one_by_slug($base_class_obj_or_id);
226
-            if ($obj) {
227
-                return $obj;
228
-            }
229
-        }
230
-        // ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID)
231
-        try {
232
-            return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db);
233
-        } catch (EE_Error $e) {
234
-            // handle it outside the catch
235
-        }
236
-        throw new EE_Error(sprintf(__("'%s' is neither a Payment Method ID, slug, nor object.", "event_espresso"), $base_class_obj_or_id));
237
-    }
238
-
239
-
240
-
241
-    /**
242
-     * Gets the ID of this object, or if its a string finds the object's id
243
-     * associated with that slug
244
-     * @param mixed $base_obj_or_id_or_slug
245
-     * @return int
246
-     */
247
-    public function ensure_is_ID($base_obj_or_id_or_slug)
248
-    {
249
-        if (is_string($base_obj_or_id_or_slug)) {
250
-            // assume it's a slug
251
-            $base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug);
252
-        }
253
-        return parent::ensure_is_ID($base_obj_or_id_or_slug);
254
-    }
255
-
256
-
257
-
258
-    /**
259
-     * Verifies the button urls on all the passed payment methods have a valid button url. If not, resets them to their default.
260
-     * @param EE_Payment_Method[] $payment_methods. If NULL is provided defaults to all payment methods active in the cart
261
-     */
262
-    public function verify_button_urls($payment_methods = null)
263
-    {
264
-        $payment_methods = is_array($payment_methods) ? $payment_methods : $this->get_all_active(EEM_Payment_Method::scope_cart);
265
-        foreach ($payment_methods as $payment_method) {
266
-            try {
267
-                $current_button_url = $payment_method->button_url();
268
-                $buttons_urls_to_try = apply_filters('FHEE__EEM_Payment_Method__verify_button_urls__button_urls_to_try', array(
269
-                    'current_ssl' => str_replace("http://", "https://", $current_button_url),
270
-                    'current' => str_replace("https://", "http://", $current_button_url),
271
-                    'default_ssl' => str_replace("http://", "https://", $payment_method->type_obj()->default_button_url()),
272
-                    'default' => str_replace("https://", "http://", $payment_method->type_obj()->default_button_url()),
273
-                ));
274
-                foreach ($buttons_urls_to_try as $button_url_to_try) {
275
-                    if ((// this is the current url and it exists, regardless of SSL issues
276
-                                $button_url_to_try == $current_button_url &&
277
-                                EEH_URL::remote_file_exists(
278
-                                    $button_url_to_try,
279
-                                    array(
280
-                                            'sslverify' => false,
281
-                                            'limit_response_size' => 4095,// we don't really care for a full response, but we do want headers at least. Lets just ask for a one block
282
-                                            )
283
-                                )
284
-                            )
285
-                            ||
286
-                            (// this is NOT the current url and it exists with a working SSL cert
287
-                                $button_url_to_try != $current_button_url &&
288
-                                EEH_URL::remote_file_exists($button_url_to_try)
289
-                            ) ) {
290
-                        if ($current_button_url != $button_url_to_try) {
291
-                            $payment_method->save(array( 'PMD_button_url' => $button_url_to_try ));
292
-                            EE_Error::add_attention(sprintf(__("Payment Method %s's button url was set to %s, because the old image either didnt exist or SSL was recently enabled.", "event_espresso"), $payment_method->name(), $button_url_to_try));
293
-                        }
294
-                        // this image exists. So if wasn't set before, now it is;
295
-                        // or if it was already set, we have nothing to do
296
-                        break;
297
-                    }
298
-                }
299
-            } catch (EE_Error $e) {
300
-                $payment_method->set_active(false);
301
-            }
302
-        }
303
-    }
304
-
305
-
306
-
307
-    /**
308
-     * Overrides parent to not only turn wpdb results into EE_Payment_Method objects,
309
-     * but also verifies the payment method type of each is a usable object. If not,
310
-     * deactivate it, sets a notification, and deactivates it
311
-     *
312
-     * @param array $rows
313
-     * @return EE_Payment_Method[]
314
-     * @throws InvalidDataTypeException
315
-     */
316
-    protected function _create_objects($rows = array())
317
-    {
318
-        EE_Registry::instance()->load_lib('Payment_Method_Manager');
319
-        $payment_methods = parent::_create_objects($rows);
320
-        /* @var $payment_methods EE_Payment_Method[] */
321
-        $usable_payment_methods = array();
322
-        foreach ($payment_methods as $key => $payment_method) {
323
-            if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) {
324
-                $usable_payment_methods[ $key ] = $payment_method;
325
-                // some payment methods enqueue their scripts in EE_PMT_*::__construct
326
-                // which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue
327
-                // its scripts). but for backwards-compat we should continue to do that
328
-                $payment_method->type_obj();
329
-            } elseif ($payment_method->active()) {
330
-                // only deactivate and notify the admin if the payment is active somewhere
331
-                $payment_method->deactivate();
332
-                $payment_method->save();
333
-                do_action(
334
-                    'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method',
335
-                    $payment_method
336
-                );
337
-                new PersistentAdminNotice(
338
-                    'auto-deactivated-' . $payment_method->type(),
339
-                    sprintf(
340
-                        __(
341
-                            'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.',
342
-                            'event_espresso'
343
-                        ),
344
-                        $payment_method->admin_name(),
345
-                        '<br />',
346
-                        '<a href="' . admin_url('plugins.php') . '">',
347
-                        '</a>'
348
-                    ),
349
-                    true
350
-                );
351
-            }
352
-        }
353
-        return $usable_payment_methods;
354
-    }
355
-
356
-
357
-
358
-    /**
359
-     * Gets all the payment methods which can be used for transaction
360
-     * (according to the relations between payment methods and events, and
361
-     * the currencies used for the transaction and their relation to payment methods)
362
-     * @param EE_Transaction $transaction
363
-     * @param string    $scope @see EEM_Payment_Method::get_all_for_events
364
-     * @return EE_Payment_Method[]
365
-     */
366
-    public function get_all_for_transaction($transaction, $scope)
367
-    {
368
-        // give addons a chance to override what payment methods are chosen based on the transaction
369
-        return apply_filters(
370
-            'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods',
371
-            $this->get_all_active($scope, array( 'group_by' => 'PMD_type' )),
372
-            $transaction,
373
-            $scope
374
-        );
375
-    }
376
-
377
-
378
-    /**
379
-     * Returns the payment method used for the last payment made for a registration.
380
-     *
381
-     * Note: if an offline payment method was selected on the related transaction then this will have no payment methods returned.
382
-     * It will ONLY return a payment method for a PAYMENT recorded against the registration.
383
-     *
384
-     * @param EE_Registration|int $registration_or_reg_id  Either the EE_Registration object or the id for the registration.
385
-     * @return EE_Payment|null
386
-     */
387
-    public function get_last_used_for_registration($registration_or_reg_id)
388
-    {
389
-        $registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id);
390
-
391
-        $query_params = array(
392
-            0 => array(
393
-                'Payment.Registration.REG_ID' => $registration_id,
394
-            ),
395
-            'order_by' => array( 'Payment.PAY_ID' => 'DESC' )
396
-        );
397
-        return $this->get_one($query_params);
398
-    }
23
+	const scope_cart = 'CART';
24
+
25
+	const scope_admin = 'ADMIN';
26
+
27
+	const scope_api = 'API';
28
+
29
+	/**
30
+	 *
31
+	 * @type EEM_Payment_Method
32
+	 */
33
+	protected static $_instance = null;
34
+
35
+
36
+
37
+	/**
38
+	 * private constructor to prevent direct creation
39
+	 * @Constructor
40
+	 * @access   protected
41
+	 * @return EEM_Payment_Method
42
+	 */
43
+	protected function __construct($timezone = null)
44
+	{
45
+		$this->singlular_item = __('Payment Method', 'event_espresso');
46
+		$this->plural_item = __('Payment Methods', 'event_espresso');
47
+		$this->_tables = array( 'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID') );
48
+		$this->_fields = array(
49
+			'Payment_Method' => array(
50
+				'PMD_ID' => new EE_Primary_Key_Int_Field('PMD_ID', __("ID", 'event_espresso')),
51
+				'PMD_type' => new EE_Plain_Text_Field('PMD_type', __("Payment Method Type", 'event_espresso'), false, 'Admin_Only'),
52
+				'PMD_name' => new EE_Plain_Text_Field('PMD_name', __("Name", 'event_espresso'), false),
53
+				'PMD_desc' => new EE_Post_Content_Field('PMD_desc', __("Description", 'event_espresso'), false, ''),
54
+				'PMD_admin_name' => new EE_Plain_Text_Field('PMD_admin_name', __("Admin-Only Name", 'event_espresso'), true),
55
+				'PMD_admin_desc' => new EE_Post_Content_Field('PMD_admin_desc', __("Admin-Only Description", 'event_espresso'), true),
56
+				'PMD_slug' => new EE_Slug_Field('PMD_slug', __("Slug", 'event_espresso'), false),
57
+				'PMD_order' => new EE_Integer_Field('PMD_order', __("Order", 'event_espresso'), false, 0),
58
+				'PMD_debug_mode' => new EE_Boolean_Field('PMD_debug_mode', __("Debug Mode On?", 'event_espresso'), false, false),
59
+				'PMD_wp_user' => new EE_WP_User_Field('PMD_wp_user', __("Payment Method Creator ID", 'event_espresso'), false),
60
+				'PMD_open_by_default' => new EE_Boolean_Field('PMD_open_by_default', __("Open by Default?", 'event_espresso'), false, false), 'PMD_button_url' => new EE_Plain_Text_Field('PMD_button_url', __("Button URL", 'event_espresso'), true, ''),
61
+				'PMD_scope' => new EE_Serialized_Text_Field('PMD_scope', __("Usable From?", 'event_espresso'), false, array()), // possible values currently are 'CART','ADMIN','API'
62
+		) );
63
+		$this->_model_relations = array(
64
+			'Payment' => new EE_Has_Many_Relation(),
65
+			'Currency' => new EE_HABTM_Relation('Currency_Payment_Method'),
66
+			'Transaction' => new EE_Has_Many_Relation(),
67
+			'WP_User' => new EE_Belongs_To_Relation(),
68
+		);
69
+		parent::__construct($timezone);
70
+	}
71
+
72
+
73
+
74
+	/**
75
+	 * Gets one by the slug provided
76
+	 * @param string $slug
77
+	 * @return EE_Payment_Method
78
+	 */
79
+	public function get_one_by_slug($slug)
80
+	{
81
+		return $this->get_one(array( array( 'PMD_slug' => $slug ) ));
82
+	}
83
+
84
+
85
+
86
+	/**
87
+	 * Gets all the acceptable scopes for payment methods.
88
+	 * Keys are their names as store din the DB, and values are nice names for displaying them
89
+	 * @return array
90
+	 */
91
+	public function scopes()
92
+	{
93
+		return apply_filters(
94
+			'FHEE__EEM_Payment_Method__scopes',
95
+			array(
96
+				self::scope_cart        => __("Front-end Registration Page", 'event_espresso'),
97
+				self::scope_admin   => __("Admin Registration Page (no online processing)", 'event_espresso')
98
+			)
99
+		);
100
+	}
101
+
102
+
103
+
104
+	/**
105
+	 * Determines if this is an valid scope
106
+	 * @param string $scope like one of EEM_Payment_Method::instance()->scopes()
107
+	 * @return boolean
108
+	 */
109
+	public function is_valid_scope($scope)
110
+	{
111
+		$scopes = $this->scopes();
112
+		if (isset($scopes[ $scope ])) {
113
+			return true;
114
+		} else {
115
+			return false;
116
+		}
117
+	}
118
+
119
+
120
+
121
+	/**
122
+	 * Gets all active payment methods
123
+	 * @param string $scope one of
124
+	 * @param array  $query_params
125
+	 * @throws EE_Error
126
+	 * @return EE_Payment_Method[]
127
+	 */
128
+	public function get_all_active($scope = null, $query_params = array())
129
+	{
130
+		if (! isset($query_params['order_by']) && ! isset($query_params['order'])) {
131
+			$query_params['order_by'] = array( 'PMD_order' => 'ASC', 'PMD_ID' => 'ASC' );
132
+		}
133
+		return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params));
134
+	}
135
+
136
+	/**
137
+	 * Counts all active gateways in the specified scope
138
+	 * @param string $scope one of EEM_Payment_Method::scope_*
139
+	 * @param array $query_params
140
+	 * @return int
141
+	 */
142
+	public function count_active($scope = null, $query_params = array())
143
+	{
144
+		return $this->count($this->_get_query_params_for_all_active($scope, $query_params));
145
+	}
146
+
147
+	/**
148
+	 * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
149
+	 * argument to get all active for a given scope
150
+	 * @param string $scope one of the constants EEM_Payment_Method::scope_*
151
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
152
+	 * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
153
+	 * @throws EE_Error
154
+	 */
155
+	protected function _get_query_params_for_all_active($scope = null, $query_params = array())
156
+	{
157
+		if ($scope) {
158
+			if ($this->is_valid_scope($scope)) {
159
+				return array_replace_recursive(array( array( 'PMD_scope' => array( 'LIKE', "%$scope%" ) ) ), $query_params);
160
+			} else {
161
+				throw new EE_Error(sprintf(__("'%s' is not a valid scope for a payment method", "event_espresso"), $scope));
162
+			}
163
+		} else {
164
+			$acceptable_scopes = array();
165
+			$count = 0;
166
+			foreach ($this->scopes() as $scope_name => $desc) {
167
+				$count++;
168
+				$acceptable_scopes[ 'PMD_scope*' . $count ] = array( 'LIKE', '%' . $scope_name . '%' );
169
+			}
170
+			return array_replace_recursive(array( array( 'OR*active_scope' => $acceptable_scopes ) ), $query_params);
171
+		}
172
+	}
173
+
174
+	/**
175
+	 * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
176
+	 * argument to get all active for a given scope
177
+	 * @param string $scope one of the constants EEM_Payment_Method::scope_*
178
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
179
+	 * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
180
+	 * @throws EE_Error
181
+	 */
182
+	public function get_query_params_for_all_active($scope = null, $query_params = array())
183
+	{
184
+		return $this->_get_query_params_for_all_active($scope, $query_params);
185
+	}
186
+
187
+
188
+	/**
189
+	 * Gets one active payment method. see @get_all_active for documentation
190
+	 * @param string $scope
191
+	 * @param array  $query_params
192
+	 * @return EE_Payment_Method
193
+	 */
194
+	public function get_one_active($scope = null, $query_params = array())
195
+	{
196
+		return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params));
197
+	}
198
+
199
+
200
+
201
+	/**
202
+	 * Gets one payment method of that type, regardless of whether its active or not
203
+	 * @param string $type
204
+	 * @return EE_Payment_Method
205
+	 */
206
+	public function get_one_of_type($type)
207
+	{
208
+		return $this->get_one(array( array( 'PMD_type' => $type ) ));
209
+	}
210
+
211
+
212
+
213
+	/**
214
+	 * Overrides parent ot also check by the slug
215
+	 * @see EEM_Base::ensure_is_obj()
216
+	 * @param string|int|EE_Payment_Method $base_class_obj_or_id
217
+	 * @param boolean                      $ensure_is_in_db
218
+	 * @return EE_Payment_Method
219
+	 * @throws EE_Error
220
+	 */
221
+	public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
222
+	{
223
+		// first: check if it's a slug
224
+		if (is_string($base_class_obj_or_id)) {
225
+			$obj = $this->get_one_by_slug($base_class_obj_or_id);
226
+			if ($obj) {
227
+				return $obj;
228
+			}
229
+		}
230
+		// ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID)
231
+		try {
232
+			return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db);
233
+		} catch (EE_Error $e) {
234
+			// handle it outside the catch
235
+		}
236
+		throw new EE_Error(sprintf(__("'%s' is neither a Payment Method ID, slug, nor object.", "event_espresso"), $base_class_obj_or_id));
237
+	}
238
+
239
+
240
+
241
+	/**
242
+	 * Gets the ID of this object, or if its a string finds the object's id
243
+	 * associated with that slug
244
+	 * @param mixed $base_obj_or_id_or_slug
245
+	 * @return int
246
+	 */
247
+	public function ensure_is_ID($base_obj_or_id_or_slug)
248
+	{
249
+		if (is_string($base_obj_or_id_or_slug)) {
250
+			// assume it's a slug
251
+			$base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug);
252
+		}
253
+		return parent::ensure_is_ID($base_obj_or_id_or_slug);
254
+	}
255
+
256
+
257
+
258
+	/**
259
+	 * Verifies the button urls on all the passed payment methods have a valid button url. If not, resets them to their default.
260
+	 * @param EE_Payment_Method[] $payment_methods. If NULL is provided defaults to all payment methods active in the cart
261
+	 */
262
+	public function verify_button_urls($payment_methods = null)
263
+	{
264
+		$payment_methods = is_array($payment_methods) ? $payment_methods : $this->get_all_active(EEM_Payment_Method::scope_cart);
265
+		foreach ($payment_methods as $payment_method) {
266
+			try {
267
+				$current_button_url = $payment_method->button_url();
268
+				$buttons_urls_to_try = apply_filters('FHEE__EEM_Payment_Method__verify_button_urls__button_urls_to_try', array(
269
+					'current_ssl' => str_replace("http://", "https://", $current_button_url),
270
+					'current' => str_replace("https://", "http://", $current_button_url),
271
+					'default_ssl' => str_replace("http://", "https://", $payment_method->type_obj()->default_button_url()),
272
+					'default' => str_replace("https://", "http://", $payment_method->type_obj()->default_button_url()),
273
+				));
274
+				foreach ($buttons_urls_to_try as $button_url_to_try) {
275
+					if ((// this is the current url and it exists, regardless of SSL issues
276
+								$button_url_to_try == $current_button_url &&
277
+								EEH_URL::remote_file_exists(
278
+									$button_url_to_try,
279
+									array(
280
+											'sslverify' => false,
281
+											'limit_response_size' => 4095,// we don't really care for a full response, but we do want headers at least. Lets just ask for a one block
282
+											)
283
+								)
284
+							)
285
+							||
286
+							(// this is NOT the current url and it exists with a working SSL cert
287
+								$button_url_to_try != $current_button_url &&
288
+								EEH_URL::remote_file_exists($button_url_to_try)
289
+							) ) {
290
+						if ($current_button_url != $button_url_to_try) {
291
+							$payment_method->save(array( 'PMD_button_url' => $button_url_to_try ));
292
+							EE_Error::add_attention(sprintf(__("Payment Method %s's button url was set to %s, because the old image either didnt exist or SSL was recently enabled.", "event_espresso"), $payment_method->name(), $button_url_to_try));
293
+						}
294
+						// this image exists. So if wasn't set before, now it is;
295
+						// or if it was already set, we have nothing to do
296
+						break;
297
+					}
298
+				}
299
+			} catch (EE_Error $e) {
300
+				$payment_method->set_active(false);
301
+			}
302
+		}
303
+	}
304
+
305
+
306
+
307
+	/**
308
+	 * Overrides parent to not only turn wpdb results into EE_Payment_Method objects,
309
+	 * but also verifies the payment method type of each is a usable object. If not,
310
+	 * deactivate it, sets a notification, and deactivates it
311
+	 *
312
+	 * @param array $rows
313
+	 * @return EE_Payment_Method[]
314
+	 * @throws InvalidDataTypeException
315
+	 */
316
+	protected function _create_objects($rows = array())
317
+	{
318
+		EE_Registry::instance()->load_lib('Payment_Method_Manager');
319
+		$payment_methods = parent::_create_objects($rows);
320
+		/* @var $payment_methods EE_Payment_Method[] */
321
+		$usable_payment_methods = array();
322
+		foreach ($payment_methods as $key => $payment_method) {
323
+			if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) {
324
+				$usable_payment_methods[ $key ] = $payment_method;
325
+				// some payment methods enqueue their scripts in EE_PMT_*::__construct
326
+				// which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue
327
+				// its scripts). but for backwards-compat we should continue to do that
328
+				$payment_method->type_obj();
329
+			} elseif ($payment_method->active()) {
330
+				// only deactivate and notify the admin if the payment is active somewhere
331
+				$payment_method->deactivate();
332
+				$payment_method->save();
333
+				do_action(
334
+					'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method',
335
+					$payment_method
336
+				);
337
+				new PersistentAdminNotice(
338
+					'auto-deactivated-' . $payment_method->type(),
339
+					sprintf(
340
+						__(
341
+							'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.',
342
+							'event_espresso'
343
+						),
344
+						$payment_method->admin_name(),
345
+						'<br />',
346
+						'<a href="' . admin_url('plugins.php') . '">',
347
+						'</a>'
348
+					),
349
+					true
350
+				);
351
+			}
352
+		}
353
+		return $usable_payment_methods;
354
+	}
355
+
356
+
357
+
358
+	/**
359
+	 * Gets all the payment methods which can be used for transaction
360
+	 * (according to the relations between payment methods and events, and
361
+	 * the currencies used for the transaction and their relation to payment methods)
362
+	 * @param EE_Transaction $transaction
363
+	 * @param string    $scope @see EEM_Payment_Method::get_all_for_events
364
+	 * @return EE_Payment_Method[]
365
+	 */
366
+	public function get_all_for_transaction($transaction, $scope)
367
+	{
368
+		// give addons a chance to override what payment methods are chosen based on the transaction
369
+		return apply_filters(
370
+			'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods',
371
+			$this->get_all_active($scope, array( 'group_by' => 'PMD_type' )),
372
+			$transaction,
373
+			$scope
374
+		);
375
+	}
376
+
377
+
378
+	/**
379
+	 * Returns the payment method used for the last payment made for a registration.
380
+	 *
381
+	 * Note: if an offline payment method was selected on the related transaction then this will have no payment methods returned.
382
+	 * It will ONLY return a payment method for a PAYMENT recorded against the registration.
383
+	 *
384
+	 * @param EE_Registration|int $registration_or_reg_id  Either the EE_Registration object or the id for the registration.
385
+	 * @return EE_Payment|null
386
+	 */
387
+	public function get_last_used_for_registration($registration_or_reg_id)
388
+	{
389
+		$registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id);
390
+
391
+		$query_params = array(
392
+			0 => array(
393
+				'Payment.Registration.REG_ID' => $registration_id,
394
+			),
395
+			'order_by' => array( 'Payment.PAY_ID' => 'DESC' )
396
+		);
397
+		return $this->get_one($query_params);
398
+	}
399 399
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 3 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -723,7 +723,7 @@  discard block
 block discarded – undo
723 723
      * @since 4.9.74.p
724 724
      * @param $model
725 725
      * @param $results_so_far
726
-     * @param $protected
726
+     * @param boolean $protected
727 727
      * @return array results
728 728
      */
729 729
     protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
@@ -1262,7 +1262,7 @@  discard block
 block discarded – undo
1262 1262
      * Also, this method's contents might be candidate for moving to Model_Data_Translator
1263 1263
      *
1264 1264
      * @param EEM_Base $model
1265
-     * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1265
+     * @param array    $query_params  from $_GET parameter @see Read:handle_request_get_all
1266 1266
      * @return array model query params (@see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1267 1267
      *                                    or FALSE to indicate that absolutely no results should be returned
1268 1268
      * @throws EE_Error
@@ -1519,7 +1519,7 @@  discard block
 block discarded – undo
1519 1519
      *
1520 1520
      * @param EEM_Base $model
1521 1521
      * @param WP_REST_Request $request
1522
-     * @param null $context
1522
+     * @param string $context
1523 1523
      * @return array
1524 1524
      * @throws EE_Error
1525 1525
      */
Please login to merge, or discard this patch.
Indentation   +1554 added lines, -1554 removed lines patch added patch discarded remove patch
@@ -45,1558 +45,1558 @@
 block discarded – undo
45 45
 {
46 46
 
47 47
 
48
-    /**
49
-     * @var CalculatedModelFields
50
-     */
51
-    protected $fields_calculator;
52
-
53
-
54
-    /**
55
-     * Read constructor.
56
-     * @param CalculatedModelFields $fields_calculator
57
-     */
58
-    public function __construct(CalculatedModelFields $fields_calculator)
59
-    {
60
-        parent::__construct();
61
-        $this->fields_calculator = $fields_calculator;
62
-    }
63
-
64
-
65
-    /**
66
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
67
-     *
68
-     * @param WP_REST_Request $request
69
-     * @param string $version
70
-     * @param string $model_name
71
-     * @return WP_REST_Response|WP_Error
72
-     * @throws InvalidArgumentException
73
-     * @throws InvalidDataTypeException
74
-     * @throws InvalidInterfaceException
75
-     */
76
-    public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
77
-    {
78
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
79
-        try {
80
-            $controller->setRequestedVersion($version);
81
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
82
-                return $controller->sendResponse(
83
-                    new WP_Error(
84
-                        'endpoint_parsing_error',
85
-                        sprintf(
86
-                            __(
87
-                                'There is no model for endpoint %s. Please contact event espresso support',
88
-                                'event_espresso'
89
-                            ),
90
-                            $model_name
91
-                        )
92
-                    )
93
-                );
94
-            }
95
-            return $controller->sendResponse(
96
-                $controller->getEntitiesFromModel(
97
-                    $controller->getModelVersionInfo()->loadModel($model_name),
98
-                    $request
99
-                )
100
-            );
101
-        } catch (Exception $e) {
102
-            return $controller->sendResponse($e);
103
-        }
104
-    }
105
-
106
-
107
-    /**
108
-     * Prepares and returns schema for any OPTIONS request.
109
-     *
110
-     * @param string $version The API endpoint version being used.
111
-     * @param string $model_name Something like `Event` or `Registration`
112
-     * @return array
113
-     * @throws InvalidArgumentException
114
-     * @throws InvalidDataTypeException
115
-     * @throws InvalidInterfaceException
116
-     */
117
-    public static function handleSchemaRequest($version, $model_name)
118
-    {
119
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
120
-        try {
121
-            $controller->setRequestedVersion($version);
122
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
123
-                return array();
124
-            }
125
-            // get the model for this version
126
-            $model = $controller->getModelVersionInfo()->loadModel($model_name);
127
-            $model_schema = new JsonModelSchema($model, LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields'));
128
-            return $model_schema->getModelSchemaForRelations(
129
-                $controller->getModelVersionInfo()->relationSettings($model),
130
-                $controller->customizeSchemaForRestResponse(
131
-                    $model,
132
-                    $model_schema->getModelSchemaForFields(
133
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
134
-                        $model_schema->getInitialSchemaStructure()
135
-                    )
136
-                )
137
-            );
138
-        } catch (Exception $e) {
139
-            return array();
140
-        }
141
-    }
142
-
143
-
144
-    /**
145
-     * This loops through each field in the given schema for the model and does the following:
146
-     * - add any extra fields that are REST API specific and related to existing fields.
147
-     * - transform default values into the correct format for a REST API response.
148
-     *
149
-     * @param EEM_Base $model
150
-     * @param array    $schema
151
-     * @return array  The final schema.
152
-     */
153
-    protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
154
-    {
155
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
156
-            $schema = $this->translateDefaultsForRestResponse(
157
-                $field_name,
158
-                $field,
159
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
160
-            );
161
-        }
162
-        return $schema;
163
-    }
164
-
165
-
166
-    /**
167
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
168
-     * response.
169
-     *
170
-     * @param                      $field_name
171
-     * @param EE_Model_Field_Base  $field
172
-     * @param array                $schema
173
-     * @return array
174
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
175
-     * did, let's know about it ASAP, so let the exception bubble up)
176
-     */
177
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
178
-    {
179
-        if (isset($schema['properties'][ $field_name ]['default'])) {
180
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
181
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
182
-                    if ($default_key === 'raw') {
183
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
184
-                            ModelDataTranslator::prepareFieldValueForJson(
185
-                                $field,
186
-                                $default_value,
187
-                                $this->getModelVersionInfo()->requestedVersion()
188
-                            );
189
-                    }
190
-                }
191
-            } else {
192
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
193
-                    $field,
194
-                    $schema['properties'][ $field_name ]['default'],
195
-                    $this->getModelVersionInfo()->requestedVersion()
196
-                );
197
-            }
198
-        }
199
-        return $schema;
200
-    }
201
-
202
-
203
-    /**
204
-     * Adds additional fields to the schema
205
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
206
-     * needs to be added to the schema.
207
-     *
208
-     * @param                      $field_name
209
-     * @param EE_Model_Field_Base  $field
210
-     * @param array                $schema
211
-     * @return array
212
-     */
213
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
214
-    {
215
-        if ($field instanceof EE_Datetime_Field) {
216
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
217
-            // modify the description
218
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
219
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
220
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
221
-            );
222
-        }
223
-        return $schema;
224
-    }
225
-
226
-
227
-    /**
228
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
229
-     *
230
-     * @return string
231
-     */
232
-    protected function getRouteFromRequest()
233
-    {
234
-        if (isset($GLOBALS['wp'])
235
-            && $GLOBALS['wp'] instanceof \WP
236
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
237
-        ) {
238
-            return $GLOBALS['wp']->query_vars['rest_route'];
239
-        } else {
240
-            return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
241
-        }
242
-    }
243
-
244
-
245
-    /**
246
-     * Gets a single entity related to the model indicated in the path and its id
247
-     *
248
-     * @param WP_REST_Request $request
249
-     * @param string $version
250
-     * @param string $model_name
251
-     * @return WP_REST_Response|WP_Error
252
-     * @throws InvalidDataTypeException
253
-     * @throws InvalidInterfaceException
254
-     * @throws InvalidArgumentException
255
-     */
256
-    public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
257
-    {
258
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
259
-        try {
260
-            $controller->setRequestedVersion($version);
261
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
262
-                return $controller->sendResponse(
263
-                    new WP_Error(
264
-                        'endpoint_parsing_error',
265
-                        sprintf(
266
-                            __(
267
-                                'There is no model for endpoint %s. Please contact event espresso support',
268
-                                'event_espresso'
269
-                            ),
270
-                            $model_name
271
-                        )
272
-                    )
273
-                );
274
-            }
275
-            return $controller->sendResponse(
276
-                $controller->getEntityFromModel(
277
-                    $controller->getModelVersionInfo()->loadModel($model_name),
278
-                    $request
279
-                )
280
-            );
281
-        } catch (Exception $e) {
282
-            return $controller->sendResponse($e);
283
-        }
284
-    }
285
-
286
-
287
-    /**
288
-     * Gets all the related entities (or if its a belongs-to relation just the one)
289
-     * to the item with the given id
290
-     *
291
-     * @param WP_REST_Request $request
292
-     * @param string $version
293
-     * @param string $model_name
294
-     * @param string $related_model_name
295
-     * @return WP_REST_Response|WP_Error
296
-     * @throws InvalidDataTypeException
297
-     * @throws InvalidInterfaceException
298
-     * @throws InvalidArgumentException
299
-     */
300
-    public static function handleRequestGetRelated(
301
-        WP_REST_Request $request,
302
-        $version,
303
-        $model_name,
304
-        $related_model_name
305
-    ) {
306
-        $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
307
-        try {
308
-            $controller->setRequestedVersion($version);
309
-            $main_model = $controller->validateModel($model_name);
310
-            $controller->validateModel($related_model_name);
311
-            return $controller->sendResponse(
312
-                $controller->getEntitiesFromRelation(
313
-                    $request->get_param('id'),
314
-                    $main_model->related_settings_for($related_model_name),
315
-                    $request
316
-                )
317
-            );
318
-        } catch (Exception $e) {
319
-            return $controller->sendResponse($e);
320
-        }
321
-    }
322
-
323
-
324
-    /**
325
-     * Gets a collection for the given model and filters
326
-     *
327
-     * @param EEM_Base $model
328
-     * @param WP_REST_Request $request
329
-     * @return array
330
-     * @throws EE_Error
331
-     * @throws InvalidArgumentException
332
-     * @throws InvalidDataTypeException
333
-     * @throws InvalidInterfaceException
334
-     * @throws ReflectionException
335
-     * @throws RestException
336
-     */
337
-    public function getEntitiesFromModel($model, $request)
338
-    {
339
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
340
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
341
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
342
-            throw new RestException(
343
-                sprintf('rest_%s_cannot_list', $model_name_plural),
344
-                sprintf(
345
-                    __('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
346
-                    $model_name_plural,
347
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
348
-                ),
349
-                array('status' => 403)
350
-            );
351
-        }
352
-        if (! $request->get_header('no_rest_headers')) {
353
-            $this->setHeadersFromQueryParams($model, $query_params);
354
-        }
355
-        /** @type array $results */
356
-        $results = $model->get_all_wpdb_results($query_params);
357
-        $nice_results = array();
358
-        foreach ($results as $result) {
359
-            $nice_results[] =  $this->createEntityFromWpdbResult(
360
-                $model,
361
-                $result,
362
-                $request
363
-            );
364
-        }
365
-        return $nice_results;
366
-    }
367
-
368
-
369
-    /**
370
-     * Gets the collection for given relation object
371
-     * The same as Read::get_entities_from_model(), except if the relation
372
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
373
-     * the join-model-object into the results
374
-     *
375
-     * @param array $primary_model_query_params query params for finding the item from which
376
-     *                                                            relations will be based
377
-     * @param \EE_Model_Relation_Base $relation
378
-     * @param WP_REST_Request $request
379
-     * @return array
380
-     * @throws EE_Error
381
-     * @throws InvalidArgumentException
382
-     * @throws InvalidDataTypeException
383
-     * @throws InvalidInterfaceException
384
-     * @throws ReflectionException
385
-     * @throws RestException
386
-     * @throws \EventEspresso\core\exceptions\ModelConfigurationException
387
-     */
388
-    protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
389
-    {
390
-        $context = $this->validateContext($request->get_param('caps'));
391
-        $model = $relation->get_this_model();
392
-        $related_model = $relation->get_other_model();
393
-        if (! isset($primary_model_query_params[0])) {
394
-            $primary_model_query_params[0] = array();
395
-        }
396
-        // check if they can access the 1st model object
397
-        $primary_model_query_params = array(
398
-            0       => $primary_model_query_params[0],
399
-            'limit' => 1,
400
-        );
401
-        if ($model instanceof EEM_Soft_Delete_Base) {
402
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
403
-                $primary_model_query_params
404
-            );
405
-        }
406
-        $restricted_query_params = $primary_model_query_params;
407
-        $restricted_query_params['caps'] = $context;
408
-        $restricted_query_params['limit'] = 1;
409
-        $this->setDebugInfo('main model query params', $restricted_query_params);
410
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
411
-        $primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
412
-        $primary_model_row = null;
413
-        if (is_array($primary_model_rows)) {
414
-            $primary_model_row = reset($primary_model_rows);
415
-        }
416
-        if (! (
417
-            Capabilities::currentUserHasPartialAccessTo($related_model, $context)
418
-            && $primary_model_row
419
-        )
420
-        ) {
421
-            if ($relation instanceof EE_Belongs_To_Relation) {
422
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
423
-            } else {
424
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
425
-                    $related_model->get_this_model_name()
426
-                );
427
-            }
428
-            throw new RestException(
429
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
430
-                sprintf(
431
-                    __(
432
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
433
-                        'event_espresso'
434
-                    ),
435
-                    $related_model_name_maybe_plural,
436
-                    $relation->get_this_model()->get_this_model_name(),
437
-                    implode(
438
-                        ',',
439
-                        array_keys(
440
-                            Capabilities::getMissingPermissions($related_model, $context)
441
-                        )
442
-                    )
443
-                ),
444
-                array('status' => 403)
445
-            );
446
-        }
447
-
448
-        $this->checkPassword(
449
-            $model,
450
-            $primary_model_row,
451
-            $restricted_query_params,
452
-            $request
453
-        );
454
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
455
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
456
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
457
-                              . '.'
458
-                              . $where_condition_key ] = $where_condition_value;
459
-        }
460
-        $query_params['default_where_conditions'] = 'none';
461
-        $query_params['caps'] = $context;
462
-        if (! $request->get_header('no_rest_headers')) {
463
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
464
-        }
465
-        /** @type array $results */
466
-        $results = $relation->get_other_model()->get_all_wpdb_results($query_params);
467
-        $nice_results = array();
468
-        foreach ($results as $result) {
469
-            $nice_result = $this->createEntityFromWpdbResult(
470
-                $relation->get_other_model(),
471
-                $result,
472
-                $request
473
-            );
474
-            if ($relation instanceof \EE_HABTM_Relation) {
475
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
476
-                // if there are conflicts we prefer the properties from the main model
477
-                $join_model_result = $this->createEntityFromWpdbResult(
478
-                    $relation->get_join_model(),
479
-                    $result,
480
-                    $request
481
-                );
482
-                $joined_result = array_merge($nice_result, $join_model_result);
483
-                // but keep the meta stuff from the main model
484
-                if (isset($nice_result['meta'])) {
485
-                    $joined_result['meta'] = $nice_result['meta'];
486
-                }
487
-                $nice_result = $joined_result;
488
-            }
489
-            $nice_results[] = $nice_result;
490
-        }
491
-        if ($relation instanceof EE_Belongs_To_Relation) {
492
-            return array_shift($nice_results);
493
-        } else {
494
-            return $nice_results;
495
-        }
496
-    }
497
-
498
-
499
-    /**
500
-     * Gets the collection for given relation object
501
-     * The same as Read::get_entities_from_model(), except if the relation
502
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
503
-     * the join-model-object into the results
504
-     *
505
-     * @param string                  $id the ID of the thing we are fetching related stuff from
506
-     * @param \EE_Model_Relation_Base $relation
507
-     * @param WP_REST_Request         $request
508
-     * @return array
509
-     * @throws EE_Error
510
-     */
511
-    public function getEntitiesFromRelation($id, $relation, $request)
512
-    {
513
-        if (! $relation->get_this_model()->has_primary_key_field()) {
514
-            throw new EE_Error(
515
-                sprintf(
516
-                    __(
517
-                    // @codingStandardsIgnoreStart
518
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
519
-                        // @codingStandardsIgnoreEnd
520
-                        'event_espresso'
521
-                    ),
522
-                    $relation->get_this_model()->get_this_model_name()
523
-                )
524
-            );
525
-        }
526
-        // can we edit that main item?
527
-        // if not, show nothing but an error
528
-        // otherwise, please proceed
529
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
530
-            array(
531
-                array(
532
-                    $relation->get_this_model()->primary_key_name() => $id,
533
-                ),
534
-            ),
535
-            $relation,
536
-            $request
537
-        );
538
-    }
539
-
540
-
541
-    /**
542
-     * Sets the headers that are based on the model and query params,
543
-     * like the total records. This should only be called on the original request
544
-     * from the client, not on subsequent internal
545
-     *
546
-     * @param EEM_Base $model
547
-     * @param array    $query_params
548
-     * @return void
549
-     */
550
-    protected function setHeadersFromQueryParams($model, $query_params)
551
-    {
552
-        $this->setDebugInfo('model query params', $query_params);
553
-        $this->setDebugInfo(
554
-            'missing caps',
555
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
556
-        );
557
-        // normally the limit to a 2-part array, where the 2nd item is the limit
558
-        if (! isset($query_params['limit'])) {
559
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
560
-        }
561
-        if (is_array($query_params['limit'])) {
562
-            $limit_parts = $query_params['limit'];
563
-        } else {
564
-            $limit_parts = explode(',', $query_params['limit']);
565
-            if (count($limit_parts) == 1) {
566
-                $limit_parts = array(0, $limit_parts[0]);
567
-            }
568
-        }
569
-        // remove the group by and having parts of the query, as those will
570
-        // make the sql query return an array of values, instead of just a single value
571
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
572
-        $count = $model->count($query_params, null, true);
573
-        $pages = $count / $limit_parts[1];
574
-        $this->setResponseHeader('Total', $count, false);
575
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
576
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
577
-    }
578
-
579
-
580
-    /**
581
-     * Changes database results into REST API entities
582
-     *
583
-     * @param EEM_Base $model
584
-     * @param array $db_row like results from $wpdb->get_results()
585
-     * @param WP_REST_Request $rest_request
586
-     * @param string $deprecated no longer used
587
-     * @return array ready for being converted into json for sending to client
588
-     * @throws EE_Error
589
-     * @throws RestException
590
-     * @throws InvalidDataTypeException
591
-     * @throws InvalidInterfaceException
592
-     * @throws InvalidArgumentException
593
-     * @throws ReflectionException
594
-     */
595
-    public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
596
-    {
597
-        if (! $rest_request instanceof WP_REST_Request) {
598
-            // ok so this was called in the old style, where the 3rd arg was
599
-            // $include, and the 4th arg was $context
600
-            // now setup the request just to avoid fatal errors, although we won't be able
601
-            // to truly make use of it because it's kinda devoid of info
602
-            $rest_request = new WP_REST_Request();
603
-            $rest_request->set_param('include', $rest_request);
604
-            $rest_request->set_param('caps', $deprecated);
605
-        }
606
-        if ($rest_request->get_param('caps') == null) {
607
-            $rest_request->set_param('caps', EEM_Base::caps_read);
608
-        }
609
-        $current_user_full_access_to_entity = $model->currentUserCan(
610
-            EEM_Base::caps_read_admin,
611
-            $model->deduce_fields_n_values_from_cols_n_values($db_row)
612
-        );
613
-        $entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
614
-        $entity_array = $this->addExtraFields($model, $db_row, $entity_array);
615
-        $entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
616
-        // when it's a regular read request for a model with a password and the password wasn't provided
617
-        // remove the password protected fields
618
-        $has_protected_fields = false;
619
-        try {
620
-            $this->checkPassword(
621
-                $model,
622
-                $db_row,
623
-                $model->alter_query_params_to_restrict_by_ID(
624
-                    $model->get_index_primary_key_string(
625
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
626
-                    )
627
-                ),
628
-                $rest_request
629
-            );
630
-        } catch (RestPasswordRequiredException $e) {
631
-            if ($model->hasPassword()) {
632
-                // just remove protected fields
633
-                $has_protected_fields = true;
634
-                $entity_array = Capabilities::filterOutPasswordProtectedFields(
635
-                    $entity_array,
636
-                    $model,
637
-                    $this->getModelVersionInfo()
638
-                );
639
-            } else {
640
-                // that's a problem. None of this should be accessible if no password was provided
641
-                throw $e;
642
-            }
643
-        }
644
-
645
-        $entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields);
646
-        $entity_array = apply_filters(
647
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
648
-            $entity_array,
649
-            $model,
650
-            $rest_request->get_param('caps'),
651
-            $rest_request,
652
-            $this
653
-        );
654
-        // add an empty protected property for now. If it's still around after we remove everything the request didn't
655
-        // want, we'll populate it then. k?
656
-        $entity_array['_protected'] = array();
657
-        // remove any properties the request didn't want. This way _protected won't bother mentioning them
658
-        $entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
659
-        $entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields);
660
-        // if they still wanted the _protected property, add it.
661
-        if (isset($entity_array['_protected'])) {
662
-            $entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
663
-        }
664
-        $entity_array = apply_filters(
665
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
666
-            $entity_array,
667
-            $model,
668
-            $rest_request->get_param('caps'),
669
-            $rest_request,
670
-            $this
671
-        );
672
-        if (! $current_user_full_access_to_entity) {
673
-            $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
674
-                $entity_array,
675
-                $model,
676
-                $rest_request->get_param('caps'),
677
-                $this->getModelVersionInfo()
678
-            );
679
-        } else {
680
-            $result_without_inaccessible_fields = $entity_array;
681
-        }
682
-        $this->setDebugInfo(
683
-            'inaccessible fields',
684
-            array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
685
-        );
686
-        return apply_filters(
687
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
688
-            $result_without_inaccessible_fields,
689
-            $model,
690
-            $rest_request->get_param('caps')
691
-        );
692
-    }
693
-
694
-    /**
695
-     * Returns an array describing which fields can be protected, and which actually were removed this request
696
-     * @since 4.9.74.p
697
-     * @param $model
698
-     * @param $results_so_far
699
-     * @param $protected
700
-     * @return array results
701
-     */
702
-    protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
703
-    {
704
-        if (! $model->hasPassword() || ! $protected) {
705
-            return $results_so_far;
706
-        }
707
-        $password_field = $model->getPasswordField();
708
-        $all_protected = array_merge(
709
-            array($password_field->get_name()),
710
-            $password_field->protectedFields()
711
-        );
712
-        $fields_included = array_keys($results_so_far);
713
-        $fields_included = array_intersect(
714
-            $all_protected,
715
-            $fields_included
716
-        );
717
-        foreach ($fields_included as $field_name) {
718
-            $results_so_far['_protected'][] = $field_name ;
719
-        }
720
-        return $results_so_far;
721
-    }
722
-
723
-    /**
724
-     * Creates a REST entity array (JSON object we're going to return in the response, but
725
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
726
-     * from $wpdb->get_row( $sql, ARRAY_A)
727
-     *
728
-     * @param EEM_Base $model
729
-     * @param array    $db_row
730
-     * @return array entity mostly ready for converting to JSON and sending in the response
731
-     */
732
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
733
-    {
734
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
735
-        $result = array_intersect_key(
736
-            $result,
737
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
738
-        );
739
-        // if this is a CPT, we need to set the global $post to it,
740
-        // otherwise shortcodes etc won't work properly while rendering it
741
-        if ($model instanceof \EEM_CPT_Base) {
742
-            $do_chevy_shuffle = true;
743
-        } else {
744
-            $do_chevy_shuffle = false;
745
-        }
746
-        if ($do_chevy_shuffle) {
747
-            global $post;
748
-            $old_post = $post;
749
-            $post = get_post($result[ $model->primary_key_name() ]);
750
-            if (! $post instanceof \WP_Post) {
751
-                // well that's weird, because $result is what we JUST fetched from the database
752
-                throw new RestException(
753
-                    'error_fetching_post_from_database_results',
754
-                    esc_html__(
755
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
756
-                        'event_espresso'
757
-                    )
758
-                );
759
-            }
760
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
761
-            $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
762
-                $model_object_classname,
763
-                $result,
764
-                false,
765
-                false
766
-            );
767
-        }
768
-        foreach ($result as $field_name => $field_value) {
769
-            $field_obj = $model->field_settings_for($field_name);
770
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
771
-                unset($result[ $field_name ]);
772
-            } elseif ($this->isSubclassOfOne(
773
-                $field_obj,
774
-                $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
775
-            )
776
-            ) {
777
-                $result[ $field_name ] = array(
778
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
779
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
780
-                );
781
-            } elseif ($this->isSubclassOfOne(
782
-                $field_obj,
783
-                $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
784
-            )
785
-            ) {
786
-                $result[ $field_name ] = array(
787
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
788
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
789
-                );
790
-            } elseif ($field_obj instanceof \EE_Datetime_Field) {
791
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
792
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
793
-                if (is_null($field_value)) {
794
-                    $field_value = $field_obj->getDefaultDateTimeObj();
795
-                }
796
-                if (is_null($field_value)) {
797
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
798
-                        $field_obj,
799
-                        $field_value,
800
-                        $this->getModelVersionInfo()->requestedVersion()
801
-                    );
802
-                } else {
803
-                    $timezone = $field_value->getTimezone();
804
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
805
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
806
-                        $field_obj,
807
-                        $field_value,
808
-                        $this->getModelVersionInfo()->requestedVersion()
809
-                    );
810
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
811
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
812
-                        $field_obj,
813
-                        $field_value,
814
-                        $this->getModelVersionInfo()->requestedVersion()
815
-                    );
816
-                }
817
-                $result[ $field_name . '_gmt' ] = $gmt_date;
818
-                $result[ $field_name ] = $local_date;
819
-            } else {
820
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
821
-            }
822
-        }
823
-        if ($do_chevy_shuffle) {
824
-            $post = $old_post;
825
-        }
826
-        return $result;
827
-    }
828
-
829
-
830
-    /**
831
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
832
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
833
-     * representation using $field_obj->prepare_for_set_from_db())
834
-     *
835
-     * @param EE_Model_Field_Base $field_obj
836
-     * @param mixed               $value  as it's stored on a model object
837
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
838
-     * @return mixed
839
-     * @throws ObjectDetectedException if $value contains a PHP object
840
-     */
841
-    protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
842
-    {
843
-        $value = $field_obj->prepare_for_set_from_db($value);
844
-        switch ($format) {
845
-            case 'pretty':
846
-                $value = $field_obj->prepare_for_pretty_echoing($value);
847
-                break;
848
-            case 'normal':
849
-            default:
850
-                $value = $field_obj->prepare_for_get($value);
851
-                break;
852
-        }
853
-        return ModelDataTranslator::prepareFieldValuesForJson(
854
-            $field_obj,
855
-            $value,
856
-            $this->getModelVersionInfo()->requestedVersion()
857
-        );
858
-    }
859
-
860
-
861
-    /**
862
-     * Adds a few extra fields to the entity response
863
-     *
864
-     * @param EEM_Base $model
865
-     * @param array    $db_row
866
-     * @param array    $entity_array
867
-     * @return array modified entity
868
-     */
869
-    protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
870
-    {
871
-        if ($model instanceof EEM_CPT_Base) {
872
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
873
-        }
874
-        return $entity_array;
875
-    }
876
-
877
-
878
-    /**
879
-     * Gets links we want to add to the response
880
-     *
881
-     * @global \WP_REST_Server $wp_rest_server
882
-     * @param EEM_Base         $model
883
-     * @param array            $db_row
884
-     * @param array            $entity_array
885
-     * @return array the _links item in the entity
886
-     */
887
-    protected function getEntityLinks($model, $db_row, $entity_array)
888
-    {
889
-        // add basic links
890
-        $links = array();
891
-        if ($model->has_primary_key_field()) {
892
-            $links['self'] = array(
893
-                array(
894
-                    'href' => $this->getVersionedLinkTo(
895
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
896
-                        . '/'
897
-                        . $entity_array[ $model->primary_key_name() ]
898
-                    ),
899
-                ),
900
-            );
901
-        }
902
-        $links['collection'] = array(
903
-            array(
904
-                'href' => $this->getVersionedLinkTo(
905
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
906
-                ),
907
-            ),
908
-        );
909
-        // add links to related models
910
-        if ($model->has_primary_key_field()) {
911
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
912
-                $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
913
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
914
-                    array(
915
-                        'href'   => $this->getVersionedLinkTo(
916
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
917
-                            . '/'
918
-                            . $entity_array[ $model->primary_key_name() ]
919
-                            . '/'
920
-                            . $related_model_part
921
-                        ),
922
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
923
-                    ),
924
-                );
925
-            }
926
-        }
927
-        return $links;
928
-    }
929
-
930
-
931
-    /**
932
-     * Adds the included models indicated in the request to the entity provided
933
-     *
934
-     * @param EEM_Base $model
935
-     * @param WP_REST_Request $rest_request
936
-     * @param array $entity_array
937
-     * @param array $db_row
938
-     * @param boolean $included_items_protected if the original item is password protected, don't include any related models.
939
-     * @return array the modified entity
940
-     * @throws RestException
941
-     */
942
-    protected function includeRequestedModels(
943
-        EEM_Base $model,
944
-        WP_REST_Request $rest_request,
945
-        $entity_array,
946
-        $db_row = array(),
947
-        $included_items_protected = false
948
-    ) {
949
-        // if $db_row not included, hope the entity array has what we need
950
-        if (! $db_row) {
951
-            $db_row = $entity_array;
952
-        }
953
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
954
-        foreach ($relation_settings as $relation_name => $relation_obj) {
955
-            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
956
-                $rest_request->get_param('include'),
957
-                $relation_name
958
-            );
959
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
960
-                $rest_request->get_param('calculate'),
961
-                $relation_name
962
-            );
963
-            // did they specify they wanted to include a related model, or
964
-            // specific fields from a related model?
965
-            // or did they specify to calculate a field from a related model?
966
-            if ($related_fields_to_include || $related_fields_to_calculate) {
967
-                // if so, we should include at least some part of the related model
968
-                $pretend_related_request = new WP_REST_Request();
969
-                $pretend_related_request->set_query_params(
970
-                    array(
971
-                        'caps'      => $rest_request->get_param('caps'),
972
-                        'include'   => $related_fields_to_include,
973
-                        'calculate' => $related_fields_to_calculate,
974
-                        'password' => $rest_request->get_param('password')
975
-                    )
976
-                );
977
-                $pretend_related_request->add_header('no_rest_headers', true);
978
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
979
-                    $model->get_index_primary_key_string(
980
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
981
-                    )
982
-                );
983
-                if (! $included_items_protected) {
984
-                    try {
985
-                        $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
986
-                            $primary_model_query_params,
987
-                            $relation_obj,
988
-                            $pretend_related_request
989
-                        );
990
-                    } catch (RestException $e) {
991
-                        $related_results = null;
992
-                    }
993
-                } else {
994
-                    // they're protected, hide them.
995
-                    $related_results = null;
996
-                    $entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
997
-                }
998
-                if ($related_results instanceof WP_Error || $related_results === null) {
999
-                    $related_results = $relation_obj instanceof EE_Belongs_To_Relation ? null : array();
1000
-                }
1001
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1002
-            }
1003
-        }
1004
-        return $entity_array;
1005
-    }
1006
-
1007
-    /**
1008
-     * If the user has requested only specific properties (including meta properties like _links or _protected)
1009
-     * remove everything else.
1010
-     * @since 4.9.74.p
1011
-     * @param EEM_Base $model
1012
-     * @param WP_REST_Request $rest_request
1013
-     * @param $entity_array
1014
-     * @return array
1015
-     * @throws EE_Error
1016
-     */
1017
-    protected function includeOnlyRequestedProperties(
1018
-        EEM_Base $model,
1019
-        WP_REST_Request $rest_request,
1020
-        $entity_array
1021
-    ) {
1022
-
1023
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1024
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1025
-        // if they passed in * or didn't specify any includes, return everything
1026
-        if (! in_array('*', $includes_for_this_model)
1027
-            && ! empty($includes_for_this_model)
1028
-        ) {
1029
-            if ($model->has_primary_key_field()) {
1030
-                // always include the primary key. ya just gotta know that at least
1031
-                $includes_for_this_model[] = $model->primary_key_name();
1032
-            }
1033
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1034
-                $includes_for_this_model[] = '_calculated_fields';
1035
-            }
1036
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1037
-        }
1038
-        return $entity_array;
1039
-    }
1040
-
1041
-
1042
-    /**
1043
-     * Returns a new array with all the names of models removed. Eg
1044
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1045
-     *
1046
-     * @param array $arr
1047
-     * @return array
1048
-     */
1049
-    private function removeModelNamesFromArray($arr)
1050
-    {
1051
-        return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
1052
-    }
1053
-
1054
-
1055
-    /**
1056
-     * Gets the calculated fields for the response
1057
-     *
1058
-     * @param EEM_Base        $model
1059
-     * @param array           $wpdb_row
1060
-     * @param WP_REST_Request $rest_request
1061
-     * @param boolean $row_is_protected whether this row is password protected or not
1062
-     * @return \stdClass the _calculations item in the entity
1063
-     * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
1064
-     * did, let's know about it ASAP, so let the exception bubble up)
1065
-     */
1066
-    protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false)
1067
-    {
1068
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1069
-            $rest_request->get_param('calculate'),
1070
-            ''
1071
-        );
1072
-        // note: setting calculate=* doesn't do anything
1073
-        $calculated_fields_to_return = new \stdClass();
1074
-        $protected_fields = array();
1075
-        foreach ($calculated_fields as $field_to_calculate) {
1076
-            try {
1077
-                // it's password protected, so they shouldn't be able to read this. Remove the value
1078
-                $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1079
-                if ($row_is_protected
1080
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1081
-                    && $schema['properties'][ $field_to_calculate ]['protected']) {
1082
-                    $calculated_value = null;
1083
-                    $protected_fields[] = $field_to_calculate;
1084
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1085
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1086
-                            case 'boolean':
1087
-                                $calculated_value = false;
1088
-                                break;
1089
-                            case 'integer':
1090
-                                $calculated_value = 0;
1091
-                                break;
1092
-                            case 'string':
1093
-                                $calculated_value = '';
1094
-                                break;
1095
-                            case 'array':
1096
-                                $calculated_value = array();
1097
-                                break;
1098
-                            case 'object':
1099
-                                $calculated_value = new stdClass();
1100
-                                break;
1101
-                        }
1102
-                    }
1103
-                } else {
1104
-                    $calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1105
-                        null,
1106
-                        $this->fields_calculator->retrieveCalculatedFieldValue(
1107
-                            $model,
1108
-                            $field_to_calculate,
1109
-                            $wpdb_row,
1110
-                            $rest_request,
1111
-                            $this
1112
-                        ),
1113
-                        $this->getModelVersionInfo()->requestedVersion()
1114
-                    );
1115
-                }
1116
-                $calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1117
-            } catch (RestException $e) {
1118
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
1119
-                $this->setResponseHeader(
1120
-                    'Notices-Field-Calculation-Errors['
1121
-                    . $e->getStringCode()
1122
-                    . ']['
1123
-                    . $model->get_this_model_name()
1124
-                    . ']['
1125
-                    . $field_to_calculate
1126
-                    . ']',
1127
-                    $e->getMessage(),
1128
-                    true
1129
-                );
1130
-            }
1131
-        }
1132
-        $calculated_fields_to_return->_protected = $protected_fields;
1133
-        return $calculated_fields_to_return;
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * Gets the full URL to the resource, taking the requested version into account
1139
-     *
1140
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1141
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1142
-     */
1143
-    public function getVersionedLinkTo($link_part_after_version_and_slash)
1144
-    {
1145
-        return rest_url(
1146
-            EED_Core_Rest_Api::get_versioned_route_to(
1147
-                $link_part_after_version_and_slash,
1148
-                $this->getModelVersionInfo()->requestedVersion()
1149
-            )
1150
-        );
1151
-    }
1152
-
1153
-
1154
-    /**
1155
-     * Gets the correct lowercase name for the relation in the API according
1156
-     * to the relation's type
1157
-     *
1158
-     * @param string                  $relation_name
1159
-     * @param \EE_Model_Relation_Base $relation_obj
1160
-     * @return string
1161
-     */
1162
-    public static function getRelatedEntityName($relation_name, $relation_obj)
1163
-    {
1164
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1165
-            return strtolower($relation_name);
1166
-        } else {
1167
-            return EEH_Inflector::pluralize_and_lower($relation_name);
1168
-        }
1169
-    }
1170
-
1171
-
1172
-    /**
1173
-     * Gets the one model object with the specified id for the specified model
1174
-     *
1175
-     * @param EEM_Base        $model
1176
-     * @param WP_REST_Request $request
1177
-     * @return array
1178
-     */
1179
-    public function getEntityFromModel($model, $request)
1180
-    {
1181
-        $context = $this->validateContext($request->get_param('caps'));
1182
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1183
-    }
1184
-
1185
-
1186
-    /**
1187
-     * If a context is provided which isn't valid, maybe it was added in a future
1188
-     * version so just treat it as a default read
1189
-     *
1190
-     * @param string $context
1191
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1192
-     */
1193
-    public function validateContext($context)
1194
-    {
1195
-        if (! $context) {
1196
-            $context = EEM_Base::caps_read;
1197
-        }
1198
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1199
-        if (in_array($context, $valid_contexts)) {
1200
-            return $context;
1201
-        } else {
1202
-            return EEM_Base::caps_read;
1203
-        }
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     * Verifies the passed in value is an allowable default where conditions value.
1209
-     *
1210
-     * @param $default_query_params
1211
-     * @return string
1212
-     */
1213
-    public function validateDefaultQueryParams($default_query_params)
1214
-    {
1215
-        $valid_default_where_conditions_for_api_calls = array(
1216
-            EEM_Base::default_where_conditions_all,
1217
-            EEM_Base::default_where_conditions_minimum_all,
1218
-            EEM_Base::default_where_conditions_minimum_others,
1219
-        );
1220
-        if (! $default_query_params) {
1221
-            $default_query_params = EEM_Base::default_where_conditions_all;
1222
-        }
1223
-        if (in_array(
1224
-            $default_query_params,
1225
-            $valid_default_where_conditions_for_api_calls,
1226
-            true
1227
-        )) {
1228
-            return $default_query_params;
1229
-        } else {
1230
-            return EEM_Base::default_where_conditions_all;
1231
-        }
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     * Translates API filter get parameter into model query params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1237
-     * Note: right now the query parameter keys for fields (and related fields)
1238
-     * can be left as-is, but it's quite possible this will change someday.
1239
-     * Also, this method's contents might be candidate for moving to Model_Data_Translator
1240
-     *
1241
-     * @param EEM_Base $model
1242
-     * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1243
-     * @return array model query params (@see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1244
-     *                                    or FALSE to indicate that absolutely no results should be returned
1245
-     * @throws EE_Error
1246
-     * @throws RestException
1247
-     */
1248
-    public function createModelQueryParams($model, $query_params)
1249
-    {
1250
-        $model_query_params = array();
1251
-        if (isset($query_params['where'])) {
1252
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1253
-                $query_params['where'],
1254
-                $model,
1255
-                $this->getModelVersionInfo()->requestedVersion()
1256
-            );
1257
-        }
1258
-        if (isset($query_params['order_by'])) {
1259
-            $order_by = $query_params['order_by'];
1260
-        } elseif (isset($query_params['orderby'])) {
1261
-            $order_by = $query_params['orderby'];
1262
-        } else {
1263
-            $order_by = null;
1264
-        }
1265
-        if ($order_by !== null) {
1266
-            if (is_array($order_by)) {
1267
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1268
-            } else {
1269
-                // it's a single item
1270
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1271
-            }
1272
-            $model_query_params['order_by'] = $order_by;
1273
-        }
1274
-        if (isset($query_params['group_by'])) {
1275
-            $group_by = $query_params['group_by'];
1276
-        } elseif (isset($query_params['groupby'])) {
1277
-            $group_by = $query_params['groupby'];
1278
-        } else {
1279
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1280
-        }
1281
-        // make sure they're all real names
1282
-        if (is_array($group_by)) {
1283
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1284
-        }
1285
-        if ($group_by !== null) {
1286
-            $model_query_params['group_by'] = $group_by;
1287
-        }
1288
-        if (isset($query_params['having'])) {
1289
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1290
-                $query_params['having'],
1291
-                $model,
1292
-                $this->getModelVersionInfo()->requestedVersion()
1293
-            );
1294
-        }
1295
-        if (isset($query_params['order'])) {
1296
-            $model_query_params['order'] = $query_params['order'];
1297
-        }
1298
-        if (isset($query_params['mine'])) {
1299
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1300
-        }
1301
-        if (isset($query_params['limit'])) {
1302
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1303
-            if (! is_array($query_params['limit'])) {
1304
-                $limit_array = explode(',', (string) $query_params['limit']);
1305
-            } else {
1306
-                $limit_array = $query_params['limit'];
1307
-            }
1308
-            $sanitized_limit = array();
1309
-            foreach ($limit_array as $key => $limit_part) {
1310
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1311
-                    throw new EE_Error(
1312
-                        sprintf(
1313
-                            __(
1314
-                            // @codingStandardsIgnoreStart
1315
-                                '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.',
1316
-                                // @codingStandardsIgnoreEnd
1317
-                                'event_espresso'
1318
-                            ),
1319
-                            wp_json_encode($query_params['limit'])
1320
-                        )
1321
-                    );
1322
-                }
1323
-                $sanitized_limit[] = (int) $limit_part;
1324
-            }
1325
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1326
-        } else {
1327
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1328
-        }
1329
-        if (isset($query_params['caps'])) {
1330
-            $model_query_params['caps'] = $this->validateContext($query_params['caps']);
1331
-        } else {
1332
-            $model_query_params['caps'] = EEM_Base::caps_read;
1333
-        }
1334
-        if (isset($query_params['default_where_conditions'])) {
1335
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1336
-                $query_params['default_where_conditions']
1337
-            );
1338
-        }
1339
-        // if this is a model protected by a password on another model, exclude the password protected
1340
-        // entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1341
-        // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1342
-        if (! $model->hasPassword()
1343
-            && $model->restrictedByRelatedModelPassword()
1344
-            && $model_query_params['caps'] === EEM_Base::caps_read) {
1345
-            if (empty($query_params['password'])) {
1346
-                $model_query_params['exclude_protected'] = true;
1347
-            }
1348
-        }
1349
-
1350
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1351
-    }
1352
-
1353
-
1354
-    /**
1355
-     * Changes the REST-style query params for use in the models
1356
-     *
1357
-     * @deprecated
1358
-     * @param EEM_Base $model
1359
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1360
-     * @return array
1361
-     */
1362
-    public function prepareRestQueryParamsKeyForModels($model, $query_params)
1363
-    {
1364
-        $model_ready_query_params = array();
1365
-        foreach ($query_params as $key => $value) {
1366
-            if (is_array($value)) {
1367
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1368
-            } else {
1369
-                $model_ready_query_params[ $key ] = $value;
1370
-            }
1371
-        }
1372
-        return $model_ready_query_params;
1373
-    }
1374
-
1375
-
1376
-    /**
1377
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1378
-     * @param $model
1379
-     * @param $query_params
1380
-     * @return array
1381
-     */
1382
-    public function prepareRestQueryParamsValuesForModels($model, $query_params)
1383
-    {
1384
-        $model_ready_query_params = array();
1385
-        foreach ($query_params as $key => $value) {
1386
-            if (is_array($value)) {
1387
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1388
-            } else {
1389
-                $model_ready_query_params[ $key ] = $value;
1390
-            }
1391
-        }
1392
-        return $model_ready_query_params;
1393
-    }
1394
-
1395
-
1396
-    /**
1397
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1398
-     * If no prefix is specified, returns items with no period.
1399
-     *
1400
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1401
-     * @param string       $prefix            "Event" or "foobar"
1402
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1403
-     *                                        we only return strings starting with that and a period; if no prefix was
1404
-     *                                        specified we return all items containing NO periods
1405
-     */
1406
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1407
-    {
1408
-        if (is_string($string_to_explode)) {
1409
-            $exploded_contents = explode(',', $string_to_explode);
1410
-        } elseif (is_array($string_to_explode)) {
1411
-            $exploded_contents = $string_to_explode;
1412
-        } else {
1413
-            $exploded_contents = array();
1414
-        }
1415
-        // if the string was empty, we want an empty array
1416
-        $exploded_contents = array_filter($exploded_contents);
1417
-        $contents_with_prefix = array();
1418
-        foreach ($exploded_contents as $item) {
1419
-            $item = trim($item);
1420
-            // if no prefix was provided, so we look for items with no "." in them
1421
-            if (! $prefix) {
1422
-                // does this item have a period?
1423
-                if (strpos($item, '.') === false) {
1424
-                    // if not, then its what we're looking for
1425
-                    $contents_with_prefix[] = $item;
1426
-                }
1427
-            } elseif (strpos($item, $prefix . '.') === 0) {
1428
-                // this item has the prefix and a period, grab it
1429
-                $contents_with_prefix[] = substr(
1430
-                    $item,
1431
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1432
-                );
1433
-            } elseif ($item === $prefix) {
1434
-                // this item is JUST the prefix
1435
-                // so let's grab everything after, which is a blank string
1436
-                $contents_with_prefix[] = '';
1437
-            }
1438
-        }
1439
-        return $contents_with_prefix;
1440
-    }
1441
-
1442
-
1443
-    /**
1444
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1445
-     * Deprecated because its return values were really quite confusing- sometimes it returned
1446
-     * an empty array (when the include string was blank or '*') or sometimes it returned
1447
-     * array('*') (when you provided a model and a model of that kind was found).
1448
-     * Parses the $include_string so we fetch all the field names relating to THIS model
1449
-     * (ie have NO period in them), or for the provided model (ie start with the model
1450
-     * name and then a period).
1451
-     * @param string $include_string @see Read:handle_request_get_all
1452
-     * @param string $model_name
1453
-     * @return array of fields for this model. If $model_name is provided, then
1454
-     *                               the fields for that model, with the model's name removed from each.
1455
-     *                               If $include_string was blank or '*' returns an empty array
1456
-     */
1457
-    public function extractIncludesForThisModel($include_string, $model_name = null)
1458
-    {
1459
-        if (is_array($include_string)) {
1460
-            $include_string = implode(',', $include_string);
1461
-        }
1462
-        if ($include_string === '*' || $include_string === '') {
1463
-            return array();
1464
-        }
1465
-        $includes = explode(',', $include_string);
1466
-        $extracted_fields_to_include = array();
1467
-        if ($model_name) {
1468
-            foreach ($includes as $field_to_include) {
1469
-                $field_to_include = trim($field_to_include);
1470
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1471
-                    // found the model name at the exact start
1472
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1473
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1474
-                } elseif ($field_to_include == $model_name) {
1475
-                    $extracted_fields_to_include[] = '*';
1476
-                }
1477
-            }
1478
-        } else {
1479
-            // look for ones with no period
1480
-            foreach ($includes as $field_to_include) {
1481
-                $field_to_include = trim($field_to_include);
1482
-                if (strpos($field_to_include, '.') === false
1483
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1484
-                ) {
1485
-                    $extracted_fields_to_include[] = $field_to_include;
1486
-                }
1487
-            }
1488
-        }
1489
-        return $extracted_fields_to_include;
1490
-    }
1491
-
1492
-
1493
-    /**
1494
-     * Gets the single item using the model according to the request in the context given, otherwise
1495
-     * returns that it's inaccessible to the current user
1496
-     *
1497
-     * @param EEM_Base $model
1498
-     * @param WP_REST_Request $request
1499
-     * @param null $context
1500
-     * @return array
1501
-     * @throws EE_Error
1502
-     */
1503
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1504
-    {
1505
-        $query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1506
-        if ($model instanceof EEM_Soft_Delete_Base) {
1507
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1508
-        }
1509
-        $restricted_query_params = $query_params;
1510
-        $restricted_query_params['caps'] = $context;
1511
-        $this->setDebugInfo('model query params', $restricted_query_params);
1512
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1513
-        if (! empty($model_rows)) {
1514
-            return $this->createEntityFromWpdbResult(
1515
-                $model,
1516
-                reset($model_rows),
1517
-                $request
1518
-            );
1519
-        } else {
1520
-            // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1521
-            $lowercase_model_name = strtolower($model->get_this_model_name());
1522
-            if ($model->exists($query_params)) {
1523
-                // you got shafted- it existed but we didn't want to tell you!
1524
-                throw new RestException(
1525
-                    'rest_user_cannot_' . $context,
1526
-                    sprintf(
1527
-                        __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1528
-                        $context,
1529
-                        $lowercase_model_name,
1530
-                        Capabilities::getMissingPermissionsString(
1531
-                            $model,
1532
-                            $context
1533
-                        )
1534
-                    ),
1535
-                    array('status' => 403)
1536
-                );
1537
-            } else {
1538
-                // it's not you. It just doesn't exist
1539
-                throw new RestException(
1540
-                    sprintf('rest_%s_invalid_id', $lowercase_model_name),
1541
-                    sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1542
-                    array('status' => 404)
1543
-                );
1544
-            }
1545
-        }
1546
-    }
1547
-
1548
-    /**
1549
-     * Checks that if this content requires a password to be read, that it's been provided and is correct.
1550
-     * @since 4.9.74.p
1551
-     * @param EEM_Base $model
1552
-     * @param $model_row
1553
-     * @param $query_params Adds 'default_where_conditions' => 'minimum' to ensure we don't confuse trashed with
1554
-     *                      password protected.
1555
-     * @param WP_REST_Request $request
1556
-     * @throws EE_Error
1557
-     * @throws InvalidArgumentException
1558
-     * @throws InvalidDataTypeException
1559
-     * @throws InvalidInterfaceException
1560
-     * @throws RestPasswordRequiredException
1561
-     * @throws RestPasswordIncorrectException
1562
-     * @throws \EventEspresso\core\exceptions\ModelConfigurationException
1563
-     * @throws ReflectionException
1564
-     */
1565
-    protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request)
1566
-    {
1567
-        $query_params['default_where_conditions'] = 'minimum';
1568
-        // stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1569
-        // or you don't.
1570
-        $request_caps = $request->get_param('caps');
1571
-        if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1572
-            return;
1573
-        }
1574
-        // if this entity requires a password, they better give it and it better be right!
1575
-        if ($model->hasPassword()
1576
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '') {
1577
-            if (empty($request['password'])) {
1578
-                throw new RestPasswordRequiredException();
1579
-            } elseif (!hash_equals(
1580
-                $model_row[ $model->getPasswordField()->get_qualified_column() ],
1581
-                $request['password']
1582
-            )) {
1583
-                throw new RestPasswordIncorrectException();
1584
-            }
1585
-        } // wait! maybe this content is password protected
1586
-        elseif ($model->restrictedByRelatedModelPassword()
1587
-            && $request->get_param('caps') === EEM_Base::caps_read) {
1588
-            $password_supplied = $request->get_param('password');
1589
-            if (empty($password_supplied)) {
1590
-                $query_params['exclude_protected'] = true;
1591
-                if (!$model->exists($query_params)) {
1592
-                    throw new RestPasswordRequiredException();
1593
-                }
1594
-            } else {
1595
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1596
-                if (!$model->exists($query_params)) {
1597
-                    throw new RestPasswordIncorrectException();
1598
-                }
1599
-            }
1600
-        }
1601
-    }
48
+	/**
49
+	 * @var CalculatedModelFields
50
+	 */
51
+	protected $fields_calculator;
52
+
53
+
54
+	/**
55
+	 * Read constructor.
56
+	 * @param CalculatedModelFields $fields_calculator
57
+	 */
58
+	public function __construct(CalculatedModelFields $fields_calculator)
59
+	{
60
+		parent::__construct();
61
+		$this->fields_calculator = $fields_calculator;
62
+	}
63
+
64
+
65
+	/**
66
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
67
+	 *
68
+	 * @param WP_REST_Request $request
69
+	 * @param string $version
70
+	 * @param string $model_name
71
+	 * @return WP_REST_Response|WP_Error
72
+	 * @throws InvalidArgumentException
73
+	 * @throws InvalidDataTypeException
74
+	 * @throws InvalidInterfaceException
75
+	 */
76
+	public static function handleRequestGetAll(WP_REST_Request $request, $version, $model_name)
77
+	{
78
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
79
+		try {
80
+			$controller->setRequestedVersion($version);
81
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
82
+				return $controller->sendResponse(
83
+					new WP_Error(
84
+						'endpoint_parsing_error',
85
+						sprintf(
86
+							__(
87
+								'There is no model for endpoint %s. Please contact event espresso support',
88
+								'event_espresso'
89
+							),
90
+							$model_name
91
+						)
92
+					)
93
+				);
94
+			}
95
+			return $controller->sendResponse(
96
+				$controller->getEntitiesFromModel(
97
+					$controller->getModelVersionInfo()->loadModel($model_name),
98
+					$request
99
+				)
100
+			);
101
+		} catch (Exception $e) {
102
+			return $controller->sendResponse($e);
103
+		}
104
+	}
105
+
106
+
107
+	/**
108
+	 * Prepares and returns schema for any OPTIONS request.
109
+	 *
110
+	 * @param string $version The API endpoint version being used.
111
+	 * @param string $model_name Something like `Event` or `Registration`
112
+	 * @return array
113
+	 * @throws InvalidArgumentException
114
+	 * @throws InvalidDataTypeException
115
+	 * @throws InvalidInterfaceException
116
+	 */
117
+	public static function handleSchemaRequest($version, $model_name)
118
+	{
119
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
120
+		try {
121
+			$controller->setRequestedVersion($version);
122
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
123
+				return array();
124
+			}
125
+			// get the model for this version
126
+			$model = $controller->getModelVersionInfo()->loadModel($model_name);
127
+			$model_schema = new JsonModelSchema($model, LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields'));
128
+			return $model_schema->getModelSchemaForRelations(
129
+				$controller->getModelVersionInfo()->relationSettings($model),
130
+				$controller->customizeSchemaForRestResponse(
131
+					$model,
132
+					$model_schema->getModelSchemaForFields(
133
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
134
+						$model_schema->getInitialSchemaStructure()
135
+					)
136
+				)
137
+			);
138
+		} catch (Exception $e) {
139
+			return array();
140
+		}
141
+	}
142
+
143
+
144
+	/**
145
+	 * This loops through each field in the given schema for the model and does the following:
146
+	 * - add any extra fields that are REST API specific and related to existing fields.
147
+	 * - transform default values into the correct format for a REST API response.
148
+	 *
149
+	 * @param EEM_Base $model
150
+	 * @param array    $schema
151
+	 * @return array  The final schema.
152
+	 */
153
+	protected function customizeSchemaForRestResponse(EEM_Base $model, array $schema)
154
+	{
155
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
156
+			$schema = $this->translateDefaultsForRestResponse(
157
+				$field_name,
158
+				$field,
159
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
160
+			);
161
+		}
162
+		return $schema;
163
+	}
164
+
165
+
166
+	/**
167
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
168
+	 * response.
169
+	 *
170
+	 * @param                      $field_name
171
+	 * @param EE_Model_Field_Base  $field
172
+	 * @param array                $schema
173
+	 * @return array
174
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
175
+	 * did, let's know about it ASAP, so let the exception bubble up)
176
+	 */
177
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
178
+	{
179
+		if (isset($schema['properties'][ $field_name ]['default'])) {
180
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
181
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
182
+					if ($default_key === 'raw') {
183
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
184
+							ModelDataTranslator::prepareFieldValueForJson(
185
+								$field,
186
+								$default_value,
187
+								$this->getModelVersionInfo()->requestedVersion()
188
+							);
189
+					}
190
+				}
191
+			} else {
192
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
193
+					$field,
194
+					$schema['properties'][ $field_name ]['default'],
195
+					$this->getModelVersionInfo()->requestedVersion()
196
+				);
197
+			}
198
+		}
199
+		return $schema;
200
+	}
201
+
202
+
203
+	/**
204
+	 * Adds additional fields to the schema
205
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
206
+	 * needs to be added to the schema.
207
+	 *
208
+	 * @param                      $field_name
209
+	 * @param EE_Model_Field_Base  $field
210
+	 * @param array                $schema
211
+	 * @return array
212
+	 */
213
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
214
+	{
215
+		if ($field instanceof EE_Datetime_Field) {
216
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
217
+			// modify the description
218
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
219
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
220
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
221
+			);
222
+		}
223
+		return $schema;
224
+	}
225
+
226
+
227
+	/**
228
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
229
+	 *
230
+	 * @return string
231
+	 */
232
+	protected function getRouteFromRequest()
233
+	{
234
+		if (isset($GLOBALS['wp'])
235
+			&& $GLOBALS['wp'] instanceof \WP
236
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
237
+		) {
238
+			return $GLOBALS['wp']->query_vars['rest_route'];
239
+		} else {
240
+			return isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
241
+		}
242
+	}
243
+
244
+
245
+	/**
246
+	 * Gets a single entity related to the model indicated in the path and its id
247
+	 *
248
+	 * @param WP_REST_Request $request
249
+	 * @param string $version
250
+	 * @param string $model_name
251
+	 * @return WP_REST_Response|WP_Error
252
+	 * @throws InvalidDataTypeException
253
+	 * @throws InvalidInterfaceException
254
+	 * @throws InvalidArgumentException
255
+	 */
256
+	public static function handleRequestGetOne(WP_REST_Request $request, $version, $model_name)
257
+	{
258
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
259
+		try {
260
+			$controller->setRequestedVersion($version);
261
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
262
+				return $controller->sendResponse(
263
+					new WP_Error(
264
+						'endpoint_parsing_error',
265
+						sprintf(
266
+							__(
267
+								'There is no model for endpoint %s. Please contact event espresso support',
268
+								'event_espresso'
269
+							),
270
+							$model_name
271
+						)
272
+					)
273
+				);
274
+			}
275
+			return $controller->sendResponse(
276
+				$controller->getEntityFromModel(
277
+					$controller->getModelVersionInfo()->loadModel($model_name),
278
+					$request
279
+				)
280
+			);
281
+		} catch (Exception $e) {
282
+			return $controller->sendResponse($e);
283
+		}
284
+	}
285
+
286
+
287
+	/**
288
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
289
+	 * to the item with the given id
290
+	 *
291
+	 * @param WP_REST_Request $request
292
+	 * @param string $version
293
+	 * @param string $model_name
294
+	 * @param string $related_model_name
295
+	 * @return WP_REST_Response|WP_Error
296
+	 * @throws InvalidDataTypeException
297
+	 * @throws InvalidInterfaceException
298
+	 * @throws InvalidArgumentException
299
+	 */
300
+	public static function handleRequestGetRelated(
301
+		WP_REST_Request $request,
302
+		$version,
303
+		$model_name,
304
+		$related_model_name
305
+	) {
306
+		$controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
307
+		try {
308
+			$controller->setRequestedVersion($version);
309
+			$main_model = $controller->validateModel($model_name);
310
+			$controller->validateModel($related_model_name);
311
+			return $controller->sendResponse(
312
+				$controller->getEntitiesFromRelation(
313
+					$request->get_param('id'),
314
+					$main_model->related_settings_for($related_model_name),
315
+					$request
316
+				)
317
+			);
318
+		} catch (Exception $e) {
319
+			return $controller->sendResponse($e);
320
+		}
321
+	}
322
+
323
+
324
+	/**
325
+	 * Gets a collection for the given model and filters
326
+	 *
327
+	 * @param EEM_Base $model
328
+	 * @param WP_REST_Request $request
329
+	 * @return array
330
+	 * @throws EE_Error
331
+	 * @throws InvalidArgumentException
332
+	 * @throws InvalidDataTypeException
333
+	 * @throws InvalidInterfaceException
334
+	 * @throws ReflectionException
335
+	 * @throws RestException
336
+	 */
337
+	public function getEntitiesFromModel($model, $request)
338
+	{
339
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
340
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
341
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
342
+			throw new RestException(
343
+				sprintf('rest_%s_cannot_list', $model_name_plural),
344
+				sprintf(
345
+					__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
346
+					$model_name_plural,
347
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
348
+				),
349
+				array('status' => 403)
350
+			);
351
+		}
352
+		if (! $request->get_header('no_rest_headers')) {
353
+			$this->setHeadersFromQueryParams($model, $query_params);
354
+		}
355
+		/** @type array $results */
356
+		$results = $model->get_all_wpdb_results($query_params);
357
+		$nice_results = array();
358
+		foreach ($results as $result) {
359
+			$nice_results[] =  $this->createEntityFromWpdbResult(
360
+				$model,
361
+				$result,
362
+				$request
363
+			);
364
+		}
365
+		return $nice_results;
366
+	}
367
+
368
+
369
+	/**
370
+	 * Gets the collection for given relation object
371
+	 * The same as Read::get_entities_from_model(), except if the relation
372
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
373
+	 * the join-model-object into the results
374
+	 *
375
+	 * @param array $primary_model_query_params query params for finding the item from which
376
+	 *                                                            relations will be based
377
+	 * @param \EE_Model_Relation_Base $relation
378
+	 * @param WP_REST_Request $request
379
+	 * @return array
380
+	 * @throws EE_Error
381
+	 * @throws InvalidArgumentException
382
+	 * @throws InvalidDataTypeException
383
+	 * @throws InvalidInterfaceException
384
+	 * @throws ReflectionException
385
+	 * @throws RestException
386
+	 * @throws \EventEspresso\core\exceptions\ModelConfigurationException
387
+	 */
388
+	protected function getEntitiesFromRelationUsingModelQueryParams($primary_model_query_params, $relation, $request)
389
+	{
390
+		$context = $this->validateContext($request->get_param('caps'));
391
+		$model = $relation->get_this_model();
392
+		$related_model = $relation->get_other_model();
393
+		if (! isset($primary_model_query_params[0])) {
394
+			$primary_model_query_params[0] = array();
395
+		}
396
+		// check if they can access the 1st model object
397
+		$primary_model_query_params = array(
398
+			0       => $primary_model_query_params[0],
399
+			'limit' => 1,
400
+		);
401
+		if ($model instanceof EEM_Soft_Delete_Base) {
402
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
403
+				$primary_model_query_params
404
+			);
405
+		}
406
+		$restricted_query_params = $primary_model_query_params;
407
+		$restricted_query_params['caps'] = $context;
408
+		$restricted_query_params['limit'] = 1;
409
+		$this->setDebugInfo('main model query params', $restricted_query_params);
410
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
411
+		$primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
412
+		$primary_model_row = null;
413
+		if (is_array($primary_model_rows)) {
414
+			$primary_model_row = reset($primary_model_rows);
415
+		}
416
+		if (! (
417
+			Capabilities::currentUserHasPartialAccessTo($related_model, $context)
418
+			&& $primary_model_row
419
+		)
420
+		) {
421
+			if ($relation instanceof EE_Belongs_To_Relation) {
422
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
423
+			} else {
424
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
425
+					$related_model->get_this_model_name()
426
+				);
427
+			}
428
+			throw new RestException(
429
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
430
+				sprintf(
431
+					__(
432
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
433
+						'event_espresso'
434
+					),
435
+					$related_model_name_maybe_plural,
436
+					$relation->get_this_model()->get_this_model_name(),
437
+					implode(
438
+						',',
439
+						array_keys(
440
+							Capabilities::getMissingPermissions($related_model, $context)
441
+						)
442
+					)
443
+				),
444
+				array('status' => 403)
445
+			);
446
+		}
447
+
448
+		$this->checkPassword(
449
+			$model,
450
+			$primary_model_row,
451
+			$restricted_query_params,
452
+			$request
453
+		);
454
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
455
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
456
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
457
+							  . '.'
458
+							  . $where_condition_key ] = $where_condition_value;
459
+		}
460
+		$query_params['default_where_conditions'] = 'none';
461
+		$query_params['caps'] = $context;
462
+		if (! $request->get_header('no_rest_headers')) {
463
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
464
+		}
465
+		/** @type array $results */
466
+		$results = $relation->get_other_model()->get_all_wpdb_results($query_params);
467
+		$nice_results = array();
468
+		foreach ($results as $result) {
469
+			$nice_result = $this->createEntityFromWpdbResult(
470
+				$relation->get_other_model(),
471
+				$result,
472
+				$request
473
+			);
474
+			if ($relation instanceof \EE_HABTM_Relation) {
475
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
476
+				// if there are conflicts we prefer the properties from the main model
477
+				$join_model_result = $this->createEntityFromWpdbResult(
478
+					$relation->get_join_model(),
479
+					$result,
480
+					$request
481
+				);
482
+				$joined_result = array_merge($nice_result, $join_model_result);
483
+				// but keep the meta stuff from the main model
484
+				if (isset($nice_result['meta'])) {
485
+					$joined_result['meta'] = $nice_result['meta'];
486
+				}
487
+				$nice_result = $joined_result;
488
+			}
489
+			$nice_results[] = $nice_result;
490
+		}
491
+		if ($relation instanceof EE_Belongs_To_Relation) {
492
+			return array_shift($nice_results);
493
+		} else {
494
+			return $nice_results;
495
+		}
496
+	}
497
+
498
+
499
+	/**
500
+	 * Gets the collection for given relation object
501
+	 * The same as Read::get_entities_from_model(), except if the relation
502
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
503
+	 * the join-model-object into the results
504
+	 *
505
+	 * @param string                  $id the ID of the thing we are fetching related stuff from
506
+	 * @param \EE_Model_Relation_Base $relation
507
+	 * @param WP_REST_Request         $request
508
+	 * @return array
509
+	 * @throws EE_Error
510
+	 */
511
+	public function getEntitiesFromRelation($id, $relation, $request)
512
+	{
513
+		if (! $relation->get_this_model()->has_primary_key_field()) {
514
+			throw new EE_Error(
515
+				sprintf(
516
+					__(
517
+					// @codingStandardsIgnoreStart
518
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
519
+						// @codingStandardsIgnoreEnd
520
+						'event_espresso'
521
+					),
522
+					$relation->get_this_model()->get_this_model_name()
523
+				)
524
+			);
525
+		}
526
+		// can we edit that main item?
527
+		// if not, show nothing but an error
528
+		// otherwise, please proceed
529
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
530
+			array(
531
+				array(
532
+					$relation->get_this_model()->primary_key_name() => $id,
533
+				),
534
+			),
535
+			$relation,
536
+			$request
537
+		);
538
+	}
539
+
540
+
541
+	/**
542
+	 * Sets the headers that are based on the model and query params,
543
+	 * like the total records. This should only be called on the original request
544
+	 * from the client, not on subsequent internal
545
+	 *
546
+	 * @param EEM_Base $model
547
+	 * @param array    $query_params
548
+	 * @return void
549
+	 */
550
+	protected function setHeadersFromQueryParams($model, $query_params)
551
+	{
552
+		$this->setDebugInfo('model query params', $query_params);
553
+		$this->setDebugInfo(
554
+			'missing caps',
555
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
556
+		);
557
+		// normally the limit to a 2-part array, where the 2nd item is the limit
558
+		if (! isset($query_params['limit'])) {
559
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
560
+		}
561
+		if (is_array($query_params['limit'])) {
562
+			$limit_parts = $query_params['limit'];
563
+		} else {
564
+			$limit_parts = explode(',', $query_params['limit']);
565
+			if (count($limit_parts) == 1) {
566
+				$limit_parts = array(0, $limit_parts[0]);
567
+			}
568
+		}
569
+		// remove the group by and having parts of the query, as those will
570
+		// make the sql query return an array of values, instead of just a single value
571
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
572
+		$count = $model->count($query_params, null, true);
573
+		$pages = $count / $limit_parts[1];
574
+		$this->setResponseHeader('Total', $count, false);
575
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
576
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
577
+	}
578
+
579
+
580
+	/**
581
+	 * Changes database results into REST API entities
582
+	 *
583
+	 * @param EEM_Base $model
584
+	 * @param array $db_row like results from $wpdb->get_results()
585
+	 * @param WP_REST_Request $rest_request
586
+	 * @param string $deprecated no longer used
587
+	 * @return array ready for being converted into json for sending to client
588
+	 * @throws EE_Error
589
+	 * @throws RestException
590
+	 * @throws InvalidDataTypeException
591
+	 * @throws InvalidInterfaceException
592
+	 * @throws InvalidArgumentException
593
+	 * @throws ReflectionException
594
+	 */
595
+	public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
596
+	{
597
+		if (! $rest_request instanceof WP_REST_Request) {
598
+			// ok so this was called in the old style, where the 3rd arg was
599
+			// $include, and the 4th arg was $context
600
+			// now setup the request just to avoid fatal errors, although we won't be able
601
+			// to truly make use of it because it's kinda devoid of info
602
+			$rest_request = new WP_REST_Request();
603
+			$rest_request->set_param('include', $rest_request);
604
+			$rest_request->set_param('caps', $deprecated);
605
+		}
606
+		if ($rest_request->get_param('caps') == null) {
607
+			$rest_request->set_param('caps', EEM_Base::caps_read);
608
+		}
609
+		$current_user_full_access_to_entity = $model->currentUserCan(
610
+			EEM_Base::caps_read_admin,
611
+			$model->deduce_fields_n_values_from_cols_n_values($db_row)
612
+		);
613
+		$entity_array = $this->createBareEntityFromWpdbResults($model, $db_row);
614
+		$entity_array = $this->addExtraFields($model, $db_row, $entity_array);
615
+		$entity_array['_links'] = $this->getEntityLinks($model, $db_row, $entity_array);
616
+		// when it's a regular read request for a model with a password and the password wasn't provided
617
+		// remove the password protected fields
618
+		$has_protected_fields = false;
619
+		try {
620
+			$this->checkPassword(
621
+				$model,
622
+				$db_row,
623
+				$model->alter_query_params_to_restrict_by_ID(
624
+					$model->get_index_primary_key_string(
625
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
626
+					)
627
+				),
628
+				$rest_request
629
+			);
630
+		} catch (RestPasswordRequiredException $e) {
631
+			if ($model->hasPassword()) {
632
+				// just remove protected fields
633
+				$has_protected_fields = true;
634
+				$entity_array = Capabilities::filterOutPasswordProtectedFields(
635
+					$entity_array,
636
+					$model,
637
+					$this->getModelVersionInfo()
638
+				);
639
+			} else {
640
+				// that's a problem. None of this should be accessible if no password was provided
641
+				throw $e;
642
+			}
643
+		}
644
+
645
+		$entity_array['_calculated_fields'] = $this->getEntityCalculations($model, $db_row, $rest_request, $has_protected_fields);
646
+		$entity_array = apply_filters(
647
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
648
+			$entity_array,
649
+			$model,
650
+			$rest_request->get_param('caps'),
651
+			$rest_request,
652
+			$this
653
+		);
654
+		// add an empty protected property for now. If it's still around after we remove everything the request didn't
655
+		// want, we'll populate it then. k?
656
+		$entity_array['_protected'] = array();
657
+		// remove any properties the request didn't want. This way _protected won't bother mentioning them
658
+		$entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
659
+		$entity_array = $this->includeRequestedModels($model, $rest_request, $entity_array, $db_row, $has_protected_fields);
660
+		// if they still wanted the _protected property, add it.
661
+		if (isset($entity_array['_protected'])) {
662
+			$entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
663
+		}
664
+		$entity_array = apply_filters(
665
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
666
+			$entity_array,
667
+			$model,
668
+			$rest_request->get_param('caps'),
669
+			$rest_request,
670
+			$this
671
+		);
672
+		if (! $current_user_full_access_to_entity) {
673
+			$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
674
+				$entity_array,
675
+				$model,
676
+				$rest_request->get_param('caps'),
677
+				$this->getModelVersionInfo()
678
+			);
679
+		} else {
680
+			$result_without_inaccessible_fields = $entity_array;
681
+		}
682
+		$this->setDebugInfo(
683
+			'inaccessible fields',
684
+			array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
685
+		);
686
+		return apply_filters(
687
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
688
+			$result_without_inaccessible_fields,
689
+			$model,
690
+			$rest_request->get_param('caps')
691
+		);
692
+	}
693
+
694
+	/**
695
+	 * Returns an array describing which fields can be protected, and which actually were removed this request
696
+	 * @since 4.9.74.p
697
+	 * @param $model
698
+	 * @param $results_so_far
699
+	 * @param $protected
700
+	 * @return array results
701
+	 */
702
+	protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
703
+	{
704
+		if (! $model->hasPassword() || ! $protected) {
705
+			return $results_so_far;
706
+		}
707
+		$password_field = $model->getPasswordField();
708
+		$all_protected = array_merge(
709
+			array($password_field->get_name()),
710
+			$password_field->protectedFields()
711
+		);
712
+		$fields_included = array_keys($results_so_far);
713
+		$fields_included = array_intersect(
714
+			$all_protected,
715
+			$fields_included
716
+		);
717
+		foreach ($fields_included as $field_name) {
718
+			$results_so_far['_protected'][] = $field_name ;
719
+		}
720
+		return $results_so_far;
721
+	}
722
+
723
+	/**
724
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
725
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
726
+	 * from $wpdb->get_row( $sql, ARRAY_A)
727
+	 *
728
+	 * @param EEM_Base $model
729
+	 * @param array    $db_row
730
+	 * @return array entity mostly ready for converting to JSON and sending in the response
731
+	 */
732
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, $db_row)
733
+	{
734
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
735
+		$result = array_intersect_key(
736
+			$result,
737
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
738
+		);
739
+		// if this is a CPT, we need to set the global $post to it,
740
+		// otherwise shortcodes etc won't work properly while rendering it
741
+		if ($model instanceof \EEM_CPT_Base) {
742
+			$do_chevy_shuffle = true;
743
+		} else {
744
+			$do_chevy_shuffle = false;
745
+		}
746
+		if ($do_chevy_shuffle) {
747
+			global $post;
748
+			$old_post = $post;
749
+			$post = get_post($result[ $model->primary_key_name() ]);
750
+			if (! $post instanceof \WP_Post) {
751
+				// well that's weird, because $result is what we JUST fetched from the database
752
+				throw new RestException(
753
+					'error_fetching_post_from_database_results',
754
+					esc_html__(
755
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
756
+						'event_espresso'
757
+					)
758
+				);
759
+			}
760
+			$model_object_classname = 'EE_' . $model->get_this_model_name();
761
+			$post->{$model_object_classname} = \EE_Registry::instance()->load_class(
762
+				$model_object_classname,
763
+				$result,
764
+				false,
765
+				false
766
+			);
767
+		}
768
+		foreach ($result as $field_name => $field_value) {
769
+			$field_obj = $model->field_settings_for($field_name);
770
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
771
+				unset($result[ $field_name ]);
772
+			} elseif ($this->isSubclassOfOne(
773
+				$field_obj,
774
+				$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
775
+			)
776
+			) {
777
+				$result[ $field_name ] = array(
778
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
779
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
780
+				);
781
+			} elseif ($this->isSubclassOfOne(
782
+				$field_obj,
783
+				$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
784
+			)
785
+			) {
786
+				$result[ $field_name ] = array(
787
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
788
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
789
+				);
790
+			} elseif ($field_obj instanceof \EE_Datetime_Field) {
791
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
792
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
793
+				if (is_null($field_value)) {
794
+					$field_value = $field_obj->getDefaultDateTimeObj();
795
+				}
796
+				if (is_null($field_value)) {
797
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
798
+						$field_obj,
799
+						$field_value,
800
+						$this->getModelVersionInfo()->requestedVersion()
801
+					);
802
+				} else {
803
+					$timezone = $field_value->getTimezone();
804
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
805
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
806
+						$field_obj,
807
+						$field_value,
808
+						$this->getModelVersionInfo()->requestedVersion()
809
+					);
810
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
811
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
812
+						$field_obj,
813
+						$field_value,
814
+						$this->getModelVersionInfo()->requestedVersion()
815
+					);
816
+				}
817
+				$result[ $field_name . '_gmt' ] = $gmt_date;
818
+				$result[ $field_name ] = $local_date;
819
+			} else {
820
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
821
+			}
822
+		}
823
+		if ($do_chevy_shuffle) {
824
+			$post = $old_post;
825
+		}
826
+		return $result;
827
+	}
828
+
829
+
830
+	/**
831
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
832
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
833
+	 * representation using $field_obj->prepare_for_set_from_db())
834
+	 *
835
+	 * @param EE_Model_Field_Base $field_obj
836
+	 * @param mixed               $value  as it's stored on a model object
837
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
838
+	 * @return mixed
839
+	 * @throws ObjectDetectedException if $value contains a PHP object
840
+	 */
841
+	protected function prepareFieldObjValueForJson(EE_Model_Field_Base $field_obj, $value, $format = 'normal')
842
+	{
843
+		$value = $field_obj->prepare_for_set_from_db($value);
844
+		switch ($format) {
845
+			case 'pretty':
846
+				$value = $field_obj->prepare_for_pretty_echoing($value);
847
+				break;
848
+			case 'normal':
849
+			default:
850
+				$value = $field_obj->prepare_for_get($value);
851
+				break;
852
+		}
853
+		return ModelDataTranslator::prepareFieldValuesForJson(
854
+			$field_obj,
855
+			$value,
856
+			$this->getModelVersionInfo()->requestedVersion()
857
+		);
858
+	}
859
+
860
+
861
+	/**
862
+	 * Adds a few extra fields to the entity response
863
+	 *
864
+	 * @param EEM_Base $model
865
+	 * @param array    $db_row
866
+	 * @param array    $entity_array
867
+	 * @return array modified entity
868
+	 */
869
+	protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
870
+	{
871
+		if ($model instanceof EEM_CPT_Base) {
872
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
873
+		}
874
+		return $entity_array;
875
+	}
876
+
877
+
878
+	/**
879
+	 * Gets links we want to add to the response
880
+	 *
881
+	 * @global \WP_REST_Server $wp_rest_server
882
+	 * @param EEM_Base         $model
883
+	 * @param array            $db_row
884
+	 * @param array            $entity_array
885
+	 * @return array the _links item in the entity
886
+	 */
887
+	protected function getEntityLinks($model, $db_row, $entity_array)
888
+	{
889
+		// add basic links
890
+		$links = array();
891
+		if ($model->has_primary_key_field()) {
892
+			$links['self'] = array(
893
+				array(
894
+					'href' => $this->getVersionedLinkTo(
895
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
896
+						. '/'
897
+						. $entity_array[ $model->primary_key_name() ]
898
+					),
899
+				),
900
+			);
901
+		}
902
+		$links['collection'] = array(
903
+			array(
904
+				'href' => $this->getVersionedLinkTo(
905
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
906
+				),
907
+			),
908
+		);
909
+		// add links to related models
910
+		if ($model->has_primary_key_field()) {
911
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
912
+				$related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
913
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
914
+					array(
915
+						'href'   => $this->getVersionedLinkTo(
916
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
917
+							. '/'
918
+							. $entity_array[ $model->primary_key_name() ]
919
+							. '/'
920
+							. $related_model_part
921
+						),
922
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation ? true : false,
923
+					),
924
+				);
925
+			}
926
+		}
927
+		return $links;
928
+	}
929
+
930
+
931
+	/**
932
+	 * Adds the included models indicated in the request to the entity provided
933
+	 *
934
+	 * @param EEM_Base $model
935
+	 * @param WP_REST_Request $rest_request
936
+	 * @param array $entity_array
937
+	 * @param array $db_row
938
+	 * @param boolean $included_items_protected if the original item is password protected, don't include any related models.
939
+	 * @return array the modified entity
940
+	 * @throws RestException
941
+	 */
942
+	protected function includeRequestedModels(
943
+		EEM_Base $model,
944
+		WP_REST_Request $rest_request,
945
+		$entity_array,
946
+		$db_row = array(),
947
+		$included_items_protected = false
948
+	) {
949
+		// if $db_row not included, hope the entity array has what we need
950
+		if (! $db_row) {
951
+			$db_row = $entity_array;
952
+		}
953
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
954
+		foreach ($relation_settings as $relation_name => $relation_obj) {
955
+			$related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
956
+				$rest_request->get_param('include'),
957
+				$relation_name
958
+			);
959
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
960
+				$rest_request->get_param('calculate'),
961
+				$relation_name
962
+			);
963
+			// did they specify they wanted to include a related model, or
964
+			// specific fields from a related model?
965
+			// or did they specify to calculate a field from a related model?
966
+			if ($related_fields_to_include || $related_fields_to_calculate) {
967
+				// if so, we should include at least some part of the related model
968
+				$pretend_related_request = new WP_REST_Request();
969
+				$pretend_related_request->set_query_params(
970
+					array(
971
+						'caps'      => $rest_request->get_param('caps'),
972
+						'include'   => $related_fields_to_include,
973
+						'calculate' => $related_fields_to_calculate,
974
+						'password' => $rest_request->get_param('password')
975
+					)
976
+				);
977
+				$pretend_related_request->add_header('no_rest_headers', true);
978
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
979
+					$model->get_index_primary_key_string(
980
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
981
+					)
982
+				);
983
+				if (! $included_items_protected) {
984
+					try {
985
+						$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
986
+							$primary_model_query_params,
987
+							$relation_obj,
988
+							$pretend_related_request
989
+						);
990
+					} catch (RestException $e) {
991
+						$related_results = null;
992
+					}
993
+				} else {
994
+					// they're protected, hide them.
995
+					$related_results = null;
996
+					$entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
997
+				}
998
+				if ($related_results instanceof WP_Error || $related_results === null) {
999
+					$related_results = $relation_obj instanceof EE_Belongs_To_Relation ? null : array();
1000
+				}
1001
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1002
+			}
1003
+		}
1004
+		return $entity_array;
1005
+	}
1006
+
1007
+	/**
1008
+	 * If the user has requested only specific properties (including meta properties like _links or _protected)
1009
+	 * remove everything else.
1010
+	 * @since 4.9.74.p
1011
+	 * @param EEM_Base $model
1012
+	 * @param WP_REST_Request $rest_request
1013
+	 * @param $entity_array
1014
+	 * @return array
1015
+	 * @throws EE_Error
1016
+	 */
1017
+	protected function includeOnlyRequestedProperties(
1018
+		EEM_Base $model,
1019
+		WP_REST_Request $rest_request,
1020
+		$entity_array
1021
+	) {
1022
+
1023
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1024
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1025
+		// if they passed in * or didn't specify any includes, return everything
1026
+		if (! in_array('*', $includes_for_this_model)
1027
+			&& ! empty($includes_for_this_model)
1028
+		) {
1029
+			if ($model->has_primary_key_field()) {
1030
+				// always include the primary key. ya just gotta know that at least
1031
+				$includes_for_this_model[] = $model->primary_key_name();
1032
+			}
1033
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1034
+				$includes_for_this_model[] = '_calculated_fields';
1035
+			}
1036
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1037
+		}
1038
+		return $entity_array;
1039
+	}
1040
+
1041
+
1042
+	/**
1043
+	 * Returns a new array with all the names of models removed. Eg
1044
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1045
+	 *
1046
+	 * @param array $arr
1047
+	 * @return array
1048
+	 */
1049
+	private function removeModelNamesFromArray($arr)
1050
+	{
1051
+		return array_diff($arr, array_keys(EE_Registry::instance()->non_abstract_db_models));
1052
+	}
1053
+
1054
+
1055
+	/**
1056
+	 * Gets the calculated fields for the response
1057
+	 *
1058
+	 * @param EEM_Base        $model
1059
+	 * @param array           $wpdb_row
1060
+	 * @param WP_REST_Request $rest_request
1061
+	 * @param boolean $row_is_protected whether this row is password protected or not
1062
+	 * @return \stdClass the _calculations item in the entity
1063
+	 * @throws ObjectDetectedException if a default value has a PHP object, which should never do (and if we
1064
+	 * did, let's know about it ASAP, so let the exception bubble up)
1065
+	 */
1066
+	protected function getEntityCalculations($model, $wpdb_row, $rest_request, $row_is_protected = false)
1067
+	{
1068
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1069
+			$rest_request->get_param('calculate'),
1070
+			''
1071
+		);
1072
+		// note: setting calculate=* doesn't do anything
1073
+		$calculated_fields_to_return = new \stdClass();
1074
+		$protected_fields = array();
1075
+		foreach ($calculated_fields as $field_to_calculate) {
1076
+			try {
1077
+				// it's password protected, so they shouldn't be able to read this. Remove the value
1078
+				$schema = $this->fields_calculator->getJsonSchemaForModel($model);
1079
+				if ($row_is_protected
1080
+					&& isset($schema['properties'][ $field_to_calculate ]['protected'])
1081
+					&& $schema['properties'][ $field_to_calculate ]['protected']) {
1082
+					$calculated_value = null;
1083
+					$protected_fields[] = $field_to_calculate;
1084
+					if ($schema['properties'][ $field_to_calculate ]['type']) {
1085
+						switch ($schema['properties'][ $field_to_calculate ]['type']) {
1086
+							case 'boolean':
1087
+								$calculated_value = false;
1088
+								break;
1089
+							case 'integer':
1090
+								$calculated_value = 0;
1091
+								break;
1092
+							case 'string':
1093
+								$calculated_value = '';
1094
+								break;
1095
+							case 'array':
1096
+								$calculated_value = array();
1097
+								break;
1098
+							case 'object':
1099
+								$calculated_value = new stdClass();
1100
+								break;
1101
+						}
1102
+					}
1103
+				} else {
1104
+					$calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1105
+						null,
1106
+						$this->fields_calculator->retrieveCalculatedFieldValue(
1107
+							$model,
1108
+							$field_to_calculate,
1109
+							$wpdb_row,
1110
+							$rest_request,
1111
+							$this
1112
+						),
1113
+						$this->getModelVersionInfo()->requestedVersion()
1114
+					);
1115
+				}
1116
+				$calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1117
+			} catch (RestException $e) {
1118
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
1119
+				$this->setResponseHeader(
1120
+					'Notices-Field-Calculation-Errors['
1121
+					. $e->getStringCode()
1122
+					. ']['
1123
+					. $model->get_this_model_name()
1124
+					. ']['
1125
+					. $field_to_calculate
1126
+					. ']',
1127
+					$e->getMessage(),
1128
+					true
1129
+				);
1130
+			}
1131
+		}
1132
+		$calculated_fields_to_return->_protected = $protected_fields;
1133
+		return $calculated_fields_to_return;
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * Gets the full URL to the resource, taking the requested version into account
1139
+	 *
1140
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1141
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1142
+	 */
1143
+	public function getVersionedLinkTo($link_part_after_version_and_slash)
1144
+	{
1145
+		return rest_url(
1146
+			EED_Core_Rest_Api::get_versioned_route_to(
1147
+				$link_part_after_version_and_slash,
1148
+				$this->getModelVersionInfo()->requestedVersion()
1149
+			)
1150
+		);
1151
+	}
1152
+
1153
+
1154
+	/**
1155
+	 * Gets the correct lowercase name for the relation in the API according
1156
+	 * to the relation's type
1157
+	 *
1158
+	 * @param string                  $relation_name
1159
+	 * @param \EE_Model_Relation_Base $relation_obj
1160
+	 * @return string
1161
+	 */
1162
+	public static function getRelatedEntityName($relation_name, $relation_obj)
1163
+	{
1164
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1165
+			return strtolower($relation_name);
1166
+		} else {
1167
+			return EEH_Inflector::pluralize_and_lower($relation_name);
1168
+		}
1169
+	}
1170
+
1171
+
1172
+	/**
1173
+	 * Gets the one model object with the specified id for the specified model
1174
+	 *
1175
+	 * @param EEM_Base        $model
1176
+	 * @param WP_REST_Request $request
1177
+	 * @return array
1178
+	 */
1179
+	public function getEntityFromModel($model, $request)
1180
+	{
1181
+		$context = $this->validateContext($request->get_param('caps'));
1182
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1183
+	}
1184
+
1185
+
1186
+	/**
1187
+	 * If a context is provided which isn't valid, maybe it was added in a future
1188
+	 * version so just treat it as a default read
1189
+	 *
1190
+	 * @param string $context
1191
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1192
+	 */
1193
+	public function validateContext($context)
1194
+	{
1195
+		if (! $context) {
1196
+			$context = EEM_Base::caps_read;
1197
+		}
1198
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1199
+		if (in_array($context, $valid_contexts)) {
1200
+			return $context;
1201
+		} else {
1202
+			return EEM_Base::caps_read;
1203
+		}
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 * Verifies the passed in value is an allowable default where conditions value.
1209
+	 *
1210
+	 * @param $default_query_params
1211
+	 * @return string
1212
+	 */
1213
+	public function validateDefaultQueryParams($default_query_params)
1214
+	{
1215
+		$valid_default_where_conditions_for_api_calls = array(
1216
+			EEM_Base::default_where_conditions_all,
1217
+			EEM_Base::default_where_conditions_minimum_all,
1218
+			EEM_Base::default_where_conditions_minimum_others,
1219
+		);
1220
+		if (! $default_query_params) {
1221
+			$default_query_params = EEM_Base::default_where_conditions_all;
1222
+		}
1223
+		if (in_array(
1224
+			$default_query_params,
1225
+			$valid_default_where_conditions_for_api_calls,
1226
+			true
1227
+		)) {
1228
+			return $default_query_params;
1229
+		} else {
1230
+			return EEM_Base::default_where_conditions_all;
1231
+		}
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 * Translates API filter get parameter into model query params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1237
+	 * Note: right now the query parameter keys for fields (and related fields)
1238
+	 * can be left as-is, but it's quite possible this will change someday.
1239
+	 * Also, this method's contents might be candidate for moving to Model_Data_Translator
1240
+	 *
1241
+	 * @param EEM_Base $model
1242
+	 * @param array    $query_parameters  from $_GET parameter @see Read:handle_request_get_all
1243
+	 * @return array model query params (@see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1244
+	 *                                    or FALSE to indicate that absolutely no results should be returned
1245
+	 * @throws EE_Error
1246
+	 * @throws RestException
1247
+	 */
1248
+	public function createModelQueryParams($model, $query_params)
1249
+	{
1250
+		$model_query_params = array();
1251
+		if (isset($query_params['where'])) {
1252
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1253
+				$query_params['where'],
1254
+				$model,
1255
+				$this->getModelVersionInfo()->requestedVersion()
1256
+			);
1257
+		}
1258
+		if (isset($query_params['order_by'])) {
1259
+			$order_by = $query_params['order_by'];
1260
+		} elseif (isset($query_params['orderby'])) {
1261
+			$order_by = $query_params['orderby'];
1262
+		} else {
1263
+			$order_by = null;
1264
+		}
1265
+		if ($order_by !== null) {
1266
+			if (is_array($order_by)) {
1267
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1268
+			} else {
1269
+				// it's a single item
1270
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1271
+			}
1272
+			$model_query_params['order_by'] = $order_by;
1273
+		}
1274
+		if (isset($query_params['group_by'])) {
1275
+			$group_by = $query_params['group_by'];
1276
+		} elseif (isset($query_params['groupby'])) {
1277
+			$group_by = $query_params['groupby'];
1278
+		} else {
1279
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1280
+		}
1281
+		// make sure they're all real names
1282
+		if (is_array($group_by)) {
1283
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1284
+		}
1285
+		if ($group_by !== null) {
1286
+			$model_query_params['group_by'] = $group_by;
1287
+		}
1288
+		if (isset($query_params['having'])) {
1289
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1290
+				$query_params['having'],
1291
+				$model,
1292
+				$this->getModelVersionInfo()->requestedVersion()
1293
+			);
1294
+		}
1295
+		if (isset($query_params['order'])) {
1296
+			$model_query_params['order'] = $query_params['order'];
1297
+		}
1298
+		if (isset($query_params['mine'])) {
1299
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1300
+		}
1301
+		if (isset($query_params['limit'])) {
1302
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1303
+			if (! is_array($query_params['limit'])) {
1304
+				$limit_array = explode(',', (string) $query_params['limit']);
1305
+			} else {
1306
+				$limit_array = $query_params['limit'];
1307
+			}
1308
+			$sanitized_limit = array();
1309
+			foreach ($limit_array as $key => $limit_part) {
1310
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1311
+					throw new EE_Error(
1312
+						sprintf(
1313
+							__(
1314
+							// @codingStandardsIgnoreStart
1315
+								'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.',
1316
+								// @codingStandardsIgnoreEnd
1317
+								'event_espresso'
1318
+							),
1319
+							wp_json_encode($query_params['limit'])
1320
+						)
1321
+					);
1322
+				}
1323
+				$sanitized_limit[] = (int) $limit_part;
1324
+			}
1325
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1326
+		} else {
1327
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1328
+		}
1329
+		if (isset($query_params['caps'])) {
1330
+			$model_query_params['caps'] = $this->validateContext($query_params['caps']);
1331
+		} else {
1332
+			$model_query_params['caps'] = EEM_Base::caps_read;
1333
+		}
1334
+		if (isset($query_params['default_where_conditions'])) {
1335
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1336
+				$query_params['default_where_conditions']
1337
+			);
1338
+		}
1339
+		// if this is a model protected by a password on another model, exclude the password protected
1340
+		// entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1341
+		// though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1342
+		if (! $model->hasPassword()
1343
+			&& $model->restrictedByRelatedModelPassword()
1344
+			&& $model_query_params['caps'] === EEM_Base::caps_read) {
1345
+			if (empty($query_params['password'])) {
1346
+				$model_query_params['exclude_protected'] = true;
1347
+			}
1348
+		}
1349
+
1350
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1351
+	}
1352
+
1353
+
1354
+	/**
1355
+	 * Changes the REST-style query params for use in the models
1356
+	 *
1357
+	 * @deprecated
1358
+	 * @param EEM_Base $model
1359
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1360
+	 * @return array
1361
+	 */
1362
+	public function prepareRestQueryParamsKeyForModels($model, $query_params)
1363
+	{
1364
+		$model_ready_query_params = array();
1365
+		foreach ($query_params as $key => $value) {
1366
+			if (is_array($value)) {
1367
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1368
+			} else {
1369
+				$model_ready_query_params[ $key ] = $value;
1370
+			}
1371
+		}
1372
+		return $model_ready_query_params;
1373
+	}
1374
+
1375
+
1376
+	/**
1377
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1378
+	 * @param $model
1379
+	 * @param $query_params
1380
+	 * @return array
1381
+	 */
1382
+	public function prepareRestQueryParamsValuesForModels($model, $query_params)
1383
+	{
1384
+		$model_ready_query_params = array();
1385
+		foreach ($query_params as $key => $value) {
1386
+			if (is_array($value)) {
1387
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1388
+			} else {
1389
+				$model_ready_query_params[ $key ] = $value;
1390
+			}
1391
+		}
1392
+		return $model_ready_query_params;
1393
+	}
1394
+
1395
+
1396
+	/**
1397
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1398
+	 * If no prefix is specified, returns items with no period.
1399
+	 *
1400
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1401
+	 * @param string       $prefix            "Event" or "foobar"
1402
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1403
+	 *                                        we only return strings starting with that and a period; if no prefix was
1404
+	 *                                        specified we return all items containing NO periods
1405
+	 */
1406
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, $prefix)
1407
+	{
1408
+		if (is_string($string_to_explode)) {
1409
+			$exploded_contents = explode(',', $string_to_explode);
1410
+		} elseif (is_array($string_to_explode)) {
1411
+			$exploded_contents = $string_to_explode;
1412
+		} else {
1413
+			$exploded_contents = array();
1414
+		}
1415
+		// if the string was empty, we want an empty array
1416
+		$exploded_contents = array_filter($exploded_contents);
1417
+		$contents_with_prefix = array();
1418
+		foreach ($exploded_contents as $item) {
1419
+			$item = trim($item);
1420
+			// if no prefix was provided, so we look for items with no "." in them
1421
+			if (! $prefix) {
1422
+				// does this item have a period?
1423
+				if (strpos($item, '.') === false) {
1424
+					// if not, then its what we're looking for
1425
+					$contents_with_prefix[] = $item;
1426
+				}
1427
+			} elseif (strpos($item, $prefix . '.') === 0) {
1428
+				// this item has the prefix and a period, grab it
1429
+				$contents_with_prefix[] = substr(
1430
+					$item,
1431
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1432
+				);
1433
+			} elseif ($item === $prefix) {
1434
+				// this item is JUST the prefix
1435
+				// so let's grab everything after, which is a blank string
1436
+				$contents_with_prefix[] = '';
1437
+			}
1438
+		}
1439
+		return $contents_with_prefix;
1440
+	}
1441
+
1442
+
1443
+	/**
1444
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1445
+	 * Deprecated because its return values were really quite confusing- sometimes it returned
1446
+	 * an empty array (when the include string was blank or '*') or sometimes it returned
1447
+	 * array('*') (when you provided a model and a model of that kind was found).
1448
+	 * Parses the $include_string so we fetch all the field names relating to THIS model
1449
+	 * (ie have NO period in them), or for the provided model (ie start with the model
1450
+	 * name and then a period).
1451
+	 * @param string $include_string @see Read:handle_request_get_all
1452
+	 * @param string $model_name
1453
+	 * @return array of fields for this model. If $model_name is provided, then
1454
+	 *                               the fields for that model, with the model's name removed from each.
1455
+	 *                               If $include_string was blank or '*' returns an empty array
1456
+	 */
1457
+	public function extractIncludesForThisModel($include_string, $model_name = null)
1458
+	{
1459
+		if (is_array($include_string)) {
1460
+			$include_string = implode(',', $include_string);
1461
+		}
1462
+		if ($include_string === '*' || $include_string === '') {
1463
+			return array();
1464
+		}
1465
+		$includes = explode(',', $include_string);
1466
+		$extracted_fields_to_include = array();
1467
+		if ($model_name) {
1468
+			foreach ($includes as $field_to_include) {
1469
+				$field_to_include = trim($field_to_include);
1470
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1471
+					// found the model name at the exact start
1472
+					$field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1473
+					$extracted_fields_to_include[] = $field_sans_model_name;
1474
+				} elseif ($field_to_include == $model_name) {
1475
+					$extracted_fields_to_include[] = '*';
1476
+				}
1477
+			}
1478
+		} else {
1479
+			// look for ones with no period
1480
+			foreach ($includes as $field_to_include) {
1481
+				$field_to_include = trim($field_to_include);
1482
+				if (strpos($field_to_include, '.') === false
1483
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1484
+				) {
1485
+					$extracted_fields_to_include[] = $field_to_include;
1486
+				}
1487
+			}
1488
+		}
1489
+		return $extracted_fields_to_include;
1490
+	}
1491
+
1492
+
1493
+	/**
1494
+	 * Gets the single item using the model according to the request in the context given, otherwise
1495
+	 * returns that it's inaccessible to the current user
1496
+	 *
1497
+	 * @param EEM_Base $model
1498
+	 * @param WP_REST_Request $request
1499
+	 * @param null $context
1500
+	 * @return array
1501
+	 * @throws EE_Error
1502
+	 */
1503
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null)
1504
+	{
1505
+		$query_params = array(array($model->primary_key_name() => $request->get_param('id')), 'limit' => 1);
1506
+		if ($model instanceof EEM_Soft_Delete_Base) {
1507
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1508
+		}
1509
+		$restricted_query_params = $query_params;
1510
+		$restricted_query_params['caps'] = $context;
1511
+		$this->setDebugInfo('model query params', $restricted_query_params);
1512
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1513
+		if (! empty($model_rows)) {
1514
+			return $this->createEntityFromWpdbResult(
1515
+				$model,
1516
+				reset($model_rows),
1517
+				$request
1518
+			);
1519
+		} else {
1520
+			// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1521
+			$lowercase_model_name = strtolower($model->get_this_model_name());
1522
+			if ($model->exists($query_params)) {
1523
+				// you got shafted- it existed but we didn't want to tell you!
1524
+				throw new RestException(
1525
+					'rest_user_cannot_' . $context,
1526
+					sprintf(
1527
+						__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1528
+						$context,
1529
+						$lowercase_model_name,
1530
+						Capabilities::getMissingPermissionsString(
1531
+							$model,
1532
+							$context
1533
+						)
1534
+					),
1535
+					array('status' => 403)
1536
+				);
1537
+			} else {
1538
+				// it's not you. It just doesn't exist
1539
+				throw new RestException(
1540
+					sprintf('rest_%s_invalid_id', $lowercase_model_name),
1541
+					sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1542
+					array('status' => 404)
1543
+				);
1544
+			}
1545
+		}
1546
+	}
1547
+
1548
+	/**
1549
+	 * Checks that if this content requires a password to be read, that it's been provided and is correct.
1550
+	 * @since 4.9.74.p
1551
+	 * @param EEM_Base $model
1552
+	 * @param $model_row
1553
+	 * @param $query_params Adds 'default_where_conditions' => 'minimum' to ensure we don't confuse trashed with
1554
+	 *                      password protected.
1555
+	 * @param WP_REST_Request $request
1556
+	 * @throws EE_Error
1557
+	 * @throws InvalidArgumentException
1558
+	 * @throws InvalidDataTypeException
1559
+	 * @throws InvalidInterfaceException
1560
+	 * @throws RestPasswordRequiredException
1561
+	 * @throws RestPasswordIncorrectException
1562
+	 * @throws \EventEspresso\core\exceptions\ModelConfigurationException
1563
+	 * @throws ReflectionException
1564
+	 */
1565
+	protected function checkPassword(EEM_Base $model, $model_row, $query_params, WP_REST_Request $request)
1566
+	{
1567
+		$query_params['default_where_conditions'] = 'minimum';
1568
+		// stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1569
+		// or you don't.
1570
+		$request_caps = $request->get_param('caps');
1571
+		if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1572
+			return;
1573
+		}
1574
+		// if this entity requires a password, they better give it and it better be right!
1575
+		if ($model->hasPassword()
1576
+			&& $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '') {
1577
+			if (empty($request['password'])) {
1578
+				throw new RestPasswordRequiredException();
1579
+			} elseif (!hash_equals(
1580
+				$model_row[ $model->getPasswordField()->get_qualified_column() ],
1581
+				$request['password']
1582
+			)) {
1583
+				throw new RestPasswordIncorrectException();
1584
+			}
1585
+		} // wait! maybe this content is password protected
1586
+		elseif ($model->restrictedByRelatedModelPassword()
1587
+			&& $request->get_param('caps') === EEM_Base::caps_read) {
1588
+			$password_supplied = $request->get_param('password');
1589
+			if (empty($password_supplied)) {
1590
+				$query_params['exclude_protected'] = true;
1591
+				if (!$model->exists($query_params)) {
1592
+					throw new RestPasswordRequiredException();
1593
+				}
1594
+			} else {
1595
+				$query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1596
+				if (!$model->exists($query_params)) {
1597
+					throw new RestPasswordIncorrectException();
1598
+				}
1599
+			}
1600
+		}
1601
+	}
1602 1602
 }
Please login to merge, or discard this patch.
Spacing   +68 added lines, -68 removed lines patch added patch discarded remove patch
@@ -78,7 +78,7 @@  discard block
 block discarded – undo
78 78
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
79 79
         try {
80 80
             $controller->setRequestedVersion($version);
81
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
81
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
82 82
                 return $controller->sendResponse(
83 83
                     new WP_Error(
84 84
                         'endpoint_parsing_error',
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
120 120
         try {
121 121
             $controller->setRequestedVersion($version);
122
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
122
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
123 123
                 return array();
124 124
             }
125 125
             // get the model for this version
@@ -176,11 +176,11 @@  discard block
 block discarded – undo
176 176
      */
177 177
     protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema)
178 178
     {
179
-        if (isset($schema['properties'][ $field_name ]['default'])) {
180
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
181
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
179
+        if (isset($schema['properties'][$field_name]['default'])) {
180
+            if (is_array($schema['properties'][$field_name]['default'])) {
181
+                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
182 182
                     if ($default_key === 'raw') {
183
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
183
+                        $schema['properties'][$field_name]['default'][$default_key] =
184 184
                             ModelDataTranslator::prepareFieldValueForJson(
185 185
                                 $field,
186 186
                                 $default_value,
@@ -189,9 +189,9 @@  discard block
 block discarded – undo
189 189
                     }
190 190
                 }
191 191
             } else {
192
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
192
+                $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson(
193 193
                     $field,
194
-                    $schema['properties'][ $field_name ]['default'],
194
+                    $schema['properties'][$field_name]['default'],
195 195
                     $this->getModelVersionInfo()->requestedVersion()
196 196
                 );
197 197
             }
@@ -213,9 +213,9 @@  discard block
 block discarded – undo
213 213
     protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema)
214 214
     {
215 215
         if ($field instanceof EE_Datetime_Field) {
216
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
216
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
217 217
             // modify the description
218
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
218
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
219 219
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
220 220
                 wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
221 221
             );
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
         $controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
259 259
         try {
260 260
             $controller->setRequestedVersion($version);
261
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
261
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
262 262
                 return $controller->sendResponse(
263 263
                     new WP_Error(
264 264
                         'endpoint_parsing_error',
@@ -337,7 +337,7 @@  discard block
 block discarded – undo
337 337
     public function getEntitiesFromModel($model, $request)
338 338
     {
339 339
         $query_params = $this->createModelQueryParams($model, $request->get_params());
340
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
340
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
341 341
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
342 342
             throw new RestException(
343 343
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -349,14 +349,14 @@  discard block
 block discarded – undo
349 349
                 array('status' => 403)
350 350
             );
351 351
         }
352
-        if (! $request->get_header('no_rest_headers')) {
352
+        if ( ! $request->get_header('no_rest_headers')) {
353 353
             $this->setHeadersFromQueryParams($model, $query_params);
354 354
         }
355 355
         /** @type array $results */
356 356
         $results = $model->get_all_wpdb_results($query_params);
357 357
         $nice_results = array();
358 358
         foreach ($results as $result) {
359
-            $nice_results[] =  $this->createEntityFromWpdbResult(
359
+            $nice_results[] = $this->createEntityFromWpdbResult(
360 360
                 $model,
361 361
                 $result,
362 362
                 $request
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
         $context = $this->validateContext($request->get_param('caps'));
391 391
         $model = $relation->get_this_model();
392 392
         $related_model = $relation->get_other_model();
393
-        if (! isset($primary_model_query_params[0])) {
393
+        if ( ! isset($primary_model_query_params[0])) {
394 394
             $primary_model_query_params[0] = array();
395 395
         }
396 396
         // check if they can access the 1st model object
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
         if (is_array($primary_model_rows)) {
414 414
             $primary_model_row = reset($primary_model_rows);
415 415
         }
416
-        if (! (
416
+        if ( ! (
417 417
             Capabilities::currentUserHasPartialAccessTo($related_model, $context)
418 418
             && $primary_model_row
419 419
         )
@@ -453,13 +453,13 @@  discard block
 block discarded – undo
453 453
         );
454 454
         $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
455 455
         foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
456
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
456
+            $query_params[0][$relation->get_this_model()->get_this_model_name()
457 457
                               . '.'
458
-                              . $where_condition_key ] = $where_condition_value;
458
+                              . $where_condition_key] = $where_condition_value;
459 459
         }
460 460
         $query_params['default_where_conditions'] = 'none';
461 461
         $query_params['caps'] = $context;
462
-        if (! $request->get_header('no_rest_headers')) {
462
+        if ( ! $request->get_header('no_rest_headers')) {
463 463
             $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
464 464
         }
465 465
         /** @type array $results */
@@ -510,7 +510,7 @@  discard block
 block discarded – undo
510 510
      */
511 511
     public function getEntitiesFromRelation($id, $relation, $request)
512 512
     {
513
-        if (! $relation->get_this_model()->has_primary_key_field()) {
513
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
514 514
             throw new EE_Error(
515 515
                 sprintf(
516 516
                     __(
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
             Capabilities::getMissingPermissionsString($model, $query_params['caps'])
556 556
         );
557 557
         // normally the limit to a 2-part array, where the 2nd item is the limit
558
-        if (! isset($query_params['limit'])) {
558
+        if ( ! isset($query_params['limit'])) {
559 559
             $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
560 560
         }
561 561
         if (is_array($query_params['limit'])) {
@@ -594,7 +594,7 @@  discard block
 block discarded – undo
594 594
      */
595 595
     public function createEntityFromWpdbResult($model, $db_row, $rest_request, $deprecated = null)
596 596
     {
597
-        if (! $rest_request instanceof WP_REST_Request) {
597
+        if ( ! $rest_request instanceof WP_REST_Request) {
598 598
             // ok so this was called in the old style, where the 3rd arg was
599 599
             // $include, and the 4th arg was $context
600 600
             // now setup the request just to avoid fatal errors, although we won't be able
@@ -669,7 +669,7 @@  discard block
 block discarded – undo
669 669
             $rest_request,
670 670
             $this
671 671
         );
672
-        if (! $current_user_full_access_to_entity) {
672
+        if ( ! $current_user_full_access_to_entity) {
673 673
             $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
674 674
                 $entity_array,
675 675
                 $model,
@@ -701,7 +701,7 @@  discard block
 block discarded – undo
701 701
      */
702 702
     protected function addProtectedProperty(EEM_Base $model, $results_so_far, $protected)
703 703
     {
704
-        if (! $model->hasPassword() || ! $protected) {
704
+        if ( ! $model->hasPassword() || ! $protected) {
705 705
             return $results_so_far;
706 706
         }
707 707
         $password_field = $model->getPasswordField();
@@ -715,7 +715,7 @@  discard block
 block discarded – undo
715 715
             $fields_included
716 716
         );
717 717
         foreach ($fields_included as $field_name) {
718
-            $results_so_far['_protected'][] = $field_name ;
718
+            $results_so_far['_protected'][] = $field_name;
719 719
         }
720 720
         return $results_so_far;
721 721
     }
@@ -746,8 +746,8 @@  discard block
 block discarded – undo
746 746
         if ($do_chevy_shuffle) {
747 747
             global $post;
748 748
             $old_post = $post;
749
-            $post = get_post($result[ $model->primary_key_name() ]);
750
-            if (! $post instanceof \WP_Post) {
749
+            $post = get_post($result[$model->primary_key_name()]);
750
+            if ( ! $post instanceof \WP_Post) {
751 751
                 // well that's weird, because $result is what we JUST fetched from the database
752 752
                 throw new RestException(
753 753
                     'error_fetching_post_from_database_results',
@@ -757,7 +757,7 @@  discard block
 block discarded – undo
757 757
                     )
758 758
                 );
759 759
             }
760
-            $model_object_classname = 'EE_' . $model->get_this_model_name();
760
+            $model_object_classname = 'EE_'.$model->get_this_model_name();
761 761
             $post->{$model_object_classname} = \EE_Registry::instance()->load_class(
762 762
                 $model_object_classname,
763 763
                 $result,
@@ -768,13 +768,13 @@  discard block
 block discarded – undo
768 768
         foreach ($result as $field_name => $field_value) {
769 769
             $field_obj = $model->field_settings_for($field_name);
770 770
             if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
771
-                unset($result[ $field_name ]);
771
+                unset($result[$field_name]);
772 772
             } elseif ($this->isSubclassOfOne(
773 773
                 $field_obj,
774 774
                 $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
775 775
             )
776 776
             ) {
777
-                $result[ $field_name ] = array(
777
+                $result[$field_name] = array(
778 778
                     'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
779 779
                     'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
780 780
                 );
@@ -783,7 +783,7 @@  discard block
 block discarded – undo
783 783
                 $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
784 784
             )
785 785
             ) {
786
-                $result[ $field_name ] = array(
786
+                $result[$field_name] = array(
787 787
                     'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
788 788
                     'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
789 789
                 );
@@ -814,10 +814,10 @@  discard block
 block discarded – undo
814 814
                         $this->getModelVersionInfo()->requestedVersion()
815 815
                     );
816 816
                 }
817
-                $result[ $field_name . '_gmt' ] = $gmt_date;
818
-                $result[ $field_name ] = $local_date;
817
+                $result[$field_name.'_gmt'] = $gmt_date;
818
+                $result[$field_name] = $local_date;
819 819
             } else {
820
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
820
+                $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
821 821
             }
822 822
         }
823 823
         if ($do_chevy_shuffle) {
@@ -869,7 +869,7 @@  discard block
 block discarded – undo
869 869
     protected function addExtraFields(EEM_Base $model, $db_row, $entity_array)
870 870
     {
871 871
         if ($model instanceof EEM_CPT_Base) {
872
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
872
+            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
873 873
         }
874 874
         return $entity_array;
875 875
     }
@@ -894,7 +894,7 @@  discard block
 block discarded – undo
894 894
                     'href' => $this->getVersionedLinkTo(
895 895
                         EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
896 896
                         . '/'
897
-                        . $entity_array[ $model->primary_key_name() ]
897
+                        . $entity_array[$model->primary_key_name()]
898 898
                     ),
899 899
                 ),
900 900
             );
@@ -910,12 +910,12 @@  discard block
 block discarded – undo
910 910
         if ($model->has_primary_key_field()) {
911 911
             foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
912 912
                 $related_model_part = Read::getRelatedEntityName($relation_name, $relation_obj);
913
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
913
+                $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = array(
914 914
                     array(
915 915
                         'href'   => $this->getVersionedLinkTo(
916 916
                             EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
917 917
                             . '/'
918
-                            . $entity_array[ $model->primary_key_name() ]
918
+                            . $entity_array[$model->primary_key_name()]
919 919
                             . '/'
920 920
                             . $related_model_part
921 921
                         ),
@@ -947,7 +947,7 @@  discard block
 block discarded – undo
947 947
         $included_items_protected = false
948 948
     ) {
949 949
         // if $db_row not included, hope the entity array has what we need
950
-        if (! $db_row) {
950
+        if ( ! $db_row) {
951 951
             $db_row = $entity_array;
952 952
         }
953 953
         $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
@@ -980,7 +980,7 @@  discard block
 block discarded – undo
980 980
                         $model->deduce_fields_n_values_from_cols_n_values($db_row)
981 981
                     )
982 982
                 );
983
-                if (! $included_items_protected) {
983
+                if ( ! $included_items_protected) {
984 984
                     try {
985 985
                         $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
986 986
                             $primary_model_query_params,
@@ -998,7 +998,7 @@  discard block
 block discarded – undo
998 998
                 if ($related_results instanceof WP_Error || $related_results === null) {
999 999
                     $related_results = $relation_obj instanceof EE_Belongs_To_Relation ? null : array();
1000 1000
                 }
1001
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1001
+                $entity_array[Read::getRelatedEntityName($relation_name, $relation_obj)] = $related_results;
1002 1002
             }
1003 1003
         }
1004 1004
         return $entity_array;
@@ -1023,7 +1023,7 @@  discard block
 block discarded – undo
1023 1023
         $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1024 1024
         $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1025 1025
         // if they passed in * or didn't specify any includes, return everything
1026
-        if (! in_array('*', $includes_for_this_model)
1026
+        if ( ! in_array('*', $includes_for_this_model)
1027 1027
             && ! empty($includes_for_this_model)
1028 1028
         ) {
1029 1029
             if ($model->has_primary_key_field()) {
@@ -1077,12 +1077,12 @@  discard block
 block discarded – undo
1077 1077
                 // it's password protected, so they shouldn't be able to read this. Remove the value
1078 1078
                 $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1079 1079
                 if ($row_is_protected
1080
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1081
-                    && $schema['properties'][ $field_to_calculate ]['protected']) {
1080
+                    && isset($schema['properties'][$field_to_calculate]['protected'])
1081
+                    && $schema['properties'][$field_to_calculate]['protected']) {
1082 1082
                     $calculated_value = null;
1083 1083
                     $protected_fields[] = $field_to_calculate;
1084
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1085
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1084
+                    if ($schema['properties'][$field_to_calculate]['type']) {
1085
+                        switch ($schema['properties'][$field_to_calculate]['type']) {
1086 1086
                             case 'boolean':
1087 1087
                                 $calculated_value = false;
1088 1088
                                 break;
@@ -1192,7 +1192,7 @@  discard block
 block discarded – undo
1192 1192
      */
1193 1193
     public function validateContext($context)
1194 1194
     {
1195
-        if (! $context) {
1195
+        if ( ! $context) {
1196 1196
             $context = EEM_Base::caps_read;
1197 1197
         }
1198 1198
         $valid_contexts = EEM_Base::valid_cap_contexts();
@@ -1217,7 +1217,7 @@  discard block
 block discarded – undo
1217 1217
             EEM_Base::default_where_conditions_minimum_all,
1218 1218
             EEM_Base::default_where_conditions_minimum_others,
1219 1219
         );
1220
-        if (! $default_query_params) {
1220
+        if ( ! $default_query_params) {
1221 1221
             $default_query_params = EEM_Base::default_where_conditions_all;
1222 1222
         }
1223 1223
         if (in_array(
@@ -1300,14 +1300,14 @@  discard block
 block discarded – undo
1300 1300
         }
1301 1301
         if (isset($query_params['limit'])) {
1302 1302
             // limit should be either a string like '23' or '23,43', or an array with two items in it
1303
-            if (! is_array($query_params['limit'])) {
1303
+            if ( ! is_array($query_params['limit'])) {
1304 1304
                 $limit_array = explode(',', (string) $query_params['limit']);
1305 1305
             } else {
1306 1306
                 $limit_array = $query_params['limit'];
1307 1307
             }
1308 1308
             $sanitized_limit = array();
1309 1309
             foreach ($limit_array as $key => $limit_part) {
1310
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1310
+                if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1311 1311
                     throw new EE_Error(
1312 1312
                         sprintf(
1313 1313
                             __(
@@ -1339,7 +1339,7 @@  discard block
 block discarded – undo
1339 1339
         // if this is a model protected by a password on another model, exclude the password protected
1340 1340
         // entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1341 1341
         // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1342
-        if (! $model->hasPassword()
1342
+        if ( ! $model->hasPassword()
1343 1343
             && $model->restrictedByRelatedModelPassword()
1344 1344
             && $model_query_params['caps'] === EEM_Base::caps_read) {
1345 1345
             if (empty($query_params['password'])) {
@@ -1364,9 +1364,9 @@  discard block
 block discarded – undo
1364 1364
         $model_ready_query_params = array();
1365 1365
         foreach ($query_params as $key => $value) {
1366 1366
             if (is_array($value)) {
1367
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1367
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsKeyForModels($model, $value);
1368 1368
             } else {
1369
-                $model_ready_query_params[ $key ] = $value;
1369
+                $model_ready_query_params[$key] = $value;
1370 1370
             }
1371 1371
         }
1372 1372
         return $model_ready_query_params;
@@ -1384,9 +1384,9 @@  discard block
 block discarded – undo
1384 1384
         $model_ready_query_params = array();
1385 1385
         foreach ($query_params as $key => $value) {
1386 1386
             if (is_array($value)) {
1387
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1387
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1388 1388
             } else {
1389
-                $model_ready_query_params[ $key ] = $value;
1389
+                $model_ready_query_params[$key] = $value;
1390 1390
             }
1391 1391
         }
1392 1392
         return $model_ready_query_params;
@@ -1418,17 +1418,17 @@  discard block
 block discarded – undo
1418 1418
         foreach ($exploded_contents as $item) {
1419 1419
             $item = trim($item);
1420 1420
             // if no prefix was provided, so we look for items with no "." in them
1421
-            if (! $prefix) {
1421
+            if ( ! $prefix) {
1422 1422
                 // does this item have a period?
1423 1423
                 if (strpos($item, '.') === false) {
1424 1424
                     // if not, then its what we're looking for
1425 1425
                     $contents_with_prefix[] = $item;
1426 1426
                 }
1427
-            } elseif (strpos($item, $prefix . '.') === 0) {
1427
+            } elseif (strpos($item, $prefix.'.') === 0) {
1428 1428
                 // this item has the prefix and a period, grab it
1429 1429
                 $contents_with_prefix[] = substr(
1430 1430
                     $item,
1431
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1431
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1432 1432
                 );
1433 1433
             } elseif ($item === $prefix) {
1434 1434
                 // this item is JUST the prefix
@@ -1467,9 +1467,9 @@  discard block
 block discarded – undo
1467 1467
         if ($model_name) {
1468 1468
             foreach ($includes as $field_to_include) {
1469 1469
                 $field_to_include = trim($field_to_include);
1470
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1470
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1471 1471
                     // found the model name at the exact start
1472
-                    $field_sans_model_name = str_replace($model_name . '.', '', $field_to_include);
1472
+                    $field_sans_model_name = str_replace($model_name.'.', '', $field_to_include);
1473 1473
                     $extracted_fields_to_include[] = $field_sans_model_name;
1474 1474
                 } elseif ($field_to_include == $model_name) {
1475 1475
                     $extracted_fields_to_include[] = '*';
@@ -1510,7 +1510,7 @@  discard block
 block discarded – undo
1510 1510
         $restricted_query_params['caps'] = $context;
1511 1511
         $this->setDebugInfo('model query params', $restricted_query_params);
1512 1512
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1513
-        if (! empty($model_rows)) {
1513
+        if ( ! empty($model_rows)) {
1514 1514
             return $this->createEntityFromWpdbResult(
1515 1515
                 $model,
1516 1516
                 reset($model_rows),
@@ -1522,7 +1522,7 @@  discard block
 block discarded – undo
1522 1522
             if ($model->exists($query_params)) {
1523 1523
                 // you got shafted- it existed but we didn't want to tell you!
1524 1524
                 throw new RestException(
1525
-                    'rest_user_cannot_' . $context,
1525
+                    'rest_user_cannot_'.$context,
1526 1526
                     sprintf(
1527 1527
                         __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1528 1528
                         $context,
@@ -1573,11 +1573,11 @@  discard block
 block discarded – undo
1573 1573
         }
1574 1574
         // if this entity requires a password, they better give it and it better be right!
1575 1575
         if ($model->hasPassword()
1576
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== '') {
1576
+            && $model_row[$model->getPasswordField()->get_qualified_column()] !== '') {
1577 1577
             if (empty($request['password'])) {
1578 1578
                 throw new RestPasswordRequiredException();
1579
-            } elseif (!hash_equals(
1580
-                $model_row[ $model->getPasswordField()->get_qualified_column() ],
1579
+            } elseif ( ! hash_equals(
1580
+                $model_row[$model->getPasswordField()->get_qualified_column()],
1581 1581
                 $request['password']
1582 1582
             )) {
1583 1583
                 throw new RestPasswordIncorrectException();
@@ -1588,12 +1588,12 @@  discard block
 block discarded – undo
1588 1588
             $password_supplied = $request->get_param('password');
1589 1589
             if (empty($password_supplied)) {
1590 1590
                 $query_params['exclude_protected'] = true;
1591
-                if (!$model->exists($query_params)) {
1591
+                if ( ! $model->exists($query_params)) {
1592 1592
                     throw new RestPasswordRequiredException();
1593 1593
                 }
1594 1594
             } else {
1595
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1596
-                if (!$model->exists($query_params)) {
1595
+                $query_params[0][$model->modelChainAndPassword()] = $password_supplied;
1596
+                if ( ! $model->exists($query_params)) {
1597 1597
                     throw new RestPasswordIncorrectException();
1598 1598
                 }
1599 1599
             }
Please login to merge, or discard this patch.
core/entities/models/JsonModelSchema.php 1 patch
Indentation   +234 added lines, -234 removed lines patch added patch discarded remove patch
@@ -25,255 +25,255 @@
 block discarded – undo
25 25
 class JsonModelSchema
26 26
 {
27 27
 
28
-    /**
29
-     * @var EEM_Base
30
-     */
31
-    protected $model;
28
+	/**
29
+	 * @var EEM_Base
30
+	 */
31
+	protected $model;
32 32
 
33
-    /**
34
-     * @var CalculatedModelFields
35
-     */
36
-    protected $fields_calculator;
33
+	/**
34
+	 * @var CalculatedModelFields
35
+	 */
36
+	protected $fields_calculator;
37 37
 
38 38
 
39
-    /**
40
-     * JsonModelSchema constructor.
41
-     *
42
-     * @param EEM_Base              $model
43
-     * @param CalculatedModelFields $fields_calculator
44
-     */
45
-    public function __construct(EEM_Base $model, CalculatedModelFields $fields_calculator)
46
-    {
47
-        $this->model = $model;
48
-        $this->fields_calculator = $fields_calculator;
49
-    }
39
+	/**
40
+	 * JsonModelSchema constructor.
41
+	 *
42
+	 * @param EEM_Base              $model
43
+	 * @param CalculatedModelFields $fields_calculator
44
+	 */
45
+	public function __construct(EEM_Base $model, CalculatedModelFields $fields_calculator)
46
+	{
47
+		$this->model = $model;
48
+		$this->fields_calculator = $fields_calculator;
49
+	}
50 50
 
51 51
 
52
-    /**
53
-     * Return the schema for a given model from a given model.
54
-     *
55
-     * @return array
56
-     */
57
-    public function getModelSchema()
58
-    {
59
-        return $this->getModelSchemaForRelations(
60
-            $this->model->relation_settings(),
61
-            $this->getModelSchemaForFields(
62
-                $this->model->field_settings(),
63
-                $this->getInitialSchemaStructure()
64
-            )
65
-        );
66
-    }
52
+	/**
53
+	 * Return the schema for a given model from a given model.
54
+	 *
55
+	 * @return array
56
+	 */
57
+	public function getModelSchema()
58
+	{
59
+		return $this->getModelSchemaForRelations(
60
+			$this->model->relation_settings(),
61
+			$this->getModelSchemaForFields(
62
+				$this->model->field_settings(),
63
+				$this->getInitialSchemaStructure()
64
+			)
65
+		);
66
+	}
67 67
 
68 68
 
69
-    /**
70
-     * Get the schema for a given set of model fields.
71
-     *
72
-     * @param EE_Model_Field_Base[] $model_fields
73
-     * @param array                  $schema
74
-     * @return array
75
-     */
76
-    public function getModelSchemaForFields(array $model_fields, array $schema)
77
-    {
78
-        foreach ($model_fields as $field => $model_field) {
79
-            if (! $model_field instanceof EE_Model_Field_Base) {
80
-                continue;
81
-            }
82
-            $schema['properties'][ $field ] = $model_field->getSchema();
69
+	/**
70
+	 * Get the schema for a given set of model fields.
71
+	 *
72
+	 * @param EE_Model_Field_Base[] $model_fields
73
+	 * @param array                  $schema
74
+	 * @return array
75
+	 */
76
+	public function getModelSchemaForFields(array $model_fields, array $schema)
77
+	{
78
+		foreach ($model_fields as $field => $model_field) {
79
+			if (! $model_field instanceof EE_Model_Field_Base) {
80
+				continue;
81
+			}
82
+			$schema['properties'][ $field ] = $model_field->getSchema();
83 83
 
84
-            // if this is a primary key field add the primary key item
85
-            if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
-                $schema['properties'][ $field ]['primary_key'] = true;
87
-                if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
-                    $schema['properties'][ $field ]['readonly'] = true;
89
-                }
90
-            }
84
+			// if this is a primary key field add the primary key item
85
+			if ($model_field instanceof EE_Primary_Key_Field_Base) {
86
+				$schema['properties'][ $field ]['primary_key'] = true;
87
+				if ($model_field instanceof EE_Primary_Key_Int_Field) {
88
+					$schema['properties'][ $field ]['readonly'] = true;
89
+				}
90
+			}
91 91
 
92
-            // if this is a foreign key field add the foreign key item
93
-            if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
-                $schema['properties'][ $field ]['foreign_key'] = array(
95
-                    'description' => esc_html__(
96
-                        'This is a foreign key the points to the given models.',
97
-                        'event_espresso'
98
-                    ),
99
-                    'type'        => 'array',
100
-                    'enum'        => $model_field->get_model_class_names_pointed_to(),
101
-                );
102
-            }
103
-        }
104
-        return $schema;
105
-    }
92
+			// if this is a foreign key field add the foreign key item
93
+			if ($model_field instanceof EE_Foreign_Key_Field_Base) {
94
+				$schema['properties'][ $field ]['foreign_key'] = array(
95
+					'description' => esc_html__(
96
+						'This is a foreign key the points to the given models.',
97
+						'event_espresso'
98
+					),
99
+					'type'        => 'array',
100
+					'enum'        => $model_field->get_model_class_names_pointed_to(),
101
+				);
102
+			}
103
+		}
104
+		return $schema;
105
+	}
106 106
 
107 107
 
108
-    /**
109
-     * Get the schema for a given set of model relations
110
-     *
111
-     * @param EE_Model_Relation_Base[] $relations_on_model
112
-     * @param array                    $schema
113
-     * @return array
114
-     */
115
-    public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116
-    {
117
-        foreach ($relations_on_model as $model_name => $relation) {
118
-            if (! $relation instanceof EE_Model_Relation_Base) {
119
-                continue;
120
-            }
121
-            $model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122
-                ? strtolower($model_name)
123
-                : EEH_Inflector::pluralize_and_lower($model_name);
124
-            $schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
-            $schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
108
+	/**
109
+	 * Get the schema for a given set of model relations
110
+	 *
111
+	 * @param EE_Model_Relation_Base[] $relations_on_model
112
+	 * @param array                    $schema
113
+	 * @return array
114
+	 */
115
+	public function getModelSchemaForRelations(array $relations_on_model, array $schema)
116
+	{
117
+		foreach ($relations_on_model as $model_name => $relation) {
118
+			if (! $relation instanceof EE_Model_Relation_Base) {
119
+				continue;
120
+			}
121
+			$model_name_for_schema = $relation instanceof EE_Belongs_To_Relation
122
+				? strtolower($model_name)
123
+				: EEH_Inflector::pluralize_and_lower($model_name);
124
+			$schema['properties'][ $model_name_for_schema ] = $relation->getSchema();
125
+			$schema['properties'][ $model_name_for_schema ]['relation_model'] = $model_name;
126 126
 
127
-            // links schema
128
-            $links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
-            $schema['properties']['_links']['properties'][ $links_key ] = array(
130
-                'description' => esc_html__(
131
-                    'Array of objects describing the link(s) for this relation resource.',
132
-                    'event_espresso'
133
-                ),
134
-                'type' => 'array',
135
-                'readonly' => true,
136
-                'items' => array(
137
-                    'type' => 'object',
138
-                    'properties' => array(
139
-                        'href' => array(
140
-                            'type' => 'string',
141
-                            'description' => sprintf(
142
-                                // translators: placeholder is the model name for the relation.
143
-                                esc_html__(
144
-                                    'The link to the resource for the %s relation(s) to this entity',
145
-                                    'event_espresso'
146
-                                ),
147
-                                $model_name
148
-                            ),
149
-                        ),
150
-                        'single' => array(
151
-                            'type' => 'boolean',
152
-                            'description' => sprintf(
153
-                                // translators: placeholder is the model name for the relation.
154
-                                esc_html__(
155
-                                    'Whether or not there is only a single %s relation to this entity',
156
-                                    'event_espresso'
157
-                                ),
158
-                                $model_name
159
-                            ),
160
-                        ),
161
-                    ),
162
-                    'additionalProperties' => false
163
-                ),
164
-            );
165
-        }
166
-        return $schema;
167
-    }
127
+			// links schema
128
+			$links_key = 'https://api.eventespresso.com/' . strtolower($model_name);
129
+			$schema['properties']['_links']['properties'][ $links_key ] = array(
130
+				'description' => esc_html__(
131
+					'Array of objects describing the link(s) for this relation resource.',
132
+					'event_espresso'
133
+				),
134
+				'type' => 'array',
135
+				'readonly' => true,
136
+				'items' => array(
137
+					'type' => 'object',
138
+					'properties' => array(
139
+						'href' => array(
140
+							'type' => 'string',
141
+							'description' => sprintf(
142
+								// translators: placeholder is the model name for the relation.
143
+								esc_html__(
144
+									'The link to the resource for the %s relation(s) to this entity',
145
+									'event_espresso'
146
+								),
147
+								$model_name
148
+							),
149
+						),
150
+						'single' => array(
151
+							'type' => 'boolean',
152
+							'description' => sprintf(
153
+								// translators: placeholder is the model name for the relation.
154
+								esc_html__(
155
+									'Whether or not there is only a single %s relation to this entity',
156
+									'event_espresso'
157
+								),
158
+								$model_name
159
+							),
160
+						),
161
+					),
162
+					'additionalProperties' => false
163
+				),
164
+			);
165
+		}
166
+		return $schema;
167
+	}
168 168
 
169 169
 
170
-    /**
171
-     * Outputs the schema header for a model.
172
-     *
173
-     * @return array
174
-     */
175
-    public function getInitialSchemaStructure()
176
-    {
177
-        return array(
178
-            '$schema'    => 'http://json-schema.org/draft-04/schema#',
179
-            'title'      => $this->model->get_this_model_name(),
180
-            'type'       => 'object',
181
-            'properties' => array(
182
-                'link' => array(
183
-                    'description' => esc_html__(
184
-                        'Link to event on WordPress site hosting events.',
185
-                        'event_espresso'
186
-                    ),
187
-                    'type' => 'string',
188
-                    'readonly' => true,
189
-                ),
190
-                '_links' => array(
191
-                    'description' => esc_html__(
192
-                        'Various links for resources related to the entity.',
193
-                        'event_espresso'
194
-                    ),
195
-                    'type' => 'object',
196
-                    'readonly' => true,
197
-                    'properties' => array(
198
-                        'self' => array(
199
-                            'description' => esc_html__(
200
-                                'Link to this entities resource.',
201
-                                'event_espresso'
202
-                            ),
203
-                            'type' => 'array',
204
-                            'items' => array(
205
-                                'type' => 'object',
206
-                                'properties' => array(
207
-                                    'href' => array(
208
-                                        'type' => 'string',
209
-                                    ),
210
-                                ),
211
-                                'additionalProperties' => false
212
-                            ),
213
-                            'readonly' => true
214
-                        ),
215
-                        'collection' => array(
216
-                            'description' => esc_html__(
217
-                                'Link to this entities collection resource.',
218
-                                'event_espresso'
219
-                            ),
220
-                            'type' => 'array',
221
-                            'items' => array(
222
-                                'type' => 'object',
223
-                                'properties' => array(
224
-                                    'href' => array(
225
-                                        'type' => 'string'
226
-                                    ),
227
-                                ),
228
-                                'additionalProperties' => false
229
-                            ),
230
-                            'readonly' => true
231
-                        ),
232
-                    ),
233
-                    'additionalProperties' => false,
234
-                ),
235
-                '_calculated_fields' => array_merge(
236
-                    $this->fields_calculator->getJsonSchemaForModel($this->model),
237
-                    array(
238
-                        '_protected' => $this->getProtectedFieldsSchema()
239
-                    )
240
-                ),
241
-                '_protected' => $this->getProtectedFieldsSchema()
242
-            ),
243
-            'additionalProperties' => false,
244
-        );
245
-    }
170
+	/**
171
+	 * Outputs the schema header for a model.
172
+	 *
173
+	 * @return array
174
+	 */
175
+	public function getInitialSchemaStructure()
176
+	{
177
+		return array(
178
+			'$schema'    => 'http://json-schema.org/draft-04/schema#',
179
+			'title'      => $this->model->get_this_model_name(),
180
+			'type'       => 'object',
181
+			'properties' => array(
182
+				'link' => array(
183
+					'description' => esc_html__(
184
+						'Link to event on WordPress site hosting events.',
185
+						'event_espresso'
186
+					),
187
+					'type' => 'string',
188
+					'readonly' => true,
189
+				),
190
+				'_links' => array(
191
+					'description' => esc_html__(
192
+						'Various links for resources related to the entity.',
193
+						'event_espresso'
194
+					),
195
+					'type' => 'object',
196
+					'readonly' => true,
197
+					'properties' => array(
198
+						'self' => array(
199
+							'description' => esc_html__(
200
+								'Link to this entities resource.',
201
+								'event_espresso'
202
+							),
203
+							'type' => 'array',
204
+							'items' => array(
205
+								'type' => 'object',
206
+								'properties' => array(
207
+									'href' => array(
208
+										'type' => 'string',
209
+									),
210
+								),
211
+								'additionalProperties' => false
212
+							),
213
+							'readonly' => true
214
+						),
215
+						'collection' => array(
216
+							'description' => esc_html__(
217
+								'Link to this entities collection resource.',
218
+								'event_espresso'
219
+							),
220
+							'type' => 'array',
221
+							'items' => array(
222
+								'type' => 'object',
223
+								'properties' => array(
224
+									'href' => array(
225
+										'type' => 'string'
226
+									),
227
+								),
228
+								'additionalProperties' => false
229
+							),
230
+							'readonly' => true
231
+						),
232
+					),
233
+					'additionalProperties' => false,
234
+				),
235
+				'_calculated_fields' => array_merge(
236
+					$this->fields_calculator->getJsonSchemaForModel($this->model),
237
+					array(
238
+						'_protected' => $this->getProtectedFieldsSchema()
239
+					)
240
+				),
241
+				'_protected' => $this->getProtectedFieldsSchema()
242
+			),
243
+			'additionalProperties' => false,
244
+		);
245
+	}
246 246
 
247
-    /**
248
-     * Returns an array of JSON schema to describe the _protected property on responses
249
-     * @since 4.9.74.p
250
-     * @return array
251
-     */
252
-    protected function getProtectedFieldsSchema()
253
-    {
254
-        return array(
255
-            'description' => esc_html__('Array of property names whose values were replaced with their default (because they are related to a password-protected entity.)', 'event_espresso'),
256
-            'type' => 'array',
257
-            'items' => array(
258
-                'description' => esc_html__('Each name corresponds to a property that is protected by password for this entity and has its default value returned in the response.', 'event_espresso'),
259
-                'type' => 'string',
260
-                'readonly' => true,
261
-            ),
262
-            'readonly' => true
263
-        );
264
-    }
247
+	/**
248
+	 * Returns an array of JSON schema to describe the _protected property on responses
249
+	 * @since 4.9.74.p
250
+	 * @return array
251
+	 */
252
+	protected function getProtectedFieldsSchema()
253
+	{
254
+		return array(
255
+			'description' => esc_html__('Array of property names whose values were replaced with their default (because they are related to a password-protected entity.)', 'event_espresso'),
256
+			'type' => 'array',
257
+			'items' => array(
258
+				'description' => esc_html__('Each name corresponds to a property that is protected by password for this entity and has its default value returned in the response.', 'event_espresso'),
259
+				'type' => 'string',
260
+				'readonly' => true,
261
+			),
262
+			'readonly' => true
263
+		);
264
+	}
265 265
 
266 266
 
267
-    /**
268
-     * Allows one to just use the object as a string to get the json.
269
-     * eg.
270
-     * $json_schema = new JsonModelSchema(EEM_Event::instance(), new CalculatedModelFields);
271
-     * echo $json_schema; //outputs the schema as a json formatted string.
272
-     *
273
-     * @return bool|false|mixed|string
274
-     */
275
-    public function __toString()
276
-    {
277
-        return wp_json_encode($this->getModelSchema());
278
-    }
267
+	/**
268
+	 * Allows one to just use the object as a string to get the json.
269
+	 * eg.
270
+	 * $json_schema = new JsonModelSchema(EEM_Event::instance(), new CalculatedModelFields);
271
+	 * echo $json_schema; //outputs the schema as a json formatted string.
272
+	 *
273
+	 * @return bool|false|mixed|string
274
+	 */
275
+	public function __toString()
276
+	{
277
+		return wp_json_encode($this->getModelSchema());
278
+	}
279 279
 }
Please login to merge, or discard this patch.
core/db_models/fields/EE_Password_Field.php 1 patch
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -12,45 +12,45 @@
 block discarded – undo
12 12
  */
13 13
 class EE_Password_Field extends EE_Text_Field_Base
14 14
 {
15
-    /**
16
-     * @var array
17
-     */
18
-    protected $protected_fields;
15
+	/**
16
+	 * @var array
17
+	 */
18
+	protected $protected_fields;
19 19
 
20
-    /**
21
-     * EE_Password_Field constructor.
22
-     * @param $table_column
23
-     * @param $nicename
24
-     * @param $nullable
25
-     * @param null $default_value
26
-     * @param array $protected_fields
27
-     */
28
-    public function __construct($table_column, $nicename, $nullable, $default_value = null, $protected_fields = array())
29
-    {
30
-        $this->protected_fields = $protected_fields;
31
-        parent::__construct($table_column, $nicename, $nullable, $default_value);
32
-    }
20
+	/**
21
+	 * EE_Password_Field constructor.
22
+	 * @param $table_column
23
+	 * @param $nicename
24
+	 * @param $nullable
25
+	 * @param null $default_value
26
+	 * @param array $protected_fields
27
+	 */
28
+	public function __construct($table_column, $nicename, $nullable, $default_value = null, $protected_fields = array())
29
+	{
30
+		$this->protected_fields = $protected_fields;
31
+		parent::__construct($table_column, $nicename, $nullable, $default_value);
32
+	}
33 33
 
34
-    /**
35
-     * Returns the names of the fields on this model that this password field should protect
36
-     * @since 4.9.74.p
37
-     * @return array
38
-     */
39
-    public function protectedFields()
40
-    {
41
-        return $this->protected_fields;
42
-    }
34
+	/**
35
+	 * Returns the names of the fields on this model that this password field should protect
36
+	 * @since 4.9.74.p
37
+	 * @return array
38
+	 */
39
+	public function protectedFields()
40
+	{
41
+		return $this->protected_fields;
42
+	}
43 43
 
44
-    /**
45
-     * Returns whether or not the specified field is protected by this model
46
-     * @since 4.9.74.p
47
-     * @param $field_name
48
-     * @return bool
49
-     */
50
-    public function fieldIsProtected($field_name)
51
-    {
52
-        return in_array($field_name, $this->protectedFields(), true);
53
-    }
44
+	/**
45
+	 * Returns whether or not the specified field is protected by this model
46
+	 * @since 4.9.74.p
47
+	 * @param $field_name
48
+	 * @return bool
49
+	 */
50
+	public function fieldIsProtected($field_name)
51
+	{
52
+		return in_array($field_name, $this->protectedFields(), true);
53
+	}
54 54
 }
55 55
 // End of file EE_Password_Field.php
56 56
 // Location: ${NAMESPACE}/EE_Password_Field.php
Please login to merge, or discard this patch.
core/libraries/rest_api/RestIncomingQueryParamMetadata.php 1 patch
Indentation   +698 added lines, -698 removed lines patch added patch discarded remove patch
@@ -28,704 +28,704 @@
 block discarded – undo
28 28
  */
29 29
 class RestIncomingQueryParamMetadata
30 30
 {
31
-    private $query_param_key;
32
-    private $query_param_value;
33
-    /**
34
-     * @var RestIncomingQueryParamContext
35
-     */
36
-    private $context;
37
-
38
-    /**
39
-     * @var EE_Model_Field_Base|null
40
-     */
41
-    private $field;
42
-
43
-    /**
44
-     * @var string same as $query_param_key but has the * and anything after it removed
45
-     */
46
-    private $query_param_key_sans_stars;
47
-
48
-    /**
49
-     * @var string for timezone or timezone offset
50
-     */
51
-    private $timezone;
52
-
53
-    /**
54
-     * @var boolean if the field in $query_param_key is for a GMT field (eg `EVT_modified_gmt`)
55
-     */
56
-    private $is_gmt_field = false;
57
-
58
-    /**
59
-     * RestIncomingQueryParamMetadata constructor.
60
-     * You probably want to call
61
-     * @param string $query_param_key
62
-     * @param string $query_param_value
63
-     * @param RestIncomingQueryParamContext $context
64
-     */
65
-    public function __construct($query_param_key, $query_param_value, RestIncomingQueryParamContext $context)
66
-    {
67
-        $this->query_param_key = $query_param_key;
68
-        $this->query_param_value = $query_param_value;
69
-        $this->context = $context;
70
-        $this->determineFieldAndTimezone();
71
-    }
72
-
73
-    /**
74
-     * Gets the query parameter key. This may have been modified (see setQueryParamValue())
75
-     * @return string
76
-     */
77
-    public function getQueryParamKey()
78
-    {
79
-        return $this->query_param_key;
80
-    }
81
-
82
-    /**
83
-     * Modifies the query parameter key passed in (Eg this is done when rewriting the simplified specified operator REST
84
-     * query parameters into the legacy structure)
85
-     * @param string|array|int|float $query_param_value
86
-     */
87
-    private function setQueryParamValue($query_param_value)
88
-    {
89
-        $this->query_param_value = $query_param_value;
90
-    }
91
-
92
-    /**
93
-     * Gets the original query parameter value passed in.
94
-     * @return string
95
-     */
96
-    public function getQueryParamValue()
97
-    {
98
-        return $this->query_param_value;
99
-    }
100
-
101
-    /**
102
-     * Gets the context object.
103
-     * @return RestIncomingQueryParamContext
104
-     */
105
-    public function getContext()
106
-    {
107
-        return $this->context;
108
-    }
109
-
110
-    /**
111
-     * Sets the query parameter key. This may be used to rewrite a key into its non-GMT alternative.
112
-     * @param string $query_param_key
113
-     */
114
-    private function setQueryParamKey($query_param_key)
115
-    {
116
-        $this->query_param_key = $query_param_key;
117
-    }
118
-
119
-    /**
120
-     * Gets the field the query parameter key indicated. This may be null (in cases where the query parameter key
121
-     * did not indicate a field, eg if it were `OR`).
122
-     * @return EE_Model_Field_Base|null
123
-     */
124
-    public function getField()
125
-    {
126
-        return $this->field;
127
-    }
128
-
129
-    /**
130
-     * Gets the query parameter key (with the star and everything afterwards removed).
131
-     * @return string
132
-     */
133
-    public function getQueryParamKeySansStars()
134
-    {
135
-        return $this->query_param_key_sans_stars;
136
-    }
137
-
138
-    /**
139
-     * Gets the timezone associated with this model (the site timezone, except for GMT datetime fields).
140
-     * @return string
141
-     */
142
-    public function getTimezone()
143
-    {
144
-        return $this->timezone;
145
-    }
146
-
147
-    /**
148
-     * Returns whether or not this is a GMT field
149
-     * @return boolean
150
-     */
151
-    public function isGmtField()
152
-    {
153
-        return $this->is_gmt_field;
154
-    }
155
-
156
-    /**
157
-     * Sets the field indicated by the query parameter key (might be null).
158
-     * @param EE_Model_Field_Base|null $field
159
-     */
160
-    private function setField(EE_Model_Field_Base $field = null)
161
-    {
162
-        $this->field = $field;
163
-    }
164
-
165
-    /**
166
-     * Sets the query parameter key-with-stars-removed.
167
-     * @param string $query_param_key_sans_stars
168
-     */
169
-    private function setQueryParamKeySansStars($query_param_key_sans_stars)
170
-    {
171
-        $this->query_param_key_sans_stars = $query_param_key_sans_stars;
172
-    }
173
-
174
-    /**
175
-     * Sets the timezone (this could be a timezeon offset string).
176
-     * @param string $timezone
177
-     */
178
-    private function setTimezone($timezone)
179
-    {
180
-        $this->timezone = $timezone;
181
-    }
182
-
183
-    /**
184
-     * @param mixed $is_gmt_field
185
-     */
186
-    private function setIsGmtField($is_gmt_field)
187
-    {
188
-        $this->is_gmt_field = $is_gmt_field;
189
-    }
190
-
191
-    /**
192
-     * Determines what field, query param name, and query param name without stars, and timezone to use.
193
-     * @since 4.9.72.p
194
-     * @type EE_Model_Field_Base $field
195
-     * @return void {
196
-     * @throws EE_Error
197
-     * @throws InvalidDataTypeException
198
-     * @throws InvalidInterfaceException
199
-     * @throws InvalidArgumentException
200
-     */
201
-    private function determineFieldAndTimezone()
202
-    {
203
-        $this->setQueryParamKeySansStars(ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
204
-            $this->getQueryParamKey()
205
-        ));
206
-        $this->setField(ModelDataTranslator::deduceFieldFromQueryParam(
207
-            $this->getQueryParamKeySansStars(),
208
-            $this->getContext()->getModel()
209
-        ));
210
-        // double-check is it a *_gmt field?
211
-        if (!$this->getField() instanceof EE_Model_Field_Base
212
-            && ModelDataTranslator::isGmtDateFieldName($this->getQueryParamKeySansStars())
213
-        ) {
214
-            // yep, take off '_gmt', and find the field
215
-            $this->setQueryParamKey(ModelDataTranslator::removeGmtFromFieldName($this->getQueryParamKeySansStars()));
216
-            $this->setField(ModelDataTranslator::deduceFieldFromQueryParam(
217
-                $this->getQueryParamKey(),
218
-                $this->context->getModel()
219
-            ));
220
-            $this->setTimezone('UTC');
221
-            $this->setIsGmtField(true);
222
-        } elseif ($this->getField() instanceof EE_Datetime_Field) {
223
-            // so it's not a GMT field. Set the timezone on the model to the default
224
-            $this->setTimezone(EEH_DTT_Helper::get_valid_timezone_string());
225
-        } else {
226
-            // just keep using what's already set for the timezone
227
-            $this->setTimezone($this->context->getModel()->get_timezone());
228
-        }
229
-        $this->assertOnlyAdminCanReadPasswordFields();
230
-    }
231
-
232
-    /**
233
-     * Throws an exception if a non-admin is trying to query by password.
234
-     * @since 4.9.74.p
235
-     * @throws RestException
236
-     */
237
-    private function assertOnlyAdminCanReadPasswordFields()
238
-    {
239
-        if ($this->getField() instanceof EE_Password_Field
240
-            && ! current_user_can(EE_Restriction_Generator_Base::get_default_restrictions_cap())) {
241
-            // only full admins can query by password. sorry bub!
242
-            throw new RestException(
243
-                'only_admins_can_query_by_password',
244
-                // @codingStandardsIgnoreStart
245
-                esc_html__('You attempted to filter by a password field without the needed privileges. Only a full admin is allowed to do that.', 'event_espresso'),
246
-                // @codingStandardsIgnoreEnd
247
-                array(
248
-                    'status' => 403
249
-                )
250
-            );
251
-        }
252
-    }
253
-
254
-    /**
255
-     * Given a ton of input, determines the value to use for the models.
256
-     * @since 4.9.72.p
257
-     * @return array|null
258
-     * @throws DomainException
259
-     * @throws EE_Error
260
-     * @throws RestException
261
-     * @throws DomainException
262
-     */
263
-    public function determineConditionsQueryParameterValue()
264
-    {
265
-        if ($this->valueIsArrayDuringRead()) {
266
-            return $this->determineModelValueGivenRestInputArray();
267
-        }
268
-        return ModelDataTranslator::prepareFieldValueFromJson(
269
-            $this->getField(),
270
-            $this->getQueryParamValue(),
271
-            $this->getContext()->getRequestedVersion(),
272
-            $this->getTimezone()
273
-        );
274
-    }
275
-
276
-    /**
277
-     * Given that the array value provided was itself an array, handles finding the correct value to pass to the model.
278
-     * @since 4.9.72.p
279
-     * @return array|null
280
-     * @throws RestException
281
-     */
282
-    private function determineModelValueGivenRestInputArray()
283
-    {
284
-        $this->transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax();
285
-        // did they specify an operator?
286
-        if ($this->valueIsLegacySpecifiedOperator()) {
287
-            $query_param_value = $this->getQueryParamValue();
288
-            $sub_array_key = $query_param_value[0];
289
-            $translated_value = array($sub_array_key);
290
-            if ($this->operatorIsNAry($sub_array_key)) {
291
-                $translated_value[] = $this->prepareValuesFromJson($query_param_value[1]);
292
-            } elseif ($this->operatorIsTernary($sub_array_key)) {
293
-                $translated_value[] = array(
294
-                    $this->prepareValuesFromJson($query_param_value[1][0]),
295
-                    $this->prepareValuesFromJson($query_param_value[1][1])
296
-                );
297
-            } elseif ($this->operatorIsLike($sub_array_key)) {
298
-                // we want to leave this value mostly-as-is (eg don't force it to be a float
299
-                // or a boolean or an enum value. Leave it as-is with wildcards etc)
300
-                // but do verify it at least doesn't have any serialized data
301
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
302
-                $translated_value[] = $query_param_value[1];
303
-            } elseif ($this->operatorIsUnary($sub_array_key)) {
304
-                // no arguments should have been provided, so don't look for any
305
-            } elseif ($this->operatorisBinary($sub_array_key)) {
306
-                // it's a valid operator, but none of the exceptions. Treat it normally.
307
-                $translated_value[] = $this->prepareValuesFromJson($query_param_value[1]);
308
-            } else {
309
-                // so they provided a valid operator, but wrong number of arguments
310
-                $this->throwWrongNumberOfArgsExceptionIfDebugging($sub_array_key);
311
-                $translated_value = null;
312
-            }
313
-        } else {
314
-            // so they didn't provide a valid operator
315
-            // if we aren't in debug mode, then just try our best to fulfill the user's request
316
-            $this->throwInvalidOperatorExceptionIfDebugging();
317
-            $translated_value = null;
318
-        }
319
-        return $translated_value;
320
-    }
321
-
322
-    /**
323
-     * Returns if this request is a "read" request and the value provided was an array.
324
-     * This will indicate is such things as `array('<', 123)` and `array('IN', array(1,2,3))` are acceptable or not.
325
-     * @since 4.9.72.p
326
-     * @return boolean
327
-     */
328
-    private function valueIsArrayDuringRead()
329
-    {
330
-        return !$this->getContext()->isWriting() && is_array($this->getQueryParamValue());
331
-    }
332
-
333
-    /**
334
-     * Returns if the value provided was an associative array (we should have already verified it's an array of some
335
-     * sort). If the value is an associative array, it had better be in the simplified specified operator structure.
336
-     * @since 4.9.72.p
337
-     * @return boolean
338
-     */
339
-    private function valueIsAssociativeArray()
340
-    {
341
-        return !EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue());
342
-    }
343
-
344
-    /**
345
-     * Checks if the array value is itself an array that fits into the simplified specified operator structure
346
-     * (eg `array('!=' => 123)`).
347
-     * @since 4.9.72.p
348
-     * @return boolean
349
-     */
350
-    private function valueIsSimplifiedSpecifiedOperator()
351
-    {
352
-        return count($this->getQueryParamValue()) === 1
353
-            && array_key_exists(
354
-                key($this->getQueryParamValue()),
355
-                $this->getContext()->getModel()->valid_operators()
356
-            );
357
-    }
358
-
359
-    /**
360
-     * Throws an exception if the sub-value is an array (eg `array('!=' => array())`). It needs to just be a string,
361
-     * of either comma-separated-values, or a JSON array.
362
-     * @since 4.9.72.p
363
-     * @param $sub_array_key
364
-     * @param $sub_array_value
365
-     * @throws RestException
366
-     */
367
-    private function assertSubValueIsntArray($sub_array_key, $sub_array_value)
368
-    {
369
-        if (is_array($sub_array_value) && EED_Core_Rest_Api::debugMode()) {
370
-            throw new RestException(
371
-                'csv_or_json_string_only',
372
-                sprintf(
373
-                    /* translators: 1: variable name*/
374
-                    esc_html__(
375
-                        'The value provided for the operator "%1$s" should be comma-separated value string or a JSON array.',
376
-                        'event_espresso'
377
-                    ),
378
-                    $sub_array_key
379
-                ),
380
-                array(
381
-                    'status' => 400,
382
-                )
383
-            );
384
-        }
385
-    }
386
-
387
-    /**
388
-     * Determines if the sub-array key is an operator taking 3 or more operators.
389
-     * @since 4.9.72.p
390
-     * @param $sub_array_key
391
-     * @return boolean
392
-     */
393
-    private function subArrayKeyIsNonBinaryOperator($sub_array_key)
394
-    {
395
-        return array_key_exists(
396
-            $sub_array_key,
397
-            array_merge(
398
-                $this->getContext()->getModel()->valid_in_style_operators(),
399
-                $this->getContext()->getModel()->valid_between_style_operators()
400
-            )
401
-        );
402
-    }
403
-
404
-    /**
405
-     * Given that the $sub_array_key is a string, checks if it's an operator taking only 1 argument.
406
-     * @since 4.9.72.p
407
-     * @param string $sub_array_key
408
-     * @return boolean
409
-     */
410
-    private function subArrayKeyIsUnaryOperator($sub_array_key)
411
-    {
412
-        return array_key_exists(
413
-            $sub_array_key,
414
-            $this->getContext()->getModel()->valid_null_style_operators()
415
-        );
416
-    }
417
-
418
-    /**
419
-     * Parses the $sub_array_value string into an array (given it could either be a comma-separated-list or a JSON
420
-     * array). eg `"1,2,3"` or `"[1,2,3]"` into `array(1,2,3)`.
421
-     * @since 4.9.72.p
422
-     * @param $sub_array_value
423
-     * @return array|mixed|object
424
-     */
425
-    private function extractQuickStyleSpecifiedOperatorValue($sub_array_value)
426
-    {
427
-        // the value should be JSON or CSV
428
-        $values = json_decode($sub_array_value);
429
-        if (!is_array($values)) {
430
-            $values = array_filter(
431
-                array_map(
432
-                    'trim',
433
-                    explode(
434
-                        ',',
435
-                        $sub_array_value
436
-                    )
437
-                )
438
-            );
439
-        }
440
-        return $values;
441
-    }
442
-
443
-    /**
444
-     * Throws an exception if the value isn't a simplified specified operator (only called when we expect that).
445
-     * @since 4.9.72.p
446
-     * @throws RestException
447
-     */
448
-    private function assertSimplifiedSpecifiedOperator()
449
-    {
450
-        if (!$this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) {
451
-            throw new RestException(
452
-                'numerically_indexed_array_of_values_only',
453
-                sprintf(
454
-                    /* translators: 1: variable name*/
455
-                    esc_html__(
456
-                        'The array provided for the parameter "%1$s" should be numerically indexed.',
457
-                        'event_espresso'
458
-                    ),
459
-                    $this->getQueryParamKey()
460
-                ),
461
-                array(
462
-                    'status' => 400,
463
-                )
464
-            );
465
-        }
466
-    }
467
-
468
-    /**
469
-     * If query_param_value were in the simplified specific operator structure, change it into the legacy structure.
470
-     * @since 4.9.72.p
471
-     * @throws RestException
472
-     */
473
-    private function transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax()
474
-    {
475
-        if ($this->valueIsAssociativeArray()) {
476
-            $this->assertSimplifiedSpecifiedOperator();
477
-            $query_param_value = $this->getQueryParamValue();
478
-            $sub_array_value = reset($query_param_value);
479
-            $sub_array_key = key($query_param_value);
480
-            $this->assertSubValueIsntArray($sub_array_key, $sub_array_value);
481
-            // they're doing something like "&where[EVT_ID][IN]=1,2,3" or "&where[EVT_ID][>]=5"
482
-            if ($this->subArrayKeyIsNonBinaryOperator($sub_array_key)) {
483
-                $this->setQueryParamValue(array(
484
-                    $sub_array_key,
485
-                    $this->extractQuickStyleSpecifiedOperatorValue($sub_array_value)
486
-                ));
487
-            } elseif ($this->subArrayKeyIsUnaryOperator($sub_array_key)) {
488
-                $this->setQueryParamValue(array($sub_array_key));
489
-            } else {
490
-                $this->setQueryParamValue(array($sub_array_key, $sub_array_value));
491
-            }
492
-        }
493
-    }
494
-
495
-    /**
496
-     * Returns true is the value is an array using the legacy structure to specify the operator. Eg `array('!=',123)`.
497
-     * @since 4.9.72.p
498
-     * @return boolean
499
-     */
500
-    private function valueIsLegacySpecifiedOperator()
501
-    {
502
-        $valid_operators = $this->getContext()->getModel()->valid_operators();
503
-        $query_param_value = $this->getQueryParamValue();
504
-        return isset($query_param_value[0])
505
-            && isset($valid_operators[ $query_param_value[0] ]);
506
-    }
507
-
508
-    /**
509
-     * Returns true if the value specified operator accepts arbitrary number of arguments, like "IN".
510
-     * @since 4.9.72.p
511
-     * @param $operator
512
-     * @return boolean
513
-     */
514
-    private function operatorIsNAry($operator)
515
-    {
516
-        $valueArray = $this->getQueryParamValue();
517
-        return array_key_exists(
518
-            $operator,
519
-            $this->getContext()->getModel()->valid_in_style_operators()
520
-        )
521
-            && isset($valueArray[1])
522
-            && is_array($valueArray[1])
523
-            && !isset($valueArray[2]);
524
-    }
525
-
526
-    /**
527
-     * Returns true if the operator accepts 3 arguments (eg "BETWEEN").
528
-     * So we're looking for a value that looks like
529
-     * `array('BETWEEN', array('2015-01-01T00:00:00', '2016-01-01T00:00:00'))`.
530
-     * @since 4.9.72.p
531
-     * @param $operator
532
-     * @return boolean
533
-     */
534
-    private function operatorIsTernary($operator)
535
-    {
536
-        $query_param_value = $this->getQueryParamValue();
537
-        return array_key_exists($operator, $this->getContext()->getModel()->valid_between_style_operators())
538
-            && isset($query_param_value[1])
539
-            && is_array($query_param_value[1])
540
-            && isset($query_param_value[1][0], $query_param_value[1][1])
541
-            && !isset($query_param_value[1][2])
542
-            && !isset($query_param_value[2]);
543
-    }
544
-
545
-    /**
546
-     * Returns true if the operator is a similar to LIKE, indicating the value may have wildcards we should leave alone.
547
-     * @since 4.9.72.p
548
-     * @param $operator
549
-     * @return boolean
550
-     */
551
-    private function operatorIsLike($operator)
552
-    {
553
-        $query_param_value = $this->getQueryParamValue();
554
-        return array_key_exists($operator, $this->getContext()->getModel()->valid_like_style_operators())
555
-            && isset($query_param_value[1])
556
-            && !isset($query_param_value[2]);
557
-    }
558
-
559
-    /**
560
-     * Returns true if the operator only takes one argument (eg it's like `IS NULL`).
561
-     * @since 4.9.72.p
562
-     * @param $operator
563
-     * @return boolean
564
-     */
565
-    private function operatorIsUnary($operator)
566
-    {
567
-        $query_param_value = $this->getQueryParamValue();
568
-        return array_key_exists($operator, $this->getContext()->getModel()->valid_null_style_operators())
569
-            && !isset($query_param_value[1]);
570
-    }
571
-
572
-    /**
573
-     * Returns true if the operator specified is a binary opeator (eg `=`, `!=`)
574
-     * @since 4.9.72.p
575
-     * @param $operator
576
-     * @return boolean
577
-     */
578
-    private function operatorisBinary($operator)
579
-    {
580
-        $query_param_value = $this->getQueryParamValue();
581
-        $model = $this->getContext()->getModel();
582
-        return isset($query_param_value[1])
583
-            && !isset($query_param_value[2])
584
-            && !array_key_exists(
585
-                $operator,
586
-                array_merge(
587
-                    $model->valid_in_style_operators(),
588
-                    $model->valid_null_style_operators(),
589
-                    $model->valid_like_style_operators(),
590
-                    $model->valid_between_style_operators()
591
-                )
592
-            );
593
-    }
594
-
595
-    /**
596
-     * If we're debugging, throws an exception saying that the wrong number of arguments was provided.
597
-     * @since 4.9.72.p
598
-     * @param $operator
599
-     * @throws RestException
600
-     */
601
-    private function throwWrongNumberOfArgsExceptionIfDebugging($operator)
602
-    {
603
-        if (EED_Core_Rest_Api::debugMode()) {
604
-            throw new RestException(
605
-                'wrong_number_of_arguments',
606
-                sprintf(
607
-                    esc_html__(
608
-                        'The operator you provided, "%1$s" had the wrong number of arguments',
609
-                        'event_espresso'
610
-                    ),
611
-                    $operator
612
-                ),
613
-                array(
614
-                    'status' => 400,
615
-                )
616
-            );
617
-        }
618
-    }
619
-
620
-    /**
621
-     * Wrapper for ModelDataTranslator::prepareFieldValuesFromJson(), just a tad more DRY.
622
-     * @since 4.9.72.p
623
-     * @param $value
624
-     * @return mixed
625
-     * @throws RestException
626
-     */
627
-    private function prepareValuesFromJson($value)
628
-    {
629
-        return ModelDataTranslator::prepareFieldValuesFromJson(
630
-            $this->getField(),
631
-            $value,
632
-            $this->getContext()->getRequestedVersion(),
633
-            $this->getTimezone()
634
-        );
635
-    }
636
-
637
-    /**
638
-     * Throws an exception if an invalid operator was specified and we're debugging.
639
-     * @since 4.9.72.p
640
-     * @throws RestException
641
-     */
642
-    private function throwInvalidOperatorExceptionIfDebugging()
643
-    {
644
-        // so they didn't provide a valid operator
645
-        if (EED_Core_Rest_Api::debugMode()) {
646
-            throw new RestException(
647
-                'invalid_operator',
648
-                sprintf(
649
-                    esc_html__(
650
-                        'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
651
-                        'event_espresso'
652
-                    ),
653
-                    $this->getQueryParamKey(),
654
-                    $this->getQueryParamValue()
655
-                ),
656
-                array(
657
-                    'status' => 400,
658
-                )
659
-            );
660
-        }
661
-    }
662
-
663
-    /**
664
-     * Returns true if the query_param_key was a logic query parameter, eg `OR`, `AND`, `NOT`, `OR*`, etc.
665
-     * @since 4.9.72.p
666
-     * @return boolean
667
-     */
668
-    private function isLogicQueryParam()
669
-    {
670
-        return in_array($this->getQueryParamKeySansStars(), $this->getContext()->getModel()->logic_query_param_keys());
671
-    }
672
-
673
-
674
-    /**
675
-     * If the query param isn't for a field, it must be a nested query parameter which requires different logic.
676
-     * @since 4.9.72.p
677
-     * @return array
678
-     * @throws DomainException
679
-     * @throws EE_Error
680
-     * @throws RestException
681
-     * @throws InvalidDataTypeException
682
-     * @throws InvalidInterfaceException
683
-     * @throws InvalidArgumentException
684
-     */
685
-    public function determineNestedConditionQueryParameters()
686
-    {
687
-
688
-        // so this param doesn't correspond to a field eh?
689
-        if ($this->getContext()->isWriting()) {
690
-            // always tell API clients about invalid parameters when they're creating data. Otherwise,
691
-            // they are probably going to create invalid data
692
-            throw new RestException(
693
-                'invalid_field',
694
-                sprintf(
695
-                    /* translators: 1: variable name */
696
-                    esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
697
-                    $this->getQueryParamKey()
698
-                )
699
-            );
700
-        }
701
-        // so it's not for a field, is it a logic query param key?
702
-        if ($this->isLogicQueryParam()) {
703
-            return ModelDataTranslator::prepareConditionsQueryParamsForModels(
704
-                $this->getQueryParamValue(),
705
-                $this->getContext()->getModel(),
706
-                $this->getContext()->getRequestedVersion()
707
-            );
708
-        }
709
-        if (EED_Core_Rest_Api::debugMode()) {
710
-            // only tell API clients they got it wrong if we're in debug mode
711
-            // otherwise try our best ot fulfill their request by ignoring this invalid data
712
-            throw new RestException(
713
-                'invalid_parameter',
714
-                sprintf(
715
-                    /* translators: 1: variable name */
716
-                    esc_html__(
717
-                        'You provided an invalid parameter, with key "%1$s"',
718
-                        'event_espresso'
719
-                    ),
720
-                    $this->getQueryParamKey()
721
-                ),
722
-                array(
723
-                    'status' => 400,
724
-                )
725
-            );
726
-        }
727
-        return null;
728
-    }
31
+	private $query_param_key;
32
+	private $query_param_value;
33
+	/**
34
+	 * @var RestIncomingQueryParamContext
35
+	 */
36
+	private $context;
37
+
38
+	/**
39
+	 * @var EE_Model_Field_Base|null
40
+	 */
41
+	private $field;
42
+
43
+	/**
44
+	 * @var string same as $query_param_key but has the * and anything after it removed
45
+	 */
46
+	private $query_param_key_sans_stars;
47
+
48
+	/**
49
+	 * @var string for timezone or timezone offset
50
+	 */
51
+	private $timezone;
52
+
53
+	/**
54
+	 * @var boolean if the field in $query_param_key is for a GMT field (eg `EVT_modified_gmt`)
55
+	 */
56
+	private $is_gmt_field = false;
57
+
58
+	/**
59
+	 * RestIncomingQueryParamMetadata constructor.
60
+	 * You probably want to call
61
+	 * @param string $query_param_key
62
+	 * @param string $query_param_value
63
+	 * @param RestIncomingQueryParamContext $context
64
+	 */
65
+	public function __construct($query_param_key, $query_param_value, RestIncomingQueryParamContext $context)
66
+	{
67
+		$this->query_param_key = $query_param_key;
68
+		$this->query_param_value = $query_param_value;
69
+		$this->context = $context;
70
+		$this->determineFieldAndTimezone();
71
+	}
72
+
73
+	/**
74
+	 * Gets the query parameter key. This may have been modified (see setQueryParamValue())
75
+	 * @return string
76
+	 */
77
+	public function getQueryParamKey()
78
+	{
79
+		return $this->query_param_key;
80
+	}
81
+
82
+	/**
83
+	 * Modifies the query parameter key passed in (Eg this is done when rewriting the simplified specified operator REST
84
+	 * query parameters into the legacy structure)
85
+	 * @param string|array|int|float $query_param_value
86
+	 */
87
+	private function setQueryParamValue($query_param_value)
88
+	{
89
+		$this->query_param_value = $query_param_value;
90
+	}
91
+
92
+	/**
93
+	 * Gets the original query parameter value passed in.
94
+	 * @return string
95
+	 */
96
+	public function getQueryParamValue()
97
+	{
98
+		return $this->query_param_value;
99
+	}
100
+
101
+	/**
102
+	 * Gets the context object.
103
+	 * @return RestIncomingQueryParamContext
104
+	 */
105
+	public function getContext()
106
+	{
107
+		return $this->context;
108
+	}
109
+
110
+	/**
111
+	 * Sets the query parameter key. This may be used to rewrite a key into its non-GMT alternative.
112
+	 * @param string $query_param_key
113
+	 */
114
+	private function setQueryParamKey($query_param_key)
115
+	{
116
+		$this->query_param_key = $query_param_key;
117
+	}
118
+
119
+	/**
120
+	 * Gets the field the query parameter key indicated. This may be null (in cases where the query parameter key
121
+	 * did not indicate a field, eg if it were `OR`).
122
+	 * @return EE_Model_Field_Base|null
123
+	 */
124
+	public function getField()
125
+	{
126
+		return $this->field;
127
+	}
128
+
129
+	/**
130
+	 * Gets the query parameter key (with the star and everything afterwards removed).
131
+	 * @return string
132
+	 */
133
+	public function getQueryParamKeySansStars()
134
+	{
135
+		return $this->query_param_key_sans_stars;
136
+	}
137
+
138
+	/**
139
+	 * Gets the timezone associated with this model (the site timezone, except for GMT datetime fields).
140
+	 * @return string
141
+	 */
142
+	public function getTimezone()
143
+	{
144
+		return $this->timezone;
145
+	}
146
+
147
+	/**
148
+	 * Returns whether or not this is a GMT field
149
+	 * @return boolean
150
+	 */
151
+	public function isGmtField()
152
+	{
153
+		return $this->is_gmt_field;
154
+	}
155
+
156
+	/**
157
+	 * Sets the field indicated by the query parameter key (might be null).
158
+	 * @param EE_Model_Field_Base|null $field
159
+	 */
160
+	private function setField(EE_Model_Field_Base $field = null)
161
+	{
162
+		$this->field = $field;
163
+	}
164
+
165
+	/**
166
+	 * Sets the query parameter key-with-stars-removed.
167
+	 * @param string $query_param_key_sans_stars
168
+	 */
169
+	private function setQueryParamKeySansStars($query_param_key_sans_stars)
170
+	{
171
+		$this->query_param_key_sans_stars = $query_param_key_sans_stars;
172
+	}
173
+
174
+	/**
175
+	 * Sets the timezone (this could be a timezeon offset string).
176
+	 * @param string $timezone
177
+	 */
178
+	private function setTimezone($timezone)
179
+	{
180
+		$this->timezone = $timezone;
181
+	}
182
+
183
+	/**
184
+	 * @param mixed $is_gmt_field
185
+	 */
186
+	private function setIsGmtField($is_gmt_field)
187
+	{
188
+		$this->is_gmt_field = $is_gmt_field;
189
+	}
190
+
191
+	/**
192
+	 * Determines what field, query param name, and query param name without stars, and timezone to use.
193
+	 * @since 4.9.72.p
194
+	 * @type EE_Model_Field_Base $field
195
+	 * @return void {
196
+	 * @throws EE_Error
197
+	 * @throws InvalidDataTypeException
198
+	 * @throws InvalidInterfaceException
199
+	 * @throws InvalidArgumentException
200
+	 */
201
+	private function determineFieldAndTimezone()
202
+	{
203
+		$this->setQueryParamKeySansStars(ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
204
+			$this->getQueryParamKey()
205
+		));
206
+		$this->setField(ModelDataTranslator::deduceFieldFromQueryParam(
207
+			$this->getQueryParamKeySansStars(),
208
+			$this->getContext()->getModel()
209
+		));
210
+		// double-check is it a *_gmt field?
211
+		if (!$this->getField() instanceof EE_Model_Field_Base
212
+			&& ModelDataTranslator::isGmtDateFieldName($this->getQueryParamKeySansStars())
213
+		) {
214
+			// yep, take off '_gmt', and find the field
215
+			$this->setQueryParamKey(ModelDataTranslator::removeGmtFromFieldName($this->getQueryParamKeySansStars()));
216
+			$this->setField(ModelDataTranslator::deduceFieldFromQueryParam(
217
+				$this->getQueryParamKey(),
218
+				$this->context->getModel()
219
+			));
220
+			$this->setTimezone('UTC');
221
+			$this->setIsGmtField(true);
222
+		} elseif ($this->getField() instanceof EE_Datetime_Field) {
223
+			// so it's not a GMT field. Set the timezone on the model to the default
224
+			$this->setTimezone(EEH_DTT_Helper::get_valid_timezone_string());
225
+		} else {
226
+			// just keep using what's already set for the timezone
227
+			$this->setTimezone($this->context->getModel()->get_timezone());
228
+		}
229
+		$this->assertOnlyAdminCanReadPasswordFields();
230
+	}
231
+
232
+	/**
233
+	 * Throws an exception if a non-admin is trying to query by password.
234
+	 * @since 4.9.74.p
235
+	 * @throws RestException
236
+	 */
237
+	private function assertOnlyAdminCanReadPasswordFields()
238
+	{
239
+		if ($this->getField() instanceof EE_Password_Field
240
+			&& ! current_user_can(EE_Restriction_Generator_Base::get_default_restrictions_cap())) {
241
+			// only full admins can query by password. sorry bub!
242
+			throw new RestException(
243
+				'only_admins_can_query_by_password',
244
+				// @codingStandardsIgnoreStart
245
+				esc_html__('You attempted to filter by a password field without the needed privileges. Only a full admin is allowed to do that.', 'event_espresso'),
246
+				// @codingStandardsIgnoreEnd
247
+				array(
248
+					'status' => 403
249
+				)
250
+			);
251
+		}
252
+	}
253
+
254
+	/**
255
+	 * Given a ton of input, determines the value to use for the models.
256
+	 * @since 4.9.72.p
257
+	 * @return array|null
258
+	 * @throws DomainException
259
+	 * @throws EE_Error
260
+	 * @throws RestException
261
+	 * @throws DomainException
262
+	 */
263
+	public function determineConditionsQueryParameterValue()
264
+	{
265
+		if ($this->valueIsArrayDuringRead()) {
266
+			return $this->determineModelValueGivenRestInputArray();
267
+		}
268
+		return ModelDataTranslator::prepareFieldValueFromJson(
269
+			$this->getField(),
270
+			$this->getQueryParamValue(),
271
+			$this->getContext()->getRequestedVersion(),
272
+			$this->getTimezone()
273
+		);
274
+	}
275
+
276
+	/**
277
+	 * Given that the array value provided was itself an array, handles finding the correct value to pass to the model.
278
+	 * @since 4.9.72.p
279
+	 * @return array|null
280
+	 * @throws RestException
281
+	 */
282
+	private function determineModelValueGivenRestInputArray()
283
+	{
284
+		$this->transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax();
285
+		// did they specify an operator?
286
+		if ($this->valueIsLegacySpecifiedOperator()) {
287
+			$query_param_value = $this->getQueryParamValue();
288
+			$sub_array_key = $query_param_value[0];
289
+			$translated_value = array($sub_array_key);
290
+			if ($this->operatorIsNAry($sub_array_key)) {
291
+				$translated_value[] = $this->prepareValuesFromJson($query_param_value[1]);
292
+			} elseif ($this->operatorIsTernary($sub_array_key)) {
293
+				$translated_value[] = array(
294
+					$this->prepareValuesFromJson($query_param_value[1][0]),
295
+					$this->prepareValuesFromJson($query_param_value[1][1])
296
+				);
297
+			} elseif ($this->operatorIsLike($sub_array_key)) {
298
+				// we want to leave this value mostly-as-is (eg don't force it to be a float
299
+				// or a boolean or an enum value. Leave it as-is with wildcards etc)
300
+				// but do verify it at least doesn't have any serialized data
301
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
302
+				$translated_value[] = $query_param_value[1];
303
+			} elseif ($this->operatorIsUnary($sub_array_key)) {
304
+				// no arguments should have been provided, so don't look for any
305
+			} elseif ($this->operatorisBinary($sub_array_key)) {
306
+				// it's a valid operator, but none of the exceptions. Treat it normally.
307
+				$translated_value[] = $this->prepareValuesFromJson($query_param_value[1]);
308
+			} else {
309
+				// so they provided a valid operator, but wrong number of arguments
310
+				$this->throwWrongNumberOfArgsExceptionIfDebugging($sub_array_key);
311
+				$translated_value = null;
312
+			}
313
+		} else {
314
+			// so they didn't provide a valid operator
315
+			// if we aren't in debug mode, then just try our best to fulfill the user's request
316
+			$this->throwInvalidOperatorExceptionIfDebugging();
317
+			$translated_value = null;
318
+		}
319
+		return $translated_value;
320
+	}
321
+
322
+	/**
323
+	 * Returns if this request is a "read" request and the value provided was an array.
324
+	 * This will indicate is such things as `array('<', 123)` and `array('IN', array(1,2,3))` are acceptable or not.
325
+	 * @since 4.9.72.p
326
+	 * @return boolean
327
+	 */
328
+	private function valueIsArrayDuringRead()
329
+	{
330
+		return !$this->getContext()->isWriting() && is_array($this->getQueryParamValue());
331
+	}
332
+
333
+	/**
334
+	 * Returns if the value provided was an associative array (we should have already verified it's an array of some
335
+	 * sort). If the value is an associative array, it had better be in the simplified specified operator structure.
336
+	 * @since 4.9.72.p
337
+	 * @return boolean
338
+	 */
339
+	private function valueIsAssociativeArray()
340
+	{
341
+		return !EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue());
342
+	}
343
+
344
+	/**
345
+	 * Checks if the array value is itself an array that fits into the simplified specified operator structure
346
+	 * (eg `array('!=' => 123)`).
347
+	 * @since 4.9.72.p
348
+	 * @return boolean
349
+	 */
350
+	private function valueIsSimplifiedSpecifiedOperator()
351
+	{
352
+		return count($this->getQueryParamValue()) === 1
353
+			&& array_key_exists(
354
+				key($this->getQueryParamValue()),
355
+				$this->getContext()->getModel()->valid_operators()
356
+			);
357
+	}
358
+
359
+	/**
360
+	 * Throws an exception if the sub-value is an array (eg `array('!=' => array())`). It needs to just be a string,
361
+	 * of either comma-separated-values, or a JSON array.
362
+	 * @since 4.9.72.p
363
+	 * @param $sub_array_key
364
+	 * @param $sub_array_value
365
+	 * @throws RestException
366
+	 */
367
+	private function assertSubValueIsntArray($sub_array_key, $sub_array_value)
368
+	{
369
+		if (is_array($sub_array_value) && EED_Core_Rest_Api::debugMode()) {
370
+			throw new RestException(
371
+				'csv_or_json_string_only',
372
+				sprintf(
373
+					/* translators: 1: variable name*/
374
+					esc_html__(
375
+						'The value provided for the operator "%1$s" should be comma-separated value string or a JSON array.',
376
+						'event_espresso'
377
+					),
378
+					$sub_array_key
379
+				),
380
+				array(
381
+					'status' => 400,
382
+				)
383
+			);
384
+		}
385
+	}
386
+
387
+	/**
388
+	 * Determines if the sub-array key is an operator taking 3 or more operators.
389
+	 * @since 4.9.72.p
390
+	 * @param $sub_array_key
391
+	 * @return boolean
392
+	 */
393
+	private function subArrayKeyIsNonBinaryOperator($sub_array_key)
394
+	{
395
+		return array_key_exists(
396
+			$sub_array_key,
397
+			array_merge(
398
+				$this->getContext()->getModel()->valid_in_style_operators(),
399
+				$this->getContext()->getModel()->valid_between_style_operators()
400
+			)
401
+		);
402
+	}
403
+
404
+	/**
405
+	 * Given that the $sub_array_key is a string, checks if it's an operator taking only 1 argument.
406
+	 * @since 4.9.72.p
407
+	 * @param string $sub_array_key
408
+	 * @return boolean
409
+	 */
410
+	private function subArrayKeyIsUnaryOperator($sub_array_key)
411
+	{
412
+		return array_key_exists(
413
+			$sub_array_key,
414
+			$this->getContext()->getModel()->valid_null_style_operators()
415
+		);
416
+	}
417
+
418
+	/**
419
+	 * Parses the $sub_array_value string into an array (given it could either be a comma-separated-list or a JSON
420
+	 * array). eg `"1,2,3"` or `"[1,2,3]"` into `array(1,2,3)`.
421
+	 * @since 4.9.72.p
422
+	 * @param $sub_array_value
423
+	 * @return array|mixed|object
424
+	 */
425
+	private function extractQuickStyleSpecifiedOperatorValue($sub_array_value)
426
+	{
427
+		// the value should be JSON or CSV
428
+		$values = json_decode($sub_array_value);
429
+		if (!is_array($values)) {
430
+			$values = array_filter(
431
+				array_map(
432
+					'trim',
433
+					explode(
434
+						',',
435
+						$sub_array_value
436
+					)
437
+				)
438
+			);
439
+		}
440
+		return $values;
441
+	}
442
+
443
+	/**
444
+	 * Throws an exception if the value isn't a simplified specified operator (only called when we expect that).
445
+	 * @since 4.9.72.p
446
+	 * @throws RestException
447
+	 */
448
+	private function assertSimplifiedSpecifiedOperator()
449
+	{
450
+		if (!$this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) {
451
+			throw new RestException(
452
+				'numerically_indexed_array_of_values_only',
453
+				sprintf(
454
+					/* translators: 1: variable name*/
455
+					esc_html__(
456
+						'The array provided for the parameter "%1$s" should be numerically indexed.',
457
+						'event_espresso'
458
+					),
459
+					$this->getQueryParamKey()
460
+				),
461
+				array(
462
+					'status' => 400,
463
+				)
464
+			);
465
+		}
466
+	}
467
+
468
+	/**
469
+	 * If query_param_value were in the simplified specific operator structure, change it into the legacy structure.
470
+	 * @since 4.9.72.p
471
+	 * @throws RestException
472
+	 */
473
+	private function transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax()
474
+	{
475
+		if ($this->valueIsAssociativeArray()) {
476
+			$this->assertSimplifiedSpecifiedOperator();
477
+			$query_param_value = $this->getQueryParamValue();
478
+			$sub_array_value = reset($query_param_value);
479
+			$sub_array_key = key($query_param_value);
480
+			$this->assertSubValueIsntArray($sub_array_key, $sub_array_value);
481
+			// they're doing something like "&where[EVT_ID][IN]=1,2,3" or "&where[EVT_ID][>]=5"
482
+			if ($this->subArrayKeyIsNonBinaryOperator($sub_array_key)) {
483
+				$this->setQueryParamValue(array(
484
+					$sub_array_key,
485
+					$this->extractQuickStyleSpecifiedOperatorValue($sub_array_value)
486
+				));
487
+			} elseif ($this->subArrayKeyIsUnaryOperator($sub_array_key)) {
488
+				$this->setQueryParamValue(array($sub_array_key));
489
+			} else {
490
+				$this->setQueryParamValue(array($sub_array_key, $sub_array_value));
491
+			}
492
+		}
493
+	}
494
+
495
+	/**
496
+	 * Returns true is the value is an array using the legacy structure to specify the operator. Eg `array('!=',123)`.
497
+	 * @since 4.9.72.p
498
+	 * @return boolean
499
+	 */
500
+	private function valueIsLegacySpecifiedOperator()
501
+	{
502
+		$valid_operators = $this->getContext()->getModel()->valid_operators();
503
+		$query_param_value = $this->getQueryParamValue();
504
+		return isset($query_param_value[0])
505
+			&& isset($valid_operators[ $query_param_value[0] ]);
506
+	}
507
+
508
+	/**
509
+	 * Returns true if the value specified operator accepts arbitrary number of arguments, like "IN".
510
+	 * @since 4.9.72.p
511
+	 * @param $operator
512
+	 * @return boolean
513
+	 */
514
+	private function operatorIsNAry($operator)
515
+	{
516
+		$valueArray = $this->getQueryParamValue();
517
+		return array_key_exists(
518
+			$operator,
519
+			$this->getContext()->getModel()->valid_in_style_operators()
520
+		)
521
+			&& isset($valueArray[1])
522
+			&& is_array($valueArray[1])
523
+			&& !isset($valueArray[2]);
524
+	}
525
+
526
+	/**
527
+	 * Returns true if the operator accepts 3 arguments (eg "BETWEEN").
528
+	 * So we're looking for a value that looks like
529
+	 * `array('BETWEEN', array('2015-01-01T00:00:00', '2016-01-01T00:00:00'))`.
530
+	 * @since 4.9.72.p
531
+	 * @param $operator
532
+	 * @return boolean
533
+	 */
534
+	private function operatorIsTernary($operator)
535
+	{
536
+		$query_param_value = $this->getQueryParamValue();
537
+		return array_key_exists($operator, $this->getContext()->getModel()->valid_between_style_operators())
538
+			&& isset($query_param_value[1])
539
+			&& is_array($query_param_value[1])
540
+			&& isset($query_param_value[1][0], $query_param_value[1][1])
541
+			&& !isset($query_param_value[1][2])
542
+			&& !isset($query_param_value[2]);
543
+	}
544
+
545
+	/**
546
+	 * Returns true if the operator is a similar to LIKE, indicating the value may have wildcards we should leave alone.
547
+	 * @since 4.9.72.p
548
+	 * @param $operator
549
+	 * @return boolean
550
+	 */
551
+	private function operatorIsLike($operator)
552
+	{
553
+		$query_param_value = $this->getQueryParamValue();
554
+		return array_key_exists($operator, $this->getContext()->getModel()->valid_like_style_operators())
555
+			&& isset($query_param_value[1])
556
+			&& !isset($query_param_value[2]);
557
+	}
558
+
559
+	/**
560
+	 * Returns true if the operator only takes one argument (eg it's like `IS NULL`).
561
+	 * @since 4.9.72.p
562
+	 * @param $operator
563
+	 * @return boolean
564
+	 */
565
+	private function operatorIsUnary($operator)
566
+	{
567
+		$query_param_value = $this->getQueryParamValue();
568
+		return array_key_exists($operator, $this->getContext()->getModel()->valid_null_style_operators())
569
+			&& !isset($query_param_value[1]);
570
+	}
571
+
572
+	/**
573
+	 * Returns true if the operator specified is a binary opeator (eg `=`, `!=`)
574
+	 * @since 4.9.72.p
575
+	 * @param $operator
576
+	 * @return boolean
577
+	 */
578
+	private function operatorisBinary($operator)
579
+	{
580
+		$query_param_value = $this->getQueryParamValue();
581
+		$model = $this->getContext()->getModel();
582
+		return isset($query_param_value[1])
583
+			&& !isset($query_param_value[2])
584
+			&& !array_key_exists(
585
+				$operator,
586
+				array_merge(
587
+					$model->valid_in_style_operators(),
588
+					$model->valid_null_style_operators(),
589
+					$model->valid_like_style_operators(),
590
+					$model->valid_between_style_operators()
591
+				)
592
+			);
593
+	}
594
+
595
+	/**
596
+	 * If we're debugging, throws an exception saying that the wrong number of arguments was provided.
597
+	 * @since 4.9.72.p
598
+	 * @param $operator
599
+	 * @throws RestException
600
+	 */
601
+	private function throwWrongNumberOfArgsExceptionIfDebugging($operator)
602
+	{
603
+		if (EED_Core_Rest_Api::debugMode()) {
604
+			throw new RestException(
605
+				'wrong_number_of_arguments',
606
+				sprintf(
607
+					esc_html__(
608
+						'The operator you provided, "%1$s" had the wrong number of arguments',
609
+						'event_espresso'
610
+					),
611
+					$operator
612
+				),
613
+				array(
614
+					'status' => 400,
615
+				)
616
+			);
617
+		}
618
+	}
619
+
620
+	/**
621
+	 * Wrapper for ModelDataTranslator::prepareFieldValuesFromJson(), just a tad more DRY.
622
+	 * @since 4.9.72.p
623
+	 * @param $value
624
+	 * @return mixed
625
+	 * @throws RestException
626
+	 */
627
+	private function prepareValuesFromJson($value)
628
+	{
629
+		return ModelDataTranslator::prepareFieldValuesFromJson(
630
+			$this->getField(),
631
+			$value,
632
+			$this->getContext()->getRequestedVersion(),
633
+			$this->getTimezone()
634
+		);
635
+	}
636
+
637
+	/**
638
+	 * Throws an exception if an invalid operator was specified and we're debugging.
639
+	 * @since 4.9.72.p
640
+	 * @throws RestException
641
+	 */
642
+	private function throwInvalidOperatorExceptionIfDebugging()
643
+	{
644
+		// so they didn't provide a valid operator
645
+		if (EED_Core_Rest_Api::debugMode()) {
646
+			throw new RestException(
647
+				'invalid_operator',
648
+				sprintf(
649
+					esc_html__(
650
+						'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
651
+						'event_espresso'
652
+					),
653
+					$this->getQueryParamKey(),
654
+					$this->getQueryParamValue()
655
+				),
656
+				array(
657
+					'status' => 400,
658
+				)
659
+			);
660
+		}
661
+	}
662
+
663
+	/**
664
+	 * Returns true if the query_param_key was a logic query parameter, eg `OR`, `AND`, `NOT`, `OR*`, etc.
665
+	 * @since 4.9.72.p
666
+	 * @return boolean
667
+	 */
668
+	private function isLogicQueryParam()
669
+	{
670
+		return in_array($this->getQueryParamKeySansStars(), $this->getContext()->getModel()->logic_query_param_keys());
671
+	}
672
+
673
+
674
+	/**
675
+	 * If the query param isn't for a field, it must be a nested query parameter which requires different logic.
676
+	 * @since 4.9.72.p
677
+	 * @return array
678
+	 * @throws DomainException
679
+	 * @throws EE_Error
680
+	 * @throws RestException
681
+	 * @throws InvalidDataTypeException
682
+	 * @throws InvalidInterfaceException
683
+	 * @throws InvalidArgumentException
684
+	 */
685
+	public function determineNestedConditionQueryParameters()
686
+	{
687
+
688
+		// so this param doesn't correspond to a field eh?
689
+		if ($this->getContext()->isWriting()) {
690
+			// always tell API clients about invalid parameters when they're creating data. Otherwise,
691
+			// they are probably going to create invalid data
692
+			throw new RestException(
693
+				'invalid_field',
694
+				sprintf(
695
+					/* translators: 1: variable name */
696
+					esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
697
+					$this->getQueryParamKey()
698
+				)
699
+			);
700
+		}
701
+		// so it's not for a field, is it a logic query param key?
702
+		if ($this->isLogicQueryParam()) {
703
+			return ModelDataTranslator::prepareConditionsQueryParamsForModels(
704
+				$this->getQueryParamValue(),
705
+				$this->getContext()->getModel(),
706
+				$this->getContext()->getRequestedVersion()
707
+			);
708
+		}
709
+		if (EED_Core_Rest_Api::debugMode()) {
710
+			// only tell API clients they got it wrong if we're in debug mode
711
+			// otherwise try our best ot fulfill their request by ignoring this invalid data
712
+			throw new RestException(
713
+				'invalid_parameter',
714
+				sprintf(
715
+					/* translators: 1: variable name */
716
+					esc_html__(
717
+						'You provided an invalid parameter, with key "%1$s"',
718
+						'event_espresso'
719
+					),
720
+					$this->getQueryParamKey()
721
+				),
722
+				array(
723
+					'status' => 400,
724
+				)
725
+			);
726
+		}
727
+		return null;
728
+	}
729 729
 }
730 730
 // End of file RestQueryParamMetadata.php
731 731
 // Location: EventEspresso\core\libraries\rest_api/RestQueryParamMetadata.php
Please login to merge, or discard this patch.
core/services/database/TableManager.php 1 patch
Indentation   +231 added lines, -231 removed lines patch added patch discarded remove patch
@@ -13,254 +13,254 @@
 block discarded – undo
13 13
 class TableManager extends \EE_Base
14 14
 {
15 15
 
16
-    /**
17
-     * @var TableAnalysis $table_analysis
18
-     */
19
-    private $table_analysis;
16
+	/**
17
+	 * @var TableAnalysis $table_analysis
18
+	 */
19
+	private $table_analysis;
20 20
 
21 21
 
22
-    /**
23
-     * TableManager constructor.
24
-     *
25
-     * @param TableAnalysis $TableAnalysis
26
-     */
27
-    public function __construct(TableAnalysis $TableAnalysis)
28
-    {
29
-        $this->table_analysis = $TableAnalysis;
30
-    }
22
+	/**
23
+	 * TableManager constructor.
24
+	 *
25
+	 * @param TableAnalysis $TableAnalysis
26
+	 */
27
+	public function __construct(TableAnalysis $TableAnalysis)
28
+	{
29
+		$this->table_analysis = $TableAnalysis;
30
+	}
31 31
 
32 32
 
33
-    /**
34
-     * Gets the injected table analyzer, or throws an exception
35
-     *
36
-     * @return TableAnalysis
37
-     * @throws \EE_Error
38
-     */
39
-    protected function getTableAnalysis()
40
-    {
41
-        if ($this->table_analysis instanceof TableAnalysis) {
42
-            return $this->table_analysis;
43
-        } else {
44
-            throw new \EE_Error(
45
-                sprintf(
46
-                    __('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
47
-                    get_class($this)
48
-                )
49
-            );
50
-        }
51
-    }
33
+	/**
34
+	 * Gets the injected table analyzer, or throws an exception
35
+	 *
36
+	 * @return TableAnalysis
37
+	 * @throws \EE_Error
38
+	 */
39
+	protected function getTableAnalysis()
40
+	{
41
+		if ($this->table_analysis instanceof TableAnalysis) {
42
+			return $this->table_analysis;
43
+		} else {
44
+			throw new \EE_Error(
45
+				sprintf(
46
+					__('Table analysis class on class %1$s is not set properly.', 'event_espresso'),
47
+					get_class($this)
48
+				)
49
+			);
50
+		}
51
+	}
52 52
 
53 53
 
54
-    /**
55
-     * @param string $table_name which can optionally start with $wpdb->prefix or not
56
-     * @param string $column_name
57
-     * @param string $column_info
58
-     * @return bool|false|int
59
-     */
60
-    public function addColumn($table_name, $column_name, $column_info = 'INT UNSIGNED NOT NULL')
61
-    {
62
-        if (apply_filters('FHEE__EEH_Activation__add_column_if_it_doesnt_exist__short_circuit', false)) {
63
-            return false;
64
-        }
65
-        global $wpdb;
66
-        $full_table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
67
-        $columns = $this->getTableColumns($table_name);
68
-        if (! in_array($column_name, $columns)) {
69
-            $alter_query = "ALTER TABLE {$full_table_name} ADD {$column_name} {$column_info}";
70
-            return $wpdb->query($alter_query);
71
-        }
72
-        return true;
73
-    }
54
+	/**
55
+	 * @param string $table_name which can optionally start with $wpdb->prefix or not
56
+	 * @param string $column_name
57
+	 * @param string $column_info
58
+	 * @return bool|false|int
59
+	 */
60
+	public function addColumn($table_name, $column_name, $column_info = 'INT UNSIGNED NOT NULL')
61
+	{
62
+		if (apply_filters('FHEE__EEH_Activation__add_column_if_it_doesnt_exist__short_circuit', false)) {
63
+			return false;
64
+		}
65
+		global $wpdb;
66
+		$full_table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
67
+		$columns = $this->getTableColumns($table_name);
68
+		if (! in_array($column_name, $columns)) {
69
+			$alter_query = "ALTER TABLE {$full_table_name} ADD {$column_name} {$column_info}";
70
+			return $wpdb->query($alter_query);
71
+		}
72
+		return true;
73
+	}
74 74
 
75 75
 
76
-    /**
77
-     * Gets the name of all columns on the  table. $table_name can
78
-     * optionally start with $wpdb->prefix or not
79
-     *
80
-     * @global \wpdb $wpdb
81
-     * @param string $table_name
82
-     * @return array
83
-     */
84
-    public function getTableColumns($table_name)
85
-    {
86
-        global $wpdb;
87
-        $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
88
-        $field_array = array();
89
-        if (! empty($table_name)) {
90
-            $columns = $wpdb->get_results("SHOW COLUMNS FROM {$table_name} ");
91
-            if ($columns !== false) {
92
-                foreach ($columns as $column) {
93
-                    $field_array[] = $column->Field;
94
-                }
95
-            }
96
-        }
97
-        return $field_array;
98
-    }
76
+	/**
77
+	 * Gets the name of all columns on the  table. $table_name can
78
+	 * optionally start with $wpdb->prefix or not
79
+	 *
80
+	 * @global \wpdb $wpdb
81
+	 * @param string $table_name
82
+	 * @return array
83
+	 */
84
+	public function getTableColumns($table_name)
85
+	{
86
+		global $wpdb;
87
+		$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
88
+		$field_array = array();
89
+		if (! empty($table_name)) {
90
+			$columns = $wpdb->get_results("SHOW COLUMNS FROM {$table_name} ");
91
+			if ($columns !== false) {
92
+				foreach ($columns as $column) {
93
+					$field_array[] = $column->Field;
94
+				}
95
+			}
96
+		}
97
+		return $field_array;
98
+	}
99 99
 
100 100
 
101
-    /**
102
-     * Drops the specified table from the database. $table_name can
103
-     * optionally start with $wpdb->prefix or not
104
-     *
105
-     * @global \wpdb $wpdb
106
-     * @param string $table_name
107
-     * @return int
108
-     */
109
-    public function dropTable($table_name)
110
-    {
111
-        global $wpdb;
112
-        if ($this->getTableAnalysis()->tableExists($table_name)) {
113
-            $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
114
-            return $wpdb->query("DROP TABLE IF EXISTS {$table_name}");
115
-        }
116
-        return 0;
117
-    }
101
+	/**
102
+	 * Drops the specified table from the database. $table_name can
103
+	 * optionally start with $wpdb->prefix or not
104
+	 *
105
+	 * @global \wpdb $wpdb
106
+	 * @param string $table_name
107
+	 * @return int
108
+	 */
109
+	public function dropTable($table_name)
110
+	{
111
+		global $wpdb;
112
+		if ($this->getTableAnalysis()->tableExists($table_name)) {
113
+			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
114
+			return $wpdb->query("DROP TABLE IF EXISTS {$table_name}");
115
+		}
116
+		return 0;
117
+	}
118 118
 
119 119
 
120
-    /**
121
-     * Drops all the tables mentioned in a single MYSQL query. Double-checks
122
-     * each table name provided has a wpdb prefix attached, and that it exists.
123
-     * Returns the list actually deleted
124
-     *
125
-     * @global WPDB $wpdb
126
-     * @param array $table_names
127
-     * @return array of table names which we deleted
128
-     */
129
-    public function dropTables($table_names)
130
-    {
131
-        $tables_to_delete = array();
132
-        foreach ($table_names as $table_name) {
133
-            $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
134
-            if ($this->getTableAnalysis()->tableExists($table_name)) {
135
-                $tables_to_delete[ $table_name ] = $table_name;
136
-            }
137
-        }
138
-        if (! empty($tables_to_delete)) {
139
-            global $wpdb;
140
-            // make sure we only have a unique strings in the array.
141
-            $tables_to_delete = array_unique($tables_to_delete);
142
-            $wpdb->query('DROP TABLE ' . implode(', ', $tables_to_delete));
143
-        }
144
-        return $tables_to_delete;
145
-    }
120
+	/**
121
+	 * Drops all the tables mentioned in a single MYSQL query. Double-checks
122
+	 * each table name provided has a wpdb prefix attached, and that it exists.
123
+	 * Returns the list actually deleted
124
+	 *
125
+	 * @global WPDB $wpdb
126
+	 * @param array $table_names
127
+	 * @return array of table names which we deleted
128
+	 */
129
+	public function dropTables($table_names)
130
+	{
131
+		$tables_to_delete = array();
132
+		foreach ($table_names as $table_name) {
133
+			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
134
+			if ($this->getTableAnalysis()->tableExists($table_name)) {
135
+				$tables_to_delete[ $table_name ] = $table_name;
136
+			}
137
+		}
138
+		if (! empty($tables_to_delete)) {
139
+			global $wpdb;
140
+			// make sure we only have a unique strings in the array.
141
+			$tables_to_delete = array_unique($tables_to_delete);
142
+			$wpdb->query('DROP TABLE ' . implode(', ', $tables_to_delete));
143
+		}
144
+		return $tables_to_delete;
145
+	}
146 146
 
147 147
 
148
-    /**
149
-     * Drops the specified index from the specified table. $table_name can
150
-     * optionally start with $wpdb->prefix or not
151
-     *
152
-     * @global \wpdb $wpdb
153
-     * @param string $table_name
154
-     * @param string $index_name
155
-     * @return int the number of indexes dropped. False if there was a datbase error
156
-     */
157
-    public function dropIndex($table_name, $index_name)
158
-    {
159
-        if (apply_filters('FHEE__EEH_Activation__drop_index__short_circuit', false)) {
160
-            return 0;
161
-        }
162
-        global $wpdb;
163
-        $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
164
-        $index_exists_query = "SHOW INDEX FROM {$table_name} WHERE key_name = '{$index_name}'";
165
-        if ($this->getTableAnalysis()->tableExists($table_name)
166
-            && $wpdb->get_var($index_exists_query)
167
-               === $table_name // using get_var with the $index_exists_query returns the table's name
168
-        ) {
169
-            return $wpdb->query("ALTER TABLE {$table_name} DROP INDEX {$index_name}");
170
-        }
171
-        return 0;
172
-    }
148
+	/**
149
+	 * Drops the specified index from the specified table. $table_name can
150
+	 * optionally start with $wpdb->prefix or not
151
+	 *
152
+	 * @global \wpdb $wpdb
153
+	 * @param string $table_name
154
+	 * @param string $index_name
155
+	 * @return int the number of indexes dropped. False if there was a datbase error
156
+	 */
157
+	public function dropIndex($table_name, $index_name)
158
+	{
159
+		if (apply_filters('FHEE__EEH_Activation__drop_index__short_circuit', false)) {
160
+			return 0;
161
+		}
162
+		global $wpdb;
163
+		$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
164
+		$index_exists_query = "SHOW INDEX FROM {$table_name} WHERE key_name = '{$index_name}'";
165
+		if ($this->getTableAnalysis()->tableExists($table_name)
166
+			&& $wpdb->get_var($index_exists_query)
167
+			   === $table_name // using get_var with the $index_exists_query returns the table's name
168
+		) {
169
+			return $wpdb->query("ALTER TABLE {$table_name} DROP INDEX {$index_name}");
170
+		}
171
+		return 0;
172
+	}
173 173
 
174 174
 
175
-    /**
176
-     * Just creates the requested table. $table_name can
177
-     * optionally start with $wpdb->prefix or not
178
-     *
179
-     * @param string $table_name
180
-     * @param string $create_sql defining the table's columns and indexes
181
-     * @param string $engine     (no need to specify "ENGINE=", that's implied)
182
-     * @return void
183
-     * @throws \EE_Error
184
-     */
185
-    public function createTable($table_name, $create_sql, $engine = 'MyISAM')
186
-    {
187
-        $engine = apply_filters(
188
-            'FHEE__EventEspresso_core_services_database_TableManager__createTable__engine',
189
-            $engine,
190
-            $table_name,
191
-            $create_sql
192
-        );
193
-        // does $sql contain valid column information? ( LPT: https://regex101.com/ is great for working out regex patterns )
194
-        if (preg_match('((((.*?))(,\s))+)', $create_sql, $valid_column_data)) {
195
-            $table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
196
-            /** @var \wpdb $wpdb */
197
-            global $wpdb;
198
-            $SQL = "CREATE TABLE {$table_name} ( {$create_sql} ) ENGINE={$engine} " . $wpdb->get_charset_collate();
175
+	/**
176
+	 * Just creates the requested table. $table_name can
177
+	 * optionally start with $wpdb->prefix or not
178
+	 *
179
+	 * @param string $table_name
180
+	 * @param string $create_sql defining the table's columns and indexes
181
+	 * @param string $engine     (no need to specify "ENGINE=", that's implied)
182
+	 * @return void
183
+	 * @throws \EE_Error
184
+	 */
185
+	public function createTable($table_name, $create_sql, $engine = 'MyISAM')
186
+	{
187
+		$engine = apply_filters(
188
+			'FHEE__EventEspresso_core_services_database_TableManager__createTable__engine',
189
+			$engine,
190
+			$table_name,
191
+			$create_sql
192
+		);
193
+		// does $sql contain valid column information? ( LPT: https://regex101.com/ is great for working out regex patterns )
194
+		if (preg_match('((((.*?))(,\s))+)', $create_sql, $valid_column_data)) {
195
+			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix($table_name);
196
+			/** @var \wpdb $wpdb */
197
+			global $wpdb;
198
+			$SQL = "CREATE TABLE {$table_name} ( {$create_sql} ) ENGINE={$engine} " . $wpdb->get_charset_collate();
199 199
 
200
-            // get $wpdb to echo errors, but buffer them. This way at least WE know an error
201
-            // happened. And then we can choose to tell the end user
202
-            $old_show_errors_policy = $wpdb->show_errors(true);
203
-            $old_error_suppression_policy = $wpdb->suppress_errors(false);
204
-            ob_start();
205
-            dbDelta($SQL);
206
-            $output = ob_get_contents();
207
-            ob_end_clean();
208
-            $wpdb->show_errors($old_show_errors_policy);
209
-            $wpdb->suppress_errors($old_error_suppression_policy);
210
-            if (! empty($output)) {
211
-                throw new \EE_Error($output);
212
-            }
213
-        } else {
214
-            throw new \EE_Error(
215
-                sprintf(
216
-                    __(
217
-                        'The following table creation SQL does not contain valid information about the table columns: %1$s %2$s',
218
-                        'event_espresso'
219
-                    ),
220
-                    '<br />',
221
-                    $create_sql
222
-                )
223
-            );
224
-        }
225
-    }
200
+			// get $wpdb to echo errors, but buffer them. This way at least WE know an error
201
+			// happened. And then we can choose to tell the end user
202
+			$old_show_errors_policy = $wpdb->show_errors(true);
203
+			$old_error_suppression_policy = $wpdb->suppress_errors(false);
204
+			ob_start();
205
+			dbDelta($SQL);
206
+			$output = ob_get_contents();
207
+			ob_end_clean();
208
+			$wpdb->show_errors($old_show_errors_policy);
209
+			$wpdb->suppress_errors($old_error_suppression_policy);
210
+			if (! empty($output)) {
211
+				throw new \EE_Error($output);
212
+			}
213
+		} else {
214
+			throw new \EE_Error(
215
+				sprintf(
216
+					__(
217
+						'The following table creation SQL does not contain valid information about the table columns: %1$s %2$s',
218
+						'event_espresso'
219
+					),
220
+					'<br />',
221
+					$create_sql
222
+				)
223
+			);
224
+		}
225
+	}
226 226
 
227 227
 
228
-    /**
229
-     * Drops the specified index if it's size differs from $desired_index_size.
230
-     * WordPress' dbdelta method doesn't automatically change index sizes, so this
231
-     * method can be used to only drop the index if needed, and afterwards dbdelta can be used as normal.
232
-     * If the table doesn't exist, or it exists but the index does not, or returns false
233
-     *
234
-     * @param string     $table_name
235
-     * @param string     $index_name
236
-     * @param string     $column_name        if none is provided, we assume the column name matches the index (often
237
-     *                                       true in EE)
238
-     * @param string|int $desired_index_size defaults to TableAnalysis::index_col_size, the max for utf8mb4.
239
-     * @return bool whether an index was dropped or not
240
-     * @throws /EE_Error if table analysis object isn't defined
241
-     */
242
-    public function dropIndexIfSizeNot(
243
-        $table_name,
244
-        $index_name,
245
-        $column_name = null,
246
-        $desired_index_size = TableAnalysis::INDEX_COLUMN_SIZE
247
-    ) {
248
-        if ($column_name === null) {
249
-            $column_name = $index_name;
250
-        }
251
-        if (! $this->getTableAnalysis()->tableExists($table_name)) {
252
-            return false;
253
-        }
254
-        $index_entries = $this->getTableAnalysis()->showIndexes($table_name, $index_name);
255
-        if (empty($index_entries)) {
256
-            return false;
257
-        }
258
-        foreach ($index_entries as $index_entry) {
259
-            if ($column_name === $index_entry->Column_name
260
-                && (string) $desired_index_size !== $index_entry->Sub_part) {
261
-                return $this->dropIndex($table_name, $index_name);
262
-            }
263
-        }
264
-        return false;
265
-    }
228
+	/**
229
+	 * Drops the specified index if it's size differs from $desired_index_size.
230
+	 * WordPress' dbdelta method doesn't automatically change index sizes, so this
231
+	 * method can be used to only drop the index if needed, and afterwards dbdelta can be used as normal.
232
+	 * If the table doesn't exist, or it exists but the index does not, or returns false
233
+	 *
234
+	 * @param string     $table_name
235
+	 * @param string     $index_name
236
+	 * @param string     $column_name        if none is provided, we assume the column name matches the index (often
237
+	 *                                       true in EE)
238
+	 * @param string|int $desired_index_size defaults to TableAnalysis::index_col_size, the max for utf8mb4.
239
+	 * @return bool whether an index was dropped or not
240
+	 * @throws /EE_Error if table analysis object isn't defined
241
+	 */
242
+	public function dropIndexIfSizeNot(
243
+		$table_name,
244
+		$index_name,
245
+		$column_name = null,
246
+		$desired_index_size = TableAnalysis::INDEX_COLUMN_SIZE
247
+	) {
248
+		if ($column_name === null) {
249
+			$column_name = $index_name;
250
+		}
251
+		if (! $this->getTableAnalysis()->tableExists($table_name)) {
252
+			return false;
253
+		}
254
+		$index_entries = $this->getTableAnalysis()->showIndexes($table_name, $index_name);
255
+		if (empty($index_entries)) {
256
+			return false;
257
+		}
258
+		foreach ($index_entries as $index_entry) {
259
+			if ($column_name === $index_entry->Column_name
260
+				&& (string) $desired_index_size !== $index_entry->Sub_part) {
261
+				return $this->dropIndex($table_name, $index_name);
262
+			}
263
+		}
264
+		return false;
265
+	}
266 266
 }
Please login to merge, or discard this patch.
payment_methods/Paypal_Express/EE_PMT_Paypal_Express.pm.php 1 patch
Indentation   +76 added lines, -76 removed lines patch added patch discarded remove patch
@@ -15,89 +15,89 @@
 block discarded – undo
15 15
 class EE_PMT_Paypal_Express extends EE_PMT_Base
16 16
 {
17 17
 
18
-    /**
19
-     * EE_PMT_Paypal_Express constructor.
20
-     */
21
-    public function __construct($pm_instance = null)
22
-    {
23
-        require_once($this->file_folder() . 'EEG_Paypal_Express.gateway.php');
24
-        $this->_gateway = new EEG_Paypal_Express();
18
+	/**
19
+	 * EE_PMT_Paypal_Express constructor.
20
+	 */
21
+	public function __construct($pm_instance = null)
22
+	{
23
+		require_once($this->file_folder() . 'EEG_Paypal_Express.gateway.php');
24
+		$this->_gateway = new EEG_Paypal_Express();
25 25
 
26
-        $this->_pretty_name = esc_html__('PayPal Express', 'event_espresso');
27
-        $this->_template_path = $this->file_folder() . 'templates' . DS;
28
-        $this->_default_description = esc_html__(
29
-            // @codingStandardsIgnoreStart
30
-            'After clicking \'Finalize Registration\', you will be forwarded to PayPal website to Login and make your payment.',
31
-            // @codingStandardsIgnoreEnd
32
-            'event_espresso'
33
-        );
34
-        $this->_default_button_url = $this->file_url() . 'lib' . DS . 'paypal-express-checkout-logo-gold-160.png';
26
+		$this->_pretty_name = esc_html__('PayPal Express', 'event_espresso');
27
+		$this->_template_path = $this->file_folder() . 'templates' . DS;
28
+		$this->_default_description = esc_html__(
29
+			// @codingStandardsIgnoreStart
30
+			'After clicking \'Finalize Registration\', you will be forwarded to PayPal website to Login and make your payment.',
31
+			// @codingStandardsIgnoreEnd
32
+			'event_espresso'
33
+		);
34
+		$this->_default_button_url = $this->file_url() . 'lib' . DS . 'paypal-express-checkout-logo-gold-160.png';
35 35
 
36
-        parent::__construct($pm_instance);
37
-    }
36
+		parent::__construct($pm_instance);
37
+	}
38 38
 
39 39
 
40
-    /**
41
-     * Adds the help tab.
42
-     *
43
-     * @see EE_PMT_Base::help_tabs_config()
44
-     * @return array
45
-     */
46
-    public function help_tabs_config()
47
-    {
48
-        return array(
49
-            $this->get_help_tab_name() => array(
50
-                'title'    => esc_html__('PayPal Express Settings', 'event_espresso'),
51
-                'filename' => 'payment_methods_overview_paypal_express'
52
-            )
53
-        );
54
-    }
40
+	/**
41
+	 * Adds the help tab.
42
+	 *
43
+	 * @see EE_PMT_Base::help_tabs_config()
44
+	 * @return array
45
+	 */
46
+	public function help_tabs_config()
47
+	{
48
+		return array(
49
+			$this->get_help_tab_name() => array(
50
+				'title'    => esc_html__('PayPal Express Settings', 'event_espresso'),
51
+				'filename' => 'payment_methods_overview_paypal_express'
52
+			)
53
+		);
54
+	}
55 55
 
56 56
 
57
-    /**
58
-     * Gets the form for all the settings related to this payment method type.
59
-     *
60
-     * @return EE_Payment_Method_Form
61
-     */
62
-    public function generate_new_settings_form()
63
-    {
64
-        return new SettingsForm(array(), $this->get_help_tab_link());
65
-    }
57
+	/**
58
+	 * Gets the form for all the settings related to this payment method type.
59
+	 *
60
+	 * @return EE_Payment_Method_Form
61
+	 */
62
+	public function generate_new_settings_form()
63
+	{
64
+		return new SettingsForm(array(), $this->get_help_tab_link());
65
+	}
66 66
 
67 67
 
68
-    /**
69
-     * Creates a billing form for this payment method type.
70
-     *
71
-     * @param \EE_Transaction $transaction
72
-     * @return \EE_Billing_Info_Form
73
-     */
74
-    public function generate_new_billing_form(EE_Transaction $transaction = null)
75
-    {
76
-        if ($this->_pm_instance->debug_mode()) {
77
-            $form = new EE_Billing_Info_Form(
78
-                $this->_pm_instance,
79
-                array(
80
-                    'name' => 'paypal_express_Info_Form',
81
-                    'subsections' => array(
82
-                        'paypal_express_debug_info' => new EE_Form_Section_Proper(
83
-                            array(
84
-                                'layout_strategy' => new EE_Template_Layout(
85
-                                    array(
86
-                                        'layout_template_file' => $this->_template_path
87
-                                                                    . 'paypal_express_debug_info.template.php',
88
-                                        'template_args'        => array(
89
-                                            'debug_mode' => $this->_pm_instance->debug_mode()
90
-                                        )
91
-                                    )
92
-                                )
93
-                            )
94
-                        )
95
-                    )
96
-                )
97
-            );
98
-            return $form;
99
-        }
68
+	/**
69
+	 * Creates a billing form for this payment method type.
70
+	 *
71
+	 * @param \EE_Transaction $transaction
72
+	 * @return \EE_Billing_Info_Form
73
+	 */
74
+	public function generate_new_billing_form(EE_Transaction $transaction = null)
75
+	{
76
+		if ($this->_pm_instance->debug_mode()) {
77
+			$form = new EE_Billing_Info_Form(
78
+				$this->_pm_instance,
79
+				array(
80
+					'name' => 'paypal_express_Info_Form',
81
+					'subsections' => array(
82
+						'paypal_express_debug_info' => new EE_Form_Section_Proper(
83
+							array(
84
+								'layout_strategy' => new EE_Template_Layout(
85
+									array(
86
+										'layout_template_file' => $this->_template_path
87
+																	. 'paypal_express_debug_info.template.php',
88
+										'template_args'        => array(
89
+											'debug_mode' => $this->_pm_instance->debug_mode()
90
+										)
91
+									)
92
+								)
93
+							)
94
+						)
95
+					)
96
+				)
97
+			);
98
+			return $form;
99
+		}
100 100
 
101
-        return false;
102
-    }
101
+		return false;
102
+	}
103 103
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Country.model.php 2 patches
Indentation   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -11,112 +11,112 @@
 block discarded – undo
11 11
 class EEM_Country extends EEM_Base
12 12
 {
13 13
 
14
-    // private instance of the Attendee object
15
-    protected static $_instance = null;
16
-    // array of all countries
17
-    private static $_all_countries = false;
18
-    // array of all active countries
19
-    private static $_active_countries = false;
14
+	// private instance of the Attendee object
15
+	protected static $_instance = null;
16
+	// array of all countries
17
+	private static $_all_countries = false;
18
+	// array of all active countries
19
+	private static $_active_countries = false;
20 20
 
21 21
 
22 22
 
23
-    /**
24
-     * Resets the country
25
-     * @return EEM_Country
26
-     */
27
-    public static function reset($timezone = null)
28
-    {
29
-        self::$_active_countries = null;
30
-        self::$_all_countries = null;
31
-        return parent::reset($timezone);
32
-    }
23
+	/**
24
+	 * Resets the country
25
+	 * @return EEM_Country
26
+	 */
27
+	public static function reset($timezone = null)
28
+	{
29
+		self::$_active_countries = null;
30
+		self::$_all_countries = null;
31
+		return parent::reset($timezone);
32
+	}
33 33
 
34
-    protected function __construct($timezone = null)
35
-    {
36
-        $this->singular_item = esc_html__('Country', 'event_espresso');
37
-        $this->plural_item = esc_html__('Countries', 'event_espresso');
34
+	protected function __construct($timezone = null)
35
+	{
36
+		$this->singular_item = esc_html__('Country', 'event_espresso');
37
+		$this->plural_item = esc_html__('Countries', 'event_espresso');
38 38
 
39 39
 
40
-        $this->_tables = array(
41
-            'Country'=> new EE_Primary_Table('esp_country', 'CNT_ISO')
42
-        );
43
-        $this->_fields = array(
44
-            'Country'=>array(
45
-                'CNT_active' => new EE_Boolean_Field('CNT_active', esc_html__('Country Appears in Dropdown Select Lists', 'event_espresso'), false, true),
46
-                'CNT_ISO'=> new EE_Primary_Key_String_Field('CNT_ISO', esc_html__('Country ISO Code', 'event_espresso')),
47
-                'CNT_ISO3'=>new EE_All_Caps_Text_Field('CNT_ISO3', esc_html__('Country ISO3 Code', 'event_espresso'), false, ''),
48
-                'RGN_ID'=>new EE_Integer_Field('RGN_ID', esc_html__('Region ID', 'event_espresso'), false, 0),// should be a foreign key, but no region table exists yet
49
-                'CNT_name'=>new EE_Plain_Text_Field('CNT_name', esc_html__('Country Name', 'event_espresso'), false, ''),
50
-                'CNT_cur_code'=>new EE_All_Caps_Text_Field('CNT_cur_code', esc_html__('Country Currency Code', 'event_espresso'), false),
51
-                'CNT_cur_single' => new EE_Plain_Text_Field('CNT_cur_single', esc_html__('Currency Name Singular', 'event_espresso'), false),
52
-                'CNT_cur_plural' => new EE_Plain_Text_Field('CNT_cur_plural', esc_html__('Currency Name Plural', 'event_espresso'), false),
53
-                'CNT_cur_sign' => new EE_Plain_Text_Field('CNT_cur_sign', esc_html__('Currency Sign', 'event_espresso'), false),
54
-                'CNT_cur_sign_b4' => new EE_Boolean_Field('CNT_cur_sign_b4', esc_html__('Currency Sign Before Number', 'event_espresso'), false, true),
55
-                'CNT_cur_dec_plc' => new EE_Integer_Field('CNT_cur_dec_plc', esc_html__('Currency Decimal Places', 'event_espresso'), false, 2),
56
-                'CNT_cur_dec_mrk' => new EE_Plain_Text_Field('CNT_cur_dec_mrk', esc_html__('Currency Decimal Mark', 'event_espresso'), false, '.'),
57
-                'CNT_cur_thsnds' => new EE_Plain_Text_Field('CNT_cur_thsnds', esc_html__('Currency Thousands Separator', 'event_espresso'), false, ','),
58
-                'CNT_tel_code' => new EE_Plain_Text_Field('CNT_tel_code', esc_html__('Country Telephone Code', 'event_espresso'), false, ''),
59
-                'CNT_is_EU' => new EE_Boolean_Field('CNT_is_EU', esc_html__('Country is Member of EU', 'event_espresso'), false, false)
60
-            ));
61
-        $this->_model_relations = array(
62
-            'Attendee'=>new EE_Has_Many_Relation(),
63
-            'State'=>new EE_Has_Many_Relation(),
64
-            'Venue'=>new EE_Has_Many_Relation(),
65
-        );
66
-        // only anyone to view, but only those with the default role can do anything
67
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
40
+		$this->_tables = array(
41
+			'Country'=> new EE_Primary_Table('esp_country', 'CNT_ISO')
42
+		);
43
+		$this->_fields = array(
44
+			'Country'=>array(
45
+				'CNT_active' => new EE_Boolean_Field('CNT_active', esc_html__('Country Appears in Dropdown Select Lists', 'event_espresso'), false, true),
46
+				'CNT_ISO'=> new EE_Primary_Key_String_Field('CNT_ISO', esc_html__('Country ISO Code', 'event_espresso')),
47
+				'CNT_ISO3'=>new EE_All_Caps_Text_Field('CNT_ISO3', esc_html__('Country ISO3 Code', 'event_espresso'), false, ''),
48
+				'RGN_ID'=>new EE_Integer_Field('RGN_ID', esc_html__('Region ID', 'event_espresso'), false, 0),// should be a foreign key, but no region table exists yet
49
+				'CNT_name'=>new EE_Plain_Text_Field('CNT_name', esc_html__('Country Name', 'event_espresso'), false, ''),
50
+				'CNT_cur_code'=>new EE_All_Caps_Text_Field('CNT_cur_code', esc_html__('Country Currency Code', 'event_espresso'), false),
51
+				'CNT_cur_single' => new EE_Plain_Text_Field('CNT_cur_single', esc_html__('Currency Name Singular', 'event_espresso'), false),
52
+				'CNT_cur_plural' => new EE_Plain_Text_Field('CNT_cur_plural', esc_html__('Currency Name Plural', 'event_espresso'), false),
53
+				'CNT_cur_sign' => new EE_Plain_Text_Field('CNT_cur_sign', esc_html__('Currency Sign', 'event_espresso'), false),
54
+				'CNT_cur_sign_b4' => new EE_Boolean_Field('CNT_cur_sign_b4', esc_html__('Currency Sign Before Number', 'event_espresso'), false, true),
55
+				'CNT_cur_dec_plc' => new EE_Integer_Field('CNT_cur_dec_plc', esc_html__('Currency Decimal Places', 'event_espresso'), false, 2),
56
+				'CNT_cur_dec_mrk' => new EE_Plain_Text_Field('CNT_cur_dec_mrk', esc_html__('Currency Decimal Mark', 'event_espresso'), false, '.'),
57
+				'CNT_cur_thsnds' => new EE_Plain_Text_Field('CNT_cur_thsnds', esc_html__('Currency Thousands Separator', 'event_espresso'), false, ','),
58
+				'CNT_tel_code' => new EE_Plain_Text_Field('CNT_tel_code', esc_html__('Country Telephone Code', 'event_espresso'), false, ''),
59
+				'CNT_is_EU' => new EE_Boolean_Field('CNT_is_EU', esc_html__('Country is Member of EU', 'event_espresso'), false, false)
60
+			));
61
+		$this->_model_relations = array(
62
+			'Attendee'=>new EE_Has_Many_Relation(),
63
+			'State'=>new EE_Has_Many_Relation(),
64
+			'Venue'=>new EE_Has_Many_Relation(),
65
+		);
66
+		// only anyone to view, but only those with the default role can do anything
67
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
68 68
 
69
-        parent::__construct($timezone);
70
-    }
69
+		parent::__construct($timezone);
70
+	}
71 71
 
72 72
 
73 73
 
74 74
 
75
-    /**
76
-    *       _get_countries
77
-    *
78
-    *       @access     public
79
-    *       @return         array
80
-    */
81
-    public function get_all_countries()
82
-    {
83
-        if (! self::$_all_countries) {
84
-            self::$_all_countries = $this->get_all(array( 'order_by'=>array('CNT_name'=>'ASC'), 'limit'=> array( 0,99999 )));
85
-        }
86
-        return self::$_all_countries;
87
-    }
75
+	/**
76
+	 *       _get_countries
77
+	 *
78
+	 *       @access     public
79
+	 *       @return         array
80
+	 */
81
+	public function get_all_countries()
82
+	{
83
+		if (! self::$_all_countries) {
84
+			self::$_all_countries = $this->get_all(array( 'order_by'=>array('CNT_name'=>'ASC'), 'limit'=> array( 0,99999 )));
85
+		}
86
+		return self::$_all_countries;
87
+	}
88 88
 
89
-    /**
90
-    *       _get_countries
91
-    *       Gets and caches the list of active countries. If you know the list of active countries
92
-    *       has changed during this request, first use EEM_Country::reset() to flush the cache
93
-    *       @access     public
94
-    *       @return         array
95
-    */
96
-    public function get_all_active_countries()
97
-    {
98
-        if (! self::$_active_countries) {
99
-            self::$_active_countries =  $this->get_all(array( array( 'CNT_active' => true ), 'order_by'=>array('CNT_name'=>'ASC'), 'limit'=>array( 0, 99999 )));
100
-        }
101
-        return self::$_active_countries;
102
-    }
89
+	/**
90
+	 *       _get_countries
91
+	 *       Gets and caches the list of active countries. If you know the list of active countries
92
+	 *       has changed during this request, first use EEM_Country::reset() to flush the cache
93
+	 *       @access     public
94
+	 *       @return         array
95
+	 */
96
+	public function get_all_active_countries()
97
+	{
98
+		if (! self::$_active_countries) {
99
+			self::$_active_countries =  $this->get_all(array( array( 'CNT_active' => true ), 'order_by'=>array('CNT_name'=>'ASC'), 'limit'=>array( 0, 99999 )));
100
+		}
101
+		return self::$_active_countries;
102
+	}
103 103
 
104
-    /**
105
-     * Gets the country's name by its ISO
106
-     * @param string $country_ISO
107
-     * @return string
108
-     */
109
-    public function get_country_name_by_ISO($country_ISO)
110
-    {
111
-        if (isset(self::$_all_countries[ $country_ISO ]) &&
112
-                self::$_all_countries[ $country_ISO ] instanceof EE_Country ) {
113
-            return self::$_all_countries[ $country_ISO ]->name();
114
-        }
115
-        $names = $this->get_col(array( array( 'CNT_ISO' => $country_ISO ), 'limit' => 1), 'CNT_name');
116
-        if (is_array($names) && ! empty($names)) {
117
-            return reset($names);
118
-        } else {
119
-            return '';
120
-        }
121
-    }
104
+	/**
105
+	 * Gets the country's name by its ISO
106
+	 * @param string $country_ISO
107
+	 * @return string
108
+	 */
109
+	public function get_country_name_by_ISO($country_ISO)
110
+	{
111
+		if (isset(self::$_all_countries[ $country_ISO ]) &&
112
+				self::$_all_countries[ $country_ISO ] instanceof EE_Country ) {
113
+			return self::$_all_countries[ $country_ISO ]->name();
114
+		}
115
+		$names = $this->get_col(array( array( 'CNT_ISO' => $country_ISO ), 'limit' => 1), 'CNT_name');
116
+		if (is_array($names) && ! empty($names)) {
117
+			return reset($names);
118
+		} else {
119
+			return '';
120
+		}
121
+	}
122 122
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -45,7 +45,7 @@  discard block
 block discarded – undo
45 45
                 'CNT_active' => new EE_Boolean_Field('CNT_active', esc_html__('Country Appears in Dropdown Select Lists', 'event_espresso'), false, true),
46 46
                 'CNT_ISO'=> new EE_Primary_Key_String_Field('CNT_ISO', esc_html__('Country ISO Code', 'event_espresso')),
47 47
                 'CNT_ISO3'=>new EE_All_Caps_Text_Field('CNT_ISO3', esc_html__('Country ISO3 Code', 'event_espresso'), false, ''),
48
-                'RGN_ID'=>new EE_Integer_Field('RGN_ID', esc_html__('Region ID', 'event_espresso'), false, 0),// should be a foreign key, but no region table exists yet
48
+                'RGN_ID'=>new EE_Integer_Field('RGN_ID', esc_html__('Region ID', 'event_espresso'), false, 0), // should be a foreign key, but no region table exists yet
49 49
                 'CNT_name'=>new EE_Plain_Text_Field('CNT_name', esc_html__('Country Name', 'event_espresso'), false, ''),
50 50
                 'CNT_cur_code'=>new EE_All_Caps_Text_Field('CNT_cur_code', esc_html__('Country Currency Code', 'event_espresso'), false),
51 51
                 'CNT_cur_single' => new EE_Plain_Text_Field('CNT_cur_single', esc_html__('Currency Name Singular', 'event_espresso'), false),
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
             'Venue'=>new EE_Has_Many_Relation(),
65 65
         );
66 66
         // only anyone to view, but only those with the default role can do anything
67
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
67
+        $this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Public();
68 68
 
69 69
         parent::__construct($timezone);
70 70
     }
@@ -80,8 +80,8 @@  discard block
 block discarded – undo
80 80
     */
81 81
     public function get_all_countries()
82 82
     {
83
-        if (! self::$_all_countries) {
84
-            self::$_all_countries = $this->get_all(array( 'order_by'=>array('CNT_name'=>'ASC'), 'limit'=> array( 0,99999 )));
83
+        if ( ! self::$_all_countries) {
84
+            self::$_all_countries = $this->get_all(array('order_by'=>array('CNT_name'=>'ASC'), 'limit'=> array(0, 99999)));
85 85
         }
86 86
         return self::$_all_countries;
87 87
     }
@@ -95,8 +95,8 @@  discard block
 block discarded – undo
95 95
     */
96 96
     public function get_all_active_countries()
97 97
     {
98
-        if (! self::$_active_countries) {
99
-            self::$_active_countries =  $this->get_all(array( array( 'CNT_active' => true ), 'order_by'=>array('CNT_name'=>'ASC'), 'limit'=>array( 0, 99999 )));
98
+        if ( ! self::$_active_countries) {
99
+            self::$_active_countries = $this->get_all(array(array('CNT_active' => true), 'order_by'=>array('CNT_name'=>'ASC'), 'limit'=>array(0, 99999)));
100 100
         }
101 101
         return self::$_active_countries;
102 102
     }
@@ -108,11 +108,11 @@  discard block
 block discarded – undo
108 108
      */
109 109
     public function get_country_name_by_ISO($country_ISO)
110 110
     {
111
-        if (isset(self::$_all_countries[ $country_ISO ]) &&
112
-                self::$_all_countries[ $country_ISO ] instanceof EE_Country ) {
113
-            return self::$_all_countries[ $country_ISO ]->name();
111
+        if (isset(self::$_all_countries[$country_ISO]) &&
112
+                self::$_all_countries[$country_ISO] instanceof EE_Country) {
113
+            return self::$_all_countries[$country_ISO]->name();
114 114
         }
115
-        $names = $this->get_col(array( array( 'CNT_ISO' => $country_ISO ), 'limit' => 1), 'CNT_name');
115
+        $names = $this->get_col(array(array('CNT_ISO' => $country_ISO), 'limit' => 1), 'CNT_name');
116 116
         if (is_array($names) && ! empty($names)) {
117 117
             return reset($names);
118 118
         } else {
Please login to merge, or discard this patch.
caffeinated/payment_methods/Paypal_Pro/EE_PMT_Paypal_Pro.pm.php 1 patch
Indentation   +146 added lines, -146 removed lines patch added patch discarded remove patch
@@ -14,150 +14,150 @@
 block discarded – undo
14 14
 class EE_PMT_Paypal_Pro extends EE_PMT_Base
15 15
 {
16 16
 
17
-    /**
18
-     * @param EE_Payment_Method $pm_instance
19
-     * @return EE_PMT_Paypal_Pro
20
-     */
21
-    public function __construct($pm_instance = null)
22
-    {
23
-        require_once($this->file_folder().'EEG_Paypal_Pro.gateway.php');
24
-        $this->_gateway = new EEG_Paypal_Pro();
25
-        $this->_pretty_name = __("Paypal Pro", 'event_espresso');
26
-        $this->_default_description = __('Please provide the following billing information.', 'event_espresso');
27
-        $this->_requires_https = true;
28
-        parent::__construct($pm_instance);
29
-    }
30
-
31
-
32
-    /**
33
-     * Gets the form for all the settings related to this payment method type
34
-     * @return EE_Payment_Method_Form
35
-     * @throws InvalidArgumentException
36
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
37
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
38
-     */
39
-    public function generate_new_settings_form()
40
-    {
41
-        return new PayPalProSettingsForm(array(), $this->get_help_tab_link());
42
-    }
43
-
44
-
45
-    /**
46
-     * Creates the billing form for this payment method type
47
-     * @param \EE_Transaction $transaction
48
-     * @throws \EE_Error
49
-     * @return EE_Billing_Info_Form
50
-     */
51
-    public function generate_new_billing_form(EE_Transaction $transaction = null)
52
-    {
53
-        $allowed_types = $this->_pm_instance->get_extra_meta('credit_card_types', true);
54
-        // if allowed types is a string or empty array or null...
55
-        if (empty($allowed_types)) {
56
-            $allowed_types = array();
57
-        }
58
-
59
-        $billing_form = new EE_Billing_Attendee_Info_Form(
60
-            $this->_pm_instance,
61
-            array(
62
-                'name'=> 'Paypal_Pro_Billing_Form',
63
-            //              'html_id'=> 'ee-Paypal_Pro-billing-form',
64
-                'subsections'=>array(
65
-                    'credit_card'=>new EE_Credit_Card_Input(
66
-                        array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('Card Number', 'event_espresso'))
67
-                    ),
68
-                    'credit_card_type'=>new EE_Select_Input(
69
-                        // the options are set dynamically
70
-                        array_intersect_key(EE_PMT_Paypal_Pro::card_types_supported(), array_flip($allowed_types)),
71
-                        array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('Card Type', 'event_espresso'))
72
-                    ),
73
-                    'exp_month'=>new EE_Credit_Card_Month_Input(
74
-                        true,
75
-                        array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' =>  __('Expiry Month', 'event_espresso')  )
76
-                    ),
77
-                    'exp_year'=>new EE_Credit_Card_Year_Input(
78
-                        array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('Expiry Year', 'event_espresso')  )
79
-                    ),
80
-                    'cvv'=>new EE_CVV_Input(
81
-                        array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('CVV', 'event_espresso') )
82
-                    ),
83
-                )
84
-            )
85
-        );
86
-        return $this->apply_billing_form_debug_settings($billing_form);
87
-    }
88
-
89
-
90
-
91
-    /**
92
-     * apply_billing_form_debug_settings
93
-     * applies debug data to the form
94
-     *
95
-     * @param \EE_Billing_Info_Form $billing_form
96
-     * @return \EE_Billing_Info_Form
97
-     */
98
-    public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
99
-    {
100
-        if ($this->_pm_instance->debug_mode()) {
101
-            $billing_form->add_subsections(
102
-                array( 'fyi_about_autofill' => $billing_form->payment_fields_autofilled_notice_html() ),
103
-                'credit_card'
104
-            );
105
-            $billing_form->add_subsections(
106
-                array( 'debug_content' => new EE_Form_Section_HTML_From_Template(dirname(__FILE__).DS.'templates'.DS.'paypal_pro_debug_info.template.php')),
107
-                'first_name'
108
-            );
109
-            $billing_form->get_input('credit_card_type')->set_default('Visa');
110
-            $billing_form->get_input('exp_year')->set_default(2018);
111
-            $billing_form->get_input('cvv')->set_default('115');
112
-        }
113
-        return $billing_form;
114
-    }
115
-
116
-
117
-
118
-    /**
119
-     * Returns an array of all the payment cards possibly supported by paypal pro.
120
-     * Keys are their values, values are their pretty names.
121
-     * @return array
122
-     */
123
-    public static function card_types_supported()
124
-    {
125
-        return array(
126
-            'Visa'=>  __("Visa", 'event_espresso'),
127
-            'MasterCard'=>  __("MasterCard", 'event_espresso'),
128
-            'Amex'=>  __("American Express", 'event_espresso'),
129
-            'Discover'=>  __("Discover", 'event_espresso')
130
-            );
131
-    }
132
-
133
-
134
-
135
-    /**
136
-     * Adds the help tab
137
-     * @see EE_PMT_Base::help_tabs_config()
138
-     * @return array
139
-     */
140
-    public function help_tabs_config()
141
-    {
142
-        return array(
143
-            $this->get_help_tab_name() => array(
144
-                        'title' => __('PayPal Pro Settings', 'event_espresso'),
145
-                        'filename' => 'payment_methods_overview_paypalpro'
146
-                        ),
147
-        );
148
-    }
149
-
150
-    /**
151
-     * Overrides parent's _get_billing_values_from_form because we want to
152
-     * get the country's 2-character ISO code, not the name like most gateways
153
-     * @param EE_Billing_Info_Form $billing_form
154
-     * @return array
155
-     */
156
-    protected function _get_billing_values_from_form($billing_form)
157
-    {
158
-        $billing_values = parent::_get_billing_values_from_form($billing_form);
159
-        $billing_values['country'] = $billing_form->get_input_value('country');
160
-        $billing_values['credit_card_type'] = $billing_form->get_input_value('credit_card_type');
161
-        return $billing_values;
162
-    }
17
+	/**
18
+	 * @param EE_Payment_Method $pm_instance
19
+	 * @return EE_PMT_Paypal_Pro
20
+	 */
21
+	public function __construct($pm_instance = null)
22
+	{
23
+		require_once($this->file_folder().'EEG_Paypal_Pro.gateway.php');
24
+		$this->_gateway = new EEG_Paypal_Pro();
25
+		$this->_pretty_name = __("Paypal Pro", 'event_espresso');
26
+		$this->_default_description = __('Please provide the following billing information.', 'event_espresso');
27
+		$this->_requires_https = true;
28
+		parent::__construct($pm_instance);
29
+	}
30
+
31
+
32
+	/**
33
+	 * Gets the form for all the settings related to this payment method type
34
+	 * @return EE_Payment_Method_Form
35
+	 * @throws InvalidArgumentException
36
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
37
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
38
+	 */
39
+	public function generate_new_settings_form()
40
+	{
41
+		return new PayPalProSettingsForm(array(), $this->get_help_tab_link());
42
+	}
43
+
44
+
45
+	/**
46
+	 * Creates the billing form for this payment method type
47
+	 * @param \EE_Transaction $transaction
48
+	 * @throws \EE_Error
49
+	 * @return EE_Billing_Info_Form
50
+	 */
51
+	public function generate_new_billing_form(EE_Transaction $transaction = null)
52
+	{
53
+		$allowed_types = $this->_pm_instance->get_extra_meta('credit_card_types', true);
54
+		// if allowed types is a string or empty array or null...
55
+		if (empty($allowed_types)) {
56
+			$allowed_types = array();
57
+		}
58
+
59
+		$billing_form = new EE_Billing_Attendee_Info_Form(
60
+			$this->_pm_instance,
61
+			array(
62
+				'name'=> 'Paypal_Pro_Billing_Form',
63
+			//              'html_id'=> 'ee-Paypal_Pro-billing-form',
64
+				'subsections'=>array(
65
+					'credit_card'=>new EE_Credit_Card_Input(
66
+						array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('Card Number', 'event_espresso'))
67
+					),
68
+					'credit_card_type'=>new EE_Select_Input(
69
+						// the options are set dynamically
70
+						array_intersect_key(EE_PMT_Paypal_Pro::card_types_supported(), array_flip($allowed_types)),
71
+						array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('Card Type', 'event_espresso'))
72
+					),
73
+					'exp_month'=>new EE_Credit_Card_Month_Input(
74
+						true,
75
+						array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' =>  __('Expiry Month', 'event_espresso')  )
76
+					),
77
+					'exp_year'=>new EE_Credit_Card_Year_Input(
78
+						array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('Expiry Year', 'event_espresso')  )
79
+					),
80
+					'cvv'=>new EE_CVV_Input(
81
+						array( 'required'=>true, 'html_class' => 'ee-billing-qstn', 'html_label_text' => __('CVV', 'event_espresso') )
82
+					),
83
+				)
84
+			)
85
+		);
86
+		return $this->apply_billing_form_debug_settings($billing_form);
87
+	}
88
+
89
+
90
+
91
+	/**
92
+	 * apply_billing_form_debug_settings
93
+	 * applies debug data to the form
94
+	 *
95
+	 * @param \EE_Billing_Info_Form $billing_form
96
+	 * @return \EE_Billing_Info_Form
97
+	 */
98
+	public function apply_billing_form_debug_settings(EE_Billing_Info_Form $billing_form)
99
+	{
100
+		if ($this->_pm_instance->debug_mode()) {
101
+			$billing_form->add_subsections(
102
+				array( 'fyi_about_autofill' => $billing_form->payment_fields_autofilled_notice_html() ),
103
+				'credit_card'
104
+			);
105
+			$billing_form->add_subsections(
106
+				array( 'debug_content' => new EE_Form_Section_HTML_From_Template(dirname(__FILE__).DS.'templates'.DS.'paypal_pro_debug_info.template.php')),
107
+				'first_name'
108
+			);
109
+			$billing_form->get_input('credit_card_type')->set_default('Visa');
110
+			$billing_form->get_input('exp_year')->set_default(2018);
111
+			$billing_form->get_input('cvv')->set_default('115');
112
+		}
113
+		return $billing_form;
114
+	}
115
+
116
+
117
+
118
+	/**
119
+	 * Returns an array of all the payment cards possibly supported by paypal pro.
120
+	 * Keys are their values, values are their pretty names.
121
+	 * @return array
122
+	 */
123
+	public static function card_types_supported()
124
+	{
125
+		return array(
126
+			'Visa'=>  __("Visa", 'event_espresso'),
127
+			'MasterCard'=>  __("MasterCard", 'event_espresso'),
128
+			'Amex'=>  __("American Express", 'event_espresso'),
129
+			'Discover'=>  __("Discover", 'event_espresso')
130
+			);
131
+	}
132
+
133
+
134
+
135
+	/**
136
+	 * Adds the help tab
137
+	 * @see EE_PMT_Base::help_tabs_config()
138
+	 * @return array
139
+	 */
140
+	public function help_tabs_config()
141
+	{
142
+		return array(
143
+			$this->get_help_tab_name() => array(
144
+						'title' => __('PayPal Pro Settings', 'event_espresso'),
145
+						'filename' => 'payment_methods_overview_paypalpro'
146
+						),
147
+		);
148
+	}
149
+
150
+	/**
151
+	 * Overrides parent's _get_billing_values_from_form because we want to
152
+	 * get the country's 2-character ISO code, not the name like most gateways
153
+	 * @param EE_Billing_Info_Form $billing_form
154
+	 * @return array
155
+	 */
156
+	protected function _get_billing_values_from_form($billing_form)
157
+	{
158
+		$billing_values = parent::_get_billing_values_from_form($billing_form);
159
+		$billing_values['country'] = $billing_form->get_input_value('country');
160
+		$billing_values['credit_card_type'] = $billing_form->get_input_value('credit_card_type');
161
+		return $billing_values;
162
+	}
163 163
 }
Please login to merge, or discard this patch.