Completed
Branch EDTR/input-labels (73d1b5)
by
unknown
11:26 queued 01:08
created
core/services/blocks/BlockRendererInterface.php 1 patch
Indentation   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -14,11 +14,11 @@
 block discarded – undo
14 14
 interface BlockRendererInterface
15 15
 {
16 16
 
17
-    /**
18
-     * This receives an array of attributes and returns rendered content for the block using those attributes.
19
-     *
20
-     * @param array $attributes
21
-     * @return string Rendered Content
22
-     */
23
-    public function render(array $attributes);
17
+	/**
18
+	 * This receives an array of attributes and returns rendered content for the block using those attributes.
19
+	 *
20
+	 * @param array $attributes
21
+	 * @return string Rendered Content
22
+	 */
23
+	public function render(array $attributes);
24 24
 }
Please login to merge, or discard this patch.
core/services/blocks/BlockRenderer.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -42,7 +42,7 @@
 block discarded – undo
42 42
      */
43 43
     private function setTemplateRootPath()
44 44
     {
45
-        $this->template_root_path = $this->domain->pluginPath() . 'ui/blocks/';
45
+        $this->template_root_path = $this->domain->pluginPath().'ui/blocks/';
46 46
     }
47 47
 
48 48
 
Please login to merge, or discard this patch.
Indentation   +44 added lines, -44 removed lines patch added patch discarded remove patch
@@ -15,57 +15,57 @@
 block discarded – undo
15 15
 abstract class BlockRenderer implements BlockRendererInterface
16 16
 {
17 17
 
18
-    /**
19
-     * @var DomainInterface
20
-     */
21
-    protected $domain;
18
+	/**
19
+	 * @var DomainInterface
20
+	 */
21
+	protected $domain;
22 22
 
23
-    /**
24
-     * @var string
25
-     */
26
-    private $template_root_path;
23
+	/**
24
+	 * @var string
25
+	 */
26
+	private $template_root_path;
27 27
 
28 28
 
29
-    /**
30
-     * BlockRenderer constructor.
31
-     *
32
-     * @param DomainInterface $domain
33
-     */
34
-    public function __construct(DomainInterface $domain)
35
-    {
36
-        $this->domain = $domain;
37
-        $this->setTemplateRootPath();
38
-    }
29
+	/**
30
+	 * BlockRenderer constructor.
31
+	 *
32
+	 * @param DomainInterface $domain
33
+	 */
34
+	public function __construct(DomainInterface $domain)
35
+	{
36
+		$this->domain = $domain;
37
+		$this->setTemplateRootPath();
38
+	}
39 39
 
40 40
 
41
-    /**
42
-     * Sets the root path to the main block template.
43
-     */
44
-    private function setTemplateRootPath()
45
-    {
46
-        $this->template_root_path = $this->domain->pluginPath() . 'ui/blocks/';
47
-    }
41
+	/**
42
+	 * Sets the root path to the main block template.
43
+	 */
44
+	private function setTemplateRootPath()
45
+	{
46
+		$this->template_root_path = $this->domain->pluginPath() . 'ui/blocks/';
47
+	}
48 48
 
49 49
 
50
-    /**
51
-     * Exposes the root path for the main block template.
52
-     * @return string
53
-     */
54
-    public function templateRootPath()
55
-    {
56
-        return $this->template_root_path;
57
-    }
50
+	/**
51
+	 * Exposes the root path for the main block template.
52
+	 * @return string
53
+	 */
54
+	public function templateRootPath()
55
+	{
56
+		return $this->template_root_path;
57
+	}
58 58
 
59 59
 
60
-    /**
61
-     * converts GraphQL GUID into EE DB ID
62
-     *
63
-     * @param string $GUID
64
-     * @return int
65
-     */
66
-    protected function parseGUID($GUID)
67
-    {
68
-        $parts = Relay::fromGlobalId($GUID);
69
-        return ! empty($parts['id']) ? $parts['id'] : 0;
70
-    }
60
+	/**
61
+	 * converts GraphQL GUID into EE DB ID
62
+	 *
63
+	 * @param string $GUID
64
+	 * @return int
65
+	 */
66
+	protected function parseGUID($GUID)
67
+	{
68
+		$parts = Relay::fromGlobalId($GUID);
69
+		return ! empty($parts['id']) ? $parts['id'] : 0;
70
+	}
71 71
 }
Please login to merge, or discard this patch.
ui/blocks/event-attendees.php 2 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -23,14 +23,14 @@
 block discarded – undo
23 23
                 )
24 24
                 : '';
25 25
             $gravatar_class = $attributes['avatarClass']
26
-                ? $attributes['avatarClass'] . ' contact-avatar-img avatar'
26
+                ? $attributes['avatarClass'].' contact-avatar-img avatar'
27 27
                 : 'contact-avatar-img avatar';
28 28
             $gravatar = $gravatar !== ''
29 29
                 ? '<div class="contact-image-wrap-div">'
30
-                    . '<img class="' . $gravatar_class . '"'
31
-                    . ' width="' . $attributes['avatarSize'] . '"'
32
-                    . ' height="' . $attributes['avatarSize'] . '"'
33
-                    . ' src="' . $gravatar . '" alt="contact avatar">'
30
+                    . '<img class="'.$gravatar_class.'"'
31
+                    . ' width="'.$attributes['avatarSize'].'"'
32
+                    . ' height="'.$attributes['avatarSize'].'"'
33
+                    . ' src="'.$gravatar.'" alt="contact avatar">'
34 34
                     . '</div>'
35 35
                 : '';
36 36
             echo "<li>{$gravatar}<span>{$attendee->full_name()}</span>";
Please login to merge, or discard this patch.
Indentation   +24 added lines, -24 removed lines patch added patch discarded remove patch
@@ -11,29 +11,29 @@
 block discarded – undo
11 11
 <div id="ee-block-event-attendees" class="ee-core-blocks event-espresso-blocks event-attendees">
12 12
     <ul>
13 13
         <?php
14
-        foreach ($attendees as $attendee) {
15
-            $gravatar = $attributes['showGravatar']
16
-                ? get_avatar_url(
17
-                    $attendee->email(),
18
-                    array(
19
-                        'width'   => $attributes['avatarSize'],
20
-                        'height'  => $attributes['avatarSize']
21
-                    )
22
-                )
23
-                : '';
24
-            $gravatar_class = $attributes['avatarClass']
25
-                ? $attributes['avatarClass'] . ' contact-avatar-img avatar'
26
-                : 'contact-avatar-img avatar';
27
-            $gravatar = $gravatar !== ''
28
-                ? '<div class="contact-image-wrap-div">'
29
-                    . '<img class="' . $gravatar_class . '"'
30
-                    . ' width="' . $attributes['avatarSize'] . '"'
31
-                    . ' height="' . $attributes['avatarSize'] . '"'
32
-                    . ' src="' . $gravatar . '" alt="contact avatar">'
33
-                    . '</div>'
34
-                : '';
35
-            echo "<li>{$gravatar}<span>{$attendee->full_name()}</span>";
36
-        }
37
-        ?>
14
+		foreach ($attendees as $attendee) {
15
+			$gravatar = $attributes['showGravatar']
16
+				? get_avatar_url(
17
+					$attendee->email(),
18
+					array(
19
+						'width'   => $attributes['avatarSize'],
20
+						'height'  => $attributes['avatarSize']
21
+					)
22
+				)
23
+				: '';
24
+			$gravatar_class = $attributes['avatarClass']
25
+				? $attributes['avatarClass'] . ' contact-avatar-img avatar'
26
+				: 'contact-avatar-img avatar';
27
+			$gravatar = $gravatar !== ''
28
+				? '<div class="contact-image-wrap-div">'
29
+					. '<img class="' . $gravatar_class . '"'
30
+					. ' width="' . $attributes['avatarSize'] . '"'
31
+					. ' height="' . $attributes['avatarSize'] . '"'
32
+					. ' src="' . $gravatar . '" alt="contact avatar">'
33
+					. '</div>'
34
+				: '';
35
+			echo "<li>{$gravatar}<span>{$attendee->full_name()}</span>";
36
+		}
37
+		?>
38 38
     </ul>
39 39
 </div>
Please login to merge, or discard this patch.
core/EE_Network_Config.core.php 2 patches
Indentation   +197 added lines, -197 removed lines patch added patch discarded remove patch
@@ -14,180 +14,180 @@  discard block
 block discarded – undo
14 14
 final class EE_Network_Config
15 15
 {
16 16
 
17
-    /**
18
-     * @var EE_Network_Config $_instance
19
-     */
20
-    private static $_instance;
21
-
22
-    /**
23
-     * addons can add their specific network_config objects to this property
24
-     *
25
-     * @var EE_Config_Base[] $addons
26
-     */
27
-    public $addons;
28
-
29
-    /**
30
-     * @var EE_Network_Core_Config $core
31
-     */
32
-    public $core;
33
-
34
-
35
-    /**
36
-     * @singleton method used to instantiate class object
37
-     * @return EE_Network_Config instance
38
-     */
39
-    public static function instance()
40
-    {
41
-        // check if class object is instantiated, and instantiated properly
42
-        if (! self::$_instance instanceof EE_Network_Config) {
43
-            self::$_instance = new self();
44
-        }
45
-        return self::$_instance;
46
-    }
47
-
48
-
49
-    /**
50
-     * class constructor
51
-     */
52
-    private function __construct()
53
-    {
54
-        do_action('AHEE__EE_Network_Config__construct__begin', $this);
55
-        // set defaults
56
-        $this->core = apply_filters('FHEE__EE_Network_Config___construct__core', new EE_Network_Core_Config());
57
-        $this->addons = array();
58
-
59
-        $this->_load_config();
60
-
61
-        // construct__end hook
62
-        do_action('AHEE__EE_Network_Config__construct__end', $this);
63
-    }
64
-
65
-
66
-    /**
67
-     * load EE Network Config options
68
-     *
69
-     * @return void
70
-     */
71
-    private function _load_config()
72
-    {
73
-        // load network config start hook
74
-        do_action('AHEE__EE_Network_Config___load_config__start', $this);
75
-        $config = $this->get_config();
76
-        foreach ($config as $config_prop => $settings) {
77
-            if ($config_prop === 'core' && ! $settings instanceof EE_Network_Core_Config) {
78
-                $core = new EE_Network_Core_Config();
79
-                foreach ($settings as $prop => $setting) {
80
-                    if (property_exists($core, $prop)) {
81
-                        $core->{$prop} = $setting;
82
-                    }
83
-                }
84
-                $settings = $core;
85
-                add_filter('FHEE__EE_Network_Config___load_config__update_network_config', '__return_true');
86
-            }
87
-            if (is_object($settings) && property_exists($this, $config_prop)) {
88
-                $this->{$config_prop} = apply_filters(
89
-                    'FHEE__EE_Network_Config___load_config__config_settings',
90
-                    $settings,
91
-                    $config_prop,
92
-                    $this
93
-                );
94
-                if (method_exists($settings, 'populate')) {
95
-                    $this->{$config_prop}->populate();
96
-                }
97
-                if (method_exists($settings, 'do_hooks')) {
98
-                    $this->{$config_prop}->do_hooks();
99
-                }
100
-            }
101
-        }
102
-        if (apply_filters('FHEE__EE_Network_Config___load_config__update_network_config', false)) {
103
-            $this->update_config();
104
-        }
105
-
106
-        // load network config end hook
107
-        do_action('AHEE__EE_Network_Config___load_config__end', $this);
108
-    }
109
-
110
-
111
-    /**
112
-     * get_config
113
-     *
114
-     * @return array of network config stuff
115
-     */
116
-    public function get_config()
117
-    {
118
-        // grab network configuration
119
-        $CFG = get_site_option('ee_network_config', array());
120
-        $CFG = apply_filters('FHEE__EE_Network_Config__get_config__CFG', $CFG);
121
-        return $CFG;
122
-    }
123
-
124
-
125
-    /**
126
-     * update_config
127
-     *
128
-     * @param bool $add_success
129
-     * @param bool $add_error
130
-     * @return bool success
131
-     */
132
-    public function update_config($add_success = false, $add_error = true)
133
-    {
134
-        do_action('AHEE__EE_Network_Config__update_config__begin', $this);
135
-
136
-        // need to bust cache for comparing original if this is a multisite install
137
-        if (is_multisite()) {
138
-            global $current_site;
139
-            $cache_key = $current_site->id . ':ee_network_config';
140
-            wp_cache_delete($cache_key, 'site-options');
141
-        }
142
-
143
-        // we have to compare existing saved config with config in memory because if there is no difference that means
144
-        // that the method executed fine but there just was no update.  WordPress doesn't distinguish between false because
145
-        // there were 0 records updated because of no change vs false because some error produced problems with the update.
146
-        $original = get_site_option('ee_network_config');
147
-
148
-        if ($original == $this) {
149
-            return true;
150
-        }
151
-        // update
152
-        $saved = update_site_option('ee_network_config', $this);
153
-
154
-        do_action('AHEE__EE_Network_Config__update_config__end', $this, $saved);
155
-        // if config remains the same or was updated successfully
156
-        if ($saved) {
157
-            if ($add_success) {
158
-                $msg = is_multisite() ? __(
159
-                    'The Event Espresso Network Configuration Settings have been successfully updated.',
160
-                    'event_espresso'
161
-                ) : __('Extra Event Espresso Configuration settings were successfully updated.', 'event_espresso');
162
-                EE_Error::add_success($msg);
163
-            }
164
-            return true;
165
-        }
166
-        if ($add_error) {
167
-            $msg = is_multisite() ? __(
168
-                'The Event Espresso Network Configuration Settings were not updated.',
169
-                'event_espresso'
170
-            ) : __('Extra Event Espresso Network Configuration settings were not updated.', 'event_espresso');
171
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
172
-        }
173
-        return false;
174
-    }
175
-
176
-
177
-    /**
178
-     * __sleep
179
-     *
180
-     * @return array
181
-     */
182
-    public function __sleep()
183
-    {
184
-        return apply_filters(
185
-            'FHEE__EE_Network_Config__sleep',
186
-            array(
187
-                'core',
188
-            )
189
-        );
190
-    }
17
+	/**
18
+	 * @var EE_Network_Config $_instance
19
+	 */
20
+	private static $_instance;
21
+
22
+	/**
23
+	 * addons can add their specific network_config objects to this property
24
+	 *
25
+	 * @var EE_Config_Base[] $addons
26
+	 */
27
+	public $addons;
28
+
29
+	/**
30
+	 * @var EE_Network_Core_Config $core
31
+	 */
32
+	public $core;
33
+
34
+
35
+	/**
36
+	 * @singleton method used to instantiate class object
37
+	 * @return EE_Network_Config instance
38
+	 */
39
+	public static function instance()
40
+	{
41
+		// check if class object is instantiated, and instantiated properly
42
+		if (! self::$_instance instanceof EE_Network_Config) {
43
+			self::$_instance = new self();
44
+		}
45
+		return self::$_instance;
46
+	}
47
+
48
+
49
+	/**
50
+	 * class constructor
51
+	 */
52
+	private function __construct()
53
+	{
54
+		do_action('AHEE__EE_Network_Config__construct__begin', $this);
55
+		// set defaults
56
+		$this->core = apply_filters('FHEE__EE_Network_Config___construct__core', new EE_Network_Core_Config());
57
+		$this->addons = array();
58
+
59
+		$this->_load_config();
60
+
61
+		// construct__end hook
62
+		do_action('AHEE__EE_Network_Config__construct__end', $this);
63
+	}
64
+
65
+
66
+	/**
67
+	 * load EE Network Config options
68
+	 *
69
+	 * @return void
70
+	 */
71
+	private function _load_config()
72
+	{
73
+		// load network config start hook
74
+		do_action('AHEE__EE_Network_Config___load_config__start', $this);
75
+		$config = $this->get_config();
76
+		foreach ($config as $config_prop => $settings) {
77
+			if ($config_prop === 'core' && ! $settings instanceof EE_Network_Core_Config) {
78
+				$core = new EE_Network_Core_Config();
79
+				foreach ($settings as $prop => $setting) {
80
+					if (property_exists($core, $prop)) {
81
+						$core->{$prop} = $setting;
82
+					}
83
+				}
84
+				$settings = $core;
85
+				add_filter('FHEE__EE_Network_Config___load_config__update_network_config', '__return_true');
86
+			}
87
+			if (is_object($settings) && property_exists($this, $config_prop)) {
88
+				$this->{$config_prop} = apply_filters(
89
+					'FHEE__EE_Network_Config___load_config__config_settings',
90
+					$settings,
91
+					$config_prop,
92
+					$this
93
+				);
94
+				if (method_exists($settings, 'populate')) {
95
+					$this->{$config_prop}->populate();
96
+				}
97
+				if (method_exists($settings, 'do_hooks')) {
98
+					$this->{$config_prop}->do_hooks();
99
+				}
100
+			}
101
+		}
102
+		if (apply_filters('FHEE__EE_Network_Config___load_config__update_network_config', false)) {
103
+			$this->update_config();
104
+		}
105
+
106
+		// load network config end hook
107
+		do_action('AHEE__EE_Network_Config___load_config__end', $this);
108
+	}
109
+
110
+
111
+	/**
112
+	 * get_config
113
+	 *
114
+	 * @return array of network config stuff
115
+	 */
116
+	public function get_config()
117
+	{
118
+		// grab network configuration
119
+		$CFG = get_site_option('ee_network_config', array());
120
+		$CFG = apply_filters('FHEE__EE_Network_Config__get_config__CFG', $CFG);
121
+		return $CFG;
122
+	}
123
+
124
+
125
+	/**
126
+	 * update_config
127
+	 *
128
+	 * @param bool $add_success
129
+	 * @param bool $add_error
130
+	 * @return bool success
131
+	 */
132
+	public function update_config($add_success = false, $add_error = true)
133
+	{
134
+		do_action('AHEE__EE_Network_Config__update_config__begin', $this);
135
+
136
+		// need to bust cache for comparing original if this is a multisite install
137
+		if (is_multisite()) {
138
+			global $current_site;
139
+			$cache_key = $current_site->id . ':ee_network_config';
140
+			wp_cache_delete($cache_key, 'site-options');
141
+		}
142
+
143
+		// we have to compare existing saved config with config in memory because if there is no difference that means
144
+		// that the method executed fine but there just was no update.  WordPress doesn't distinguish between false because
145
+		// there were 0 records updated because of no change vs false because some error produced problems with the update.
146
+		$original = get_site_option('ee_network_config');
147
+
148
+		if ($original == $this) {
149
+			return true;
150
+		}
151
+		// update
152
+		$saved = update_site_option('ee_network_config', $this);
153
+
154
+		do_action('AHEE__EE_Network_Config__update_config__end', $this, $saved);
155
+		// if config remains the same or was updated successfully
156
+		if ($saved) {
157
+			if ($add_success) {
158
+				$msg = is_multisite() ? __(
159
+					'The Event Espresso Network Configuration Settings have been successfully updated.',
160
+					'event_espresso'
161
+				) : __('Extra Event Espresso Configuration settings were successfully updated.', 'event_espresso');
162
+				EE_Error::add_success($msg);
163
+			}
164
+			return true;
165
+		}
166
+		if ($add_error) {
167
+			$msg = is_multisite() ? __(
168
+				'The Event Espresso Network Configuration Settings were not updated.',
169
+				'event_espresso'
170
+			) : __('Extra Event Espresso Network Configuration settings were not updated.', 'event_espresso');
171
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
172
+		}
173
+		return false;
174
+	}
175
+
176
+
177
+	/**
178
+	 * __sleep
179
+	 *
180
+	 * @return array
181
+	 */
182
+	public function __sleep()
183
+	{
184
+		return apply_filters(
185
+			'FHEE__EE_Network_Config__sleep',
186
+			array(
187
+				'core',
188
+			)
189
+		);
190
+	}
191 191
 }
192 192
 
193 193
 
@@ -197,27 +197,27 @@  discard block
 block discarded – undo
197 197
 class EE_Network_Core_Config extends EE_Config_Base
198 198
 {
199 199
 
200
-    /**
201
-     * PUE site license key
202
-     *
203
-     * @var string $site_license_key
204
-     */
205
-    public $site_license_key;
206
-
207
-    /**
208
-     * This indicates whether messages system processing should be done on the same request or not.
209
-     *
210
-     * @var boolean $do_messages_on_same_request
211
-     */
212
-    public $do_messages_on_same_request;
213
-
214
-
215
-    /**
216
-     * EE_Network_Core_Config constructor.
217
-     */
218
-    public function __construct()
219
-    {
220
-        $this->site_license_key = '';
221
-        $this->do_messages_on_same_request = false;
222
-    }
200
+	/**
201
+	 * PUE site license key
202
+	 *
203
+	 * @var string $site_license_key
204
+	 */
205
+	public $site_license_key;
206
+
207
+	/**
208
+	 * This indicates whether messages system processing should be done on the same request or not.
209
+	 *
210
+	 * @var boolean $do_messages_on_same_request
211
+	 */
212
+	public $do_messages_on_same_request;
213
+
214
+
215
+	/**
216
+	 * EE_Network_Core_Config constructor.
217
+	 */
218
+	public function __construct()
219
+	{
220
+		$this->site_license_key = '';
221
+		$this->do_messages_on_same_request = false;
222
+	}
223 223
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -39,7 +39,7 @@  discard block
 block discarded – undo
39 39
     public static function instance()
40 40
     {
41 41
         // check if class object is instantiated, and instantiated properly
42
-        if (! self::$_instance instanceof EE_Network_Config) {
42
+        if ( ! self::$_instance instanceof EE_Network_Config) {
43 43
             self::$_instance = new self();
44 44
         }
45 45
         return self::$_instance;
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
         // need to bust cache for comparing original if this is a multisite install
137 137
         if (is_multisite()) {
138 138
             global $current_site;
139
-            $cache_key = $current_site->id . ':ee_network_config';
139
+            $cache_key = $current_site->id.':ee_network_config';
140 140
             wp_cache_delete($cache_key, 'site-options');
141 141
         }
142 142
 
Please login to merge, or discard this patch.
core/libraries/rest_api/RestIncomingQueryParamMetadata.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -179,7 +179,7 @@
 block discarded – undo
179 179
     }
180 180
 
181 181
     /**
182
-     * @param mixed $is_gmt_field
182
+     * @param boolean $is_gmt_field
183 183
      */
184 184
     private function setIsGmtField($is_gmt_field)
185 185
     {
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
             $this->getContext()->getModel()
207 207
         ));
208 208
         // double-check is it a *_gmt field?
209
-        if (!$this->getField() instanceof EE_Model_Field_Base
209
+        if ( ! $this->getField() instanceof EE_Model_Field_Base
210 210
             && ModelDataTranslator::isGmtDateFieldName($this->getQueryParamKeySansStars())
211 211
         ) {
212 212
             // yep, take off '_gmt', and find the field
@@ -304,7 +304,7 @@  discard block
 block discarded – undo
304 304
      */
305 305
     private function valueIsArrayDuringRead()
306 306
     {
307
-        return !$this->getContext()->isWriting() && is_array($this->getQueryParamValue());
307
+        return ! $this->getContext()->isWriting() && is_array($this->getQueryParamValue());
308 308
     }
309 309
 
310 310
     /**
@@ -315,7 +315,7 @@  discard block
 block discarded – undo
315 315
      */
316 316
     private function valueIsAssociativeArray()
317 317
     {
318
-        return !EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue());
318
+        return ! EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue());
319 319
     }
320 320
 
321 321
     /**
@@ -403,7 +403,7 @@  discard block
 block discarded – undo
403 403
     {
404 404
         // the value should be JSON or CSV
405 405
         $values = json_decode($sub_array_value);
406
-        if (!is_array($values)) {
406
+        if ( ! is_array($values)) {
407 407
             $values = array_filter(
408 408
                 array_map(
409 409
                     'trim',
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
      */
425 425
     private function assertSimplifiedSpecifiedOperator()
426 426
     {
427
-        if (!$this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) {
427
+        if ( ! $this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) {
428 428
             throw new RestException(
429 429
                 'numerically_indexed_array_of_values_only',
430 430
                 sprintf(
@@ -479,7 +479,7 @@  discard block
 block discarded – undo
479 479
         $valid_operators = $this->getContext()->getModel()->valid_operators();
480 480
         $query_param_value = $this->getQueryParamValue();
481 481
         return isset($query_param_value[0])
482
-            && isset($valid_operators[ $query_param_value[0] ]);
482
+            && isset($valid_operators[$query_param_value[0]]);
483 483
     }
484 484
 
485 485
     /**
@@ -497,7 +497,7 @@  discard block
 block discarded – undo
497 497
         )
498 498
             && isset($valueArray[1])
499 499
             && is_array($valueArray[1])
500
-            && !isset($valueArray[2]);
500
+            && ! isset($valueArray[2]);
501 501
     }
502 502
 
503 503
     /**
@@ -512,8 +512,8 @@  discard block
 block discarded – undo
512 512
             && isset($query_param_value[1])
513 513
             && is_array($query_param_value[1])
514 514
             && isset($query_param_value[1][0], $query_param_value[1][1])
515
-            && !isset($query_param_value[1][2])
516
-            && !isset($query_param_value[2]);
515
+            && ! isset($query_param_value[1][2])
516
+            && ! isset($query_param_value[2]);
517 517
     }
518 518
 
519 519
     /**
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
         $query_param_value = $this->getQueryParamValue();
528 528
         return array_key_exists($operator, $this->getContext()->getModel()->valid_like_style_operators())
529 529
             && isset($query_param_value[1])
530
-            && !isset($query_param_value[2]);
530
+            && ! isset($query_param_value[2]);
531 531
     }
532 532
 
533 533
     /**
@@ -540,7 +540,7 @@  discard block
 block discarded – undo
540 540
     {
541 541
         $query_param_value = $this->getQueryParamValue();
542 542
         return array_key_exists($operator, $this->getContext()->getModel()->valid_null_style_operators())
543
-            && !isset($query_param_value[1]);
543
+            && ! isset($query_param_value[1]);
544 544
     }
545 545
 
546 546
     /**
@@ -554,8 +554,8 @@  discard block
 block discarded – undo
554 554
         $query_param_value = $this->getQueryParamValue();
555 555
         $model = $this->getContext()->getModel();
556 556
         return isset($query_param_value[1])
557
-            && !isset($query_param_value[2])
558
-            && !array_key_exists(
557
+            && ! isset($query_param_value[2])
558
+            && ! array_key_exists(
559 559
                 $operator,
560 560
                 array_merge(
561 561
                     $model->valid_in_style_operators(),
Please login to merge, or discard this 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/libraries/rest_api/ModelDataTranslator.php 3 patches
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
         ) {
65 65
             $new_value_maybe_array = array();
66 66
             foreach ($original_value_maybe_array as $array_key => $array_item) {
67
-                $new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
67
+                $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
68 68
                     $field_obj,
69 69
                     $array_item,
70 70
                     $requested_version,
@@ -96,7 +96,7 @@  discard block
 block discarded – undo
96 96
         if (is_array($original_value_maybe_array)) {
97 97
             $new_value = array();
98 98
             foreach ($original_value_maybe_array as $key => $value) {
99
-                $new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
99
+                $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson(
100 100
                     $field_obj,
101 101
                     $value,
102 102
                     $request_version
@@ -229,7 +229,7 @@  discard block
 block discarded – undo
229 229
                 '0',
230 230
                 STR_PAD_LEFT
231 231
             );
232
-        return $original_timestamp . $offset_sign . $offset_string;
232
+        return $original_timestamp.$offset_sign.$offset_string;
233 233
     }
234 234
 
235 235
 
@@ -306,7 +306,7 @@  discard block
 block discarded – undo
306 306
                     // first, check if its a MySQL timestamp in GMT
307 307
                     $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
308 308
                 }
309
-                if (! $datetime_obj instanceof \DateTime) {
309
+                if ( ! $datetime_obj instanceof \DateTime) {
310 310
                     // so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
311 311
                     $datetime_obj = $field_obj->prepare_for_set($original_value);
312 312
                 }
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
                         $original_value,
333 333
                         $field_obj->get_name(),
334 334
                         $field_obj->get_model_name(),
335
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
335
+                        $field_obj->get_time_format().' '.$field_obj->get_time_format()
336 336
                     )
337 337
                 );
338 338
             }
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
         }
345 345
         // are we about to send an object? just don't. We have no good way to represent it in JSON.
346 346
         // can't just check using is_object() because that missed PHP incomplete objects
347
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
347
+        if ( ! ModelDataTranslator::isRepresentableInJson($new_value)) {
348 348
             $new_value = array(
349 349
                 'error_code'    => 'php_object_not_return',
350 350
                 'error_message' => esc_html__(
@@ -394,7 +394,7 @@  discard block
 block discarded – undo
394 394
             $query_param_meta = new RestIncomingQueryParamMetadata($query_param_key, $query_param_value, $context);
395 395
             if ($query_param_meta->getField() instanceof EE_Model_Field_Base) {
396 396
                 $translated_value = $query_param_meta->determineConditionsQueryParameterValue();
397
-                if ((isset($query_param_for_models[ $query_param_meta->getQueryParamKey() ]) && $query_param_meta->isGmtField())
397
+                if ((isset($query_param_for_models[$query_param_meta->getQueryParamKey()]) && $query_param_meta->isGmtField())
398 398
                     || $translated_value === null
399 399
                 ) {
400 400
                     // they have already provided a non-gmt field, ignore the gmt one. That's what WP core
@@ -402,11 +402,11 @@  discard block
 block discarded – undo
402 402
                     // OR we couldn't create a translated value from their input
403 403
                     continue;
404 404
                 }
405
-                $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $translated_value;
405
+                $query_param_for_models[$query_param_meta->getQueryParamKey()] = $translated_value;
406 406
             } else {
407 407
                 $nested_query_params = $query_param_meta->determineNestedConditionQueryParameters();
408 408
                 if ($nested_query_params) {
409
-                    $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $nested_query_params;
409
+                    $query_param_for_models[$query_param_meta->getQueryParamKey()] = $nested_query_params;
410 410
                 }
411 411
             }
412 412
         }
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
      */
439 439
     public static function removeGmtFromFieldName($field_name)
440 440
     {
441
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
441
+        if ( ! ModelDataTranslator::isGmtDateFieldName($field_name)) {
442 442
             return $field_name;
443 443
         }
444 444
         $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
@@ -481,7 +481,7 @@  discard block
 block discarded – undo
481 481
     {
482 482
         $new_array = array();
483 483
         foreach ($field_names as $key => $field_name) {
484
-            $new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
484
+            $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
485 485
         }
486 486
         return $new_array;
487 487
     }
@@ -498,7 +498,7 @@  discard block
 block discarded – undo
498 498
     {
499 499
         $new_array = array();
500 500
         foreach ($field_names_as_keys as $field_name => $value) {
501
-            $new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
501
+            $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
502 502
         }
503 503
         return $new_array;
504 504
     }
@@ -591,10 +591,10 @@  discard block
 block discarded – undo
591 591
                         $requested_version
592 592
                     );
593 593
                 }
594
-                $query_param_for_models[ $query_param_key ] = $translated_value;
594
+                $query_param_for_models[$query_param_key] = $translated_value;
595 595
             } else {
596 596
                 // so it's not for a field, assume it's a logic query param key
597
-                $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
597
+                $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
598 598
                     $query_param_value,
599 599
                     $model,
600 600
                     $requested_version
@@ -646,13 +646,13 @@  discard block
 block discarded – undo
646 646
             );
647 647
         }
648 648
         $number_of_parts = count($query_param_parts);
649
-        $last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
649
+        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
650 650
         if ($number_of_parts === 1) {
651 651
             $field_name = $last_query_param_part;
652 652
         } else {// $number_of_parts >= 2
653 653
             // the last part is the column name, and there are only 2parts. therefore...
654 654
             $field_name = $last_query_param_part;
655
-            $model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
655
+            $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
656 656
         }
657 657
         try {
658 658
             return $model->field_settings_for($field_name, false);
Please login to merge, or discard this patch.
Unused Use Statements   -4 removed lines patch added patch discarded remove patch
@@ -4,14 +4,10 @@
 block discarded – undo
4 4
 
5 5
 use DomainException;
6 6
 use EE_Boolean_Field;
7
-use EE_Capabilities;
8 7
 use EE_Datetime_Field;
9 8
 use EE_Error;
10 9
 use EE_Infinite_Integer_Field;
11
-use EE_Maybe_Serialized_Simple_HTML_Field;
12 10
 use EE_Model_Field_Base;
13
-use EE_Password_Field;
14
-use EE_Restriction_Generator_Base;
15 11
 use EE_Serialized_Text_Field;
16 12
 use EED_Core_Rest_Api;
17 13
 use EEM_Base;
Please login to merge, or discard this patch.
Indentation   +642 added lines, -642 removed lines patch added patch discarded remove patch
@@ -39,646 +39,646 @@
 block discarded – undo
39 39
 class ModelDataTranslator
40 40
 {
41 41
 
42
-    /**
43
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
44
-     * fields that COULD contain -1; so we use null
45
-     */
46
-    const EE_INF_IN_REST = null;
47
-
48
-
49
-    /**
50
-     * Prepares a possible array of input values from JSON for use by the models
51
-     *
52
-     * @param EE_Model_Field_Base $field_obj
53
-     * @param mixed               $original_value_maybe_array
54
-     * @param string              $requested_version
55
-     * @param string              $timezone_string treat values as being in this timezone
56
-     * @return mixed
57
-     * @throws RestException
58
-     */
59
-    public static function prepareFieldValuesFromJson(
60
-        $field_obj,
61
-        $original_value_maybe_array,
62
-        $requested_version,
63
-        $timezone_string = 'UTC'
64
-    ) {
65
-        if (is_array($original_value_maybe_array)
66
-            && ! $field_obj instanceof EE_Serialized_Text_Field
67
-        ) {
68
-            $new_value_maybe_array = array();
69
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
70
-                $new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
71
-                    $field_obj,
72
-                    $array_item,
73
-                    $requested_version,
74
-                    $timezone_string
75
-                );
76
-            }
77
-        } else {
78
-            $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
79
-                $field_obj,
80
-                $original_value_maybe_array,
81
-                $requested_version,
82
-                $timezone_string
83
-            );
84
-        }
85
-        return $new_value_maybe_array;
86
-    }
87
-
88
-
89
-    /**
90
-     * Prepares an array of field values FOR use in JSON/REST API
91
-     *
92
-     * @param EE_Model_Field_Base $field_obj
93
-     * @param mixed               $original_value_maybe_array
94
-     * @param string              $request_version (eg 4.8.36)
95
-     * @return array
96
-     */
97
-    public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
98
-    {
99
-        if (is_array($original_value_maybe_array)) {
100
-            $new_value = array();
101
-            foreach ($original_value_maybe_array as $key => $value) {
102
-                $new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
103
-                    $field_obj,
104
-                    $value,
105
-                    $request_version
106
-                );
107
-            }
108
-        } else {
109
-            $new_value = ModelDataTranslator::prepareFieldValueForJson(
110
-                $field_obj,
111
-                $original_value_maybe_array,
112
-                $request_version
113
-            );
114
-        }
115
-        return $new_value;
116
-    }
117
-
118
-
119
-    /**
120
-     * Prepares incoming data from the json or $_REQUEST parameters for the models'
121
-     * "$query_params".
122
-     *
123
-     * @param EE_Model_Field_Base $field_obj
124
-     * @param mixed               $original_value
125
-     * @param string              $requested_version
126
-     * @param string              $timezone_string treat values as being in this timezone
127
-     * @return mixed
128
-     * @throws RestException
129
-     * @throws DomainException
130
-     * @throws EE_Error
131
-     */
132
-    public static function prepareFieldValueFromJson(
133
-        $field_obj,
134
-        $original_value,
135
-        $requested_version,
136
-        $timezone_string = 'UTC' // UTC
137
-    ) {
138
-        // check if they accidentally submitted an error value. If so throw an exception
139
-        if (is_array($original_value)
140
-            && isset($original_value['error_code'], $original_value['error_message'])) {
141
-            throw new RestException(
142
-                'rest_submitted_error_value',
143
-                sprintf(
144
-                    esc_html__(
145
-                        'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
146
-                        'event_espresso'
147
-                    ),
148
-                    $field_obj->get_name()
149
-                ),
150
-                array(
151
-                    'status' => 400,
152
-                )
153
-            );
154
-        }
155
-        // double-check for serialized PHP. We never accept serialized PHP. No way Jose.
156
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
157
-        $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
158
-        $new_value = null;
159
-        // walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
160
-        // way Jose.
161
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
162
-        if ($field_obj instanceof EE_Infinite_Integer_Field
163
-            && in_array($original_value, array(null, ''), true)
164
-        ) {
165
-            $new_value = EE_INF;
166
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
167
-            $new_value = rest_parse_date(
168
-                self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
169
-            );
170
-            if ($new_value === false) {
171
-                throw new RestException(
172
-                    'invalid_format_for_timestamp',
173
-                    sprintf(
174
-                        esc_html__(
175
-                            'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
176
-                            'event_espresso'
177
-                        ),
178
-                        'RFC3339',
179
-                        'ISO8601',
180
-                        $original_value
181
-                    ),
182
-                    array(
183
-                        'status' => 400,
184
-                    )
185
-                );
186
-            }
187
-        } elseif ($field_obj instanceof EE_Boolean_Field) {
188
-            // Interpreted the strings "false", "true", "on", "off" appropriately.
189
-            $new_value = filter_var($original_value, FILTER_VALIDATE_BOOLEAN);
190
-        } else {
191
-            $new_value = $original_value;
192
-        }
193
-        return $new_value;
194
-    }
195
-
196
-
197
-    /**
198
-     * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
199
-     * information via details obtained from the host site.
200
-     *
201
-     * @param string            $original_timestamp
202
-     * @param EE_Datetime_Field $datetime_field
203
-     * @param                   $timezone_string
204
-     * @return string
205
-     * @throws DomainException
206
-     */
207
-    private static function getTimestampWithTimezoneOffset(
208
-        $original_timestamp,
209
-        EE_Datetime_Field $datetime_field,
210
-        $timezone_string
211
-    ) {
212
-        // already have timezone information?
213
-        if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
214
-            // yes, we're ignoring the timezone.
215
-            return $original_timestamp;
216
-        }
217
-        // need to append timezone
218
-        list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
219
-            $datetime_field->get_timezone_offset(
220
-                new \DateTimeZone($timezone_string),
221
-                $original_timestamp
222
-            )
223
-        );
224
-        $offset_string =
225
-            str_pad(
226
-                floor($offset_secs / HOUR_IN_SECONDS),
227
-                2,
228
-                '0',
229
-                STR_PAD_LEFT
230
-            )
231
-            . ':'
232
-            . str_pad(
233
-                ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
234
-                2,
235
-                '0',
236
-                STR_PAD_LEFT
237
-            );
238
-        return $original_timestamp . $offset_sign . $offset_string;
239
-    }
240
-
241
-
242
-    /**
243
-     * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
244
-     * think that can happen). If $data is an array, recurses into its keys and values
245
-     *
246
-     * @param mixed $data
247
-     * @throws RestException
248
-     * @return void
249
-     */
250
-    public static function throwExceptionIfContainsSerializedData($data)
251
-    {
252
-        if (is_array($data)) {
253
-            foreach ($data as $key => $value) {
254
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
255
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
256
-            }
257
-        } else {
258
-            if (is_serialized($data) || is_object($data)) {
259
-                throw new RestException(
260
-                    'serialized_data_submission_prohibited',
261
-                    esc_html__(
262
-                    // @codingStandardsIgnoreStart
263
-                        'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
264
-                        // @codingStandardsIgnoreEnd
265
-                        'event_espresso'
266
-                    )
267
-                );
268
-            }
269
-        }
270
-    }
271
-
272
-
273
-    /**
274
-     * determines what's going on with them timezone strings
275
-     *
276
-     * @param int $timezone_offset
277
-     * @return array
278
-     */
279
-    private static function parseTimezoneOffset($timezone_offset)
280
-    {
281
-        $first_char = substr((string) $timezone_offset, 0, 1);
282
-        if ($first_char === '+' || $first_char === '-') {
283
-            $offset_sign = $first_char;
284
-            $offset_secs = substr((string) $timezone_offset, 1);
285
-        } else {
286
-            $offset_sign = '+';
287
-            $offset_secs = $timezone_offset;
288
-        }
289
-        return array($offset_sign, $offset_secs);
290
-    }
291
-
292
-
293
-    /**
294
-     * Prepares a field's value for display in the API
295
-     *
296
-     * @param EE_Model_Field_Base $field_obj
297
-     * @param mixed               $original_value
298
-     * @param string              $requested_version
299
-     * @return mixed
300
-     */
301
-    public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
302
-    {
303
-        if ($original_value === EE_INF) {
304
-            $new_value = ModelDataTranslator::EE_INF_IN_REST;
305
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
306
-            if (is_string($original_value)) {
307
-                // did they submit a string of a unix timestamp?
308
-                if (is_numeric($original_value)) {
309
-                    $datetime_obj = new \DateTime();
310
-                    $datetime_obj->setTimestamp((int) $original_value);
311
-                } else {
312
-                    // first, check if its a MySQL timestamp in GMT
313
-                    $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
314
-                }
315
-                if (! $datetime_obj instanceof \DateTime) {
316
-                    // so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
317
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
318
-                }
319
-                $original_value = $datetime_obj;
320
-            }
321
-            if ($original_value instanceof \DateTime) {
322
-                $new_value = $original_value->format('Y-m-d H:i:s');
323
-            } elseif (is_int($original_value) || is_float($original_value)) {
324
-                $new_value = date('Y-m-d H:i:s', $original_value);
325
-            } elseif ($original_value === null || $original_value === '') {
326
-                $new_value = null;
327
-            } else {
328
-                // so it's not a datetime object, unix timestamp (as string or int),
329
-                // MySQL timestamp, or even a string in the field object's format. So no idea what it is
330
-                throw new \EE_Error(
331
-                    sprintf(
332
-                        esc_html__(
333
-                        // @codingStandardsIgnoreStart
334
-                            'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
335
-                            // @codingStandardsIgnoreEnd
336
-                            'event_espresso'
337
-                        ),
338
-                        $original_value,
339
-                        $field_obj->get_name(),
340
-                        $field_obj->get_model_name(),
341
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
342
-                    )
343
-                );
344
-            }
345
-            if ($new_value !== null) {
346
-                $new_value = mysql_to_rfc3339($new_value);
347
-            }
348
-        } else {
349
-            $new_value = $original_value;
350
-        }
351
-        // are we about to send an object? just don't. We have no good way to represent it in JSON.
352
-        // can't just check using is_object() because that missed PHP incomplete objects
353
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
354
-            $new_value = array(
355
-                'error_code'    => 'php_object_not_return',
356
-                'error_message' => esc_html__(
357
-                    'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
358
-                    'event_espresso'
359
-                ),
360
-            );
361
-        }
362
-        return apply_filters(
363
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
364
-            $new_value,
365
-            $field_obj,
366
-            $original_value,
367
-            $requested_version
368
-        );
369
-    }
370
-
371
-
372
-    /**
373
-     * Prepares condition-query-parameters (like what's in where and having) from
374
-     * the format expected in the API to use in the models
375
-     *
376
-     * @param array $inputted_query_params_of_this_type
377
-     * @param EEM_Base $model
378
-     * @param string $requested_version
379
-     * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
380
-     *                          If we're writing to the DB, we don't expect any operators, or any logic query
381
-     *                          parameters, and we also won't accept serialized data unless the current user has
382
-     *                          unfiltered_html.
383
-     * @return array
384
-     * @throws DomainException
385
-     * @throws EE_Error
386
-     * @throws RestException
387
-     * @throws InvalidDataTypeException
388
-     * @throws InvalidInterfaceException
389
-     * @throws InvalidArgumentException
390
-     */
391
-    public static function prepareConditionsQueryParamsForModels(
392
-        $inputted_query_params_of_this_type,
393
-        EEM_Base $model,
394
-        $requested_version,
395
-        $writing = false
396
-    ) {
397
-        $query_param_for_models = array();
398
-        $context = new RestIncomingQueryParamContext($model, $requested_version, $writing);
399
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
400
-            $query_param_meta = new RestIncomingQueryParamMetadata($query_param_key, $query_param_value, $context);
401
-            if ($query_param_meta->getField() instanceof EE_Model_Field_Base) {
402
-                $translated_value = $query_param_meta->determineConditionsQueryParameterValue();
403
-                if ((isset($query_param_for_models[ $query_param_meta->getQueryParamKey() ]) && $query_param_meta->isGmtField())
404
-                    || $translated_value === null
405
-                ) {
406
-                    // they have already provided a non-gmt field, ignore the gmt one. That's what WP core
407
-                    // currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
408
-                    // OR we couldn't create a translated value from their input
409
-                    continue;
410
-                }
411
-                $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $translated_value;
412
-            } else {
413
-                $nested_query_params = $query_param_meta->determineNestedConditionQueryParameters();
414
-                if ($nested_query_params) {
415
-                    $query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $nested_query_params;
416
-                }
417
-            }
418
-        }
419
-        return $query_param_for_models;
420
-    }
421
-
422
-    /**
423
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
424
-     * gmt date field name
425
-     *
426
-     * @param string $field_name
427
-     * @return boolean
428
-     */
429
-    public static function isGmtDateFieldName($field_name)
430
-    {
431
-        return substr(
432
-            ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
433
-            -4,
434
-            4
435
-        ) === '_gmt';
436
-    }
437
-
438
-
439
-    /**
440
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
441
-     *
442
-     * @param string $field_name
443
-     * @return string
444
-     */
445
-    public static function removeGmtFromFieldName($field_name)
446
-    {
447
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
448
-            return $field_name;
449
-        }
450
-        $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
451
-            $field_name
452
-        );
453
-        $query_param_sans_gmt_and_sans_stars = substr(
454
-            $query_param_sans_stars,
455
-            0,
456
-            strrpos(
457
-                $field_name,
458
-                '_gmt'
459
-            )
460
-        );
461
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
462
-    }
463
-
464
-
465
-    /**
466
-     * Takes a field name from the REST API and prepares it for the model querying
467
-     *
468
-     * @param string $field_name
469
-     * @return string
470
-     */
471
-    public static function prepareFieldNameFromJson($field_name)
472
-    {
473
-        if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
474
-            return ModelDataTranslator::removeGmtFromFieldName($field_name);
475
-        }
476
-        return $field_name;
477
-    }
478
-
479
-
480
-    /**
481
-     * Takes array of field names from REST API and prepares for models
482
-     *
483
-     * @param array $field_names
484
-     * @return array of field names (possibly include model prefixes)
485
-     */
486
-    public static function prepareFieldNamesFromJson(array $field_names)
487
-    {
488
-        $new_array = array();
489
-        foreach ($field_names as $key => $field_name) {
490
-            $new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
491
-        }
492
-        return $new_array;
493
-    }
494
-
495
-
496
-    /**
497
-     * Takes array where array keys are field names (possibly with model path prefixes)
498
-     * from the REST API and prepares them for model querying
499
-     *
500
-     * @param array $field_names_as_keys
501
-     * @return array
502
-     */
503
-    public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
504
-    {
505
-        $new_array = array();
506
-        foreach ($field_names_as_keys as $field_name => $value) {
507
-            $new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
508
-        }
509
-        return $new_array;
510
-    }
511
-
512
-
513
-    /**
514
-     * Prepares an array of model query params for use in the REST API
515
-     *
516
-     * @param array    $model_query_params
517
-     * @param EEM_Base $model
518
-     * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
519
-     *                                     REST API
520
-     * @return array which can be passed into the EE4 REST API when querying a model resource
521
-     * @throws EE_Error
522
-     */
523
-    public static function prepareQueryParamsForRestApi(
524
-        array $model_query_params,
525
-        EEM_Base $model,
526
-        $requested_version = null
527
-    ) {
528
-        if ($requested_version === null) {
529
-            $requested_version = EED_Core_Rest_Api::latest_rest_api_version();
530
-        }
531
-        $rest_query_params = $model_query_params;
532
-        if (isset($model_query_params[0])) {
533
-            $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
534
-                $model_query_params[0],
535
-                $model,
536
-                $requested_version
537
-            );
538
-            unset($rest_query_params[0]);
539
-        }
540
-        if (isset($model_query_params['having'])) {
541
-            $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
542
-                $model_query_params['having'],
543
-                $model,
544
-                $requested_version
545
-            );
546
-        }
547
-        return apply_filters(
548
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
549
-            $rest_query_params,
550
-            $model_query_params,
551
-            $model,
552
-            $requested_version
553
-        );
554
-    }
555
-
556
-
557
-    /**
558
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
559
-     *
560
-     * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
561
-     *                                                      @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
562
-     * @param EEM_Base $model
563
-     * @param string   $requested_version                   eg "4.8.36"
564
-     * @return array ready for use in the rest api query params
565
-     * @throws EE_Error
566
-     * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
567
-     *                                                      (which would be really unusual)
568
-     */
569
-    public static function prepareConditionsQueryParamsForRestApi(
570
-        $inputted_query_params_of_this_type,
571
-        EEM_Base $model,
572
-        $requested_version
573
-    ) {
574
-        $query_param_for_models = array();
575
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
576
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
577
-                ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
578
-                $model
579
-            );
580
-            if ($field instanceof EE_Model_Field_Base) {
581
-                // did they specify an operator?
582
-                if (is_array($query_param_value)) {
583
-                    $op = $query_param_value[0];
584
-                    $translated_value = array($op);
585
-                    if (isset($query_param_value[1])) {
586
-                        $value = $query_param_value[1];
587
-                        $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
588
-                            $field,
589
-                            $value,
590
-                            $requested_version
591
-                        );
592
-                    }
593
-                } else {
594
-                    $translated_value = ModelDataTranslator::prepareFieldValueForJson(
595
-                        $field,
596
-                        $query_param_value,
597
-                        $requested_version
598
-                    );
599
-                }
600
-                $query_param_for_models[ $query_param_key ] = $translated_value;
601
-            } else {
602
-                // so it's not for a field, assume it's a logic query param key
603
-                $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
604
-                    $query_param_value,
605
-                    $model,
606
-                    $requested_version
607
-                );
608
-            }
609
-        }
610
-        return $query_param_for_models;
611
-    }
612
-
613
-
614
-    /**
615
-     * @param $condition_query_param_key
616
-     * @return string
617
-     */
618
-    public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
619
-    {
620
-        $pos_of_star = strpos($condition_query_param_key, '*');
621
-        if ($pos_of_star === false) {
622
-            return $condition_query_param_key;
623
-        } else {
624
-            $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
625
-            return $condition_query_param_sans_star;
626
-        }
627
-    }
628
-
629
-
630
-    /**
631
-     * Takes the input parameter and finds the model field that it indicates.
632
-     *
633
-     * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
634
-     * @param EEM_Base $model
635
-     * @return EE_Model_Field_Base
636
-     * @throws EE_Error
637
-     */
638
-    public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
639
-    {
640
-        // ok, now proceed with deducing which part is the model's name, and which is the field's name
641
-        // which will help us find the database table and column
642
-        $query_param_parts = explode('.', $query_param_name);
643
-        if (empty($query_param_parts)) {
644
-            throw new EE_Error(
645
-                sprintf(
646
-                    __(
647
-                        '_extract_column_name is empty when trying to extract column and table name from %s',
648
-                        'event_espresso'
649
-                    ),
650
-                    $query_param_name
651
-                )
652
-            );
653
-        }
654
-        $number_of_parts = count($query_param_parts);
655
-        $last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
656
-        if ($number_of_parts === 1) {
657
-            $field_name = $last_query_param_part;
658
-        } else {// $number_of_parts >= 2
659
-            // the last part is the column name, and there are only 2parts. therefore...
660
-            $field_name = $last_query_param_part;
661
-            $model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
662
-        }
663
-        try {
664
-            return $model->field_settings_for($field_name, false);
665
-        } catch (EE_Error $e) {
666
-            return null;
667
-        }
668
-    }
669
-
670
-
671
-    /**
672
-     * Returns true if $data can be easily represented in JSON.
673
-     * Basically, objects and resources can't be represented in JSON easily.
674
-     *
675
-     * @param mixed $data
676
-     * @return bool
677
-     */
678
-    protected static function isRepresentableInJson($data)
679
-    {
680
-        return is_scalar($data)
681
-               || is_array($data)
682
-               || is_null($data);
683
-    }
42
+	/**
43
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
44
+	 * fields that COULD contain -1; so we use null
45
+	 */
46
+	const EE_INF_IN_REST = null;
47
+
48
+
49
+	/**
50
+	 * Prepares a possible array of input values from JSON for use by the models
51
+	 *
52
+	 * @param EE_Model_Field_Base $field_obj
53
+	 * @param mixed               $original_value_maybe_array
54
+	 * @param string              $requested_version
55
+	 * @param string              $timezone_string treat values as being in this timezone
56
+	 * @return mixed
57
+	 * @throws RestException
58
+	 */
59
+	public static function prepareFieldValuesFromJson(
60
+		$field_obj,
61
+		$original_value_maybe_array,
62
+		$requested_version,
63
+		$timezone_string = 'UTC'
64
+	) {
65
+		if (is_array($original_value_maybe_array)
66
+			&& ! $field_obj instanceof EE_Serialized_Text_Field
67
+		) {
68
+			$new_value_maybe_array = array();
69
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
70
+				$new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
71
+					$field_obj,
72
+					$array_item,
73
+					$requested_version,
74
+					$timezone_string
75
+				);
76
+			}
77
+		} else {
78
+			$new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
79
+				$field_obj,
80
+				$original_value_maybe_array,
81
+				$requested_version,
82
+				$timezone_string
83
+			);
84
+		}
85
+		return $new_value_maybe_array;
86
+	}
87
+
88
+
89
+	/**
90
+	 * Prepares an array of field values FOR use in JSON/REST API
91
+	 *
92
+	 * @param EE_Model_Field_Base $field_obj
93
+	 * @param mixed               $original_value_maybe_array
94
+	 * @param string              $request_version (eg 4.8.36)
95
+	 * @return array
96
+	 */
97
+	public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
98
+	{
99
+		if (is_array($original_value_maybe_array)) {
100
+			$new_value = array();
101
+			foreach ($original_value_maybe_array as $key => $value) {
102
+				$new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
103
+					$field_obj,
104
+					$value,
105
+					$request_version
106
+				);
107
+			}
108
+		} else {
109
+			$new_value = ModelDataTranslator::prepareFieldValueForJson(
110
+				$field_obj,
111
+				$original_value_maybe_array,
112
+				$request_version
113
+			);
114
+		}
115
+		return $new_value;
116
+	}
117
+
118
+
119
+	/**
120
+	 * Prepares incoming data from the json or $_REQUEST parameters for the models'
121
+	 * "$query_params".
122
+	 *
123
+	 * @param EE_Model_Field_Base $field_obj
124
+	 * @param mixed               $original_value
125
+	 * @param string              $requested_version
126
+	 * @param string              $timezone_string treat values as being in this timezone
127
+	 * @return mixed
128
+	 * @throws RestException
129
+	 * @throws DomainException
130
+	 * @throws EE_Error
131
+	 */
132
+	public static function prepareFieldValueFromJson(
133
+		$field_obj,
134
+		$original_value,
135
+		$requested_version,
136
+		$timezone_string = 'UTC' // UTC
137
+	) {
138
+		// check if they accidentally submitted an error value. If so throw an exception
139
+		if (is_array($original_value)
140
+			&& isset($original_value['error_code'], $original_value['error_message'])) {
141
+			throw new RestException(
142
+				'rest_submitted_error_value',
143
+				sprintf(
144
+					esc_html__(
145
+						'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
146
+						'event_espresso'
147
+					),
148
+					$field_obj->get_name()
149
+				),
150
+				array(
151
+					'status' => 400,
152
+				)
153
+			);
154
+		}
155
+		// double-check for serialized PHP. We never accept serialized PHP. No way Jose.
156
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
157
+		$timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
158
+		$new_value = null;
159
+		// walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
160
+		// way Jose.
161
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
162
+		if ($field_obj instanceof EE_Infinite_Integer_Field
163
+			&& in_array($original_value, array(null, ''), true)
164
+		) {
165
+			$new_value = EE_INF;
166
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
167
+			$new_value = rest_parse_date(
168
+				self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
169
+			);
170
+			if ($new_value === false) {
171
+				throw new RestException(
172
+					'invalid_format_for_timestamp',
173
+					sprintf(
174
+						esc_html__(
175
+							'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
176
+							'event_espresso'
177
+						),
178
+						'RFC3339',
179
+						'ISO8601',
180
+						$original_value
181
+					),
182
+					array(
183
+						'status' => 400,
184
+					)
185
+				);
186
+			}
187
+		} elseif ($field_obj instanceof EE_Boolean_Field) {
188
+			// Interpreted the strings "false", "true", "on", "off" appropriately.
189
+			$new_value = filter_var($original_value, FILTER_VALIDATE_BOOLEAN);
190
+		} else {
191
+			$new_value = $original_value;
192
+		}
193
+		return $new_value;
194
+	}
195
+
196
+
197
+	/**
198
+	 * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
199
+	 * information via details obtained from the host site.
200
+	 *
201
+	 * @param string            $original_timestamp
202
+	 * @param EE_Datetime_Field $datetime_field
203
+	 * @param                   $timezone_string
204
+	 * @return string
205
+	 * @throws DomainException
206
+	 */
207
+	private static function getTimestampWithTimezoneOffset(
208
+		$original_timestamp,
209
+		EE_Datetime_Field $datetime_field,
210
+		$timezone_string
211
+	) {
212
+		// already have timezone information?
213
+		if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
214
+			// yes, we're ignoring the timezone.
215
+			return $original_timestamp;
216
+		}
217
+		// need to append timezone
218
+		list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
219
+			$datetime_field->get_timezone_offset(
220
+				new \DateTimeZone($timezone_string),
221
+				$original_timestamp
222
+			)
223
+		);
224
+		$offset_string =
225
+			str_pad(
226
+				floor($offset_secs / HOUR_IN_SECONDS),
227
+				2,
228
+				'0',
229
+				STR_PAD_LEFT
230
+			)
231
+			. ':'
232
+			. str_pad(
233
+				($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
234
+				2,
235
+				'0',
236
+				STR_PAD_LEFT
237
+			);
238
+		return $original_timestamp . $offset_sign . $offset_string;
239
+	}
240
+
241
+
242
+	/**
243
+	 * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
244
+	 * think that can happen). If $data is an array, recurses into its keys and values
245
+	 *
246
+	 * @param mixed $data
247
+	 * @throws RestException
248
+	 * @return void
249
+	 */
250
+	public static function throwExceptionIfContainsSerializedData($data)
251
+	{
252
+		if (is_array($data)) {
253
+			foreach ($data as $key => $value) {
254
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
255
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
256
+			}
257
+		} else {
258
+			if (is_serialized($data) || is_object($data)) {
259
+				throw new RestException(
260
+					'serialized_data_submission_prohibited',
261
+					esc_html__(
262
+					// @codingStandardsIgnoreStart
263
+						'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
264
+						// @codingStandardsIgnoreEnd
265
+						'event_espresso'
266
+					)
267
+				);
268
+			}
269
+		}
270
+	}
271
+
272
+
273
+	/**
274
+	 * determines what's going on with them timezone strings
275
+	 *
276
+	 * @param int $timezone_offset
277
+	 * @return array
278
+	 */
279
+	private static function parseTimezoneOffset($timezone_offset)
280
+	{
281
+		$first_char = substr((string) $timezone_offset, 0, 1);
282
+		if ($first_char === '+' || $first_char === '-') {
283
+			$offset_sign = $first_char;
284
+			$offset_secs = substr((string) $timezone_offset, 1);
285
+		} else {
286
+			$offset_sign = '+';
287
+			$offset_secs = $timezone_offset;
288
+		}
289
+		return array($offset_sign, $offset_secs);
290
+	}
291
+
292
+
293
+	/**
294
+	 * Prepares a field's value for display in the API
295
+	 *
296
+	 * @param EE_Model_Field_Base $field_obj
297
+	 * @param mixed               $original_value
298
+	 * @param string              $requested_version
299
+	 * @return mixed
300
+	 */
301
+	public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
302
+	{
303
+		if ($original_value === EE_INF) {
304
+			$new_value = ModelDataTranslator::EE_INF_IN_REST;
305
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
306
+			if (is_string($original_value)) {
307
+				// did they submit a string of a unix timestamp?
308
+				if (is_numeric($original_value)) {
309
+					$datetime_obj = new \DateTime();
310
+					$datetime_obj->setTimestamp((int) $original_value);
311
+				} else {
312
+					// first, check if its a MySQL timestamp in GMT
313
+					$datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
314
+				}
315
+				if (! $datetime_obj instanceof \DateTime) {
316
+					// so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
317
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
318
+				}
319
+				$original_value = $datetime_obj;
320
+			}
321
+			if ($original_value instanceof \DateTime) {
322
+				$new_value = $original_value->format('Y-m-d H:i:s');
323
+			} elseif (is_int($original_value) || is_float($original_value)) {
324
+				$new_value = date('Y-m-d H:i:s', $original_value);
325
+			} elseif ($original_value === null || $original_value === '') {
326
+				$new_value = null;
327
+			} else {
328
+				// so it's not a datetime object, unix timestamp (as string or int),
329
+				// MySQL timestamp, or even a string in the field object's format. So no idea what it is
330
+				throw new \EE_Error(
331
+					sprintf(
332
+						esc_html__(
333
+						// @codingStandardsIgnoreStart
334
+							'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
335
+							// @codingStandardsIgnoreEnd
336
+							'event_espresso'
337
+						),
338
+						$original_value,
339
+						$field_obj->get_name(),
340
+						$field_obj->get_model_name(),
341
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
342
+					)
343
+				);
344
+			}
345
+			if ($new_value !== null) {
346
+				$new_value = mysql_to_rfc3339($new_value);
347
+			}
348
+		} else {
349
+			$new_value = $original_value;
350
+		}
351
+		// are we about to send an object? just don't. We have no good way to represent it in JSON.
352
+		// can't just check using is_object() because that missed PHP incomplete objects
353
+		if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
354
+			$new_value = array(
355
+				'error_code'    => 'php_object_not_return',
356
+				'error_message' => esc_html__(
357
+					'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
358
+					'event_espresso'
359
+				),
360
+			);
361
+		}
362
+		return apply_filters(
363
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
364
+			$new_value,
365
+			$field_obj,
366
+			$original_value,
367
+			$requested_version
368
+		);
369
+	}
370
+
371
+
372
+	/**
373
+	 * Prepares condition-query-parameters (like what's in where and having) from
374
+	 * the format expected in the API to use in the models
375
+	 *
376
+	 * @param array $inputted_query_params_of_this_type
377
+	 * @param EEM_Base $model
378
+	 * @param string $requested_version
379
+	 * @param boolean $writing whether this data will be written to the DB, or if we're just building a query.
380
+	 *                          If we're writing to the DB, we don't expect any operators, or any logic query
381
+	 *                          parameters, and we also won't accept serialized data unless the current user has
382
+	 *                          unfiltered_html.
383
+	 * @return array
384
+	 * @throws DomainException
385
+	 * @throws EE_Error
386
+	 * @throws RestException
387
+	 * @throws InvalidDataTypeException
388
+	 * @throws InvalidInterfaceException
389
+	 * @throws InvalidArgumentException
390
+	 */
391
+	public static function prepareConditionsQueryParamsForModels(
392
+		$inputted_query_params_of_this_type,
393
+		EEM_Base $model,
394
+		$requested_version,
395
+		$writing = false
396
+	) {
397
+		$query_param_for_models = array();
398
+		$context = new RestIncomingQueryParamContext($model, $requested_version, $writing);
399
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
400
+			$query_param_meta = new RestIncomingQueryParamMetadata($query_param_key, $query_param_value, $context);
401
+			if ($query_param_meta->getField() instanceof EE_Model_Field_Base) {
402
+				$translated_value = $query_param_meta->determineConditionsQueryParameterValue();
403
+				if ((isset($query_param_for_models[ $query_param_meta->getQueryParamKey() ]) && $query_param_meta->isGmtField())
404
+					|| $translated_value === null
405
+				) {
406
+					// they have already provided a non-gmt field, ignore the gmt one. That's what WP core
407
+					// currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
408
+					// OR we couldn't create a translated value from their input
409
+					continue;
410
+				}
411
+				$query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $translated_value;
412
+			} else {
413
+				$nested_query_params = $query_param_meta->determineNestedConditionQueryParameters();
414
+				if ($nested_query_params) {
415
+					$query_param_for_models[ $query_param_meta->getQueryParamKey() ] = $nested_query_params;
416
+				}
417
+			}
418
+		}
419
+		return $query_param_for_models;
420
+	}
421
+
422
+	/**
423
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
424
+	 * gmt date field name
425
+	 *
426
+	 * @param string $field_name
427
+	 * @return boolean
428
+	 */
429
+	public static function isGmtDateFieldName($field_name)
430
+	{
431
+		return substr(
432
+			ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
433
+			-4,
434
+			4
435
+		) === '_gmt';
436
+	}
437
+
438
+
439
+	/**
440
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
441
+	 *
442
+	 * @param string $field_name
443
+	 * @return string
444
+	 */
445
+	public static function removeGmtFromFieldName($field_name)
446
+	{
447
+		if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
448
+			return $field_name;
449
+		}
450
+		$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
451
+			$field_name
452
+		);
453
+		$query_param_sans_gmt_and_sans_stars = substr(
454
+			$query_param_sans_stars,
455
+			0,
456
+			strrpos(
457
+				$field_name,
458
+				'_gmt'
459
+			)
460
+		);
461
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
462
+	}
463
+
464
+
465
+	/**
466
+	 * Takes a field name from the REST API and prepares it for the model querying
467
+	 *
468
+	 * @param string $field_name
469
+	 * @return string
470
+	 */
471
+	public static function prepareFieldNameFromJson($field_name)
472
+	{
473
+		if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
474
+			return ModelDataTranslator::removeGmtFromFieldName($field_name);
475
+		}
476
+		return $field_name;
477
+	}
478
+
479
+
480
+	/**
481
+	 * Takes array of field names from REST API and prepares for models
482
+	 *
483
+	 * @param array $field_names
484
+	 * @return array of field names (possibly include model prefixes)
485
+	 */
486
+	public static function prepareFieldNamesFromJson(array $field_names)
487
+	{
488
+		$new_array = array();
489
+		foreach ($field_names as $key => $field_name) {
490
+			$new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
491
+		}
492
+		return $new_array;
493
+	}
494
+
495
+
496
+	/**
497
+	 * Takes array where array keys are field names (possibly with model path prefixes)
498
+	 * from the REST API and prepares them for model querying
499
+	 *
500
+	 * @param array $field_names_as_keys
501
+	 * @return array
502
+	 */
503
+	public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
504
+	{
505
+		$new_array = array();
506
+		foreach ($field_names_as_keys as $field_name => $value) {
507
+			$new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
508
+		}
509
+		return $new_array;
510
+	}
511
+
512
+
513
+	/**
514
+	 * Prepares an array of model query params for use in the REST API
515
+	 *
516
+	 * @param array    $model_query_params
517
+	 * @param EEM_Base $model
518
+	 * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
519
+	 *                                     REST API
520
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
521
+	 * @throws EE_Error
522
+	 */
523
+	public static function prepareQueryParamsForRestApi(
524
+		array $model_query_params,
525
+		EEM_Base $model,
526
+		$requested_version = null
527
+	) {
528
+		if ($requested_version === null) {
529
+			$requested_version = EED_Core_Rest_Api::latest_rest_api_version();
530
+		}
531
+		$rest_query_params = $model_query_params;
532
+		if (isset($model_query_params[0])) {
533
+			$rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
534
+				$model_query_params[0],
535
+				$model,
536
+				$requested_version
537
+			);
538
+			unset($rest_query_params[0]);
539
+		}
540
+		if (isset($model_query_params['having'])) {
541
+			$rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
542
+				$model_query_params['having'],
543
+				$model,
544
+				$requested_version
545
+			);
546
+		}
547
+		return apply_filters(
548
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
549
+			$rest_query_params,
550
+			$model_query_params,
551
+			$model,
552
+			$requested_version
553
+		);
554
+	}
555
+
556
+
557
+	/**
558
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
559
+	 *
560
+	 * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
561
+	 *                                                      @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
562
+	 * @param EEM_Base $model
563
+	 * @param string   $requested_version                   eg "4.8.36"
564
+	 * @return array ready for use in the rest api query params
565
+	 * @throws EE_Error
566
+	 * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
567
+	 *                                                      (which would be really unusual)
568
+	 */
569
+	public static function prepareConditionsQueryParamsForRestApi(
570
+		$inputted_query_params_of_this_type,
571
+		EEM_Base $model,
572
+		$requested_version
573
+	) {
574
+		$query_param_for_models = array();
575
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
576
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
577
+				ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
578
+				$model
579
+			);
580
+			if ($field instanceof EE_Model_Field_Base) {
581
+				// did they specify an operator?
582
+				if (is_array($query_param_value)) {
583
+					$op = $query_param_value[0];
584
+					$translated_value = array($op);
585
+					if (isset($query_param_value[1])) {
586
+						$value = $query_param_value[1];
587
+						$translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
588
+							$field,
589
+							$value,
590
+							$requested_version
591
+						);
592
+					}
593
+				} else {
594
+					$translated_value = ModelDataTranslator::prepareFieldValueForJson(
595
+						$field,
596
+						$query_param_value,
597
+						$requested_version
598
+					);
599
+				}
600
+				$query_param_for_models[ $query_param_key ] = $translated_value;
601
+			} else {
602
+				// so it's not for a field, assume it's a logic query param key
603
+				$query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
604
+					$query_param_value,
605
+					$model,
606
+					$requested_version
607
+				);
608
+			}
609
+		}
610
+		return $query_param_for_models;
611
+	}
612
+
613
+
614
+	/**
615
+	 * @param $condition_query_param_key
616
+	 * @return string
617
+	 */
618
+	public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
619
+	{
620
+		$pos_of_star = strpos($condition_query_param_key, '*');
621
+		if ($pos_of_star === false) {
622
+			return $condition_query_param_key;
623
+		} else {
624
+			$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
625
+			return $condition_query_param_sans_star;
626
+		}
627
+	}
628
+
629
+
630
+	/**
631
+	 * Takes the input parameter and finds the model field that it indicates.
632
+	 *
633
+	 * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
634
+	 * @param EEM_Base $model
635
+	 * @return EE_Model_Field_Base
636
+	 * @throws EE_Error
637
+	 */
638
+	public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
639
+	{
640
+		// ok, now proceed with deducing which part is the model's name, and which is the field's name
641
+		// which will help us find the database table and column
642
+		$query_param_parts = explode('.', $query_param_name);
643
+		if (empty($query_param_parts)) {
644
+			throw new EE_Error(
645
+				sprintf(
646
+					__(
647
+						'_extract_column_name is empty when trying to extract column and table name from %s',
648
+						'event_espresso'
649
+					),
650
+					$query_param_name
651
+				)
652
+			);
653
+		}
654
+		$number_of_parts = count($query_param_parts);
655
+		$last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
656
+		if ($number_of_parts === 1) {
657
+			$field_name = $last_query_param_part;
658
+		} else {// $number_of_parts >= 2
659
+			// the last part is the column name, and there are only 2parts. therefore...
660
+			$field_name = $last_query_param_part;
661
+			$model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
662
+		}
663
+		try {
664
+			return $model->field_settings_for($field_name, false);
665
+		} catch (EE_Error $e) {
666
+			return null;
667
+		}
668
+	}
669
+
670
+
671
+	/**
672
+	 * Returns true if $data can be easily represented in JSON.
673
+	 * Basically, objects and resources can't be represented in JSON easily.
674
+	 *
675
+	 * @param mixed $data
676
+	 * @return bool
677
+	 */
678
+	protected static function isRepresentableInJson($data)
679
+	{
680
+		return is_scalar($data)
681
+			   || is_array($data)
682
+			   || is_null($data);
683
+	}
684 684
 }
Please login to merge, or discard this patch.
core/services/assets/AssetManagerInterface.php 1 patch
Indentation   +88 added lines, -88 removed lines patch added patch discarded remove patch
@@ -20,92 +20,92 @@
 block discarded – undo
20 20
  */
21 21
 interface AssetManagerInterface
22 22
 {
23
-    /**
24
-     * @since 4.9.71.p
25
-     * @return string
26
-     */
27
-    public function assetNamespace();
28
-
29
-    /**
30
-     * @since 4.9.62.p
31
-     */
32
-    public function addAssets();
33
-
34
-
35
-    /**
36
-     * @return ManifestFile
37
-     * @throws DuplicateCollectionIdentifierException
38
-     * @throws InvalidDataTypeException
39
-     * @throws InvalidEntityException
40
-     * @since 4.9.62.p
41
-     */
42
-    public function addManifestFile();
43
-
44
-
45
-    /**
46
-     * @return ManifestFile[]
47
-     * @since 4.9.62.p
48
-     */
49
-    public function getManifestFile();
50
-
51
-
52
-    /**
53
-     * @param string $handle
54
-     * @param string $source
55
-     * @param array  $dependencies
56
-     * @param bool   $load_in_footer
57
-     * @return JavascriptAsset
58
-     * @throws DuplicateCollectionIdentifierException
59
-     * @throws InvalidDataTypeException
60
-     * @throws InvalidEntityException
61
-     * @since 4.9.62.p
62
-     */
63
-    public function addJavascript(
64
-        $handle,
65
-        $source,
66
-        array $dependencies = array(),
67
-        $load_in_footer = true
68
-    );
69
-
70
-
71
-    /**
72
-     * @since 4.9.71.p
73
-     * @param string $handle
74
-     * @param array  $dependencies
75
-     * @param bool   $load_in_footer
76
-     * @return JavascriptAsset
77
-     */
78
-    public function addVendorJavascript(
79
-        $handle,
80
-        array $dependencies = array(),
81
-        $load_in_footer = true
82
-    );
83
-
84
-
85
-
86
-    /**
87
-     * @param string $handle
88
-     * @param string $source
89
-     * @param array  $dependencies
90
-     * @param string $media
91
-     * @return StylesheetAsset
92
-     * @throws DuplicateCollectionIdentifierException
93
-     * @throws InvalidDataTypeException
94
-     * @throws InvalidEntityException
95
-     * @since 4.9.62.p
96
-     */
97
-    public function addStylesheet(
98
-        $handle,
99
-        $source,
100
-        array $dependencies = array(),
101
-        $media = 'all'
102
-    );
103
-
104
-
105
-    /**
106
-     * @param string $handle
107
-     * @return bool
108
-     * @since 4.9.62.p
109
-     */
110
-    public function enqueueAsset($handle);
23
+	/**
24
+	 * @since 4.9.71.p
25
+	 * @return string
26
+	 */
27
+	public function assetNamespace();
28
+
29
+	/**
30
+	 * @since 4.9.62.p
31
+	 */
32
+	public function addAssets();
33
+
34
+
35
+	/**
36
+	 * @return ManifestFile
37
+	 * @throws DuplicateCollectionIdentifierException
38
+	 * @throws InvalidDataTypeException
39
+	 * @throws InvalidEntityException
40
+	 * @since 4.9.62.p
41
+	 */
42
+	public function addManifestFile();
43
+
44
+
45
+	/**
46
+	 * @return ManifestFile[]
47
+	 * @since 4.9.62.p
48
+	 */
49
+	public function getManifestFile();
50
+
51
+
52
+	/**
53
+	 * @param string $handle
54
+	 * @param string $source
55
+	 * @param array  $dependencies
56
+	 * @param bool   $load_in_footer
57
+	 * @return JavascriptAsset
58
+	 * @throws DuplicateCollectionIdentifierException
59
+	 * @throws InvalidDataTypeException
60
+	 * @throws InvalidEntityException
61
+	 * @since 4.9.62.p
62
+	 */
63
+	public function addJavascript(
64
+		$handle,
65
+		$source,
66
+		array $dependencies = array(),
67
+		$load_in_footer = true
68
+	);
69
+
70
+
71
+	/**
72
+	 * @since 4.9.71.p
73
+	 * @param string $handle
74
+	 * @param array  $dependencies
75
+	 * @param bool   $load_in_footer
76
+	 * @return JavascriptAsset
77
+	 */
78
+	public function addVendorJavascript(
79
+		$handle,
80
+		array $dependencies = array(),
81
+		$load_in_footer = true
82
+	);
83
+
84
+
85
+
86
+	/**
87
+	 * @param string $handle
88
+	 * @param string $source
89
+	 * @param array  $dependencies
90
+	 * @param string $media
91
+	 * @return StylesheetAsset
92
+	 * @throws DuplicateCollectionIdentifierException
93
+	 * @throws InvalidDataTypeException
94
+	 * @throws InvalidEntityException
95
+	 * @since 4.9.62.p
96
+	 */
97
+	public function addStylesheet(
98
+		$handle,
99
+		$source,
100
+		array $dependencies = array(),
101
+		$media = 'all'
102
+	);
103
+
104
+
105
+	/**
106
+	 * @param string $handle
107
+	 * @return bool
108
+	 * @since 4.9.62.p
109
+	 */
110
+	public function enqueueAsset($handle);
111 111
 }
Please login to merge, or discard this patch.
core/services/assets/BlockAssetManagerInterface.php 1 patch
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -12,42 +12,42 @@
 block discarded – undo
12 12
  */
13 13
 interface BlockAssetManagerInterface
14 14
 {
15
-    /**
16
-     * @since 4.9.71.p
17
-     * @return string
18
-     */
19
-    public function assetNamespace();
20
-
21
-    /**
22
-     * @since 4.9.71.p
23
-     * @return void
24
-     */
25
-    public function setAssetHandles();
26
-
27
-    /**
28
-     * @since 4.9.71.p
29
-     * @return string
30
-     */
31
-    public function getEditorScriptHandle();
32
-
33
-
34
-    /**
35
-     * @since 4.9.71.p
36
-     * @return string
37
-     */
38
-    public function getEditorStyleHandle();
39
-
40
-
41
-    /**
42
-     * @since 4.9.71.p
43
-     * @return string
44
-     */
45
-    public function getScriptHandle();
46
-
47
-
48
-    /**
49
-     * @since 4.9.71.p
50
-     * @return string
51
-     */
52
-    public function getStyleHandle();
15
+	/**
16
+	 * @since 4.9.71.p
17
+	 * @return string
18
+	 */
19
+	public function assetNamespace();
20
+
21
+	/**
22
+	 * @since 4.9.71.p
23
+	 * @return void
24
+	 */
25
+	public function setAssetHandles();
26
+
27
+	/**
28
+	 * @since 4.9.71.p
29
+	 * @return string
30
+	 */
31
+	public function getEditorScriptHandle();
32
+
33
+
34
+	/**
35
+	 * @since 4.9.71.p
36
+	 * @return string
37
+	 */
38
+	public function getEditorStyleHandle();
39
+
40
+
41
+	/**
42
+	 * @since 4.9.71.p
43
+	 * @return string
44
+	 */
45
+	public function getScriptHandle();
46
+
47
+
48
+	/**
49
+	 * @since 4.9.71.p
50
+	 * @return string
51
+	 */
52
+	public function getStyleHandle();
53 53
 }
54 54
\ No newline at end of file
Please login to merge, or discard this patch.
core/services/dependencies/DependencyResolverInterface.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -15,16 +15,16 @@
 block discarded – undo
15 15
  */
16 16
 interface DependencyResolverInterface
17 17
 {
18
-    /**
19
-     * Used to configure and/or setup any aliases or recursions required by the DependencyResolver
20
-     *
21
-     * @since 4.9.71.p
22
-     */
23
-    public function initialize();
18
+	/**
19
+	 * Used to configure and/or setup any aliases or recursions required by the DependencyResolver
20
+	 *
21
+	 * @since 4.9.71.p
22
+	 */
23
+	public function initialize();
24 24
 
25
-    /**
26
-     * @param string $fqcn Fully Qualified Class Name
27
-     * @since 4.9.71.p
28
-     */
29
-    public function resolveDependenciesForClass($fqcn);
25
+	/**
26
+	 * @param string $fqcn Fully Qualified Class Name
27
+	 * @since 4.9.71.p
28
+	 */
29
+	public function resolveDependenciesForClass($fqcn);
30 30
 }
Please login to merge, or discard this patch.