Completed
Branch dependabot/composer/tijsverkoy... (491ea6)
by
unknown
32:00 queued 25:42
created
admin_pages/registrations/templates/reg_admin_details_header.template.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -37,9 +37,9 @@
 block discarded – undo
37 37
         <span class='ee-admin-page-nav-strip-item'>
38 38
         <?php echo sprintf(
39 39
             esc_html__('View %1$sRegistrations%4$s /  %2$sTransactions%4$s for this %3$sevent%4$s.', 'event_espresso'),
40
-            '<a href="' . esc_url_raw($filtered_registrations_link) . '">',
41
-            '<a href="' . esc_url_raw($filtered_registrations_link) . '">',
42
-            '<a href="' . esc_url_raw($event_link) . '">',
40
+            '<a href="'.esc_url_raw($filtered_registrations_link).'">',
41
+            '<a href="'.esc_url_raw($filtered_registrations_link).'">',
42
+            '<a href="'.esc_url_raw($event_link).'">',
43 43
             '</a>'
44 44
         ); ?>
45 45
         </span>
Please login to merge, or discard this patch.
Indentation   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -19,36 +19,36 @@
 block discarded – undo
19 19
 <div class='ee-admin-page-nav-strip-wrap'>
20 20
     <div class='ee-admin-page-nav-strip'>
21 21
         <?php
22
-        echo wp_kses($previous_registration, AllowedTags::getAllowedTags());
23
-        echo '<span>';
24
-        printf(
25
-            /* translators: %s: registration number */
26
-            esc_html__('Registration # %1$s', 'event_espresso'),
27
-            esc_html($reg_nmbr['value'])
28
-        );
29
-        echo '</span>';
30
-        echo wp_kses($next_registration, AllowedTags::getAllowedTags());
31
-        ?>
22
+		echo wp_kses($previous_registration, AllowedTags::getAllowedTags());
23
+		echo '<span>';
24
+		printf(
25
+			/* translators: %s: registration number */
26
+			esc_html__('Registration # %1$s', 'event_espresso'),
27
+			esc_html($reg_nmbr['value'])
28
+		);
29
+		echo '</span>';
30
+		echo wp_kses($next_registration, AllowedTags::getAllowedTags());
31
+		?>
32 32
     </div>
33 33
     <div class='ee-admin-page-nav-strip'>
34 34
         <?php if ($registration->group_size() > 1) : ?>
35 35
             <span class='ee-admin-page-nav-strip-item'>
36 36
             <a id="scroll-to-other-attendees" class="scroll-to" href="#other-attendees">
37 37
                 <?php echo esc_html__(
38
-                    'Scroll to Other Registrations in the Same Transaction',
39
-                    'event_espresso'
40
-                ); ?>
38
+					'Scroll to Other Registrations in the Same Transaction',
39
+					'event_espresso'
40
+				); ?>
41 41
             </a>
42 42
         </span>
43 43
         <?php endif; ?>
44 44
         <span class='ee-admin-page-nav-strip-item'>
45 45
         <?php echo sprintf(
46
-            esc_html__('View %1$sRegistrations%4$s /  %2$sTransactions%4$s for this %3$sevent%4$s.', 'event_espresso'),
47
-            '<a href="' . esc_url_raw($filtered_registrations_link) . '">',
48
-            '<a href="' . esc_url_raw($filtered_registrations_link) . '">',
49
-            '<a href="' . esc_url_raw($event_link) . '">',
50
-            '</a>'
51
-        ); ?>
46
+			esc_html__('View %1$sRegistrations%4$s /  %2$sTransactions%4$s for this %3$sevent%4$s.', 'event_espresso'),
47
+			'<a href="' . esc_url_raw($filtered_registrations_link) . '">',
48
+			'<a href="' . esc_url_raw($filtered_registrations_link) . '">',
49
+			'<a href="' . esc_url_raw($event_link) . '">',
50
+			'</a>'
51
+		); ?>
52 52
         </span>
53 53
     </div>
54 54
 </div>
Please login to merge, or discard this patch.
core/helpers/EEH_Qtip_Loader.helper.php 2 patches
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -42,7 +42,7 @@  discard block
 block discarded – undo
42 42
     public static function instance()
43 43
     {
44 44
         // check if class object is instantiated
45
-        if (! EEH_Qtip_Loader::$_instance instanceof EEH_Qtip_Loader) {
45
+        if ( ! EEH_Qtip_Loader::$_instance instanceof EEH_Qtip_Loader) {
46 46
             EEH_Qtip_Loader::$_instance = new EEH_Qtip_Loader();
47 47
         }
48 48
         return EEH_Qtip_Loader::$_instance;
@@ -78,19 +78,19 @@  discard block
 block discarded – undo
78 78
      */
79 79
     public function register_and_enqueue()
80 80
     {
81
-        $qtips_js = !defined('SCRIPT_DEBUG')
81
+        $qtips_js = ! defined('SCRIPT_DEBUG')
82 82
             ? EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.js'
83
-            : EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.js';
84
-        $qtip_map = EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.map';
85
-        $qtip_css = !defined('SCRIPT_DEBUG')
83
+            : EE_THIRD_PARTY_URL.'qtip/jquery.qtip.js';
84
+        $qtip_map = EE_THIRD_PARTY_URL.'qtip/jquery.qtip.min.map';
85
+        $qtip_css = ! defined('SCRIPT_DEBUG')
86 86
             ? EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.css'
87
-            : EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.css';
87
+            : EE_THIRD_PARTY_URL.'qtip/jquery.qtip.css';
88 88
 
89 89
         wp_register_script('qtip-map', $qtip_map, array(), '3', true);
90 90
         wp_register_script('qtip', $qtips_js, array('jquery'), '3.0.3', true);
91 91
         wp_register_script(
92 92
             'ee-qtip-helper',
93
-            EE_HELPERS_ASSETS . 'ee-qtip-helper.js',
93
+            EE_HELPERS_ASSETS.'ee-qtip-helper.js',
94 94
             array('qtip', JqueryAssetManager::JS_HANDLE_JQUERY_COOKIE),
95 95
             EVENT_ESPRESSO_VERSION,
96 96
             true
@@ -101,14 +101,14 @@  discard block
 block discarded – undo
101 101
         // k now let's see if there are any registered qtips.
102 102
         // If there are, then we need to setup the localized script for ee-qtip-helper.js
103 103
         // (and enqueue ee-qtip-helper.js of course!)
104
-        if (!empty($this->_qtips)) {
104
+        if ( ! empty($this->_qtips)) {
105 105
             wp_enqueue_script('ee-qtip-helper');
106 106
             wp_enqueue_style('qtip-css');
107 107
             $qtips = array();
108 108
             foreach ($this->_qtips as $qtip) {
109 109
                 $qts = $qtip->get_tips();
110 110
                 foreach ($qts as $qt) {
111
-                    if (! $qt instanceof EE_Qtip) {
111
+                    if ( ! $qt instanceof EE_Qtip) {
112 112
                         continue;
113 113
                     }
114 114
                     $qtips[] = array(
@@ -118,8 +118,8 @@  discard block
 block discarded – undo
118 118
                         );
119 119
                 }
120 120
             }
121
-            if (!empty($qtips)) {
122
-                wp_localize_script('ee-qtip-helper', 'EE_QTIP_HELPER', array( 'qtips' => $qtips ));
121
+            if ( ! empty($qtips)) {
122
+                wp_localize_script('ee-qtip-helper', 'EE_QTIP_HELPER', array('qtips' => $qtips));
123 123
             }
124 124
         } else {
125 125
             // qtips has been requested without any registration (so assuming its just directly used in the admin).
@@ -190,10 +190,10 @@  discard block
 block discarded – undo
190 190
     {
191 191
         // before doing anything we have to make sure that EE_Qtip_Config parent is required.
192 192
         EE_Registry::instance()->load_lib('Qtip_Config', array(), true);
193
-        if (!empty($paths)) {
193
+        if ( ! empty($paths)) {
194 194
             $paths = (array) $paths;
195 195
             foreach ($paths as $path) {
196
-                $path .= $qtip . '.lib.php';
196
+                $path .= $qtip.'.lib.php';
197 197
                 if (is_readable($path)) {
198 198
                     require_once $path;
199 199
                 }
@@ -201,9 +201,9 @@  discard block
 block discarded – undo
201 201
         }
202 202
 
203 203
         // does class exist at this point?  If it does then let's instantiate.  If it doesn't then let's continue with other paths.
204
-        if (! class_exists($qtip)) {
205
-            $path = EE_LIBRARIES . 'qtips/' . $qtip . '.lib.php';
206
-            if (! is_readable($path)) {
204
+        if ( ! class_exists($qtip)) {
205
+            $path = EE_LIBRARIES.'qtips/'.$qtip.'.lib.php';
206
+            if ( ! is_readable($path)) {
207 207
                 throw new DomainException(
208 208
                     sprintf(
209 209
                         esc_html__(
@@ -218,7 +218,7 @@  discard block
 block discarded – undo
218 218
         }
219 219
 
220 220
         // now we attempt a class_exists one more time.
221
-        if (! class_exists($qtip)) {
221
+        if ( ! class_exists($qtip)) {
222 222
             throw new DomainException(
223 223
                 sprintf(
224 224
                     esc_html__(
@@ -234,7 +234,7 @@  discard block
 block discarded – undo
234 234
         $qtip_config = $this->loader->getShared($qtip);
235 235
 
236 236
         // verify that $qtip is a valid object
237
-        if (! $qtip_config instanceof EE_Qtip_Config) {
237
+        if ( ! $qtip_config instanceof EE_Qtip_Config) {
238 238
             throw new DomainException(
239 239
                 sprintf(
240 240
                     esc_html__(
@@ -286,11 +286,11 @@  discard block
 block discarded – undo
286 286
         $qts = $qtip->get_tips();
287 287
         $content = array();
288 288
         foreach ($qts as $qt) {
289
-            if (! $qt instanceof EE_Qtip) {
289
+            if ( ! $qt instanceof EE_Qtip) {
290 290
                 continue;
291 291
             }
292
-            $content[] = '<div class="ee-qtip-helper-content hidden" id="' . esc_attr($qt->content_id) . '">' .
293
-                         $qt->content . '</div>';
292
+            $content[] = '<div class="ee-qtip-helper-content hidden" id="'.esc_attr($qt->content_id).'">'.
293
+                         $qt->content.'</div>';
294 294
         }
295 295
 
296 296
         return implode('<br />', $content);
Please login to merge, or discard this patch.
Indentation   +279 added lines, -279 removed lines patch added patch discarded remove patch
@@ -15,283 +15,283 @@
 block discarded – undo
15 15
  */
16 16
 class EEH_Qtip_Loader extends EEH_Base
17 17
 {
18
-    /**
19
-     * @var LoaderInterface $loader
20
-     */
21
-    protected $loader;
22
-
23
-    /**
24
-     * @var EEH_Qtip_Loader
25
-     */
26
-    private static $_instance;
27
-
28
-    /**
29
-     * array of qtip config objects
30
-     * @var EE_Qtip_Config[]
31
-     */
32
-    private $_qtips = array();
33
-
34
-
35
-
36
-    /**
37
-     *@singleton method used to instantiate class object
38
-     *@access public
39
-     *@return EEH_Qtip_Loader instance
40
-     */
41
-    public static function instance()
42
-    {
43
-        // check if class object is instantiated
44
-        if (! EEH_Qtip_Loader::$_instance instanceof EEH_Qtip_Loader) {
45
-            EEH_Qtip_Loader::$_instance = new EEH_Qtip_Loader();
46
-        }
47
-        return EEH_Qtip_Loader::$_instance;
48
-    }
49
-
50
-
51
-
52
-    /**
53
-     * private constructor to prevent direct creation
54
-     */
55
-    private function __construct()
56
-    {
57
-        // let's just make sure this is instantiated in the right place.
58
-        if (did_action('wp_print_styles') || did_action('admin_head')) {
59
-            EE_Error::doing_it_wrong(
60
-                'EEH_Qtip_Loader',
61
-                esc_html__(
62
-                    'This helper must be instantiated before or within a callback for the WordPress wp_enqueue_scripts hook action hook.',
63
-                    'event_espresso'
64
-                ),
65
-                '4.1'
66
-            );
67
-        }
68
-        $this->loader = LoaderFactory::getLoader();
69
-    }
70
-
71
-
72
-    /**
73
-     * Call this from wp_enqueue_scripts or admin_enqueue_scripts to setup and enqueue the qtip library
74
-     *
75
-     * @access public
76
-     * @return void
77
-     */
78
-    public function register_and_enqueue()
79
-    {
80
-        $qtips_js = !defined('SCRIPT_DEBUG')
81
-            ? EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.js'
82
-            : EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.js';
83
-        $qtip_map = EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.map';
84
-        $qtip_css = !defined('SCRIPT_DEBUG')
85
-            ? EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.css'
86
-            : EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.css';
87
-
88
-        wp_register_script('qtip-map', $qtip_map, array(), '3', true);
89
-        wp_register_script('qtip', $qtips_js, array('jquery'), '3.0.3', true);
90
-        wp_register_script(
91
-            'ee-qtip-helper',
92
-            EE_HELPERS_ASSETS . 'ee-qtip-helper.js',
93
-            array('qtip', JqueryAssetManager::JS_HANDLE_JQUERY_COOKIE),
94
-            EVENT_ESPRESSO_VERSION,
95
-            true
96
-        );
97
-
98
-        wp_register_style('qtip-css', $qtip_css, array(), '2.2');
99
-
100
-        // k now let's see if there are any registered qtips.
101
-        // If there are, then we need to setup the localized script for ee-qtip-helper.js
102
-        // (and enqueue ee-qtip-helper.js of course!)
103
-        if (!empty($this->_qtips)) {
104
-            wp_enqueue_script('ee-qtip-helper');
105
-            wp_enqueue_style('qtip-css');
106
-            $qtips = array();
107
-            foreach ($this->_qtips as $qtip) {
108
-                $qts = $qtip->get_tips();
109
-                foreach ($qts as $qt) {
110
-                    if (! $qt instanceof EE_Qtip) {
111
-                        continue;
112
-                    }
113
-                    $qtips[] = array(
114
-                        'content_id' => $qt->content_id,
115
-                        'options' => $qt->options,
116
-                        'target' => $qt->target,
117
-                        );
118
-                }
119
-            }
120
-            if (!empty($qtips)) {
121
-                wp_localize_script('ee-qtip-helper', 'EE_QTIP_HELPER', array( 'qtips' => $qtips ));
122
-            }
123
-        } else {
124
-            // qtips has been requested without any registration (so assuming its just directly used in the admin).
125
-            wp_enqueue_script('qtip');
126
-            wp_enqueue_style('qtip-css');
127
-        }
128
-    }
129
-
130
-
131
-    /**
132
-     * This simply registers the given qtip config and:
133
-     * - adds it to the $_qtips property array.
134
-     * - sets up the content containers for all qtips in the config,
135
-     * - registers and enqueues the qtip scripts and styles.
136
-     *
137
-     * @access public
138
-     * @param array        $paths      Array of paths to check for the EE_Qtip class. If present we check these path(s)
139
-     *                                 first.  If not present (empty array), then it's assumed it's either in
140
-     *                                 core/libraries/qtips OR the file is already loaded.
141
-     * @param string|array $qtips      name of the Qtip class (full class name is expected and will be used for looking
142
-     *                                 for file, Qtip config classes must extend EE_Qtip_Config) [if this is an array,
143
-     *                                 then we loop through the array to instantiate and setup the qtips]
144
-     * @return void
145
-     * @throws DomainException
146
-     * @throws EE_Error
147
-     * @throws ReflectionException
148
-     */
149
-    public function register($qtips, $paths = array())
150
-    {
151
-        // let's just make sure this is instantiated in the right place.
152
-        if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
153
-            EE_Error::doing_it_wrong(
154
-                'EEH_Qtip_Loader->register()',
155
-                esc_html__(
156
-                    'EE_Qtip_Config objects must be registered before wp_enqueue_scripts is called.',
157
-                    'event_espresso'
158
-                ),
159
-                '4.1'
160
-            );
161
-        }
162
-
163
-        $qtips = (array) $qtips; // typecast to array
164
-        foreach ($qtips as $qtip) {
165
-            $this->_qtips[] = $this->_register($qtip, $paths);
166
-        }
167
-
168
-        // hook into appropriate footer
169
-        $footer_action = is_admin() ? 'admin_footer' : 'wp_footer';
170
-        add_action($footer_action, array($this, 'setup_qtip'), 10);
171
-
172
-        // make sure we "turn on" qtip js.
173
-        add_filter('FHEE_load_qtip', '__return_true');
174
-    }
175
-
176
-
177
-    /**
178
-     * private utility for registering and setting up qtip config objects
179
-     *
180
-     * @access private
181
-     * @param string $qtip  the short name of the class (will be used to generate the expected classname)
182
-     * @param array  $paths array of paths to check (or if empty we check core/libraries/qtips or assume its loaded)
183
-     * @return EE_Qtip_Config
184
-     * @throws DomainException
185
-     * @throws EE_Error
186
-     * @throws ReflectionException
187
-     */
188
-    private function _register($qtip, $paths)
189
-    {
190
-        // before doing anything we have to make sure that EE_Qtip_Config parent is required.
191
-        EE_Registry::instance()->load_lib('Qtip_Config', array(), true);
192
-        if (!empty($paths)) {
193
-            $paths = (array) $paths;
194
-            foreach ($paths as $path) {
195
-                $path .= $qtip . '.lib.php';
196
-                if (is_readable($path)) {
197
-                    require_once $path;
198
-                }
199
-            }
200
-        }
201
-
202
-        // does class exist at this point?  If it does then let's instantiate.  If it doesn't then let's continue with other paths.
203
-        if (! class_exists($qtip)) {
204
-            $path = EE_LIBRARIES . 'qtips/' . $qtip . '.lib.php';
205
-            if (! is_readable($path)) {
206
-                throw new DomainException(
207
-                    sprintf(
208
-                        esc_html__(
209
-                            'Unable to load the Qtip Config registered for this page (%s) because none of the file paths attempted are readable.  Please check the spelling of the paths you\'ve used in the registration',
210
-                            'event_espresso'
211
-                        ),
212
-                        $qtip
213
-                    )
214
-                );
215
-            }
216
-            require_once $path;
217
-        }
218
-
219
-        // now we attempt a class_exists one more time.
220
-        if (! class_exists($qtip)) {
221
-            throw new DomainException(
222
-                sprintf(
223
-                    esc_html__(
224
-                        'The Qtip_Config class being registered (%s) does not exist, please check the spelling.',
225
-                        'event_espresso'
226
-                    ),
227
-                    $qtip
228
-                )
229
-            );
230
-        }
231
-
232
-        // made it HERE?  FINALLY, let's get things setup.
233
-        $qtip_config = $this->loader->getShared($qtip);
234
-
235
-        // verify that $qtip is a valid object
236
-        if (! $qtip_config instanceof EE_Qtip_Config) {
237
-            throw new DomainException(
238
-                sprintf(
239
-                    esc_html__(
240
-                        'The class given for the Qtip loader (%1$s) is not a child of the %2$sEE_Qtip_Config%3$s class. Please make sure you are extending EE_Qtip_Config.',
241
-                        'event_espresso'
242
-                    ),
243
-                    $qtip,
244
-                    '<strong>',
245
-                    '</strong>'
246
-                )
247
-            );
248
-        }
249
-
250
-        return $qtip_config;
251
-    }
252
-
253
-
254
-
255
-    /**
256
-     * This takes care of generating the qtip content containers.
257
-     * Output gets put in the appropriate page footer (depending on context (either admin_footer or wp_footer) )
258
-     *
259
-     * @return void
260
-     */
261
-    public function setup_qtip()
262
-    {
263
-        if (empty($this->_qtips)) {
264
-            return; // no qtips!
265
-        }
266
-
267
-        $content = array();
268
-
269
-        foreach ($this->_qtips as $qtip) {
270
-            $content[] = $this->_generate_content_container($qtip);
271
-        }
272
-
273
-        echo implode('<br />', $content);
274
-    }
275
-
276
-
277
-    /**
278
-     * Generates a content container from a given EE_Qtip_Config object.
279
-     *
280
-     * @param  EE_Qtip_Config $qtip
281
-     * @return string  (html content container for qtip);
282
-     */
283
-    private function _generate_content_container($qtip)
284
-    {
285
-        $qts = $qtip->get_tips();
286
-        $content = array();
287
-        foreach ($qts as $qt) {
288
-            if (! $qt instanceof EE_Qtip) {
289
-                continue;
290
-            }
291
-            $content[] = '<div class="ee-qtip-helper-content hidden" id="' . esc_attr($qt->content_id) . '">' .
292
-                         $qt->content . '</div>';
293
-        }
294
-
295
-        return implode('<br />', $content);
296
-    }
18
+	/**
19
+	 * @var LoaderInterface $loader
20
+	 */
21
+	protected $loader;
22
+
23
+	/**
24
+	 * @var EEH_Qtip_Loader
25
+	 */
26
+	private static $_instance;
27
+
28
+	/**
29
+	 * array of qtip config objects
30
+	 * @var EE_Qtip_Config[]
31
+	 */
32
+	private $_qtips = array();
33
+
34
+
35
+
36
+	/**
37
+	 *@singleton method used to instantiate class object
38
+	 *@access public
39
+	 *@return EEH_Qtip_Loader instance
40
+	 */
41
+	public static function instance()
42
+	{
43
+		// check if class object is instantiated
44
+		if (! EEH_Qtip_Loader::$_instance instanceof EEH_Qtip_Loader) {
45
+			EEH_Qtip_Loader::$_instance = new EEH_Qtip_Loader();
46
+		}
47
+		return EEH_Qtip_Loader::$_instance;
48
+	}
49
+
50
+
51
+
52
+	/**
53
+	 * private constructor to prevent direct creation
54
+	 */
55
+	private function __construct()
56
+	{
57
+		// let's just make sure this is instantiated in the right place.
58
+		if (did_action('wp_print_styles') || did_action('admin_head')) {
59
+			EE_Error::doing_it_wrong(
60
+				'EEH_Qtip_Loader',
61
+				esc_html__(
62
+					'This helper must be instantiated before or within a callback for the WordPress wp_enqueue_scripts hook action hook.',
63
+					'event_espresso'
64
+				),
65
+				'4.1'
66
+			);
67
+		}
68
+		$this->loader = LoaderFactory::getLoader();
69
+	}
70
+
71
+
72
+	/**
73
+	 * Call this from wp_enqueue_scripts or admin_enqueue_scripts to setup and enqueue the qtip library
74
+	 *
75
+	 * @access public
76
+	 * @return void
77
+	 */
78
+	public function register_and_enqueue()
79
+	{
80
+		$qtips_js = !defined('SCRIPT_DEBUG')
81
+			? EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.js'
82
+			: EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.js';
83
+		$qtip_map = EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.map';
84
+		$qtip_css = !defined('SCRIPT_DEBUG')
85
+			? EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.min.css'
86
+			: EE_THIRD_PARTY_URL . 'qtip/jquery.qtip.css';
87
+
88
+		wp_register_script('qtip-map', $qtip_map, array(), '3', true);
89
+		wp_register_script('qtip', $qtips_js, array('jquery'), '3.0.3', true);
90
+		wp_register_script(
91
+			'ee-qtip-helper',
92
+			EE_HELPERS_ASSETS . 'ee-qtip-helper.js',
93
+			array('qtip', JqueryAssetManager::JS_HANDLE_JQUERY_COOKIE),
94
+			EVENT_ESPRESSO_VERSION,
95
+			true
96
+		);
97
+
98
+		wp_register_style('qtip-css', $qtip_css, array(), '2.2');
99
+
100
+		// k now let's see if there are any registered qtips.
101
+		// If there are, then we need to setup the localized script for ee-qtip-helper.js
102
+		// (and enqueue ee-qtip-helper.js of course!)
103
+		if (!empty($this->_qtips)) {
104
+			wp_enqueue_script('ee-qtip-helper');
105
+			wp_enqueue_style('qtip-css');
106
+			$qtips = array();
107
+			foreach ($this->_qtips as $qtip) {
108
+				$qts = $qtip->get_tips();
109
+				foreach ($qts as $qt) {
110
+					if (! $qt instanceof EE_Qtip) {
111
+						continue;
112
+					}
113
+					$qtips[] = array(
114
+						'content_id' => $qt->content_id,
115
+						'options' => $qt->options,
116
+						'target' => $qt->target,
117
+						);
118
+				}
119
+			}
120
+			if (!empty($qtips)) {
121
+				wp_localize_script('ee-qtip-helper', 'EE_QTIP_HELPER', array( 'qtips' => $qtips ));
122
+			}
123
+		} else {
124
+			// qtips has been requested without any registration (so assuming its just directly used in the admin).
125
+			wp_enqueue_script('qtip');
126
+			wp_enqueue_style('qtip-css');
127
+		}
128
+	}
129
+
130
+
131
+	/**
132
+	 * This simply registers the given qtip config and:
133
+	 * - adds it to the $_qtips property array.
134
+	 * - sets up the content containers for all qtips in the config,
135
+	 * - registers and enqueues the qtip scripts and styles.
136
+	 *
137
+	 * @access public
138
+	 * @param array        $paths      Array of paths to check for the EE_Qtip class. If present we check these path(s)
139
+	 *                                 first.  If not present (empty array), then it's assumed it's either in
140
+	 *                                 core/libraries/qtips OR the file is already loaded.
141
+	 * @param string|array $qtips      name of the Qtip class (full class name is expected and will be used for looking
142
+	 *                                 for file, Qtip config classes must extend EE_Qtip_Config) [if this is an array,
143
+	 *                                 then we loop through the array to instantiate and setup the qtips]
144
+	 * @return void
145
+	 * @throws DomainException
146
+	 * @throws EE_Error
147
+	 * @throws ReflectionException
148
+	 */
149
+	public function register($qtips, $paths = array())
150
+	{
151
+		// let's just make sure this is instantiated in the right place.
152
+		if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
153
+			EE_Error::doing_it_wrong(
154
+				'EEH_Qtip_Loader->register()',
155
+				esc_html__(
156
+					'EE_Qtip_Config objects must be registered before wp_enqueue_scripts is called.',
157
+					'event_espresso'
158
+				),
159
+				'4.1'
160
+			);
161
+		}
162
+
163
+		$qtips = (array) $qtips; // typecast to array
164
+		foreach ($qtips as $qtip) {
165
+			$this->_qtips[] = $this->_register($qtip, $paths);
166
+		}
167
+
168
+		// hook into appropriate footer
169
+		$footer_action = is_admin() ? 'admin_footer' : 'wp_footer';
170
+		add_action($footer_action, array($this, 'setup_qtip'), 10);
171
+
172
+		// make sure we "turn on" qtip js.
173
+		add_filter('FHEE_load_qtip', '__return_true');
174
+	}
175
+
176
+
177
+	/**
178
+	 * private utility for registering and setting up qtip config objects
179
+	 *
180
+	 * @access private
181
+	 * @param string $qtip  the short name of the class (will be used to generate the expected classname)
182
+	 * @param array  $paths array of paths to check (or if empty we check core/libraries/qtips or assume its loaded)
183
+	 * @return EE_Qtip_Config
184
+	 * @throws DomainException
185
+	 * @throws EE_Error
186
+	 * @throws ReflectionException
187
+	 */
188
+	private function _register($qtip, $paths)
189
+	{
190
+		// before doing anything we have to make sure that EE_Qtip_Config parent is required.
191
+		EE_Registry::instance()->load_lib('Qtip_Config', array(), true);
192
+		if (!empty($paths)) {
193
+			$paths = (array) $paths;
194
+			foreach ($paths as $path) {
195
+				$path .= $qtip . '.lib.php';
196
+				if (is_readable($path)) {
197
+					require_once $path;
198
+				}
199
+			}
200
+		}
201
+
202
+		// does class exist at this point?  If it does then let's instantiate.  If it doesn't then let's continue with other paths.
203
+		if (! class_exists($qtip)) {
204
+			$path = EE_LIBRARIES . 'qtips/' . $qtip . '.lib.php';
205
+			if (! is_readable($path)) {
206
+				throw new DomainException(
207
+					sprintf(
208
+						esc_html__(
209
+							'Unable to load the Qtip Config registered for this page (%s) because none of the file paths attempted are readable.  Please check the spelling of the paths you\'ve used in the registration',
210
+							'event_espresso'
211
+						),
212
+						$qtip
213
+					)
214
+				);
215
+			}
216
+			require_once $path;
217
+		}
218
+
219
+		// now we attempt a class_exists one more time.
220
+		if (! class_exists($qtip)) {
221
+			throw new DomainException(
222
+				sprintf(
223
+					esc_html__(
224
+						'The Qtip_Config class being registered (%s) does not exist, please check the spelling.',
225
+						'event_espresso'
226
+					),
227
+					$qtip
228
+				)
229
+			);
230
+		}
231
+
232
+		// made it HERE?  FINALLY, let's get things setup.
233
+		$qtip_config = $this->loader->getShared($qtip);
234
+
235
+		// verify that $qtip is a valid object
236
+		if (! $qtip_config instanceof EE_Qtip_Config) {
237
+			throw new DomainException(
238
+				sprintf(
239
+					esc_html__(
240
+						'The class given for the Qtip loader (%1$s) is not a child of the %2$sEE_Qtip_Config%3$s class. Please make sure you are extending EE_Qtip_Config.',
241
+						'event_espresso'
242
+					),
243
+					$qtip,
244
+					'<strong>',
245
+					'</strong>'
246
+				)
247
+			);
248
+		}
249
+
250
+		return $qtip_config;
251
+	}
252
+
253
+
254
+
255
+	/**
256
+	 * This takes care of generating the qtip content containers.
257
+	 * Output gets put in the appropriate page footer (depending on context (either admin_footer or wp_footer) )
258
+	 *
259
+	 * @return void
260
+	 */
261
+	public function setup_qtip()
262
+	{
263
+		if (empty($this->_qtips)) {
264
+			return; // no qtips!
265
+		}
266
+
267
+		$content = array();
268
+
269
+		foreach ($this->_qtips as $qtip) {
270
+			$content[] = $this->_generate_content_container($qtip);
271
+		}
272
+
273
+		echo implode('<br />', $content);
274
+	}
275
+
276
+
277
+	/**
278
+	 * Generates a content container from a given EE_Qtip_Config object.
279
+	 *
280
+	 * @param  EE_Qtip_Config $qtip
281
+	 * @return string  (html content container for qtip);
282
+	 */
283
+	private function _generate_content_container($qtip)
284
+	{
285
+		$qts = $qtip->get_tips();
286
+		$content = array();
287
+		foreach ($qts as $qt) {
288
+			if (! $qt instanceof EE_Qtip) {
289
+				continue;
290
+			}
291
+			$content[] = '<div class="ee-qtip-helper-content hidden" id="' . esc_attr($qt->content_id) . '">' .
292
+						 $qt->content . '</div>';
293
+		}
294
+
295
+		return implode('<br />', $content);
296
+	}
297 297
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Tabbed_Content.helper.php 2 patches
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -30,7 +30,7 @@  discard block
 block discarded – undo
30 30
     {
31 31
 
32 32
         // first check if $tabs_names is not empty then the count must match the count of $tabs_content otherwise we've got a problem houston
33
-        if (! empty($tabs_names) && (count((array) $tabs_names) != count((array) $tabs_content))) {
33
+        if ( ! empty($tabs_names) && (count((array) $tabs_names) != count((array) $tabs_content))) {
34 34
             throw new EE_Error(
35 35
                 esc_html__('The count for $tabs_names and $tabs_content does not match.', 'event_espresso')
36 36
             );
@@ -49,9 +49,9 @@  discard block
 block discarded – undo
49 49
 
50 50
         $index = 0;
51 51
         foreach ($tabs as $tab) {
52
-            $active            = $index === 0;
52
+            $active = $index === 0;
53 53
             $tabs_html         .= self::tab($tab, $active);
54
-            $tabs_content_html .= self::tab_content($tab, $tabs_content[ $tab ], $active);
54
+            $tabs_content_html .= self::tab_content($tab, $tabs_content[$tab], $active);
55 55
             $index++;
56 56
         }
57 57
 
@@ -118,9 +118,9 @@  discard block
 block discarded – undo
118 118
     {
119 119
         $nice_name = $nice_name ?: esc_html(ucwords(str_replace(['_', '-'], ' ', $name)));
120 120
         $name      = self::generateTabID($name);
121
-        $class     = $css ? ' ' . esc_attr($css) : '';
122
-        $class     .= $active ? ' nav-tab-active' : '';
123
-        $url       = $url ?: '#' . esc_attr($name);
121
+        $class     = $css ? ' '.esc_attr($css) : '';
122
+        $class .= $active ? ' nav-tab-active' : '';
123
+        $url       = $url ?: '#'.esc_attr($name);
124 124
         return "
125 125
         <a class='nav-tab{$class}' rel='{$name}' href='{$url}'>
126 126
             $nice_name
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
      */
137 137
     private static function generateTabID($tab_name)
138 138
     {
139
-        return 'ee-tab-' . esc_attr(str_replace(' ', '-', $tab_name));
139
+        return 'ee-tab-'.esc_attr(str_replace(' ', '-', $tab_name));
140 140
     }
141 141
 
142 142
 
@@ -187,18 +187,18 @@  discard block
 block discarded – undo
187 187
     public static function tab_text_links(array $item_array, $container_class = '', $sep = '|', $default = '')
188 188
     {
189 189
         $item_array = apply_filters('FHEE__EEH_Tabbed_Content__tab_text_links', $item_array, $container_class);
190
-        if (! is_array($item_array) || empty($item_array)) {
190
+        if ( ! is_array($item_array) || empty($item_array)) {
191 191
             return false; // get out we don't have even the basic thing we need!
192 192
         }
193 193
 
194
-        $defaults        = [
194
+        $defaults = [
195 195
             'label' => esc_html__('Item', 'event_espresso'),
196 196
             'class' => '',
197 197
             'href'  => '',
198 198
             'title' => esc_attr__('Link for Item', 'event_espresso'),
199 199
             'slug'  => 'item_slug',
200 200
         ];
201
-        $container_class = ! empty($container_class) ? ' ' . esc_attr($container_class) : '';
201
+        $container_class = ! empty($container_class) ? ' '.esc_attr($container_class) : '';
202 202
         $list            = '';
203 203
         $list_length     = count($item_array);
204 204
         // if we're' adding separators, set $current to 1, otherwise set it to list length + 1
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
         // (if we aren't adding separators $current will always be > list length cuz it started at list length + 1)
207 207
         $current = empty($sep) ? $list_length + 1 : 1;
208 208
         foreach ($item_array as $item) {
209
-            $item          = wp_parse_args($item, $defaults);
209
+            $item = wp_parse_args($item, $defaults);
210 210
             $item['class'] .= $default === $item['slug'] ? ' item_display' : '';
211 211
             $list          .= self::textLinkItem($item);
212 212
             $list          .= $current < $list_length ? self::textLinkSeparator($sep) : '';
Please login to merge, or discard this patch.
Indentation   +194 added lines, -194 removed lines patch added patch discarded remove patch
@@ -13,249 +13,249 @@
 block discarded – undo
13 13
  */
14 14
 class EEH_Tabbed_Content
15 15
 {
16
-    /**
17
-     * assembles and returns the html structure for tabs
18
-     *
19
-     * @static
20
-     * @param array $tabs_contents an array of the content for each tab [required]
21
-     * @param array $tabs_names    a numerically indexed array of names for each tab [optional]
22
-     *                             - if this isn't included then we use the indexes for $tabs_content as the tab names)
23
-     * @param bool  $small_tabs
24
-     * @param bool  $tabs_content
25
-     * @return string the assembled html string containing the tabbed content for display.
26
-     * @throws EE_Error
27
-     */
28
-    public static function display($tabs_contents, $tabs_names = [], $small_tabs = true, $tabs_content = true)
29
-    {
16
+	/**
17
+	 * assembles and returns the html structure for tabs
18
+	 *
19
+	 * @static
20
+	 * @param array $tabs_contents an array of the content for each tab [required]
21
+	 * @param array $tabs_names    a numerically indexed array of names for each tab [optional]
22
+	 *                             - if this isn't included then we use the indexes for $tabs_content as the tab names)
23
+	 * @param bool  $small_tabs
24
+	 * @param bool  $tabs_content
25
+	 * @return string the assembled html string containing the tabbed content for display.
26
+	 * @throws EE_Error
27
+	 */
28
+	public static function display($tabs_contents, $tabs_names = [], $small_tabs = true, $tabs_content = true)
29
+	{
30 30
 
31
-        // first check if $tabs_names is not empty then the count must match the count of $tabs_content otherwise we've got a problem houston
32
-        if (! empty($tabs_names) && (count((array) $tabs_names) != count((array) $tabs_content))) {
33
-            throw new EE_Error(
34
-                esc_html__('The count for $tabs_names and $tabs_content does not match.', 'event_espresso')
35
-            );
36
-        }
31
+		// first check if $tabs_names is not empty then the count must match the count of $tabs_content otherwise we've got a problem houston
32
+		if (! empty($tabs_names) && (count((array) $tabs_names) != count((array) $tabs_content))) {
33
+			throw new EE_Error(
34
+				esc_html__('The count for $tabs_names and $tabs_content does not match.', 'event_espresso')
35
+			);
36
+		}
37 37
 
38
-        // make sure we've got incoming data setup properly
39
-        $tabs         = ! empty($tabs_names)
40
-            ? (array) $tabs_names
41
-            : array_keys((array) $tabs_contents);
42
-        $tabs_content = ! empty($tabs_names)
43
-            ? array_combine((array) $tabs_names, (array) $tabs_content)
44
-            : $tabs_contents;
38
+		// make sure we've got incoming data setup properly
39
+		$tabs         = ! empty($tabs_names)
40
+			? (array) $tabs_names
41
+			: array_keys((array) $tabs_contents);
42
+		$tabs_content = ! empty($tabs_names)
43
+			? array_combine((array) $tabs_names, (array) $tabs_content)
44
+			: $tabs_contents;
45 45
 
46
-        $tabs_html         = '';
47
-        $tabs_content_html = '';
46
+		$tabs_html         = '';
47
+		$tabs_content_html = '';
48 48
 
49
-        $index = 0;
50
-        foreach ($tabs as $tab) {
51
-            $active            = $index === 0;
52
-            $tabs_html         .= self::tab($tab, $active);
53
-            $tabs_content_html .= self::tab_content($tab, $tabs_content[ $tab ], $active);
54
-            $index++;
55
-        }
49
+		$index = 0;
50
+		foreach ($tabs as $tab) {
51
+			$active            = $index === 0;
52
+			$tabs_html         .= self::tab($tab, $active);
53
+			$tabs_content_html .= self::tab_content($tab, $tabs_content[ $tab ], $active);
54
+			$index++;
55
+		}
56 56
 
57
-        $tabs_class = $small_tabs ? ' ee-nav-tabs-small' : '';
57
+		$tabs_class = $small_tabs ? ' ee-nav-tabs-small' : '';
58 58
 
59
-        return "
59
+		return "
60 60
     <div class='ee-nav-tabs{$tabs_class}'>
61 61
         <h2 class='nav-tab-wrapper'>{$tabs_html}</h2>
62 62
         {$tabs_content_html}
63 63
     </div>
64 64
     ";
65
-    }
65
+	}
66 66
 
67 67
 
68
-    /**
69
-     * display_admin_nav_tabs
70
-     * this returns the properly formatted tab html for EE_Admin_Pages.
71
-     * We are expecting an array of tabs in the following format
72
-     * array(
73
-     *    'nav_tab_name' => array(
74
-     *        'url' => 'url for tab',
75
-     *        'link_text' => 'tab text',
76
-     *        'css_class' => 'tab class' //including the nav-tab-active class if its active
77
-     *    )
78
-     * )
79
-     *
80
-     * @access public
81
-     * @static
82
-     * @param string[][] $nav_tabs tab array for nav tabs
83
-     * @return string
84
-     * @throws EE_Error
85
-     */
86
-    public static function display_admin_nav_tabs(array $nav_tabs = [], string $page_slug = '')
87
-    {
88
-        if (empty($nav_tabs)) {
89
-            throw new EE_Error(
90
-                esc_html__('Nav Tabs cannot be generated because the tab array is missing', 'event_espresso')
91
-            );
92
-        }
93
-        $tab_content = '';
94
-        $tab_count = 0;
95
-        foreach ($nav_tabs as $slug => $tab) {
96
-            $tab_count++;
97
-            $tab_content .= self::tab($slug, false, $tab['link_text'], $tab['url'], $tab['css_class']);
98
-        }
99
-        $aria_label = esc_attr__('Secondary menu', 'event_espresso');
100
-        $css_class = "ee-nav-tabs--{$tab_count}";
101
-        $css_class .= $page_slug ? " ee-nav-tabs--$page_slug" : '';
102
-        return "
68
+	/**
69
+	 * display_admin_nav_tabs
70
+	 * this returns the properly formatted tab html for EE_Admin_Pages.
71
+	 * We are expecting an array of tabs in the following format
72
+	 * array(
73
+	 *    'nav_tab_name' => array(
74
+	 *        'url' => 'url for tab',
75
+	 *        'link_text' => 'tab text',
76
+	 *        'css_class' => 'tab class' //including the nav-tab-active class if its active
77
+	 *    )
78
+	 * )
79
+	 *
80
+	 * @access public
81
+	 * @static
82
+	 * @param string[][] $nav_tabs tab array for nav tabs
83
+	 * @return string
84
+	 * @throws EE_Error
85
+	 */
86
+	public static function display_admin_nav_tabs(array $nav_tabs = [], string $page_slug = '')
87
+	{
88
+		if (empty($nav_tabs)) {
89
+			throw new EE_Error(
90
+				esc_html__('Nav Tabs cannot be generated because the tab array is missing', 'event_espresso')
91
+			);
92
+		}
93
+		$tab_content = '';
94
+		$tab_count = 0;
95
+		foreach ($nav_tabs as $slug => $tab) {
96
+			$tab_count++;
97
+			$tab_content .= self::tab($slug, false, $tab['link_text'], $tab['url'], $tab['css_class']);
98
+		}
99
+		$aria_label = esc_attr__('Secondary menu', 'event_espresso');
100
+		$css_class = "ee-nav-tabs--{$tab_count}";
101
+		$css_class .= $page_slug ? " ee-nav-tabs--$page_slug" : '';
102
+		return "
103 103
         <nav class='nav-tab-wrapper wp-clearfix $css_class' aria-label='$aria_label'>
104 104
             $tab_content
105 105
         </nav>
106 106
         ";
107
-    }
107
+	}
108 108
 
109 109
 
110
-    /**
111
-     * this simply returns a single tab given a tab name & content
112
-     *
113
-     * @param string      $name      name of tab
114
-     * @param bool        $active    true=tab active, false=tab not active
115
-     * @param bool|string $nice_name if string given then this value will be used for the tab link text.
116
-     * @param bool|string $url       If url given then tabs will be generated linking to the url.
117
-     * @param bool|string $css       If string given then the generated tab will include that as the class.
118
-     * @return string          html for tab
119
-     */
120
-    private static function tab($name, $active = false, $nice_name = false, $url = false, $css = false)
121
-    {
122
-        $nice_name = $nice_name ?: esc_html(ucwords(str_replace(['_', '-'], ' ', $name)));
123
-        $name      = self::generateTabID($name);
124
-        $class     = $css ? ' ' . esc_attr($css) : '';
125
-        $class     .= $active ? ' nav-tab-active' : '';
126
-        $url       = $url ?: '#' . esc_attr($name);
127
-        return "
110
+	/**
111
+	 * this simply returns a single tab given a tab name & content
112
+	 *
113
+	 * @param string      $name      name of tab
114
+	 * @param bool        $active    true=tab active, false=tab not active
115
+	 * @param bool|string $nice_name if string given then this value will be used for the tab link text.
116
+	 * @param bool|string $url       If url given then tabs will be generated linking to the url.
117
+	 * @param bool|string $css       If string given then the generated tab will include that as the class.
118
+	 * @return string          html for tab
119
+	 */
120
+	private static function tab($name, $active = false, $nice_name = false, $url = false, $css = false)
121
+	{
122
+		$nice_name = $nice_name ?: esc_html(ucwords(str_replace(['_', '-'], ' ', $name)));
123
+		$name      = self::generateTabID($name);
124
+		$class     = $css ? ' ' . esc_attr($css) : '';
125
+		$class     .= $active ? ' nav-tab-active' : '';
126
+		$url       = $url ?: '#' . esc_attr($name);
127
+		return "
128 128
         <a class='nav-tab{$class}' rel='{$name}' href='{$url}'>
129 129
             $nice_name
130 130
         </a>
131 131
         ";
132
-    }
132
+	}
133 133
 
134 134
 
135
-    /**
136
-     * @param string $tab_name
137
-     * @return string
138
-     * @since   4.10.14.p
139
-     */
140
-    private static function generateTabID($tab_name)
141
-    {
142
-        return 'ee-tab-' . esc_attr(str_replace(' ', '-', $tab_name));
143
-    }
135
+	/**
136
+	 * @param string $tab_name
137
+	 * @return string
138
+	 * @since   4.10.14.p
139
+	 */
140
+	private static function generateTabID($tab_name)
141
+	{
142
+		return 'ee-tab-' . esc_attr(str_replace(' ', '-', $tab_name));
143
+	}
144 144
 
145 145
 
146
-    /**
147
-     * this just returns the properly formatted tab content for our tab box.
148
-     *
149
-     * @param string $name        name of tab (used for selector)
150
-     * @param string $tab_content content of tab
151
-     * @param bool   $active
152
-     * @return string html for content area
153
-     */
154
-    private static function tab_content($name, $tab_content, $active = false)
155
-    {
156
-        $class = $active ? '' : ' hidden';
157
-        $name  = self::generateTabID($name);
158
-        return "
146
+	/**
147
+	 * this just returns the properly formatted tab content for our tab box.
148
+	 *
149
+	 * @param string $name        name of tab (used for selector)
150
+	 * @param string $tab_content content of tab
151
+	 * @param bool   $active
152
+	 * @return string html for content area
153
+	 */
154
+	private static function tab_content($name, $tab_content, $active = false)
155
+	{
156
+		$class = $active ? '' : ' hidden';
157
+		$name  = self::generateTabID($name);
158
+		return "
159 159
     <div class='nav-tab-content{$class}' id='{$name}'>
160 160
         {$tab_content}
161 161
         <div style='clear:both'></div>
162 162
     </div>";
163
-    }
163
+	}
164 164
 
165 165
 
166 166
 
167
-    /** HORIZONTAL TEXT LINKS **/
167
+	/** HORIZONTAL TEXT LINKS **/
168 168
 
169
-    /**
170
-     * This will take in an array of link items and spit out a formatted list of links that can be used to navigate to
171
-     * items. There is a corresponding js file that can be loaded to dynamically display containers with the same id as
172
-     * the href -ref.
173
-     *
174
-     * @param string[] $item_array      formatted array of items.  Format:
175
-     *                                  array(
176
-     *                                  'label' => esc_html__('localized label displayed'),
177
-     *                                  'class' => 'class_for_item',
178
-     *                                  'href' => '#some_item_id', //url/bookmark for item.  If you include a bookmark
179
-     *                                  the js will used this to show the container div.
180
-     *                                  'title' => esc_html__('localized text for the title attribute of the link'),
181
-     *                                  'slug' => 'slug_used_for_reference'
182
-     *                                  )
183
-     * @param string   $container_class class used for main container
184
-     * @param string   $sep             you can add in what is used as a separator between each link (or leave blank for
185
-     *                                  none)
186
-     * @param string   $default         You can include a string for the item that will receive the "item_display" class
187
-     *                                  for the js.
188
-     * @return string                  a html snippet of of all the formatted link elements.
189
-     */
190
-    public static function tab_text_links(array $item_array, $container_class = '', $sep = '|', $default = '')
191
-    {
192
-        $item_array = apply_filters('FHEE__EEH_Tabbed_Content__tab_text_links', $item_array, $container_class);
193
-        if (! is_array($item_array) || empty($item_array)) {
194
-            return false; // get out we don't have even the basic thing we need!
195
-        }
169
+	/**
170
+	 * This will take in an array of link items and spit out a formatted list of links that can be used to navigate to
171
+	 * items. There is a corresponding js file that can be loaded to dynamically display containers with the same id as
172
+	 * the href -ref.
173
+	 *
174
+	 * @param string[] $item_array      formatted array of items.  Format:
175
+	 *                                  array(
176
+	 *                                  'label' => esc_html__('localized label displayed'),
177
+	 *                                  'class' => 'class_for_item',
178
+	 *                                  'href' => '#some_item_id', //url/bookmark for item.  If you include a bookmark
179
+	 *                                  the js will used this to show the container div.
180
+	 *                                  'title' => esc_html__('localized text for the title attribute of the link'),
181
+	 *                                  'slug' => 'slug_used_for_reference'
182
+	 *                                  )
183
+	 * @param string   $container_class class used for main container
184
+	 * @param string   $sep             you can add in what is used as a separator between each link (or leave blank for
185
+	 *                                  none)
186
+	 * @param string   $default         You can include a string for the item that will receive the "item_display" class
187
+	 *                                  for the js.
188
+	 * @return string                  a html snippet of of all the formatted link elements.
189
+	 */
190
+	public static function tab_text_links(array $item_array, $container_class = '', $sep = '|', $default = '')
191
+	{
192
+		$item_array = apply_filters('FHEE__EEH_Tabbed_Content__tab_text_links', $item_array, $container_class);
193
+		if (! is_array($item_array) || empty($item_array)) {
194
+			return false; // get out we don't have even the basic thing we need!
195
+		}
196 196
 
197
-        $defaults        = [
198
-            'label' => esc_html__('Item', 'event_espresso'),
199
-            'class' => '',
200
-            'href'  => '',
201
-            'title' => esc_attr__('Link for Item', 'event_espresso'),
202
-            'slug'  => 'item_slug',
203
-        ];
204
-        $container_class = ! empty($container_class) ? ' ' . esc_attr($container_class) : '';
205
-        $list            = '';
206
-        $list_length     = count($item_array);
207
-        // if we're' adding separators, set $current to 1, otherwise set it to list length + 1
208
-        // then we'll increment $current while looping and only add separators if $current is < list length
209
-        // (if we aren't adding separators $current will always be > list length cuz it started at list length + 1)
210
-        $current = empty($sep) ? $list_length + 1 : 1;
211
-        foreach ($item_array as $item) {
212
-            $item          = wp_parse_args($item, $defaults);
213
-            $item['class'] .= $default === $item['slug'] ? ' item_display' : '';
214
-            $list          .= self::textLinkItem($item);
215
-            $list          .= $current < $list_length ? self::textLinkSeparator($sep) : '';
216
-            $current++;
217
-        }
197
+		$defaults        = [
198
+			'label' => esc_html__('Item', 'event_espresso'),
199
+			'class' => '',
200
+			'href'  => '',
201
+			'title' => esc_attr__('Link for Item', 'event_espresso'),
202
+			'slug'  => 'item_slug',
203
+		];
204
+		$container_class = ! empty($container_class) ? ' ' . esc_attr($container_class) : '';
205
+		$list            = '';
206
+		$list_length     = count($item_array);
207
+		// if we're' adding separators, set $current to 1, otherwise set it to list length + 1
208
+		// then we'll increment $current while looping and only add separators if $current is < list length
209
+		// (if we aren't adding separators $current will always be > list length cuz it started at list length + 1)
210
+		$current = empty($sep) ? $list_length + 1 : 1;
211
+		foreach ($item_array as $item) {
212
+			$item          = wp_parse_args($item, $defaults);
213
+			$item['class'] .= $default === $item['slug'] ? ' item_display' : '';
214
+			$list          .= self::textLinkItem($item);
215
+			$list          .= $current < $list_length ? self::textLinkSeparator($sep) : '';
216
+			$current++;
217
+		}
218 218
 
219
-        return "
219
+		return "
220 220
         <div class='ee-text-links{$container_class}'>{$list}</div>
221 221
         ";
222
-    }
222
+	}
223 223
 
224 224
 
225
-    /**
226
-     * @param string[] $item
227
-     * @return string
228
-     */
229
-    private static function textLinkItem(array $item)
230
-    {
231
-        $class = $item['class'] ? esc_attr($item['class']) : '';
232
-        $label = esc_html($item['label']);
233
-        $href  = $item['href'] ? esc_attr($item['href']) : '';
234
-        $icon  = $item['icon'] ?? '';
235
-        $title = esc_attr($item['title']);
236
-        $tag = $item['tag'] ?? 'a';
225
+	/**
226
+	 * @param string[] $item
227
+	 * @return string
228
+	 */
229
+	private static function textLinkItem(array $item)
230
+	{
231
+		$class = $item['class'] ? esc_attr($item['class']) : '';
232
+		$label = esc_html($item['label']);
233
+		$href  = $item['href'] ? esc_attr($item['href']) : '';
234
+		$icon  = $item['icon'] ?? '';
235
+		$title = esc_attr($item['title']);
236
+		$tag = $item['tag'] ?? 'a';
237 237
 
238 238
 
239
-        return ! empty($href)
240
-            ? "
239
+		return ! empty($href)
240
+			? "
241 241
             <{$tag} class='{$class} ee-text-link ee-aria-tooltip' href='#{$href}' aria-label='{$title}'>
242 242
                 {$icon}{$label}
243 243
             </{$tag}>
244 244
             "
245
-            : $label;
246
-    }
245
+			: $label;
246
+	}
247 247
 
248 248
 
249
-    /**
250
-     * @param string $separator
251
-     * @return string
252
-     * @since   4.10.14.p
253
-     */
254
-    private static function textLinkSeparator($separator)
255
-    {
256
-        $separator = esc_html($separator);
257
-        return "
249
+	/**
250
+	 * @param string $separator
251
+	 * @return string
252
+	 * @since   4.10.14.p
253
+	 */
254
+	private static function textLinkSeparator($separator)
255
+	{
256
+		$separator = esc_html($separator);
257
+		return "
258 258
         <span class='ee-text-link-sep'>{$separator}</span>
259 259
         ";
260
-    }
260
+	}
261 261
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Event_Question_Group.model.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -84,10 +84,10 @@
 block discarded – undo
84 84
         // this model is generally available for reading
85 85
         $path_to_event = 'Event';
86 86
 
87
-        $caps[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
88
-        $caps[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
89
-        $caps[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
90
-        $caps[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
87
+        $caps[EEM_Base::caps_read]       = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
88
+        $caps[EEM_Base::caps_read_admin] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
89
+        $caps[EEM_Base::caps_edit]       = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
90
+        $caps[EEM_Base::caps_delete]     = new EE_Restriction_Generator_Event_Related_Protected(
91 91
             $path_to_event,
92 92
             EEM_Base::caps_edit
93 93
         );
Please login to merge, or discard this patch.
Indentation   +103 added lines, -103 removed lines patch added patch discarded remove patch
@@ -14,116 +14,116 @@
 block discarded – undo
14 14
  */
15 15
 class EEM_Event_Question_Group extends EEM_Base
16 16
 {
17
-    /**
18
-     * Name of the field indicating an event should use the question group for the primary attendee
19
-     */
20
-    const PRIMARY = 'EQG_primary';
17
+	/**
18
+	 * Name of the field indicating an event should use the question group for the primary attendee
19
+	 */
20
+	const PRIMARY = 'EQG_primary';
21 21
 
22
-    /**
23
-     * Name of hte field indicating an event should use the question group for additional attendees
24
-     */
25
-    const ADDITIONAL = 'EQG_additional';
22
+	/**
23
+	 * Name of hte field indicating an event should use the question group for additional attendees
24
+	 */
25
+	const ADDITIONAL = 'EQG_additional';
26 26
 
27 27
 
28
-    protected static ?EEM_Event_Question_Group $_instance = null;
28
+	protected static ?EEM_Event_Question_Group $_instance = null;
29 29
 
30 30
 
31
-    /**
32
-     * @param string|null $timezone
33
-     * @throws EE_Error
34
-     */
35
-    protected function __construct(?string $timezone = '')
36
-    {
37
-        $this->singular_item    = esc_html__('Event to Question Group Link', 'event_espresso');
38
-        $this->plural_item      = esc_html__('Event to Question Group Links', 'event_espresso');
39
-        $this->_tables          = [
40
-            'Event_Question_Group' => new EE_Primary_Table('esp_event_question_group', 'EQG_ID'),
41
-        ];
42
-        $this->_fields          = [
43
-            'Event_Question_Group' => [
44
-                'EQG_ID'         => new EE_Primary_Key_Int_Field(
45
-                    'EQG_ID',
46
-                    esc_html__('Event to Question Group Link ID', 'event_espresso')
47
-                ),
48
-                'EVT_ID'         => new EE_Foreign_Key_Int_Field(
49
-                    'EVT_ID',
50
-                    esc_html__('Event ID', 'event_espresso'),
51
-                    false,
52
-                    0,
53
-                    'Event'
54
-                ),
55
-                'QSG_ID'         => new EE_Foreign_Key_Int_Field(
56
-                    'QSG_ID',
57
-                    esc_html__('Question Group Id', 'event_espresso'),
58
-                    false,
59
-                    0,
60
-                    'Question_Group'
61
-                ),
62
-                'EQG_additional' => new EE_Boolean_Field(
63
-                    'EQG_additional',
64
-                    esc_html__(
65
-                        'Flag indicating question is only for additional attendees',
66
-                        'event_espresso'
67
-                    ),
68
-                    false,
69
-                    false
70
-                ),
71
-                'EQG_primary'    => new EE_Boolean_Field(
72
-                    'EQG_primary',
73
-                    esc_html__(
74
-                        'Flag indicating question is only for primary attendees',
75
-                        'event_espresso'
76
-                    ),
77
-                    false,
78
-                    false
79
-                ),
80
-            ],
81
-        ];
82
-        $this->_model_relations = [
83
-            'Event'          => new EE_Belongs_To_Relation(),
84
-            'Question_Group' => new EE_Belongs_To_Relation(),
85
-        ];
31
+	/**
32
+	 * @param string|null $timezone
33
+	 * @throws EE_Error
34
+	 */
35
+	protected function __construct(?string $timezone = '')
36
+	{
37
+		$this->singular_item    = esc_html__('Event to Question Group Link', 'event_espresso');
38
+		$this->plural_item      = esc_html__('Event to Question Group Links', 'event_espresso');
39
+		$this->_tables          = [
40
+			'Event_Question_Group' => new EE_Primary_Table('esp_event_question_group', 'EQG_ID'),
41
+		];
42
+		$this->_fields          = [
43
+			'Event_Question_Group' => [
44
+				'EQG_ID'         => new EE_Primary_Key_Int_Field(
45
+					'EQG_ID',
46
+					esc_html__('Event to Question Group Link ID', 'event_espresso')
47
+				),
48
+				'EVT_ID'         => new EE_Foreign_Key_Int_Field(
49
+					'EVT_ID',
50
+					esc_html__('Event ID', 'event_espresso'),
51
+					false,
52
+					0,
53
+					'Event'
54
+				),
55
+				'QSG_ID'         => new EE_Foreign_Key_Int_Field(
56
+					'QSG_ID',
57
+					esc_html__('Question Group Id', 'event_espresso'),
58
+					false,
59
+					0,
60
+					'Question_Group'
61
+				),
62
+				'EQG_additional' => new EE_Boolean_Field(
63
+					'EQG_additional',
64
+					esc_html__(
65
+						'Flag indicating question is only for additional attendees',
66
+						'event_espresso'
67
+					),
68
+					false,
69
+					false
70
+				),
71
+				'EQG_primary'    => new EE_Boolean_Field(
72
+					'EQG_primary',
73
+					esc_html__(
74
+						'Flag indicating question is only for primary attendees',
75
+						'event_espresso'
76
+					),
77
+					false,
78
+					false
79
+				),
80
+			],
81
+		];
82
+		$this->_model_relations = [
83
+			'Event'          => new EE_Belongs_To_Relation(),
84
+			'Question_Group' => new EE_Belongs_To_Relation(),
85
+		];
86 86
 
87
-        // this model is generally available for reading
88
-        $path_to_event = 'Event';
87
+		// this model is generally available for reading
88
+		$path_to_event = 'Event';
89 89
 
90
-        $caps[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
91
-        $caps[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
92
-        $caps[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
93
-        $caps[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
94
-            $path_to_event,
95
-            EEM_Base::caps_edit
96
-        );
97
-        $this->_cap_restriction_generators = $caps;
98
-        parent::__construct($timezone);
99
-    }
90
+		$caps[ EEM_Base::caps_read ]       = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
91
+		$caps[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
92
+		$caps[ EEM_Base::caps_edit ]       = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
93
+		$caps[ EEM_Base::caps_delete ]     = new EE_Restriction_Generator_Event_Related_Protected(
94
+			$path_to_event,
95
+			EEM_Base::caps_edit
96
+		);
97
+		$this->_cap_restriction_generators = $caps;
98
+		parent::__construct($timezone);
99
+	}
100 100
 
101 101
 
102
-    /**
103
-     * Decides whether to use the 'EQG_primary' or newer 'EQG_additional' for use in queries, based on whether
104
-     * this is concerning primary attendees or additional attendees.
105
-     * If 1, true, or "primary" is passed in, returns EQG_primary. If 0, false, or "additional" is passed in, returns
106
-     * EQG_additional.
107
-     *
108
-     * @param string|boolean|int $context
109
-     * @return string
110
-     * @since 4.10.0.p
111
-     */
112
-    public function fieldNameForContext($context): string
113
-    {
114
-        // Basically do a strict switch statement.
115
-        switch (true) {
116
-            case $context === 'additional':
117
-            case $context === false:
118
-            case $context === 0:
119
-                $field_name = EEM_Event_Question_Group::ADDITIONAL;
120
-                break;
121
-            case $context === 'primary':
122
-            case $context === true:
123
-            case $context === 1:
124
-            default:
125
-                $field_name = EEM_Event_Question_Group::PRIMARY;
126
-        }
127
-        return apply_filters('FHEE__EEM_Event_Question_Group__fieldNameForContext', $field_name, $context);
128
-    }
102
+	/**
103
+	 * Decides whether to use the 'EQG_primary' or newer 'EQG_additional' for use in queries, based on whether
104
+	 * this is concerning primary attendees or additional attendees.
105
+	 * If 1, true, or "primary" is passed in, returns EQG_primary. If 0, false, or "additional" is passed in, returns
106
+	 * EQG_additional.
107
+	 *
108
+	 * @param string|boolean|int $context
109
+	 * @return string
110
+	 * @since 4.10.0.p
111
+	 */
112
+	public function fieldNameForContext($context): string
113
+	{
114
+		// Basically do a strict switch statement.
115
+		switch (true) {
116
+			case $context === 'additional':
117
+			case $context === false:
118
+			case $context === 0:
119
+				$field_name = EEM_Event_Question_Group::ADDITIONAL;
120
+				break;
121
+			case $context === 'primary':
122
+			case $context === true:
123
+			case $context === 1:
124
+			default:
125
+				$field_name = EEM_Event_Question_Group::PRIMARY;
126
+		}
127
+		return apply_filters('FHEE__EEM_Event_Question_Group__fieldNameForContext', $field_name, $context);
128
+	}
129 129
 }
Please login to merge, or discard this patch.
core/db_models/strategies/EE_Default_Where_Conditions.strategy.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -133,7 +133,7 @@  discard block
 block discarded – undo
133 133
         $qualified_where_conditions = [];
134 134
         foreach ($where_conditions as $key => $value) {
135 135
             if ($this->isOrHasQueryOperator($key)) {
136
-                $qualified_where_conditions[ $key ] =
136
+                $qualified_where_conditions[$key] =
137 137
                     $this->prepare_where_conditions_for_querying(
138 138
                         $value,
139 139
                         $model_relation_chain
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
         $value
184 184
     ): array {
185 185
         $model_relation_chain = $model_relation_chain !== ''
186
-            ? rtrim($model_relation_chain, '.') . '.'
186
+            ? rtrim($model_relation_chain, '.').'.'
187 187
             : $model_relation_chain;
188 188
         // check for the current user id place holder, and if present change it
189 189
         if ($value === self::current_user_placeholder) {
@@ -191,7 +191,7 @@  discard block
 block discarded – undo
191 191
         }
192 192
         // check for user field placeholder
193 193
         if ($key === self::user_field_name_placeholder) {
194
-            if (! $this->_model->wp_user_field_name()) {
194
+            if ( ! $this->_model->wp_user_field_name()) {
195 195
                 throw new EE_Error(
196 196
                     sprintf(
197 197
                         esc_html__(
@@ -204,7 +204,7 @@  discard block
 block discarded – undo
204 204
             }
205 205
             $key = $this->_model->wp_user_field_name();
206 206
         }
207
-        $qualified_where_conditions[ $model_relation_chain . $key ] = $value;
207
+        $qualified_where_conditions[$model_relation_chain.$key] = $value;
208 208
         return $qualified_where_conditions;
209 209
     }
210 210
 }
Please login to merge, or discard this patch.
Indentation   +191 added lines, -191 removed lines patch added patch discarded remove patch
@@ -15,195 +15,195 @@
 block discarded – undo
15 15
  */
16 16
 class EE_Default_Where_Conditions
17 17
 {
18
-    /**
19
-     * This const can be used in EE_Default_Where_Conditions values, and at the
20
-     * time of querying it will be replaced with the current user's ID (because
21
-     * we don't want to use the current user's ID at time of initializing the
22
-     * models because it's too early)
23
-     */
24
-    const current_user_placeholder = '%$current_user_placeholder_should_be_replaced_automatically$%';
25
-
26
-    /**
27
-     * This const can be used in EE_Default_Where_Conditions where parameters
28
-     * as the name of the user field. When we are actually generating the where
29
-     * conditions it will be replaced with the model's wp user field name
30
-     */
31
-    const user_field_name_placeholder = '%$user_field_name_placeholder$%';
32
-
33
-    /**
34
-     * Model for which this strategy find default where conditions
35
-     *
36
-     * @var EEM_Base
37
-     */
38
-    protected $_model;
39
-
40
-    /**
41
-     * Where conditions specified on construction
42
-     *
43
-     * @var array
44
-     */
45
-    protected $_where_conditions_provided = [];
46
-
47
-
48
-    /**
49
-     * Custom where conditions. Model relation chains will be automatically
50
-     * added onto any field names
51
-     *
52
-     * @param array $custom_where_conditions
53
-     */
54
-    public function __construct(array $custom_where_conditions = [])
55
-    {
56
-        $this->_where_conditions_provided = $custom_where_conditions;
57
-    }
58
-
59
-
60
-    /**
61
-     * finalizes construction of the strategy for use in getting default where
62
-     * conditions for querying of the model.
63
-     *
64
-     * @param EEM_Base $model
65
-     */
66
-    public function _finalize_construct(EEM_Base $model)
67
-    {
68
-        $this->_model = $model;
69
-    }
70
-
71
-
72
-    /**
73
-     * Returns the where conditions explicitly passed in the constructor
74
-     *
75
-     * @return array
76
-     */
77
-    public function get_where_conditions_provided(): array
78
-    {
79
-        return $this->_where_conditions_provided;
80
-    }
81
-
82
-
83
-    /**
84
-     * Gets the where conditions to be added onto the query
85
-     *
86
-     * @param string $model_relation_chain
87
-     * @return array
88
-     * @throws EE_Error
89
-     * @throws EE_Error
90
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
91
-     */
92
-    public function get_default_where_conditions(
93
-        string $model_relation_chain = ''
94
-    ): array {
95
-        return $this->prepare_where_conditions_for_querying(
96
-            array_merge(
97
-                $this->_get_default_where_conditions(),
98
-                $this->get_where_conditions_provided()
99
-            ),
100
-            $model_relation_chain
101
-        );
102
-    }
103
-
104
-
105
-    /**
106
-     * Gets the default where conditions that are specific to this child of
107
-     * EE_Default_Where_Conditions. Adding model relation chains is handled by
108
-     * the public method get_default_where_conditions
109
-     *
110
-     * @return array
111
-     */
112
-    protected function _get_default_where_conditions(): array
113
-    {
114
-        return [];
115
-    }
116
-
117
-
118
-    /**
119
-     * Takes the default query parameters, and traverses them, adding the model
120
-     * relation chain onto them (intelligently doesn't do that to logic query
121
-     * params like NOT, OR, and AND)
122
-     *
123
-     * @param array  $where_conditions
124
-     * @param string $model_relation_chain
125
-     * @return array
126
-     * @throws EE_Error
127
-     */
128
-    public function prepare_where_conditions_for_querying(
129
-        array $where_conditions = [],
130
-        string $model_relation_chain = ''
131
-    ): array {
132
-        $qualified_where_conditions = [];
133
-        foreach ($where_conditions as $key => $value) {
134
-            if ($this->isOrHasQueryOperator($key)) {
135
-                $qualified_where_conditions[ $key ] =
136
-                    $this->prepare_where_conditions_for_querying(
137
-                        $value,
138
-                        $model_relation_chain
139
-                    );
140
-            } else {
141
-                $qualified_where_conditions =
142
-                    $this->prepare_where_condition(
143
-                        $qualified_where_conditions,
144
-                        $model_relation_chain,
145
-                        $key,
146
-                        $value
147
-                    );
148
-            }
149
-        }
150
-        return $qualified_where_conditions;
151
-    }
152
-
153
-
154
-    /**
155
-     * @param string $query_string
156
-     * @return bool
157
-     */
158
-    private function isOrHasQueryOperator(string $query_string): bool
159
-    {
160
-        return in_array($query_string, ['OR', 'AND', 'NOT'])
161
-               || strpos($query_string, 'OR*') !== false
162
-               || strpos($query_string, 'AND*') !== false
163
-               || strpos($query_string, 'NOT*') !== false;
164
-    }
165
-
166
-
167
-    /**
168
-     * ensures relation name is fully qualified
169
-     * and swaps placeholders for expected values
170
-     *
171
-     * @param array  $qualified_where_conditions
172
-     * @param string $model_relation_chain
173
-     * @param string $key
174
-     * @param mixed $value
175
-     * @return array
176
-     * @throws EE_Error
177
-     */
178
-    private function prepare_where_condition(
179
-        array $qualified_where_conditions,
180
-        string $model_relation_chain,
181
-        string $key,
182
-        $value
183
-    ): array {
184
-        $model_relation_chain = $model_relation_chain !== ''
185
-            ? rtrim($model_relation_chain, '.') . '.'
186
-            : $model_relation_chain;
187
-        // check for the current user id place holder, and if present change it
188
-        if ($value === self::current_user_placeholder) {
189
-            $value = get_current_user_id();
190
-        }
191
-        // check for user field placeholder
192
-        if ($key === self::user_field_name_placeholder) {
193
-            if (! $this->_model->wp_user_field_name()) {
194
-                throw new EE_Error(
195
-                    sprintf(
196
-                        esc_html__(
197
-                            'There is no foreign key to the WP_User model on model %s. Please either modify your default where conditions, add a _model_chain_to_wp_user onto the model, or a proper EE_WP_User_Field onto the model',
198
-                            'event_espresso'
199
-                        ),
200
-                        $this->_model->get_this_model_name()
201
-                    )
202
-                );
203
-            }
204
-            $key = $this->_model->wp_user_field_name();
205
-        }
206
-        $qualified_where_conditions[ $model_relation_chain . $key ] = $value;
207
-        return $qualified_where_conditions;
208
-    }
18
+	/**
19
+	 * This const can be used in EE_Default_Where_Conditions values, and at the
20
+	 * time of querying it will be replaced with the current user's ID (because
21
+	 * we don't want to use the current user's ID at time of initializing the
22
+	 * models because it's too early)
23
+	 */
24
+	const current_user_placeholder = '%$current_user_placeholder_should_be_replaced_automatically$%';
25
+
26
+	/**
27
+	 * This const can be used in EE_Default_Where_Conditions where parameters
28
+	 * as the name of the user field. When we are actually generating the where
29
+	 * conditions it will be replaced with the model's wp user field name
30
+	 */
31
+	const user_field_name_placeholder = '%$user_field_name_placeholder$%';
32
+
33
+	/**
34
+	 * Model for which this strategy find default where conditions
35
+	 *
36
+	 * @var EEM_Base
37
+	 */
38
+	protected $_model;
39
+
40
+	/**
41
+	 * Where conditions specified on construction
42
+	 *
43
+	 * @var array
44
+	 */
45
+	protected $_where_conditions_provided = [];
46
+
47
+
48
+	/**
49
+	 * Custom where conditions. Model relation chains will be automatically
50
+	 * added onto any field names
51
+	 *
52
+	 * @param array $custom_where_conditions
53
+	 */
54
+	public function __construct(array $custom_where_conditions = [])
55
+	{
56
+		$this->_where_conditions_provided = $custom_where_conditions;
57
+	}
58
+
59
+
60
+	/**
61
+	 * finalizes construction of the strategy for use in getting default where
62
+	 * conditions for querying of the model.
63
+	 *
64
+	 * @param EEM_Base $model
65
+	 */
66
+	public function _finalize_construct(EEM_Base $model)
67
+	{
68
+		$this->_model = $model;
69
+	}
70
+
71
+
72
+	/**
73
+	 * Returns the where conditions explicitly passed in the constructor
74
+	 *
75
+	 * @return array
76
+	 */
77
+	public function get_where_conditions_provided(): array
78
+	{
79
+		return $this->_where_conditions_provided;
80
+	}
81
+
82
+
83
+	/**
84
+	 * Gets the where conditions to be added onto the query
85
+	 *
86
+	 * @param string $model_relation_chain
87
+	 * @return array
88
+	 * @throws EE_Error
89
+	 * @throws EE_Error
90
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions
91
+	 */
92
+	public function get_default_where_conditions(
93
+		string $model_relation_chain = ''
94
+	): array {
95
+		return $this->prepare_where_conditions_for_querying(
96
+			array_merge(
97
+				$this->_get_default_where_conditions(),
98
+				$this->get_where_conditions_provided()
99
+			),
100
+			$model_relation_chain
101
+		);
102
+	}
103
+
104
+
105
+	/**
106
+	 * Gets the default where conditions that are specific to this child of
107
+	 * EE_Default_Where_Conditions. Adding model relation chains is handled by
108
+	 * the public method get_default_where_conditions
109
+	 *
110
+	 * @return array
111
+	 */
112
+	protected function _get_default_where_conditions(): array
113
+	{
114
+		return [];
115
+	}
116
+
117
+
118
+	/**
119
+	 * Takes the default query parameters, and traverses them, adding the model
120
+	 * relation chain onto them (intelligently doesn't do that to logic query
121
+	 * params like NOT, OR, and AND)
122
+	 *
123
+	 * @param array  $where_conditions
124
+	 * @param string $model_relation_chain
125
+	 * @return array
126
+	 * @throws EE_Error
127
+	 */
128
+	public function prepare_where_conditions_for_querying(
129
+		array $where_conditions = [],
130
+		string $model_relation_chain = ''
131
+	): array {
132
+		$qualified_where_conditions = [];
133
+		foreach ($where_conditions as $key => $value) {
134
+			if ($this->isOrHasQueryOperator($key)) {
135
+				$qualified_where_conditions[ $key ] =
136
+					$this->prepare_where_conditions_for_querying(
137
+						$value,
138
+						$model_relation_chain
139
+					);
140
+			} else {
141
+				$qualified_where_conditions =
142
+					$this->prepare_where_condition(
143
+						$qualified_where_conditions,
144
+						$model_relation_chain,
145
+						$key,
146
+						$value
147
+					);
148
+			}
149
+		}
150
+		return $qualified_where_conditions;
151
+	}
152
+
153
+
154
+	/**
155
+	 * @param string $query_string
156
+	 * @return bool
157
+	 */
158
+	private function isOrHasQueryOperator(string $query_string): bool
159
+	{
160
+		return in_array($query_string, ['OR', 'AND', 'NOT'])
161
+			   || strpos($query_string, 'OR*') !== false
162
+			   || strpos($query_string, 'AND*') !== false
163
+			   || strpos($query_string, 'NOT*') !== false;
164
+	}
165
+
166
+
167
+	/**
168
+	 * ensures relation name is fully qualified
169
+	 * and swaps placeholders for expected values
170
+	 *
171
+	 * @param array  $qualified_where_conditions
172
+	 * @param string $model_relation_chain
173
+	 * @param string $key
174
+	 * @param mixed $value
175
+	 * @return array
176
+	 * @throws EE_Error
177
+	 */
178
+	private function prepare_where_condition(
179
+		array $qualified_where_conditions,
180
+		string $model_relation_chain,
181
+		string $key,
182
+		$value
183
+	): array {
184
+		$model_relation_chain = $model_relation_chain !== ''
185
+			? rtrim($model_relation_chain, '.') . '.'
186
+			: $model_relation_chain;
187
+		// check for the current user id place holder, and if present change it
188
+		if ($value === self::current_user_placeholder) {
189
+			$value = get_current_user_id();
190
+		}
191
+		// check for user field placeholder
192
+		if ($key === self::user_field_name_placeholder) {
193
+			if (! $this->_model->wp_user_field_name()) {
194
+				throw new EE_Error(
195
+					sprintf(
196
+						esc_html__(
197
+							'There is no foreign key to the WP_User model on model %s. Please either modify your default where conditions, add a _model_chain_to_wp_user onto the model, or a proper EE_WP_User_Field onto the model',
198
+							'event_espresso'
199
+						),
200
+						$this->_model->get_this_model_name()
201
+					)
202
+				);
203
+			}
204
+			$key = $this->_model->wp_user_field_name();
205
+		}
206
+		$qualified_where_conditions[ $model_relation_chain . $key ] = $value;
207
+		return $qualified_where_conditions;
208
+	}
209 209
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Currency.model.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
             'Payment_Method' => new EE_HABTM_Relation('Currency_Payment_Method'),
61 61
         ];
62 62
         // this model is generally available for reading
63
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
63
+        $this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Public();
64 64
 
65 65
         parent::__construct($timezone);
66 66
     }
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
     public function get_all_active($query_params = [])
78 78
     {
79 79
         $query_params[0]['CUR_active'] = true;
80
-        if (! isset($query_params['order_by'])) {
80
+        if ( ! isset($query_params['order_by'])) {
81 81
             $query_params['order_by'] = ['CUR_code' => 'ASC', 'CUR_single' => 'ASC'];
82 82
         }
83 83
         return $this->get_all($query_params);
Please login to merge, or discard this patch.
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -9,109 +9,109 @@
 block discarded – undo
9 9
  */
10 10
 class EEM_Currency extends EEM_Base
11 11
 {
12
-    protected static ?EEM_Currency $_instance = null;
12
+	protected static ?EEM_Currency $_instance = null;
13 13
 
14 14
 
15
-    /**
16
-     * @param string|null $timezone
17
-     * @throws EE_Error
18
-     */
19
-    protected function __construct(?string $timezone = '')
20
-    {
21
-        $this->singular_item    = esc_html__('Currency', 'event_espresso');
22
-        $this->plural_item      = esc_html__('Currencies', 'event_espresso');
23
-        $this->_tables          = [
24
-            'Currency' => new EE_Primary_Table('esp_currency', 'CUR_code'),
25
-        ];
26
-        $this->_fields          = [
27
-            'Currency' => [
28
-                'CUR_code'    => new EE_Primary_Key_String_Field(
29
-                    'CUR_code',
30
-                    esc_html__('Currency Code', 'event_espresso')
31
-                )
32
-                ,
33
-                'CUR_single'  => new EE_Plain_Text_Field(
34
-                    'CUR_single',
35
-                    esc_html__('Currency Name Singular', 'event_espresso'),
36
-                    false
37
-                ),
38
-                'CUR_plural'  => new EE_Plain_Text_Field(
39
-                    'CUR_plural',
40
-                    esc_html__('Currency Name Plural', 'event_espresso'),
41
-                    false
42
-                ),
43
-                'CUR_sign'    => new EE_Plain_Text_Field(
44
-                    'CUR_sign',
45
-                    esc_html__('Currency Sign', 'event_espresso'),
46
-                    false
47
-                ),
48
-                'CUR_dec_plc' => new EE_Integer_Field(
49
-                    'CUR_dec_plc',
50
-                    esc_html__('Currency Decimal Places', 'event_espresso'),
51
-                    false,
52
-                    2
53
-                ),
54
-                'CUR_active'  => new EE_Boolean_Field(
55
-                    'CUR_active',
56
-                    esc_html__('Active?', 'event_espresso'),
57
-                    false,
58
-                    true
59
-                ),
60
-            ],
61
-        ];
62
-        $this->_model_relations = [
63
-            'Payment_Method' => new EE_HABTM_Relation('Currency_Payment_Method'),
64
-        ];
65
-        // this model is generally available for reading
66
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
15
+	/**
16
+	 * @param string|null $timezone
17
+	 * @throws EE_Error
18
+	 */
19
+	protected function __construct(?string $timezone = '')
20
+	{
21
+		$this->singular_item    = esc_html__('Currency', 'event_espresso');
22
+		$this->plural_item      = esc_html__('Currencies', 'event_espresso');
23
+		$this->_tables          = [
24
+			'Currency' => new EE_Primary_Table('esp_currency', 'CUR_code'),
25
+		];
26
+		$this->_fields          = [
27
+			'Currency' => [
28
+				'CUR_code'    => new EE_Primary_Key_String_Field(
29
+					'CUR_code',
30
+					esc_html__('Currency Code', 'event_espresso')
31
+				)
32
+				,
33
+				'CUR_single'  => new EE_Plain_Text_Field(
34
+					'CUR_single',
35
+					esc_html__('Currency Name Singular', 'event_espresso'),
36
+					false
37
+				),
38
+				'CUR_plural'  => new EE_Plain_Text_Field(
39
+					'CUR_plural',
40
+					esc_html__('Currency Name Plural', 'event_espresso'),
41
+					false
42
+				),
43
+				'CUR_sign'    => new EE_Plain_Text_Field(
44
+					'CUR_sign',
45
+					esc_html__('Currency Sign', 'event_espresso'),
46
+					false
47
+				),
48
+				'CUR_dec_plc' => new EE_Integer_Field(
49
+					'CUR_dec_plc',
50
+					esc_html__('Currency Decimal Places', 'event_espresso'),
51
+					false,
52
+					2
53
+				),
54
+				'CUR_active'  => new EE_Boolean_Field(
55
+					'CUR_active',
56
+					esc_html__('Active?', 'event_espresso'),
57
+					false,
58
+					true
59
+				),
60
+			],
61
+		];
62
+		$this->_model_relations = [
63
+			'Payment_Method' => new EE_HABTM_Relation('Currency_Payment_Method'),
64
+		];
65
+		// this model is generally available for reading
66
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
67 67
 
68
-        parent::__construct($timezone);
69
-    }
68
+		parent::__construct($timezone);
69
+	}
70 70
 
71 71
 
72
-    /**
73
-     * Gets all the active currencies, and orders them by their singular name, and then their code
74
-     * (may be overridden)
75
-     *
76
-     * @param array $query_params
77
-     * @return EE_Currency[]
78
-     * @throws EE_Error
79
-     * @throws ReflectionException
80
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
81
-     */
82
-    public function get_all_active($query_params = [])
83
-    {
84
-        $query_params[0]['CUR_active'] = true;
85
-        if (! isset($query_params['order_by'])) {
86
-            $query_params['order_by'] = ['CUR_code' => 'ASC', 'CUR_single' => 'ASC'];
87
-        }
88
-        return $this->get_all($query_params);
89
-    }
72
+	/**
73
+	 * Gets all the active currencies, and orders them by their singular name, and then their code
74
+	 * (may be overridden)
75
+	 *
76
+	 * @param array $query_params
77
+	 * @return EE_Currency[]
78
+	 * @throws EE_Error
79
+	 * @throws ReflectionException
80
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
81
+	 */
82
+	public function get_all_active($query_params = [])
83
+	{
84
+		$query_params[0]['CUR_active'] = true;
85
+		if (! isset($query_params['order_by'])) {
86
+			$query_params['order_by'] = ['CUR_code' => 'ASC', 'CUR_single' => 'ASC'];
87
+		}
88
+		return $this->get_all($query_params);
89
+	}
90 90
 
91 91
 
92
-    /**
93
-     * Gets all the currencies which can be used by that payment method type
94
-     *
95
-     * @param EE_PMT_Base $payment_method_type
96
-     * @return EE_Currency[]
97
-     * @throws EE_Error
98
-     * @throws ReflectionException
99
-     */
100
-    public function get_all_currencies_usable_by($payment_method_type)
101
-    {
102
-        if (
103
-            $payment_method_type instanceof EE_PMT_Base
104
-            && $payment_method_type->get_gateway()
105
-        ) {
106
-            $currencies_supported = $payment_method_type->get_gateway()->currencies_supported();
107
-        } else {
108
-            $currencies_supported = EE_Gateway::all_currencies_supported;
109
-        }
110
-        if ($currencies_supported == EE_Gateway::all_currencies_supported || empty($currencies_supported)) {
111
-            $currencies = $this->get_all_active();
112
-        } else {
113
-            $currencies = $this->get_all_active([['CUR_code' => ['IN', $currencies_supported]]]);
114
-        }
115
-        return $currencies;
116
-    }
92
+	/**
93
+	 * Gets all the currencies which can be used by that payment method type
94
+	 *
95
+	 * @param EE_PMT_Base $payment_method_type
96
+	 * @return EE_Currency[]
97
+	 * @throws EE_Error
98
+	 * @throws ReflectionException
99
+	 */
100
+	public function get_all_currencies_usable_by($payment_method_type)
101
+	{
102
+		if (
103
+			$payment_method_type instanceof EE_PMT_Base
104
+			&& $payment_method_type->get_gateway()
105
+		) {
106
+			$currencies_supported = $payment_method_type->get_gateway()->currencies_supported();
107
+		} else {
108
+			$currencies_supported = EE_Gateway::all_currencies_supported;
109
+		}
110
+		if ($currencies_supported == EE_Gateway::all_currencies_supported || empty($currencies_supported)) {
111
+			$currencies = $this->get_all_active();
112
+		} else {
113
+			$currencies = $this->get_all_active([['CUR_code' => ['IN', $currencies_supported]]]);
114
+		}
115
+		return $currencies;
116
+	}
117 117
 }
Please login to merge, or discard this patch.
core/admin/templates/espresso_ratings_request_content.template.php 1 patch
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -1,9 +1,9 @@  discard block
 block discarded – undo
1 1
 <div class="padding">
2 2
     <p><?php
3
-        esc_html_e(
4
-            'We need your help to continue maintaining and providing this plugin for free. You can help by leaving a positive review in the WordPress plugin directory. 5 star ratings bring Event Espresso Decaf to the attention of more users which increases our support and features for this version of Event Espresso.',
5
-            'event_espresso'
6
-        ); ?></p>
3
+		esc_html_e(
4
+			'We need your help to continue maintaining and providing this plugin for free. You can help by leaving a positive review in the WordPress plugin directory. 5 star ratings bring Event Espresso Decaf to the attention of more users which increases our support and features for this version of Event Espresso.',
5
+			'event_espresso'
6
+		); ?></p>
7 7
     <p><?php esc_html_e('Rate it five stars today!', 'event_espresso'); ?></p><span
8 8
         class="ee-wp-blue dashicons dashicons-star-filled"></span><span
9 9
         class="ee-wp-blue dashicons dashicons-star-filled"></span><span
@@ -12,8 +12,8 @@  discard block
 block discarded – undo
12 12
         class="ee-wp-blue dashicons dashicons-star-filled"></span>
13 13
     <p><a class="button button--primary"
14 14
           href="https://login.wordpress.org/?redirect_to=https%3A%2F%2Fwordpress.org%2Fsupport%2Fview%2Fplugin-reviews%2Fevent-espresso-decaf%3Frate%3D5%23postform"><?php
15
-            esc_html_e(
16
-                'Rate It!',
17
-                'event_espresso'
18
-            ); ?></a></p>
15
+			esc_html_e(
16
+				'Rate It!',
17
+				'event_espresso'
18
+			); ?></a></p>
19 19
 </div>
20 20
\ No newline at end of file
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Spacing   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
         $controller = self::getReadController();
100 100
         try {
101 101
             $controller->setRequestedVersion($version);
102
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
102
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
103 103
                 return $controller->sendResponse(
104 104
                     new WP_Error(
105 105
                         'endpoint_parsing_error',
@@ -140,7 +140,7 @@  discard block
 block discarded – undo
140 140
         $controller = self::getReadController();
141 141
         try {
142 142
             $controller->setRequestedVersion($version);
143
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
143
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
144 144
                 return [];
145 145
             }
146 146
             // get the model for this version
@@ -203,11 +203,11 @@  discard block
 block discarded – undo
203 203
      */
204 204
     protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema): array
205 205
     {
206
-        if (isset($schema['properties'][ $field_name ]['default'])) {
207
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
208
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
206
+        if (isset($schema['properties'][$field_name]['default'])) {
207
+            if (is_array($schema['properties'][$field_name]['default'])) {
208
+                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
209 209
                     if ($default_key === 'raw') {
210
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
210
+                        $schema['properties'][$field_name]['default'][$default_key] =
211 211
                             ModelDataTranslator::prepareFieldValueForJson(
212 212
                                 $field,
213 213
                                 $default_value,
@@ -216,9 +216,9 @@  discard block
 block discarded – undo
216 216
                     }
217 217
                 }
218 218
             } else {
219
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
219
+                $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson(
220 220
                     $field,
221
-                    $schema['properties'][ $field_name ]['default'],
221
+                    $schema['properties'][$field_name]['default'],
222 222
                     $this->getModelVersionInfo()->requestedVersion()
223 223
                 );
224 224
             }
@@ -240,9 +240,9 @@  discard block
 block discarded – undo
240 240
     protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema): array
241 241
     {
242 242
         if ($field instanceof EE_Datetime_Field) {
243
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
243
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
244 244
             // modify the description
245
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
245
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
246 246
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
247 247
                 wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
248 248
             );
@@ -292,7 +292,7 @@  discard block
 block discarded – undo
292 292
         $controller = self::getReadController();
293 293
         try {
294 294
             $controller->setRequestedVersion($version);
295
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
295
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
296 296
                 return $controller->sendResponse(
297 297
                     new WP_Error(
298 298
                         'endpoint_parsing_error',
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
     public function getEntitiesFromModel(EEM_Base $model, WP_REST_Request $request): array
377 377
     {
378 378
         $query_params = $this->createModelQueryParams($model, $request->get_params());
379
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
379
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
380 380
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
381 381
             throw new RestException(
382 382
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -388,7 +388,7 @@  discard block
 block discarded – undo
388 388
                 ['status' => 403]
389 389
             );
390 390
         }
391
-        if (! $request->get_header('no_rest_headers')) {
391
+        if ( ! $request->get_header('no_rest_headers')) {
392 392
             $this->setHeadersFromQueryParams($model, $query_params);
393 393
         }
394 394
         /** @type array $results */
@@ -435,7 +435,7 @@  discard block
 block discarded – undo
435 435
         $context       = $this->validateContext($request->get_param('caps'));
436 436
         $model         = $relation->get_this_model();
437 437
         $related_model = $relation->get_other_model();
438
-        if (! isset($primary_model_query_params[0])) {
438
+        if ( ! isset($primary_model_query_params[0])) {
439 439
             $primary_model_query_params[0] = [];
440 440
         }
441 441
         // check if they can access the 1st model object
@@ -499,13 +499,13 @@  discard block
 block discarded – undo
499 499
         );
500 500
         $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
501 501
         foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
502
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
502
+            $query_params[0][$relation->get_this_model()->get_this_model_name()
503 503
                               . '.'
504
-                              . $where_condition_key ] = $where_condition_value;
504
+                              . $where_condition_key] = $where_condition_value;
505 505
         }
506 506
         $query_params['default_where_conditions'] = 'none';
507 507
         $query_params['caps']                     = $context;
508
-        if (! $request->get_header('no_rest_headers')) {
508
+        if ( ! $request->get_header('no_rest_headers')) {
509 509
             $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
510 510
         }
511 511
         /** @type array $results */
@@ -525,7 +525,7 @@  discard block
 block discarded – undo
525 525
                     $result,
526 526
                     $request
527 527
                 );
528
-                $joined_result     = array_merge($join_model_result, $nice_result);
528
+                $joined_result = array_merge($join_model_result, $nice_result);
529 529
                 // but keep the meta stuff from the main model
530 530
                 if (isset($nice_result['meta'])) {
531 531
                     $joined_result['meta'] = $nice_result['meta'];
@@ -564,7 +564,7 @@  discard block
 block discarded – undo
564 564
      */
565 565
     public function getEntitiesFromRelation($id, EE_Model_Relation_Base $relation, WP_REST_Request $request): array
566 566
     {
567
-        if (! $relation->get_this_model()->has_primary_key_field()) {
567
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
568 568
             throw new EE_Error(
569 569
                 sprintf(
570 570
                     esc_html__(
@@ -610,7 +610,7 @@  discard block
 block discarded – undo
610 610
             Capabilities::getMissingPermissionsString($model, $query_params['caps'])
611 611
         );
612 612
         // normally the limit to a 2-part array, where the 2nd item is the limit
613
-        if (! isset($query_params['limit'])) {
613
+        if ( ! isset($query_params['limit'])) {
614 614
             $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
615 615
         }
616 616
         if (is_array($query_params['limit'])) {
@@ -658,7 +658,7 @@  discard block
 block discarded – undo
658 658
         ?WP_REST_Request $rest_request,
659 659
         string $deprecated = null
660 660
     ): array {
661
-        if (! $rest_request instanceof WP_REST_Request) {
661
+        if ( ! $rest_request instanceof WP_REST_Request) {
662 662
             // ok so this was called in the old style, where the 3rd arg was
663 663
             // $include, and the 4th arg was $context
664 664
             // now setup the request just to avoid fatal errors, although we won't be able
@@ -712,7 +712,7 @@  discard block
 block discarded – undo
712 712
             $rest_request,
713 713
             $has_protected_fields
714 714
         );
715
-        $entity_array                       = apply_filters(
715
+        $entity_array = apply_filters(
716 716
             'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
717 717
             $entity_array,
718 718
             $model,
@@ -744,7 +744,7 @@  discard block
 block discarded – undo
744 744
             $rest_request,
745 745
             $this
746 746
         );
747
-        if (! $current_user_full_access_to_entity) {
747
+        if ( ! $current_user_full_access_to_entity) {
748 748
             $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
749 749
                 $entity_array,
750 750
                 $model,
@@ -779,7 +779,7 @@  discard block
 block discarded – undo
779 779
      */
780 780
     protected function addProtectedProperty(EEM_Base $model, array $results_so_far, bool $protected): array
781 781
     {
782
-        if (! $protected || ! $model->hasPassword()) {
782
+        if ( ! $protected || ! $model->hasPassword()) {
783 783
             return $results_so_far;
784 784
         }
785 785
         $password_field  = $model->getPasswordField();
@@ -828,8 +828,8 @@  discard block
 block discarded – undo
828 828
         if ($do_chevy_shuffle) {
829 829
             global $post;
830 830
             $old_post = $post;
831
-            $post     = get_post($result[ $model->primary_key_name() ]);
832
-            if (! $post instanceof WP_Post) {
831
+            $post     = get_post($result[$model->primary_key_name()]);
832
+            if ( ! $post instanceof WP_Post) {
833 833
                 // well that's weird, because $result is what we JUST fetched from the database
834 834
                 throw new RestException(
835 835
                     'error_fetching_post_from_database_results',
@@ -839,7 +839,7 @@  discard block
 block discarded – undo
839 839
                     )
840 840
                 );
841 841
             }
842
-            $model_object_classname          = 'EE_' . $model->get_this_model_name();
842
+            $model_object_classname          = 'EE_'.$model->get_this_model_name();
843 843
             $post->{$model_object_classname} = EE_Registry::instance()->load_class(
844 844
                 $model_object_classname,
845 845
                 $result,
@@ -850,14 +850,14 @@  discard block
 block discarded – undo
850 850
         foreach ($result as $field_name => $field_value) {
851 851
             $field_obj = $model->field_settings_for($field_name);
852 852
             if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
853
-                unset($result[ $field_name ]);
853
+                unset($result[$field_name]);
854 854
             } elseif (
855 855
                 $this->isSubclassOfOne(
856 856
                     $field_obj,
857 857
                     $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
858 858
                 )
859 859
             ) {
860
-                $result[ $field_name ] = [
860
+                $result[$field_name] = [
861 861
                     'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
862 862
                     'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
863 863
                 ];
@@ -867,7 +867,7 @@  discard block
 block discarded – undo
867 867
                     $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
868 868
                 )
869 869
             ) {
870
-                $result[ $field_name ] = [
870
+                $result[$field_name] = [
871 871
                     'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
872 872
                     'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
873 873
                 ];
@@ -898,10 +898,10 @@  discard block
 block discarded – undo
898 898
                         $this->getModelVersionInfo()->requestedVersion()
899 899
                     );
900 900
                 }
901
-                $result[ $field_name . '_gmt' ] = $gmt_date;
902
-                $result[ $field_name ]          = $local_date;
901
+                $result[$field_name.'_gmt'] = $gmt_date;
902
+                $result[$field_name]          = $local_date;
903 903
             } else {
904
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
904
+                $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
905 905
             }
906 906
         }
907 907
         if ($do_chevy_shuffle) {
@@ -958,7 +958,7 @@  discard block
 block discarded – undo
958 958
     protected function addExtraFields(EEM_Base $model, array $db_row, array $entity_array): array
959 959
     {
960 960
         if ($model instanceof EEM_CPT_Base) {
961
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
961
+            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
962 962
         }
963 963
         return $entity_array;
964 964
     }
@@ -984,7 +984,7 @@  discard block
 block discarded – undo
984 984
                     'href' => $this->getVersionedLinkTo(
985 985
                         EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
986 986
                         . '/'
987
-                        . $entity_array[ $model->primary_key_name() ]
987
+                        . $entity_array[$model->primary_key_name()]
988 988
                     ),
989 989
                 ],
990 990
             ];
@@ -1001,12 +1001,12 @@  discard block
 block discarded – undo
1001 1001
             foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
1002 1002
                 $related_model_part                                                      =
1003 1003
                     Read::getRelatedEntityName($relation_name, $relation_obj);
1004
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
1004
+                $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = [
1005 1005
                     [
1006 1006
                         'href'   => $this->getVersionedLinkTo(
1007 1007
                             EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
1008 1008
                             . '/'
1009
-                            . $entity_array[ $model->primary_key_name() ]
1009
+                            . $entity_array[$model->primary_key_name()]
1010 1010
                             . '/'
1011 1011
                             . $related_model_part
1012 1012
                         ),
@@ -1046,12 +1046,12 @@  discard block
 block discarded – undo
1046 1046
         bool $included_items_protected = false
1047 1047
     ): array {
1048 1048
         // if $db_row not included, hope the entity array has what we need
1049
-        if (! $db_row) {
1049
+        if ( ! $db_row) {
1050 1050
             $db_row = $entity_array;
1051 1051
         }
1052 1052
         $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
1053 1053
         foreach ($relation_settings as $relation_name => $relation_obj) {
1054
-            $related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1054
+            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
1055 1055
                 $rest_request->get_param('include'),
1056 1056
                 $relation_name
1057 1057
             );
@@ -1079,7 +1079,7 @@  discard block
 block discarded – undo
1079 1079
                         $model->deduce_fields_n_values_from_cols_n_values($db_row)
1080 1080
                     )
1081 1081
                 );
1082
-                if (! $included_items_protected) {
1082
+                if ( ! $included_items_protected) {
1083 1083
                     try {
1084 1084
                         $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1085 1085
                             $primary_model_query_params,
@@ -1100,7 +1100,7 @@  discard block
 block discarded – undo
1100 1100
                             ? null
1101 1101
                             : [];
1102 1102
                 }
1103
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1103
+                $entity_array[Read::getRelatedEntityName($relation_name, $relation_obj)] = $related_results;
1104 1104
             }
1105 1105
         }
1106 1106
         return $entity_array;
@@ -1127,7 +1127,7 @@  discard block
 block discarded – undo
1127 1127
         $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1128 1128
         $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1129 1129
         // if they passed in * or didn't specify any includes, return everything
1130
-        if (! empty($includes_for_this_model) && ! in_array('*', $includes_for_this_model, true)) {
1130
+        if ( ! empty($includes_for_this_model) && ! in_array('*', $includes_for_this_model, true)) {
1131 1131
             if ($model->has_primary_key_field()) {
1132 1132
                 // always include the primary key. ya just gotta know that at least
1133 1133
                 $includes_for_this_model[] = $model->primary_key_name();
@@ -1185,13 +1185,13 @@  discard block
 block discarded – undo
1185 1185
                 $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1186 1186
                 if (
1187 1187
                     $row_is_protected
1188
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1189
-                    && $schema['properties'][ $field_to_calculate ]['protected']
1188
+                    && isset($schema['properties'][$field_to_calculate]['protected'])
1189
+                    && $schema['properties'][$field_to_calculate]['protected']
1190 1190
                 ) {
1191 1191
                     $calculated_value   = null;
1192 1192
                     $protected_fields[] = $field_to_calculate;
1193
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1194
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1193
+                    if ($schema['properties'][$field_to_calculate]['type']) {
1194
+                        switch ($schema['properties'][$field_to_calculate]['type']) {
1195 1195
                             case 'boolean':
1196 1196
                                 $calculated_value = false;
1197 1197
                                 break;
@@ -1311,7 +1311,7 @@  discard block
 block discarded – undo
1311 1311
      */
1312 1312
     public function validateContext(?string $context): string
1313 1313
     {
1314
-        if (! $context) {
1314
+        if ( ! $context) {
1315 1315
             $context = EEM_Base::caps_read;
1316 1316
         }
1317 1317
         $valid_contexts = EEM_Base::valid_cap_contexts();
@@ -1335,7 +1335,7 @@  discard block
 block discarded – undo
1335 1335
             EEM_Base::default_where_conditions_minimum_all,
1336 1336
             EEM_Base::default_where_conditions_minimum_others,
1337 1337
         ];
1338
-        if (! $default_where_conditions) {
1338
+        if ( ! $default_where_conditions) {
1339 1339
             $default_where_conditions = EEM_Base::default_where_conditions_all;
1340 1340
         }
1341 1341
         if (
@@ -1426,14 +1426,14 @@  discard block
 block discarded – undo
1426 1426
         }
1427 1427
         if (isset($query_params['limit'])) {
1428 1428
             // limit should be either a string like '23' or '23,43', or an array with two items in it
1429
-            if (! is_array($query_params['limit'])) {
1429
+            if ( ! is_array($query_params['limit'])) {
1430 1430
                 $limit_array = explode(',', (string) $query_params['limit']);
1431 1431
             } else {
1432 1432
                 $limit_array = $query_params['limit'];
1433 1433
             }
1434 1434
             $sanitized_limit = [];
1435 1435
             foreach ($limit_array as $limit_part) {
1436
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1436
+                if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1437 1437
                     throw new EE_Error(
1438 1438
                         sprintf(
1439 1439
                             esc_html__(
@@ -1490,7 +1490,7 @@  discard block
 block discarded – undo
1490 1490
     {
1491 1491
         $model_ready_query_params = [];
1492 1492
         foreach ($query_params as $key => $value) {
1493
-            $model_ready_query_params[ $key ] = is_array($value)
1493
+            $model_ready_query_params[$key] = is_array($value)
1494 1494
                 ? $this->prepareRestQueryParamsKeyForModels($model, $value)
1495 1495
                 : $value;
1496 1496
         }
@@ -1509,9 +1509,9 @@  discard block
 block discarded – undo
1509 1509
         $model_ready_query_params = [];
1510 1510
         foreach ($query_params as $key => $value) {
1511 1511
             if (is_array($value)) {
1512
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1512
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1513 1513
             } else {
1514
-                $model_ready_query_params[ $key ] = $value;
1514
+                $model_ready_query_params[$key] = $value;
1515 1515
             }
1516 1516
         }
1517 1517
         return $model_ready_query_params;
@@ -1543,17 +1543,17 @@  discard block
 block discarded – undo
1543 1543
         foreach ($exploded_contents as $item) {
1544 1544
             $item = trim($item);
1545 1545
             // if no prefix was provided, so we look for items with no "." in them
1546
-            if (! $prefix) {
1546
+            if ( ! $prefix) {
1547 1547
                 // does this item have a period?
1548 1548
                 if (strpos($item, '.') === false) {
1549 1549
                     // if not, then its what we're looking for
1550 1550
                     $contents_with_prefix[] = $item;
1551 1551
                 }
1552
-            } elseif (strpos($item, $prefix . '.') === 0) {
1552
+            } elseif (strpos($item, $prefix.'.') === 0) {
1553 1553
                 // this item has the prefix and a period, grab it
1554 1554
                 $contents_with_prefix[] = substr(
1555 1555
                     $item,
1556
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1556
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1557 1557
                 );
1558 1558
             } elseif ($item === $prefix) {
1559 1559
                 // this item is JUST the prefix
@@ -1596,9 +1596,9 @@  discard block
 block discarded – undo
1596 1596
         if ($model_name) {
1597 1597
             foreach ($includes as $field_to_include) {
1598 1598
                 $field_to_include = trim($field_to_include);
1599
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1599
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1600 1600
                     // found the model name at the exact start
1601
-                    $field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1601
+                    $field_sans_model_name         = str_replace($model_name.'.', '', $field_to_include);
1602 1602
                     $extracted_fields_to_include[] = $field_sans_model_name;
1603 1603
                 } elseif ($field_to_include === $model_name) {
1604 1604
                     $extracted_fields_to_include[] = '*';
@@ -1641,7 +1641,7 @@  discard block
 block discarded – undo
1641 1641
         $restricted_query_params['caps'] = $context;
1642 1642
         $this->setDebugInfo('model query params', $restricted_query_params);
1643 1643
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1644
-        if (! empty($model_rows)) {
1644
+        if ( ! empty($model_rows)) {
1645 1645
             return $this->createEntityFromWpdbResult(
1646 1646
                 $model,
1647 1647
                 reset($model_rows),
@@ -1653,7 +1653,7 @@  discard block
 block discarded – undo
1653 1653
         if ($model->exists($query_params)) {
1654 1654
             // you got shafted- it existed but we didn't want to tell you!
1655 1655
             throw new RestException(
1656
-                'rest_user_cannot_' . $context,
1656
+                'rest_user_cannot_'.$context,
1657 1657
                 sprintf(
1658 1658
                     __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1659 1659
                     $context,
@@ -1705,14 +1705,14 @@  discard block
 block discarded – undo
1705 1705
         // if this entity requires a password, they better give it and it better be right!
1706 1706
         if (
1707 1707
             $model->hasPassword()
1708
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1708
+            && $model_row[$model->getPasswordField()->get_qualified_column()] !== ''
1709 1709
         ) {
1710 1710
             if (empty($request['password'])) {
1711 1711
                 throw new RestPasswordRequiredException();
1712 1712
             }
1713 1713
             if (
1714 1714
                 ! hash_equals(
1715
-                    $model_row[ $model->getPasswordField()->get_qualified_column() ],
1715
+                    $model_row[$model->getPasswordField()->get_qualified_column()],
1716 1716
                     $request['password']
1717 1717
                 )
1718 1718
             ) {
@@ -1726,12 +1726,12 @@  discard block
 block discarded – undo
1726 1726
             $password_supplied = $request->get_param('password');
1727 1727
             if (empty($password_supplied)) {
1728 1728
                 $query_params['exclude_protected'] = true;
1729
-                if (! $model->exists($query_params)) {
1729
+                if ( ! $model->exists($query_params)) {
1730 1730
                     throw new RestPasswordRequiredException();
1731 1731
                 }
1732 1732
             } else {
1733
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1734
-                if (! $model->exists($query_params)) {
1733
+                $query_params[0][$model->modelChainAndPassword()] = $password_supplied;
1734
+                if ( ! $model->exists($query_params)) {
1735 1735
                     throw new RestPasswordIncorrectException();
1736 1736
                 }
1737 1737
             }
Please login to merge, or discard this patch.
Indentation   +1686 added lines, -1686 removed lines patch added patch discarded remove patch
@@ -51,1690 +51,1690 @@
 block discarded – undo
51 51
  */
52 52
 class Read extends Base
53 53
 {
54
-    protected CalculatedModelFields $fields_calculator;
55
-
56
-
57
-    /**
58
-     * Read constructor.
59
-     *
60
-     * @param CalculatedModelFields $fields_calculator
61
-     */
62
-    public function __construct(CalculatedModelFields $fields_calculator)
63
-    {
64
-        parent::__construct();
65
-        $this->fields_calculator = $fields_calculator;
66
-    }
67
-
68
-
69
-    /**
70
-     * @return Read
71
-     */
72
-    private static function getReadController(): Read
73
-    {
74
-        return LoaderFactory::getLoader()->getNew(Read::class);
75
-    }
76
-
77
-
78
-    /**
79
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
80
-     *
81
-     * @param WP_REST_Request $request
82
-     * @param string          $version
83
-     * @param string          $model_name
84
-     * @return WP_REST_Response
85
-     * @throws InvalidArgumentException
86
-     * @throws InvalidDataTypeException
87
-     * @throws InvalidInterfaceException
88
-     */
89
-    public static function handleRequestGetAll(
90
-        WP_REST_Request $request,
91
-        string $version,
92
-        string $model_name
93
-    ): WP_REST_Response {
94
-        $controller = self::getReadController();
95
-        try {
96
-            $controller->setRequestedVersion($version);
97
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
98
-                return $controller->sendResponse(
99
-                    new WP_Error(
100
-                        'endpoint_parsing_error',
101
-                        sprintf(
102
-                            esc_html__(
103
-                                'There is no model for endpoint %s. Please contact event espresso support',
104
-                                'event_espresso'
105
-                            ),
106
-                            $model_name
107
-                        )
108
-                    )
109
-                );
110
-            }
111
-            return $controller->sendResponse(
112
-                $controller->getEntitiesFromModel(
113
-                    $controller->getModelVersionInfo()->loadModel($model_name),
114
-                    $request
115
-                )
116
-            );
117
-        } catch (Exception $e) {
118
-            return $controller->sendResponse($e);
119
-        }
120
-    }
121
-
122
-
123
-    /**
124
-     * Prepares and returns schema for any OPTIONS request.
125
-     *
126
-     * @param string $version    The API endpoint version being used.
127
-     * @param string $model_name Something like `Event` or `Registration`
128
-     * @return array
129
-     * @throws InvalidArgumentException
130
-     * @throws InvalidDataTypeException
131
-     * @throws InvalidInterfaceException
132
-     */
133
-    public static function handleSchemaRequest(string $version, string $model_name): array
134
-    {
135
-        $controller = self::getReadController();
136
-        try {
137
-            $controller->setRequestedVersion($version);
138
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
139
-                return [];
140
-            }
141
-            // get the model for this version
142
-            $model        = $controller->getModelVersionInfo()->loadModel($model_name);
143
-            $model_schema = new JsonModelSchema(
144
-                $model,
145
-                LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields')
146
-            );
147
-            return $model_schema->getModelSchemaForRelations(
148
-                $controller->getModelVersionInfo()->relationSettings($model),
149
-                $controller->customizeSchemaForRestResponse(
150
-                    $model,
151
-                    $model_schema->getModelSchemaForFields(
152
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
153
-                        $model_schema->getInitialSchemaStructure()
154
-                    )
155
-                )
156
-            );
157
-        } catch (Exception $e) {
158
-            error_log($e->getMessage());
159
-            return [];
160
-        }
161
-    }
162
-
163
-
164
-    /**
165
-     * This loops through each field in the given schema for the model and does the following:
166
-     * - add any extra fields that are REST API specific and related to existing fields.
167
-     * - transform default values into the correct format for a REST API response.
168
-     *
169
-     * @param EEM_Base $model
170
-     * @param array    $schema
171
-     * @return array  The final schema.
172
-     * @throws EE_Error
173
-     */
174
-    public function customizeSchemaForRestResponse(EEM_Base $model, array $schema): array
175
-    {
176
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
177
-            $schema = $this->translateDefaultsForRestResponse(
178
-                $field_name,
179
-                $field,
180
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
181
-            );
182
-        }
183
-        return $schema;
184
-    }
185
-
186
-
187
-    /**
188
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
189
-     * response.
190
-     *
191
-     * @param                      $field_name
192
-     * @param EE_Model_Field_Base  $field
193
-     * @param array                $schema
194
-     * @return array
195
-     * @throws RestException  if a default value has a PHP object, which we should never do
196
-     *                                  (but if we did, let's know about it ASAP, so let the exception bubble up)
197
-     * @throws EE_Error
198
-     *
199
-     */
200
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema): array
201
-    {
202
-        if (isset($schema['properties'][ $field_name ]['default'])) {
203
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
204
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
205
-                    if ($default_key === 'raw') {
206
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
207
-                            ModelDataTranslator::prepareFieldValueForJson(
208
-                                $field,
209
-                                $default_value,
210
-                                $this->getModelVersionInfo()->requestedVersion()
211
-                            );
212
-                    }
213
-                }
214
-            } else {
215
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
216
-                    $field,
217
-                    $schema['properties'][ $field_name ]['default'],
218
-                    $this->getModelVersionInfo()->requestedVersion()
219
-                );
220
-            }
221
-        }
222
-        return $schema;
223
-    }
224
-
225
-
226
-    /**
227
-     * Adds additional fields to the schema
228
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
229
-     * needs to be added to the schema.
230
-     *
231
-     * @param                      $field_name
232
-     * @param EE_Model_Field_Base  $field
233
-     * @param array                $schema
234
-     * @return array
235
-     */
236
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema): array
237
-    {
238
-        if ($field instanceof EE_Datetime_Field) {
239
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
240
-            // modify the description
241
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
242
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
243
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
244
-            );
245
-        }
246
-        return $schema;
247
-    }
248
-
249
-
250
-    /**
251
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
252
-     *
253
-     * @return string
254
-     */
255
-    protected function getRouteFromRequest(): string
256
-    {
257
-        if (
258
-            isset($GLOBALS['wp'])
259
-            && $GLOBALS['wp'] instanceof WP
260
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
261
-        ) {
262
-            return $GLOBALS['wp']->query_vars['rest_route'];
263
-        }
264
-        /** @var RequestInterface $request */
265
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
266
-        return $request->serverParamIsSet('PATH_INFO')
267
-            ? $request->getServerParam('PATH_INFO')
268
-            : '/';
269
-    }
270
-
271
-
272
-    /**
273
-     * Gets a single entity related to the model indicated in the path and its id
274
-     *
275
-     * @param WP_REST_Request $request
276
-     * @param string          $version
277
-     * @param string          $model_name
278
-     * @return WP_REST_Response
279
-     * @throws InvalidDataTypeException
280
-     * @throws InvalidInterfaceException
281
-     * @throws InvalidArgumentException
282
-     */
283
-    public static function handleRequestGetOne(
284
-        WP_REST_Request $request,
285
-        string $version,
286
-        string $model_name
287
-    ): WP_REST_Response {
288
-        $controller = self::getReadController();
289
-        try {
290
-            $controller->setRequestedVersion($version);
291
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
292
-                return $controller->sendResponse(
293
-                    new WP_Error(
294
-                        'endpoint_parsing_error',
295
-                        sprintf(
296
-                            esc_html__(
297
-                                'There is no model for endpoint %s. Please contact event espresso support',
298
-                                'event_espresso'
299
-                            ),
300
-                            $model_name
301
-                        )
302
-                    )
303
-                );
304
-            }
305
-            return $controller->sendResponse(
306
-                $controller->getEntityFromModel(
307
-                    $controller->getModelVersionInfo()->loadModel($model_name),
308
-                    $request
309
-                )
310
-            );
311
-        } catch (Exception $e) {
312
-            return $controller->sendResponse($e);
313
-        }
314
-    }
315
-
316
-
317
-    /**
318
-     * Gets all the related entities (or if its a belongs-to relation just the one)
319
-     * to the item with the given id
320
-     *
321
-     * @param WP_REST_Request $request
322
-     * @param string          $version
323
-     * @param string          $model_name
324
-     * @param string          $related_model_name
325
-     * @return WP_REST_Response
326
-     * @throws InvalidDataTypeException
327
-     * @throws InvalidInterfaceException
328
-     * @throws InvalidArgumentException
329
-     */
330
-    public static function handleRequestGetRelated(
331
-        WP_REST_Request $request,
332
-        string $version,
333
-        string $model_name,
334
-        string $related_model_name
335
-    ): WP_REST_Response {
336
-        $controller = self::getReadController();
337
-        try {
338
-            $controller->setRequestedVersion($version);
339
-            $main_model = $controller->validateModel($model_name);
340
-            $controller->validateModel($related_model_name);
341
-            return $controller->sendResponse(
342
-                $controller->getEntitiesFromRelation(
343
-                    $request->get_param('id'),
344
-                    $main_model->related_settings_for($related_model_name),
345
-                    $request
346
-                )
347
-            );
348
-        } catch (Exception $e) {
349
-            return $controller->sendResponse($e);
350
-        }
351
-    }
352
-
353
-
354
-    /**
355
-     * Gets a collection for the given model and filters
356
-     *
357
-     * @param EEM_Base        $model
358
-     * @param WP_REST_Request $request
359
-     * @return array
360
-     * @throws DomainException
361
-     * @throws EE_Error
362
-     * @throws InvalidArgumentException
363
-     * @throws InvalidDataTypeException
364
-     * @throws InvalidInterfaceException
365
-     * @throws ModelConfigurationException
366
-     * @throws ReflectionException
367
-     * @throws RestException
368
-     * @throws RestPasswordIncorrectException
369
-     * @throws RestPasswordRequiredException
370
-     * @throws UnexpectedEntityException
371
-     */
372
-    public function getEntitiesFromModel(EEM_Base $model, WP_REST_Request $request): array
373
-    {
374
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
375
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
376
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
377
-            throw new RestException(
378
-                sprintf('rest_%s_cannot_list', $model_name_plural),
379
-                sprintf(
380
-                    esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
381
-                    $model_name_plural,
382
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
383
-                ),
384
-                ['status' => 403]
385
-            );
386
-        }
387
-        if (! $request->get_header('no_rest_headers')) {
388
-            $this->setHeadersFromQueryParams($model, $query_params);
389
-        }
390
-        /** @type array $results */
391
-        $results      = $model->get_all_wpdb_results($query_params);
392
-        $nice_results = [];
393
-        foreach ($results as $result) {
394
-            $nice_results[] = $this->createEntityFromWpdbResult(
395
-                $model,
396
-                $result,
397
-                $request
398
-            );
399
-        }
400
-        return $nice_results;
401
-    }
402
-
403
-
404
-    /**
405
-     * Gets the collection for given relation object
406
-     * The same as Read::get_entities_from_model(), except if the relation
407
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
408
-     * the join-model-object into the results
409
-     *
410
-     * @param array                  $primary_model_query_params  query params for finding the item from which
411
-     *                                                            relations will be based
412
-     * @param EE_Model_Relation_Base $relation
413
-     * @param WP_REST_Request        $request
414
-     * @return array|null
415
-     * @throws DomainException
416
-     * @throws EE_Error
417
-     * @throws InvalidArgumentException
418
-     * @throws InvalidDataTypeException
419
-     * @throws InvalidInterfaceException
420
-     * @throws ModelConfigurationException
421
-     * @throws ReflectionException
422
-     * @throws RestException
423
-     * @throws ModelConfigurationException
424
-     * @throws UnexpectedEntityException
425
-     * @throws Exception
426
-     */
427
-    protected function getEntitiesFromRelationUsingModelQueryParams(
428
-        array $primary_model_query_params,
429
-        EE_Model_Relation_Base $relation,
430
-        WP_REST_Request $request
431
-    ): ?array {
432
-        $context       = $this->validateContext($request->get_param('caps'));
433
-        $model         = $relation->get_this_model();
434
-        $related_model = $relation->get_other_model();
435
-        if (! isset($primary_model_query_params[0])) {
436
-            $primary_model_query_params[0] = [];
437
-        }
438
-        // check if they can access the 1st model object
439
-        $primary_model_query_params = [
440
-            0       => $primary_model_query_params[0],
441
-            'limit' => 1,
442
-        ];
443
-        if ($model instanceof EEM_Soft_Delete_Base) {
444
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
445
-                $primary_model_query_params
446
-            );
447
-        }
448
-        $restricted_query_params          = $primary_model_query_params;
449
-        $restricted_query_params['caps']  = $context;
450
-        $restricted_query_params['limit'] = 1;
451
-        $this->setDebugInfo('main model query params', $restricted_query_params);
452
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
453
-        $primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
454
-        $primary_model_row  = null;
455
-        if (is_array($primary_model_rows)) {
456
-            $primary_model_row = reset($primary_model_rows);
457
-        }
458
-        if (
459
-            ! (
460
-                $primary_model_row
461
-                && Capabilities::currentUserHasPartialAccessTo($related_model, $context)
462
-            )
463
-        ) {
464
-            if ($relation instanceof EE_Belongs_To_Relation) {
465
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
466
-            } else {
467
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
468
-                    $related_model->get_this_model_name()
469
-                );
470
-            }
471
-            throw new RestException(
472
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
473
-                sprintf(
474
-                    esc_html__(
475
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
476
-                        'event_espresso'
477
-                    ),
478
-                    $related_model_name_maybe_plural,
479
-                    $relation->get_this_model()->get_this_model_name(),
480
-                    implode(
481
-                        ',',
482
-                        array_keys(
483
-                            Capabilities::getMissingPermissions($related_model, $context)
484
-                        )
485
-                    )
486
-                ),
487
-                ['status' => 403]
488
-            );
489
-        }
490
-
491
-        $this->checkPassword(
492
-            $model,
493
-            $primary_model_row,
494
-            $restricted_query_params,
495
-            $request
496
-        );
497
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
498
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
499
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
500
-                              . '.'
501
-                              . $where_condition_key ] = $where_condition_value;
502
-        }
503
-        $query_params['default_where_conditions'] = 'none';
504
-        $query_params['caps']                     = $context;
505
-        if (! $request->get_header('no_rest_headers')) {
506
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
507
-        }
508
-        /** @type array $results */
509
-        $results      = $relation->get_other_model()->get_all_wpdb_results($query_params);
510
-        $nice_results = [];
511
-        foreach ($results as $result) {
512
-            $nice_result = $this->createEntityFromWpdbResult(
513
-                $relation->get_other_model(),
514
-                $result,
515
-                $request
516
-            );
517
-            if ($relation instanceof EE_HABTM_Relation) {
518
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
519
-                // if there are conflicts we prefer the properties from the main model
520
-                $join_model_result = $this->createEntityFromWpdbResult(
521
-                    $relation->get_join_model(),
522
-                    $result,
523
-                    $request
524
-                );
525
-                $joined_result     = array_merge($join_model_result, $nice_result);
526
-                // but keep the meta stuff from the main model
527
-                if (isset($nice_result['meta'])) {
528
-                    $joined_result['meta'] = $nice_result['meta'];
529
-                }
530
-                $nice_result = $joined_result;
531
-            }
532
-            $nice_results[] = $nice_result;
533
-        }
534
-        if ($relation instanceof EE_Belongs_To_Relation) {
535
-            return array_shift($nice_results);
536
-        } else {
537
-            return $nice_results;
538
-        }
539
-    }
540
-
541
-
542
-    /**
543
-     * Gets the collection for given relation object
544
-     * The same as Read::get_entities_from_model(), except if the relation
545
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
546
-     * the join-model-object into the results
547
-     *
548
-     * @param int|string             $id the ID of the thing we are fetching related stuff from
549
-     * @param EE_Model_Relation_Base $relation
550
-     * @param WP_REST_Request        $request
551
-     * @return array
552
-     * @throws DomainException
553
-     * @throws EE_Error
554
-     * @throws InvalidArgumentException
555
-     * @throws InvalidDataTypeException
556
-     * @throws InvalidInterfaceException
557
-     * @throws ReflectionException
558
-     * @throws RestException
559
-     * @throws ModelConfigurationException
560
-     * @throws UnexpectedEntityException
561
-     * @throws Exception
562
-     */
563
-    public function getEntitiesFromRelation($id, EE_Model_Relation_Base $relation, WP_REST_Request $request): array
564
-    {
565
-        if (! $relation->get_this_model()->has_primary_key_field()) {
566
-            throw new EE_Error(
567
-                sprintf(
568
-                    esc_html__(
569
-                    // @codingStandardsIgnoreStart
570
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
571
-                        // @codingStandardsIgnoreEnd
572
-                        'event_espresso'
573
-                    ),
574
-                    $relation->get_this_model()->get_this_model_name()
575
-                )
576
-            );
577
-        }
578
-        // can we edit that main item?
579
-        // if not, show nothing but an error
580
-        // otherwise, please proceed
581
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
582
-            [
583
-                [
584
-                    $relation->get_this_model()->primary_key_name() => $id,
585
-                ],
586
-            ],
587
-            $relation,
588
-            $request
589
-        );
590
-    }
591
-
592
-
593
-    /**
594
-     * Sets the headers that are based on the model and query params,
595
-     * like the total records. This should only be called on the original request
596
-     * from the client, not on subsequent internal
597
-     *
598
-     * @param EEM_Base $model
599
-     * @param array    $query_params
600
-     * @return void
601
-     * @throws EE_Error
602
-     * @throws ReflectionException
603
-     */
604
-    protected function setHeadersFromQueryParams(EEM_Base $model, array $query_params)
605
-    {
606
-        $this->setDebugInfo('model query params', $query_params);
607
-        $this->setDebugInfo(
608
-            'missing caps',
609
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
610
-        );
611
-        // normally the limit to a 2-part array, where the 2nd item is the limit
612
-        if (! isset($query_params['limit'])) {
613
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
614
-        }
615
-        if (is_array($query_params['limit'])) {
616
-            $limit_parts = $query_params['limit'];
617
-        } else {
618
-            $limit_parts = explode(',', $query_params['limit']);
619
-            if (count($limit_parts) === 1) {
620
-                $limit_parts = [0, $limit_parts[0]];
621
-            }
622
-        }
623
-        // remove the group by and having parts of the query, as those will
624
-        // make the sql query return an array of values, instead of just a single value
625
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
626
-        $count = $model->count($query_params, null, true);
627
-        $pages = $count / $limit_parts[1];
628
-        $this->setResponseHeader('Total', $count, false);
629
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
630
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
631
-    }
632
-
633
-
634
-    /**
635
-     * Changes database results into REST API entities
636
-     *
637
-     * @param EEM_Base             $model
638
-     * @param array                $db_row     like results from $wpdb->get_results()
639
-     * @param WP_REST_Request|null $rest_request
640
-     * @param string|null          $deprecated no longer used
641
-     * @return array ready for being converted into json for sending to client
642
-     * @throws DomainException
643
-     * @throws EE_Error
644
-     * @throws InvalidArgumentException
645
-     * @throws InvalidDataTypeException
646
-     * @throws InvalidInterfaceException
647
-     * @throws ModelConfigurationException
648
-     * @throws ReflectionException
649
-     * @throws RestException
650
-     * @throws RestPasswordIncorrectException
651
-     * @throws RestPasswordRequiredException
652
-     * @throws UnexpectedEntityException
653
-     */
654
-    public function createEntityFromWpdbResult(
655
-        EEM_Base $model,
656
-        array $db_row,
657
-        ?WP_REST_Request $rest_request,
658
-        string $deprecated = null
659
-    ): array {
660
-        if (! $rest_request instanceof WP_REST_Request) {
661
-            // ok so this was called in the old style, where the 3rd arg was
662
-            // $include, and the 4th arg was $context
663
-            // now setup the request just to avoid fatal errors, although we won't be able
664
-            // to truly make use of it because it's kinda devoid of info
665
-            $rest_request = new WP_REST_Request();
666
-            $rest_request->set_param('include', $rest_request);
667
-            $rest_request->set_param('caps', $deprecated);
668
-        }
669
-        if ($rest_request->get_param('caps') === null) {
670
-            $rest_request->set_param('caps', EEM_Base::caps_read);
671
-        }
672
-        $current_user_full_access_to_entity = $model->currentUserCan(
673
-            EEM_Base::caps_read_admin,
674
-            $model->deduce_fields_n_values_from_cols_n_values($db_row)
675
-        );
676
-        $entity_array                       = $this->createBareEntityFromWpdbResults($model, $db_row);
677
-        $entity_array                       = $this->addExtraFields($model, $db_row, $entity_array);
678
-        $entity_array['_links']             = $this->getEntityLinks($model, $db_row, $entity_array);
679
-        // when it's a regular read request for a model with a password and the password wasn't provided
680
-        // remove the password protected fields
681
-        $has_protected_fields = false;
682
-        try {
683
-            $this->checkPassword(
684
-                $model,
685
-                $db_row,
686
-                $model->alter_query_params_to_restrict_by_ID(
687
-                    $model->get_index_primary_key_string(
688
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
689
-                    )
690
-                ),
691
-                $rest_request
692
-            );
693
-        } catch (RestPasswordRequiredException $e) {
694
-            if ($model->hasPassword()) {
695
-                // just remove protected fields
696
-                $has_protected_fields = true;
697
-                $entity_array         = Capabilities::filterOutPasswordProtectedFields(
698
-                    $entity_array,
699
-                    $model,
700
-                    $this->getModelVersionInfo()
701
-                );
702
-            } else {
703
-                // that's a problem. None of this should be accessible if no password was provided
704
-                throw $e;
705
-            }
706
-        }
707
-
708
-        $entity_array['_calculated_fields'] = $this->getEntityCalculations(
709
-            $model,
710
-            $db_row,
711
-            $rest_request,
712
-            $has_protected_fields
713
-        );
714
-        $entity_array                       = apply_filters(
715
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
716
-            $entity_array,
717
-            $model,
718
-            $rest_request->get_param('caps'),
719
-            $rest_request,
720
-            $this
721
-        );
722
-        // add an empty protected property for now. If it's still around after we remove everything the request didn't
723
-        // want, we'll populate it then. k?
724
-        $entity_array['_protected'] = [];
725
-        // remove any properties the request didn't want. This way _protected won't bother mentioning them
726
-        $entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
727
-        $entity_array = $this->includeRequestedModels(
728
-            $model,
729
-            $rest_request,
730
-            $entity_array,
731
-            $db_row,
732
-            $has_protected_fields
733
-        );
734
-        // if they still wanted the _protected property, add it.
735
-        if (isset($entity_array['_protected'])) {
736
-            $entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
737
-        }
738
-        $entity_array = apply_filters(
739
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
740
-            $entity_array,
741
-            $model,
742
-            $rest_request->get_param('caps'),
743
-            $rest_request,
744
-            $this
745
-        );
746
-        if (! $current_user_full_access_to_entity) {
747
-            $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
748
-                $entity_array,
749
-                $model,
750
-                $rest_request->get_param('caps'),
751
-                $this->getModelVersionInfo()
752
-            );
753
-        } else {
754
-            $result_without_inaccessible_fields = $entity_array;
755
-        }
756
-        $this->setDebugInfo(
757
-            'inaccessible fields',
758
-            array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
759
-        );
760
-        return apply_filters(
761
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
762
-            $result_without_inaccessible_fields,
763
-            $model,
764
-            $rest_request->get_param('caps')
765
-        );
766
-    }
767
-
768
-
769
-    /**
770
-     * Returns an array describing which fields can be protected, and which actually were removed this request
771
-     *
772
-     * @param EEM_Base $model
773
-     * @param array    $results_so_far
774
-     * @param bool     $protected
775
-     * @return array results
776
-     * @throws EE_Error
777
-     * @since 4.9.74.p
778
-     */
779
-    protected function addProtectedProperty(EEM_Base $model, array $results_so_far, bool $protected): array
780
-    {
781
-        if (! $protected || ! $model->hasPassword()) {
782
-            return $results_so_far;
783
-        }
784
-        $password_field  = $model->getPasswordField();
785
-        $all_protected   = array_merge(
786
-            [$password_field->get_name()],
787
-            $password_field->protectedFields()
788
-        );
789
-        $fields_included = array_keys($results_so_far);
790
-        $fields_included = array_intersect(
791
-            $all_protected,
792
-            $fields_included
793
-        );
794
-        foreach ($fields_included as $field_name) {
795
-            $results_so_far['_protected'][] = $field_name;
796
-        }
797
-        return $results_so_far;
798
-    }
799
-
800
-
801
-    /**
802
-     * Creates a REST entity array (JSON object we're going to return in the response, but
803
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
804
-     * from $wpdb->get_row( $sql, ARRAY_A)
805
-     *
806
-     * @param EEM_Base $model
807
-     * @param array    $db_row
808
-     * @return array entity mostly ready for converting to JSON and sending in the response
809
-     * @throws EE_Error
810
-     * @throws ReflectionException
811
-     * @throws RestException
812
-     * @throws Exception
813
-     */
814
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, array $db_row): array
815
-    {
816
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
817
-        $result = array_intersect_key(
818
-            $result,
819
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
820
-        );
821
-        // if this is a CPT, we need to set the global $post to it,
822
-        // otherwise shortcodes etc won't work properly while rendering it
823
-        if ($model instanceof EEM_CPT_Base) {
824
-            $do_chevy_shuffle = true;
825
-        } else {
826
-            $do_chevy_shuffle = false;
827
-        }
828
-        if ($do_chevy_shuffle) {
829
-            global $post;
830
-            $old_post = $post;
831
-            $post     = get_post($result[ $model->primary_key_name() ]);
832
-            if (! $post instanceof WP_Post) {
833
-                // well that's weird, because $result is what we JUST fetched from the database
834
-                throw new RestException(
835
-                    'error_fetching_post_from_database_results',
836
-                    esc_html__(
837
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
838
-                        'event_espresso'
839
-                    )
840
-                );
841
-            }
842
-            $model_object_classname          = 'EE_' . $model->get_this_model_name();
843
-            $post->{$model_object_classname} = EE_Registry::instance()->load_class(
844
-                $model_object_classname,
845
-                $result,
846
-                false,
847
-                false
848
-            );
849
-        }
850
-        foreach ($result as $field_name => $field_value) {
851
-            $field_obj = $model->field_settings_for($field_name);
852
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
853
-                unset($result[ $field_name ]);
854
-            } elseif (
855
-                $this->isSubclassOfOne(
856
-                    $field_obj,
857
-                    $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
858
-                )
859
-            ) {
860
-                $result[ $field_name ] = [
861
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
862
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
863
-                ];
864
-            } elseif (
865
-                $this->isSubclassOfOne(
866
-                    $field_obj,
867
-                    $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
868
-                )
869
-            ) {
870
-                $result[ $field_name ] = [
871
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
872
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
873
-                ];
874
-            } elseif ($field_obj instanceof EE_Datetime_Field) {
875
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
876
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
877
-                if (is_null($field_value)) {
878
-                    $field_value = $field_obj->getDefaultDateTimeObj();
879
-                }
880
-                if (is_null($field_value)) {
881
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
882
-                        $field_obj,
883
-                        $field_value,
884
-                        $this->getModelVersionInfo()->requestedVersion()
885
-                    );
886
-                } else {
887
-                    $timezone = $field_value->getTimezone();
888
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
889
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
890
-                        $field_obj,
891
-                        $field_value,
892
-                        $this->getModelVersionInfo()->requestedVersion()
893
-                    );
894
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
895
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
896
-                        $field_obj,
897
-                        $field_value,
898
-                        $this->getModelVersionInfo()->requestedVersion()
899
-                    );
900
-                }
901
-                $result[ $field_name . '_gmt' ] = $gmt_date;
902
-                $result[ $field_name ]          = $local_date;
903
-            } else {
904
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
905
-            }
906
-        }
907
-        if ($do_chevy_shuffle) {
908
-            $post = $old_post;
909
-        }
910
-        return $result;
911
-    }
912
-
913
-
914
-    /**
915
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
916
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
917
-     * representation using $field_obj->prepare_for_set_from_db())
918
-     *
919
-     * @param EE_Model_Field_Base $field_obj
920
-     * @param mixed               $value  as it's stored on a model object
921
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
922
-     * @return array|int
923
-     * @throws RestException if $value contains a PHP object
924
-     * @throws EE_Error
925
-     */
926
-    protected function prepareFieldObjValueForJson(
927
-        EE_Model_Field_Base $field_obj,
928
-        $value,
929
-        string $format = 'normal'
930
-    ) {
931
-        $value = $field_obj->prepare_for_set_from_db($value);
932
-        switch ($format) {
933
-            case 'pretty':
934
-                $value = $field_obj->prepare_for_pretty_echoing($value);
935
-                break;
936
-            case 'normal':
937
-            default:
938
-                $value = $field_obj->prepare_for_get($value);
939
-                break;
940
-        }
941
-        return ModelDataTranslator::prepareFieldValuesForJson(
942
-            $field_obj,
943
-            $value,
944
-            $this->getModelVersionInfo()->requestedVersion()
945
-        );
946
-    }
947
-
948
-
949
-    /**
950
-     * Adds a few extra fields to the entity response
951
-     *
952
-     * @param EEM_Base $model
953
-     * @param array    $db_row
954
-     * @param array    $entity_array
955
-     * @return array modified entity
956
-     * @throws EE_Error
957
-     */
958
-    protected function addExtraFields(EEM_Base $model, array $db_row, array $entity_array): array
959
-    {
960
-        if ($model instanceof EEM_CPT_Base) {
961
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
962
-        }
963
-        return $entity_array;
964
-    }
965
-
966
-
967
-    /**
968
-     * Gets links we want to add to the response
969
-     *
970
-     * @param EEM_Base        $model
971
-     * @param array           $db_row
972
-     * @param array           $entity_array
973
-     * @return array the _links item in the entity
974
-     * @throws EE_Error
975
-     * @global WP_REST_Server $wp_rest_server
976
-     */
977
-    protected function getEntityLinks(EEM_Base $model, array $db_row, array $entity_array): array
978
-    {
979
-        // add basic links
980
-        $links = [];
981
-        if ($model->has_primary_key_field()) {
982
-            $links['self'] = [
983
-                [
984
-                    'href' => $this->getVersionedLinkTo(
985
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
986
-                        . '/'
987
-                        . $entity_array[ $model->primary_key_name() ]
988
-                    ),
989
-                ],
990
-            ];
991
-        }
992
-        $links['collection'] = [
993
-            [
994
-                'href' => $this->getVersionedLinkTo(
995
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
996
-                ),
997
-            ],
998
-        ];
999
-        // add links to related models
1000
-        if ($model->has_primary_key_field()) {
1001
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
1002
-                $related_model_part                                                      =
1003
-                    Read::getRelatedEntityName($relation_name, $relation_obj);
1004
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
1005
-                    [
1006
-                        'href'   => $this->getVersionedLinkTo(
1007
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
1008
-                            . '/'
1009
-                            . $entity_array[ $model->primary_key_name() ]
1010
-                            . '/'
1011
-                            . $related_model_part
1012
-                        ),
1013
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation,
1014
-                    ],
1015
-                ];
1016
-            }
1017
-        }
1018
-        return $links;
1019
-    }
1020
-
1021
-
1022
-    /**
1023
-     * Adds the included models indicated in the request to the entity provided
1024
-     *
1025
-     * @param EEM_Base        $model
1026
-     * @param WP_REST_Request $rest_request
1027
-     * @param array           $entity_array
1028
-     * @param array           $db_row
1029
-     * @param boolean         $included_items_protected if the original item is password protected, don't include any
1030
-     *                                                  related models.
1031
-     * @return array the modified entity
1032
-     * @throws DomainException
1033
-     * @throws EE_Error
1034
-     * @throws InvalidArgumentException
1035
-     * @throws InvalidDataTypeException
1036
-     * @throws InvalidInterfaceException
1037
-     * @throws ModelConfigurationException
1038
-     * @throws ReflectionException
1039
-     * @throws UnexpectedEntityException
1040
-     */
1041
-    protected function includeRequestedModels(
1042
-        EEM_Base $model,
1043
-        WP_REST_Request $rest_request,
1044
-        array $entity_array,
1045
-        array $db_row = [],
1046
-        bool $included_items_protected = false
1047
-    ): array {
1048
-        // if $db_row not included, hope the entity array has what we need
1049
-        if (! $db_row) {
1050
-            $db_row = $entity_array;
1051
-        }
1052
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
1053
-        foreach ($relation_settings as $relation_name => $relation_obj) {
1054
-            $related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1055
-                $rest_request->get_param('include'),
1056
-                $relation_name
1057
-            );
1058
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
1059
-                $rest_request->get_param('calculate'),
1060
-                $relation_name
1061
-            );
1062
-            // did they specify they wanted to include a related model, or
1063
-            // specific fields from a related model?
1064
-            // or did they specify to calculate a field from a related model?
1065
-            if ($related_fields_to_include || $related_fields_to_calculate) {
1066
-                // if so, we should include at least some part of the related model
1067
-                $pretend_related_request = new WP_REST_Request();
1068
-                $pretend_related_request->set_query_params(
1069
-                    [
1070
-                        'caps'      => $rest_request->get_param('caps'),
1071
-                        'include'   => $related_fields_to_include,
1072
-                        'calculate' => $related_fields_to_calculate,
1073
-                        'password'  => $rest_request->get_param('password'),
1074
-                    ]
1075
-                );
1076
-                $pretend_related_request->add_header('no_rest_headers', true);
1077
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
1078
-                    $model->get_index_primary_key_string(
1079
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
1080
-                    )
1081
-                );
1082
-                if (! $included_items_protected) {
1083
-                    try {
1084
-                        $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1085
-                            $primary_model_query_params,
1086
-                            $relation_obj,
1087
-                            $pretend_related_request
1088
-                        );
1089
-                    } catch (RestException $e) {
1090
-                        $related_results = null;
1091
-                    }
1092
-                } else {
1093
-                    // they're protected, hide them.
1094
-                    $related_results              = null;
1095
-                    $entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
1096
-                }
1097
-                if ($related_results instanceof WP_Error || $related_results === null) {
1098
-                    $related_results = $relation_obj instanceof EE_Belongs_To_Relation
1099
-                            ? null
1100
-                            : [];
1101
-                }
1102
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1103
-            }
1104
-        }
1105
-        return $entity_array;
1106
-    }
1107
-
1108
-
1109
-    /**
1110
-     * If the user has requested only specific properties (including meta properties like _links or _protected)
1111
-     * remove everything else.
1112
-     *
1113
-     * @param EEM_Base        $model
1114
-     * @param WP_REST_Request $rest_request
1115
-     * @param                 $entity_array
1116
-     * @return array
1117
-     * @throws EE_Error
1118
-     * @since 4.9.74.p
1119
-     */
1120
-    protected function includeOnlyRequestedProperties(
1121
-        EEM_Base $model,
1122
-        WP_REST_Request $rest_request,
1123
-        $entity_array
1124
-    ): array {
1125
-
1126
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1127
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1128
-        // if they passed in * or didn't specify any includes, return everything
1129
-        if (! empty($includes_for_this_model) && ! in_array('*', $includes_for_this_model, true)) {
1130
-            if ($model->has_primary_key_field()) {
1131
-                // always include the primary key. ya just gotta know that at least
1132
-                $includes_for_this_model[] = $model->primary_key_name();
1133
-            }
1134
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1135
-                $includes_for_this_model[] = '_calculated_fields';
1136
-            }
1137
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1138
-        }
1139
-        return $entity_array;
1140
-    }
1141
-
1142
-
1143
-    /**
1144
-     * Returns a new array with all the names of models removed. Eg
1145
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1146
-     *
1147
-     * @param array $array
1148
-     * @return array
1149
-     */
1150
-    private function removeModelNamesFromArray(array $array): array
1151
-    {
1152
-        return array_diff($array, array_keys(EE_Registry::instance()->non_abstract_db_models));
1153
-    }
1154
-
1155
-
1156
-    /**
1157
-     * Gets the calculated fields for the response
1158
-     *
1159
-     * @param EEM_Base        $model
1160
-     * @param array           $wpdb_row
1161
-     * @param WP_REST_Request $rest_request
1162
-     * @param bool            $row_is_protected whether this row is password protected or not
1163
-     * @return stdClass the _calculations item in the entity
1164
-     * @throws RestException if a default value has a PHP object, which should never do (and if we
1165
-     *                                          did, let's know about it ASAP, so let the exception bubble up)
1166
-     * @throws EE_Error
1167
-     */
1168
-    protected function getEntityCalculations(
1169
-        EEM_Base $model,
1170
-        array $wpdb_row,
1171
-        WP_REST_Request $rest_request,
1172
-        bool $row_is_protected = false
1173
-    ): stdClass {
1174
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1175
-            $rest_request->get_param('calculate'),
1176
-            ''
1177
-        );
1178
-        // note: setting calculate=* doesn't do anything
1179
-        $calculated_fields_to_return = new stdClass();
1180
-        $protected_fields            = [];
1181
-        foreach ($calculated_fields as $field_to_calculate) {
1182
-            try {
1183
-                // it's password protected, so they shouldn't be able to read this. Remove the value
1184
-                $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1185
-                if (
1186
-                    $row_is_protected
1187
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1188
-                    && $schema['properties'][ $field_to_calculate ]['protected']
1189
-                ) {
1190
-                    $calculated_value   = null;
1191
-                    $protected_fields[] = $field_to_calculate;
1192
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1193
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1194
-                            case 'boolean':
1195
-                                $calculated_value = false;
1196
-                                break;
1197
-                            case 'integer':
1198
-                                $calculated_value = 0;
1199
-                                break;
1200
-                            case 'string':
1201
-                                $calculated_value = '';
1202
-                                break;
1203
-                            case 'array':
1204
-                                $calculated_value = [];
1205
-                                break;
1206
-                            case 'object':
1207
-                                $calculated_value = new stdClass();
1208
-                                break;
1209
-                        }
1210
-                    }
1211
-                } else {
1212
-                    $calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1213
-                        null,
1214
-                        $this->fields_calculator->retrieveCalculatedFieldValue(
1215
-                            $model,
1216
-                            $field_to_calculate,
1217
-                            $wpdb_row,
1218
-                            $rest_request,
1219
-                            $this
1220
-                        ),
1221
-                        $this->getModelVersionInfo()->requestedVersion()
1222
-                    );
1223
-                }
1224
-                $calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1225
-            } catch (RestException $e) {
1226
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
1227
-                $this->setResponseHeader(
1228
-                    'Notices-Field-Calculation-Errors['
1229
-                    . $e->getStringCode()
1230
-                    . ']['
1231
-                    . $model->get_this_model_name()
1232
-                    . ']['
1233
-                    . $field_to_calculate
1234
-                    . ']',
1235
-                    $e->getMessage()
1236
-                );
1237
-            }
1238
-        }
1239
-        $calculated_fields_to_return->_protected = $protected_fields;
1240
-        return $calculated_fields_to_return;
1241
-    }
1242
-
1243
-
1244
-    /**
1245
-     * Gets the full URL to the resource, taking the requested version into account
1246
-     *
1247
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1248
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1249
-     * @throws EE_Error
1250
-     */
1251
-    public function getVersionedLinkTo(string $link_part_after_version_and_slash): string
1252
-    {
1253
-        return rest_url(
1254
-            EED_Core_Rest_Api::get_versioned_route_to(
1255
-                $link_part_after_version_and_slash,
1256
-                $this->getModelVersionInfo()->requestedVersion()
1257
-            )
1258
-        );
1259
-    }
1260
-
1261
-
1262
-    /**
1263
-     * Gets the correct lowercase name for the relation in the API according
1264
-     * to the relation's type
1265
-     *
1266
-     * @param string                 $relation_name
1267
-     * @param EE_Model_Relation_Base $relation_obj
1268
-     * @return string
1269
-     */
1270
-    public static function getRelatedEntityName(string $relation_name, EE_Model_Relation_Base $relation_obj): string
1271
-    {
1272
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1273
-            return strtolower($relation_name);
1274
-        }
1275
-        return EEH_Inflector::pluralize_and_lower($relation_name);
1276
-    }
1277
-
1278
-
1279
-    /**
1280
-     * Gets the one model object with the specified id for the specified model
1281
-     *
1282
-     * @param EEM_Base        $model
1283
-     * @param WP_REST_Request $request
1284
-     * @return array
1285
-     * @throws EE_Error
1286
-     * @throws InvalidArgumentException
1287
-     * @throws InvalidDataTypeException
1288
-     * @throws InvalidInterfaceException
1289
-     * @throws ModelConfigurationException
1290
-     * @throws ReflectionException
1291
-     * @throws RestException
1292
-     * @throws RestPasswordIncorrectException
1293
-     * @throws RestPasswordRequiredException
1294
-     * @throws UnexpectedEntityException
1295
-     * @throws DomainException
1296
-     */
1297
-    public function getEntityFromModel(EEM_Base $model, WP_REST_Request $request): array
1298
-    {
1299
-        $context = $this->validateContext($request->get_param('caps'));
1300
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1301
-    }
1302
-
1303
-
1304
-    /**
1305
-     * If a context is provided which isn't valid, maybe it was added in a future
1306
-     * version so just treat it as a default read
1307
-     *
1308
-     * @param string|null $context
1309
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1310
-     */
1311
-    public function validateContext(?string $context): string
1312
-    {
1313
-        if (! $context) {
1314
-            $context = EEM_Base::caps_read;
1315
-        }
1316
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1317
-        if (in_array($context, $valid_contexts, true)) {
1318
-            return $context;
1319
-        }
1320
-        return EEM_Base::caps_read;
1321
-    }
1322
-
1323
-
1324
-    /**
1325
-     * Verifies the passed in value is an allowable default where conditions value.
1326
-     *
1327
-     * @param string $default_where_conditions
1328
-     * @return string
1329
-     */
1330
-    public function validateDefaultQueryParams(string $default_where_conditions): string
1331
-    {
1332
-        $valid_default_where_conditions_for_api_calls = [
1333
-            EEM_Base::default_where_conditions_all,
1334
-            EEM_Base::default_where_conditions_minimum_all,
1335
-            EEM_Base::default_where_conditions_minimum_others,
1336
-        ];
1337
-        if (! $default_where_conditions) {
1338
-            $default_where_conditions = EEM_Base::default_where_conditions_all;
1339
-        }
1340
-        if (
1341
-            in_array(
1342
-                $default_where_conditions,
1343
-                $valid_default_where_conditions_for_api_calls,
1344
-                true
1345
-            )
1346
-        ) {
1347
-            return $default_where_conditions;
1348
-        }
1349
-        return EEM_Base::default_where_conditions_all;
1350
-    }
1351
-
1352
-
1353
-    /**
1354
-     * Translates API filter get parameter into model query params @param EEM_Base $model
1355
-     *
1356
-     * @param array $query_params
1357
-     * @return array model query params (@see
1358
-     *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1359
-     *               or FALSE to indicate that absolutely no results should be returned
1360
-     * @throws EE_Error
1361
-     * @throws InvalidArgumentException
1362
-     * @throws InvalidDataTypeException
1363
-     * @throws InvalidInterfaceException
1364
-     * @throws RestException
1365
-     * @throws DomainException
1366
-     * @throws ReflectionException
1367
-     * @see
1368
-     *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1369
-     *               Note: right now the query parameter keys for fields (and related fields) can be left as-is, but
1370
-     *               it's quite possible this will change someday. Also, this method's contents might be candidate for
1371
-     *               moving to Model_Data_Translator
1372
-     *
1373
-     */
1374
-    public function createModelQueryParams(EEM_Base $model, array $query_params): array
1375
-    {
1376
-        $model_query_params = [];
1377
-        if (isset($query_params['where'])) {
1378
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1379
-                $query_params['where'],
1380
-                $model,
1381
-                $this->getModelVersionInfo()->requestedVersion()
1382
-            );
1383
-        }
1384
-        if (isset($query_params['order_by'])) {
1385
-            $order_by = $query_params['order_by'];
1386
-        } elseif (isset($query_params['orderby'])) {
1387
-            $order_by = $query_params['orderby'];
1388
-        } else {
1389
-            $order_by = null;
1390
-        }
1391
-        if ($order_by !== null) {
1392
-            if (is_array($order_by)) {
1393
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1394
-            } else {
1395
-                // it's a single item
1396
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1397
-            }
1398
-            $model_query_params['order_by'] = $order_by;
1399
-        }
1400
-        if (isset($query_params['group_by'])) {
1401
-            $group_by = $query_params['group_by'];
1402
-        } elseif (isset($query_params['groupby'])) {
1403
-            $group_by = $query_params['groupby'];
1404
-        } else {
1405
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1406
-        }
1407
-        // make sure they're all real names
1408
-        if (is_array($group_by)) {
1409
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1410
-        }
1411
-        if ($group_by !== null) {
1412
-            $model_query_params['group_by'] = $group_by;
1413
-        }
1414
-        if (isset($query_params['having'])) {
1415
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1416
-                $query_params['having'],
1417
-                $model,
1418
-                $this->getModelVersionInfo()->requestedVersion()
1419
-            );
1420
-        }
1421
-        if (isset($query_params['order'])) {
1422
-            $model_query_params['order'] = $query_params['order'];
1423
-        }
1424
-        if (isset($query_params['mine'])) {
1425
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1426
-        }
1427
-        if (isset($query_params['limit'])) {
1428
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1429
-            if (! is_array($query_params['limit'])) {
1430
-                $limit_array = explode(',', (string) $query_params['limit']);
1431
-            } else {
1432
-                $limit_array = $query_params['limit'];
1433
-            }
1434
-            $sanitized_limit = [];
1435
-            foreach ($limit_array as $limit_part) {
1436
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1437
-                    throw new EE_Error(
1438
-                        sprintf(
1439
-                            esc_html__(
1440
-                            // @codingStandardsIgnoreStart
1441
-                                'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1442
-                                // @codingStandardsIgnoreEnd
1443
-                                'event_espresso'
1444
-                            ),
1445
-                            wp_json_encode($query_params['limit'])
1446
-                        )
1447
-                    );
1448
-                }
1449
-                $sanitized_limit[] = (int) $limit_part;
1450
-            }
1451
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1452
-        } else {
1453
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1454
-        }
1455
-        if (isset($query_params['caps'])) {
1456
-            $model_query_params['caps'] = $this->validateContext($query_params['caps']);
1457
-        } else {
1458
-            $model_query_params['caps'] = EEM_Base::caps_read;
1459
-        }
1460
-        if (isset($query_params['default_where_conditions'])) {
1461
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1462
-                $query_params['default_where_conditions']
1463
-            );
1464
-        }
1465
-        // if this is a model protected by a password on another model, exclude the password protected
1466
-        // entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1467
-        // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1468
-        if (
1469
-            $model_query_params['caps'] === EEM_Base::caps_read
1470
-            && empty($query_params['password'])
1471
-            && ! $model->hasPassword()
1472
-            && $model->restrictedByRelatedModelPassword()
1473
-        ) {
1474
-            $model_query_params['exclude_protected'] = true;
1475
-        }
1476
-
1477
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1478
-    }
1479
-
1480
-
1481
-    /**
1482
-     * Changes the REST-style query params for use in the models
1483
-     *
1484
-     * @param EEM_Base $model
1485
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1486
-     * @return array
1487
-     * @deprecated
1488
-     */
1489
-    public function prepareRestQueryParamsKeyForModels(EEM_Base $model, array $query_params): array
1490
-    {
1491
-        $model_ready_query_params = [];
1492
-        foreach ($query_params as $key => $value) {
1493
-            $model_ready_query_params[ $key ] = is_array($value)
1494
-                ? $this->prepareRestQueryParamsKeyForModels($model, $value)
1495
-                : $value;
1496
-        }
1497
-        return $model_ready_query_params;
1498
-    }
1499
-
1500
-
1501
-    /**
1502
-     * @param $model
1503
-     * @param $query_params
1504
-     * @return array
1505
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1506
-     */
1507
-    public function prepareRestQueryParamsValuesForModels($model, $query_params): array
1508
-    {
1509
-        $model_ready_query_params = [];
1510
-        foreach ($query_params as $key => $value) {
1511
-            if (is_array($value)) {
1512
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1513
-            } else {
1514
-                $model_ready_query_params[ $key ] = $value;
1515
-            }
1516
-        }
1517
-        return $model_ready_query_params;
1518
-    }
1519
-
1520
-
1521
-    /**
1522
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1523
-     * If no prefix is specified, returns items with no period.
1524
-     *
1525
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1526
-     * @param string       $prefix            "Event" or "foobar"
1527
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1528
-     *                                        we only return strings starting with that and a period; if no prefix was
1529
-     *                                        specified we return all items containing NO periods
1530
-     */
1531
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, string $prefix): array
1532
-    {
1533
-        if (is_string($string_to_explode)) {
1534
-            $exploded_contents = explode(',', $string_to_explode);
1535
-        } elseif (is_array($string_to_explode)) {
1536
-            $exploded_contents = $string_to_explode;
1537
-        } else {
1538
-            $exploded_contents = [];
1539
-        }
1540
-        // if the string was empty, we want an empty array
1541
-        $exploded_contents    = array_filter($exploded_contents);
1542
-        $contents_with_prefix = [];
1543
-        foreach ($exploded_contents as $item) {
1544
-            $item = trim($item);
1545
-            // if no prefix was provided, so we look for items with no "." in them
1546
-            if (! $prefix) {
1547
-                // does this item have a period?
1548
-                if (strpos($item, '.') === false) {
1549
-                    // if not, then its what we're looking for
1550
-                    $contents_with_prefix[] = $item;
1551
-                }
1552
-            } elseif (strpos($item, $prefix . '.') === 0) {
1553
-                // this item has the prefix and a period, grab it
1554
-                $contents_with_prefix[] = substr(
1555
-                    $item,
1556
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1557
-                );
1558
-            } elseif ($item === $prefix) {
1559
-                // this item is JUST the prefix
1560
-                // so let's grab everything after, which is a blank string
1561
-                $contents_with_prefix[] = '';
1562
-            }
1563
-        }
1564
-        return $contents_with_prefix;
1565
-    }
1566
-
1567
-
1568
-    /**
1569
-     * @param string      $include_string @see Read:handle_request_get_all
1570
-     * @param string|null $model_name
1571
-     * @return array of fields for this model. If $model_name is provided, then
1572
-     *                                    the fields for that model, with the model's name removed from each.
1573
-     *                                    If $include_string was blank or '*' returns an empty array
1574
-     * @throws EE_Error
1575
-     * @throws EE_Error
1576
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1577
-     *                                    Deprecated because its return values were really quite confusing- sometimes
1578
-     *                                    it
1579
-     *                                    returned an empty array (when the include string was blank or '*') or
1580
-     *                                    sometimes it returned array('*') (when you provided a model and a model of
1581
-     *                                    that kind was found). Parses the $include_string so we fetch all the field
1582
-     *                                    names relating to THIS model
1583
-     *                                    (ie have NO period in them), or for the provided model (ie start with the
1584
-     *                                    model name and then a period).
1585
-     */
1586
-    public function extractIncludesForThisModel(string $include_string, string $model_name = null): array
1587
-    {
1588
-        if (is_array($include_string)) {
1589
-            $include_string = implode(',', $include_string);
1590
-        }
1591
-        if ($include_string === '*' || $include_string === '') {
1592
-            return [];
1593
-        }
1594
-        $includes                    = explode(',', $include_string);
1595
-        $extracted_fields_to_include = [];
1596
-        if ($model_name) {
1597
-            foreach ($includes as $field_to_include) {
1598
-                $field_to_include = trim($field_to_include);
1599
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1600
-                    // found the model name at the exact start
1601
-                    $field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1602
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1603
-                } elseif ($field_to_include === $model_name) {
1604
-                    $extracted_fields_to_include[] = '*';
1605
-                }
1606
-            }
1607
-        } else {
1608
-            // look for ones with no period
1609
-            foreach ($includes as $field_to_include) {
1610
-                $field_to_include = trim($field_to_include);
1611
-                if (
1612
-                    strpos($field_to_include, '.') === false
1613
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1614
-                ) {
1615
-                    $extracted_fields_to_include[] = $field_to_include;
1616
-                }
1617
-            }
1618
-        }
1619
-        return $extracted_fields_to_include;
1620
-    }
1621
-
1622
-
1623
-    /**
1624
-     * Gets the single item using the model according to the request in the context given, otherwise
1625
-     * returns that it's inaccessible to the current user
1626
-     *
1627
-     * @param EEM_Base        $model
1628
-     * @param WP_REST_Request $request
1629
-     * @param null            $context
1630
-     * @return array
1631
-     * @throws EE_Error
1632
-     * @throws ReflectionException
1633
-     */
1634
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null): array
1635
-    {
1636
-        $query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1];
1637
-        if ($model instanceof EEM_Soft_Delete_Base) {
1638
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1639
-        }
1640
-        $restricted_query_params         = $query_params;
1641
-        $restricted_query_params['caps'] = $context;
1642
-        $this->setDebugInfo('model query params', $restricted_query_params);
1643
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1644
-        if (! empty($model_rows)) {
1645
-            return $this->createEntityFromWpdbResult(
1646
-                $model,
1647
-                reset($model_rows),
1648
-                $request
1649
-            );
1650
-        }
1651
-        // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1652
-        $lowercase_model_name = strtolower($model->get_this_model_name());
1653
-        if ($model->exists($query_params)) {
1654
-            // you got shafted- it existed but we didn't want to tell you!
1655
-            throw new RestException(
1656
-                'rest_user_cannot_' . $context,
1657
-                sprintf(
1658
-                    __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1659
-                    $context,
1660
-                    $lowercase_model_name,
1661
-                    Capabilities::getMissingPermissionsString(
1662
-                        $model,
1663
-                        $context
1664
-                    )
1665
-                ),
1666
-                ['status' => 403]
1667
-            );
1668
-        }
1669
-        // it's not you. It just doesn't exist
1670
-        throw new RestException(
1671
-            sprintf('rest_%s_invalid_id', $lowercase_model_name),
1672
-            sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1673
-            ['status' => 404]
1674
-        );
1675
-    }
1676
-
1677
-
1678
-    /**
1679
-     * Checks that if this content requires a password to be read, that it's been provided and is correct.
1680
-     *
1681
-     * @param EEM_Base        $model
1682
-     * @param array           $model_row
1683
-     * @param array           $query_params Adds 'default_where_conditions' => 'minimum'
1684
-     *                                      to ensure we don't confuse trashed with password protected.
1685
-     * @param WP_REST_Request $request
1686
-     * @throws EE_Error
1687
-     * @throws InvalidArgumentException
1688
-     * @throws InvalidDataTypeException
1689
-     * @throws InvalidInterfaceException
1690
-     * @throws RestPasswordRequiredException
1691
-     * @throws RestPasswordIncorrectException
1692
-     * @throws ModelConfigurationException
1693
-     * @throws ReflectionException
1694
-     * @since 4.9.74.p
1695
-     */
1696
-    protected function checkPassword(EEM_Base $model, array $model_row, array $query_params, WP_REST_Request $request)
1697
-    {
1698
-        $query_params['default_where_conditions'] = 'minimum';
1699
-        // stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1700
-        // or you don't.
1701
-        $request_caps = $request->get_param('caps');
1702
-        if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1703
-            return;
1704
-        }
1705
-        // if this entity requires a password, they better give it and it better be right!
1706
-        if (
1707
-            $model->hasPassword()
1708
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1709
-        ) {
1710
-            if (empty($request['password'])) {
1711
-                throw new RestPasswordRequiredException();
1712
-            }
1713
-            if (
1714
-                ! hash_equals(
1715
-                    $model_row[ $model->getPasswordField()->get_qualified_column() ],
1716
-                    $request['password']
1717
-                )
1718
-            ) {
1719
-                throw new RestPasswordIncorrectException();
1720
-            }
1721
-        } elseif (
1722
-            // wait! maybe this content is password protected
1723
-            $model->restrictedByRelatedModelPassword()
1724
-            && $request->get_param('caps') === EEM_Base::caps_read
1725
-        ) {
1726
-            $password_supplied = $request->get_param('password');
1727
-            if (empty($password_supplied)) {
1728
-                $query_params['exclude_protected'] = true;
1729
-                if (! $model->exists($query_params)) {
1730
-                    throw new RestPasswordRequiredException();
1731
-                }
1732
-            } else {
1733
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1734
-                if (! $model->exists($query_params)) {
1735
-                    throw new RestPasswordIncorrectException();
1736
-                }
1737
-            }
1738
-        }
1739
-    }
54
+	protected CalculatedModelFields $fields_calculator;
55
+
56
+
57
+	/**
58
+	 * Read constructor.
59
+	 *
60
+	 * @param CalculatedModelFields $fields_calculator
61
+	 */
62
+	public function __construct(CalculatedModelFields $fields_calculator)
63
+	{
64
+		parent::__construct();
65
+		$this->fields_calculator = $fields_calculator;
66
+	}
67
+
68
+
69
+	/**
70
+	 * @return Read
71
+	 */
72
+	private static function getReadController(): Read
73
+	{
74
+		return LoaderFactory::getLoader()->getNew(Read::class);
75
+	}
76
+
77
+
78
+	/**
79
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
80
+	 *
81
+	 * @param WP_REST_Request $request
82
+	 * @param string          $version
83
+	 * @param string          $model_name
84
+	 * @return WP_REST_Response
85
+	 * @throws InvalidArgumentException
86
+	 * @throws InvalidDataTypeException
87
+	 * @throws InvalidInterfaceException
88
+	 */
89
+	public static function handleRequestGetAll(
90
+		WP_REST_Request $request,
91
+		string $version,
92
+		string $model_name
93
+	): WP_REST_Response {
94
+		$controller = self::getReadController();
95
+		try {
96
+			$controller->setRequestedVersion($version);
97
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
98
+				return $controller->sendResponse(
99
+					new WP_Error(
100
+						'endpoint_parsing_error',
101
+						sprintf(
102
+							esc_html__(
103
+								'There is no model for endpoint %s. Please contact event espresso support',
104
+								'event_espresso'
105
+							),
106
+							$model_name
107
+						)
108
+					)
109
+				);
110
+			}
111
+			return $controller->sendResponse(
112
+				$controller->getEntitiesFromModel(
113
+					$controller->getModelVersionInfo()->loadModel($model_name),
114
+					$request
115
+				)
116
+			);
117
+		} catch (Exception $e) {
118
+			return $controller->sendResponse($e);
119
+		}
120
+	}
121
+
122
+
123
+	/**
124
+	 * Prepares and returns schema for any OPTIONS request.
125
+	 *
126
+	 * @param string $version    The API endpoint version being used.
127
+	 * @param string $model_name Something like `Event` or `Registration`
128
+	 * @return array
129
+	 * @throws InvalidArgumentException
130
+	 * @throws InvalidDataTypeException
131
+	 * @throws InvalidInterfaceException
132
+	 */
133
+	public static function handleSchemaRequest(string $version, string $model_name): array
134
+	{
135
+		$controller = self::getReadController();
136
+		try {
137
+			$controller->setRequestedVersion($version);
138
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
139
+				return [];
140
+			}
141
+			// get the model for this version
142
+			$model        = $controller->getModelVersionInfo()->loadModel($model_name);
143
+			$model_schema = new JsonModelSchema(
144
+				$model,
145
+				LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields')
146
+			);
147
+			return $model_schema->getModelSchemaForRelations(
148
+				$controller->getModelVersionInfo()->relationSettings($model),
149
+				$controller->customizeSchemaForRestResponse(
150
+					$model,
151
+					$model_schema->getModelSchemaForFields(
152
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
153
+						$model_schema->getInitialSchemaStructure()
154
+					)
155
+				)
156
+			);
157
+		} catch (Exception $e) {
158
+			error_log($e->getMessage());
159
+			return [];
160
+		}
161
+	}
162
+
163
+
164
+	/**
165
+	 * This loops through each field in the given schema for the model and does the following:
166
+	 * - add any extra fields that are REST API specific and related to existing fields.
167
+	 * - transform default values into the correct format for a REST API response.
168
+	 *
169
+	 * @param EEM_Base $model
170
+	 * @param array    $schema
171
+	 * @return array  The final schema.
172
+	 * @throws EE_Error
173
+	 */
174
+	public function customizeSchemaForRestResponse(EEM_Base $model, array $schema): array
175
+	{
176
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
177
+			$schema = $this->translateDefaultsForRestResponse(
178
+				$field_name,
179
+				$field,
180
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
181
+			);
182
+		}
183
+		return $schema;
184
+	}
185
+
186
+
187
+	/**
188
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
189
+	 * response.
190
+	 *
191
+	 * @param                      $field_name
192
+	 * @param EE_Model_Field_Base  $field
193
+	 * @param array                $schema
194
+	 * @return array
195
+	 * @throws RestException  if a default value has a PHP object, which we should never do
196
+	 *                                  (but if we did, let's know about it ASAP, so let the exception bubble up)
197
+	 * @throws EE_Error
198
+	 *
199
+	 */
200
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema): array
201
+	{
202
+		if (isset($schema['properties'][ $field_name ]['default'])) {
203
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
204
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
205
+					if ($default_key === 'raw') {
206
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
207
+							ModelDataTranslator::prepareFieldValueForJson(
208
+								$field,
209
+								$default_value,
210
+								$this->getModelVersionInfo()->requestedVersion()
211
+							);
212
+					}
213
+				}
214
+			} else {
215
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
216
+					$field,
217
+					$schema['properties'][ $field_name ]['default'],
218
+					$this->getModelVersionInfo()->requestedVersion()
219
+				);
220
+			}
221
+		}
222
+		return $schema;
223
+	}
224
+
225
+
226
+	/**
227
+	 * Adds additional fields to the schema
228
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
229
+	 * needs to be added to the schema.
230
+	 *
231
+	 * @param                      $field_name
232
+	 * @param EE_Model_Field_Base  $field
233
+	 * @param array                $schema
234
+	 * @return array
235
+	 */
236
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema): array
237
+	{
238
+		if ($field instanceof EE_Datetime_Field) {
239
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
240
+			// modify the description
241
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
242
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
243
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
244
+			);
245
+		}
246
+		return $schema;
247
+	}
248
+
249
+
250
+	/**
251
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
252
+	 *
253
+	 * @return string
254
+	 */
255
+	protected function getRouteFromRequest(): string
256
+	{
257
+		if (
258
+			isset($GLOBALS['wp'])
259
+			&& $GLOBALS['wp'] instanceof WP
260
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
261
+		) {
262
+			return $GLOBALS['wp']->query_vars['rest_route'];
263
+		}
264
+		/** @var RequestInterface $request */
265
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
266
+		return $request->serverParamIsSet('PATH_INFO')
267
+			? $request->getServerParam('PATH_INFO')
268
+			: '/';
269
+	}
270
+
271
+
272
+	/**
273
+	 * Gets a single entity related to the model indicated in the path and its id
274
+	 *
275
+	 * @param WP_REST_Request $request
276
+	 * @param string          $version
277
+	 * @param string          $model_name
278
+	 * @return WP_REST_Response
279
+	 * @throws InvalidDataTypeException
280
+	 * @throws InvalidInterfaceException
281
+	 * @throws InvalidArgumentException
282
+	 */
283
+	public static function handleRequestGetOne(
284
+		WP_REST_Request $request,
285
+		string $version,
286
+		string $model_name
287
+	): WP_REST_Response {
288
+		$controller = self::getReadController();
289
+		try {
290
+			$controller->setRequestedVersion($version);
291
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
292
+				return $controller->sendResponse(
293
+					new WP_Error(
294
+						'endpoint_parsing_error',
295
+						sprintf(
296
+							esc_html__(
297
+								'There is no model for endpoint %s. Please contact event espresso support',
298
+								'event_espresso'
299
+							),
300
+							$model_name
301
+						)
302
+					)
303
+				);
304
+			}
305
+			return $controller->sendResponse(
306
+				$controller->getEntityFromModel(
307
+					$controller->getModelVersionInfo()->loadModel($model_name),
308
+					$request
309
+				)
310
+			);
311
+		} catch (Exception $e) {
312
+			return $controller->sendResponse($e);
313
+		}
314
+	}
315
+
316
+
317
+	/**
318
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
319
+	 * to the item with the given id
320
+	 *
321
+	 * @param WP_REST_Request $request
322
+	 * @param string          $version
323
+	 * @param string          $model_name
324
+	 * @param string          $related_model_name
325
+	 * @return WP_REST_Response
326
+	 * @throws InvalidDataTypeException
327
+	 * @throws InvalidInterfaceException
328
+	 * @throws InvalidArgumentException
329
+	 */
330
+	public static function handleRequestGetRelated(
331
+		WP_REST_Request $request,
332
+		string $version,
333
+		string $model_name,
334
+		string $related_model_name
335
+	): WP_REST_Response {
336
+		$controller = self::getReadController();
337
+		try {
338
+			$controller->setRequestedVersion($version);
339
+			$main_model = $controller->validateModel($model_name);
340
+			$controller->validateModel($related_model_name);
341
+			return $controller->sendResponse(
342
+				$controller->getEntitiesFromRelation(
343
+					$request->get_param('id'),
344
+					$main_model->related_settings_for($related_model_name),
345
+					$request
346
+				)
347
+			);
348
+		} catch (Exception $e) {
349
+			return $controller->sendResponse($e);
350
+		}
351
+	}
352
+
353
+
354
+	/**
355
+	 * Gets a collection for the given model and filters
356
+	 *
357
+	 * @param EEM_Base        $model
358
+	 * @param WP_REST_Request $request
359
+	 * @return array
360
+	 * @throws DomainException
361
+	 * @throws EE_Error
362
+	 * @throws InvalidArgumentException
363
+	 * @throws InvalidDataTypeException
364
+	 * @throws InvalidInterfaceException
365
+	 * @throws ModelConfigurationException
366
+	 * @throws ReflectionException
367
+	 * @throws RestException
368
+	 * @throws RestPasswordIncorrectException
369
+	 * @throws RestPasswordRequiredException
370
+	 * @throws UnexpectedEntityException
371
+	 */
372
+	public function getEntitiesFromModel(EEM_Base $model, WP_REST_Request $request): array
373
+	{
374
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
375
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
376
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
377
+			throw new RestException(
378
+				sprintf('rest_%s_cannot_list', $model_name_plural),
379
+				sprintf(
380
+					esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
381
+					$model_name_plural,
382
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
383
+				),
384
+				['status' => 403]
385
+			);
386
+		}
387
+		if (! $request->get_header('no_rest_headers')) {
388
+			$this->setHeadersFromQueryParams($model, $query_params);
389
+		}
390
+		/** @type array $results */
391
+		$results      = $model->get_all_wpdb_results($query_params);
392
+		$nice_results = [];
393
+		foreach ($results as $result) {
394
+			$nice_results[] = $this->createEntityFromWpdbResult(
395
+				$model,
396
+				$result,
397
+				$request
398
+			);
399
+		}
400
+		return $nice_results;
401
+	}
402
+
403
+
404
+	/**
405
+	 * Gets the collection for given relation object
406
+	 * The same as Read::get_entities_from_model(), except if the relation
407
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
408
+	 * the join-model-object into the results
409
+	 *
410
+	 * @param array                  $primary_model_query_params  query params for finding the item from which
411
+	 *                                                            relations will be based
412
+	 * @param EE_Model_Relation_Base $relation
413
+	 * @param WP_REST_Request        $request
414
+	 * @return array|null
415
+	 * @throws DomainException
416
+	 * @throws EE_Error
417
+	 * @throws InvalidArgumentException
418
+	 * @throws InvalidDataTypeException
419
+	 * @throws InvalidInterfaceException
420
+	 * @throws ModelConfigurationException
421
+	 * @throws ReflectionException
422
+	 * @throws RestException
423
+	 * @throws ModelConfigurationException
424
+	 * @throws UnexpectedEntityException
425
+	 * @throws Exception
426
+	 */
427
+	protected function getEntitiesFromRelationUsingModelQueryParams(
428
+		array $primary_model_query_params,
429
+		EE_Model_Relation_Base $relation,
430
+		WP_REST_Request $request
431
+	): ?array {
432
+		$context       = $this->validateContext($request->get_param('caps'));
433
+		$model         = $relation->get_this_model();
434
+		$related_model = $relation->get_other_model();
435
+		if (! isset($primary_model_query_params[0])) {
436
+			$primary_model_query_params[0] = [];
437
+		}
438
+		// check if they can access the 1st model object
439
+		$primary_model_query_params = [
440
+			0       => $primary_model_query_params[0],
441
+			'limit' => 1,
442
+		];
443
+		if ($model instanceof EEM_Soft_Delete_Base) {
444
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
445
+				$primary_model_query_params
446
+			);
447
+		}
448
+		$restricted_query_params          = $primary_model_query_params;
449
+		$restricted_query_params['caps']  = $context;
450
+		$restricted_query_params['limit'] = 1;
451
+		$this->setDebugInfo('main model query params', $restricted_query_params);
452
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
453
+		$primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
454
+		$primary_model_row  = null;
455
+		if (is_array($primary_model_rows)) {
456
+			$primary_model_row = reset($primary_model_rows);
457
+		}
458
+		if (
459
+			! (
460
+				$primary_model_row
461
+				&& Capabilities::currentUserHasPartialAccessTo($related_model, $context)
462
+			)
463
+		) {
464
+			if ($relation instanceof EE_Belongs_To_Relation) {
465
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
466
+			} else {
467
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
468
+					$related_model->get_this_model_name()
469
+				);
470
+			}
471
+			throw new RestException(
472
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
473
+				sprintf(
474
+					esc_html__(
475
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
476
+						'event_espresso'
477
+					),
478
+					$related_model_name_maybe_plural,
479
+					$relation->get_this_model()->get_this_model_name(),
480
+					implode(
481
+						',',
482
+						array_keys(
483
+							Capabilities::getMissingPermissions($related_model, $context)
484
+						)
485
+					)
486
+				),
487
+				['status' => 403]
488
+			);
489
+		}
490
+
491
+		$this->checkPassword(
492
+			$model,
493
+			$primary_model_row,
494
+			$restricted_query_params,
495
+			$request
496
+		);
497
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
498
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
499
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
500
+							  . '.'
501
+							  . $where_condition_key ] = $where_condition_value;
502
+		}
503
+		$query_params['default_where_conditions'] = 'none';
504
+		$query_params['caps']                     = $context;
505
+		if (! $request->get_header('no_rest_headers')) {
506
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
507
+		}
508
+		/** @type array $results */
509
+		$results      = $relation->get_other_model()->get_all_wpdb_results($query_params);
510
+		$nice_results = [];
511
+		foreach ($results as $result) {
512
+			$nice_result = $this->createEntityFromWpdbResult(
513
+				$relation->get_other_model(),
514
+				$result,
515
+				$request
516
+			);
517
+			if ($relation instanceof EE_HABTM_Relation) {
518
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
519
+				// if there are conflicts we prefer the properties from the main model
520
+				$join_model_result = $this->createEntityFromWpdbResult(
521
+					$relation->get_join_model(),
522
+					$result,
523
+					$request
524
+				);
525
+				$joined_result     = array_merge($join_model_result, $nice_result);
526
+				// but keep the meta stuff from the main model
527
+				if (isset($nice_result['meta'])) {
528
+					$joined_result['meta'] = $nice_result['meta'];
529
+				}
530
+				$nice_result = $joined_result;
531
+			}
532
+			$nice_results[] = $nice_result;
533
+		}
534
+		if ($relation instanceof EE_Belongs_To_Relation) {
535
+			return array_shift($nice_results);
536
+		} else {
537
+			return $nice_results;
538
+		}
539
+	}
540
+
541
+
542
+	/**
543
+	 * Gets the collection for given relation object
544
+	 * The same as Read::get_entities_from_model(), except if the relation
545
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
546
+	 * the join-model-object into the results
547
+	 *
548
+	 * @param int|string             $id the ID of the thing we are fetching related stuff from
549
+	 * @param EE_Model_Relation_Base $relation
550
+	 * @param WP_REST_Request        $request
551
+	 * @return array
552
+	 * @throws DomainException
553
+	 * @throws EE_Error
554
+	 * @throws InvalidArgumentException
555
+	 * @throws InvalidDataTypeException
556
+	 * @throws InvalidInterfaceException
557
+	 * @throws ReflectionException
558
+	 * @throws RestException
559
+	 * @throws ModelConfigurationException
560
+	 * @throws UnexpectedEntityException
561
+	 * @throws Exception
562
+	 */
563
+	public function getEntitiesFromRelation($id, EE_Model_Relation_Base $relation, WP_REST_Request $request): array
564
+	{
565
+		if (! $relation->get_this_model()->has_primary_key_field()) {
566
+			throw new EE_Error(
567
+				sprintf(
568
+					esc_html__(
569
+					// @codingStandardsIgnoreStart
570
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
571
+						// @codingStandardsIgnoreEnd
572
+						'event_espresso'
573
+					),
574
+					$relation->get_this_model()->get_this_model_name()
575
+				)
576
+			);
577
+		}
578
+		// can we edit that main item?
579
+		// if not, show nothing but an error
580
+		// otherwise, please proceed
581
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
582
+			[
583
+				[
584
+					$relation->get_this_model()->primary_key_name() => $id,
585
+				],
586
+			],
587
+			$relation,
588
+			$request
589
+		);
590
+	}
591
+
592
+
593
+	/**
594
+	 * Sets the headers that are based on the model and query params,
595
+	 * like the total records. This should only be called on the original request
596
+	 * from the client, not on subsequent internal
597
+	 *
598
+	 * @param EEM_Base $model
599
+	 * @param array    $query_params
600
+	 * @return void
601
+	 * @throws EE_Error
602
+	 * @throws ReflectionException
603
+	 */
604
+	protected function setHeadersFromQueryParams(EEM_Base $model, array $query_params)
605
+	{
606
+		$this->setDebugInfo('model query params', $query_params);
607
+		$this->setDebugInfo(
608
+			'missing caps',
609
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
610
+		);
611
+		// normally the limit to a 2-part array, where the 2nd item is the limit
612
+		if (! isset($query_params['limit'])) {
613
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
614
+		}
615
+		if (is_array($query_params['limit'])) {
616
+			$limit_parts = $query_params['limit'];
617
+		} else {
618
+			$limit_parts = explode(',', $query_params['limit']);
619
+			if (count($limit_parts) === 1) {
620
+				$limit_parts = [0, $limit_parts[0]];
621
+			}
622
+		}
623
+		// remove the group by and having parts of the query, as those will
624
+		// make the sql query return an array of values, instead of just a single value
625
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
626
+		$count = $model->count($query_params, null, true);
627
+		$pages = $count / $limit_parts[1];
628
+		$this->setResponseHeader('Total', $count, false);
629
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
630
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
631
+	}
632
+
633
+
634
+	/**
635
+	 * Changes database results into REST API entities
636
+	 *
637
+	 * @param EEM_Base             $model
638
+	 * @param array                $db_row     like results from $wpdb->get_results()
639
+	 * @param WP_REST_Request|null $rest_request
640
+	 * @param string|null          $deprecated no longer used
641
+	 * @return array ready for being converted into json for sending to client
642
+	 * @throws DomainException
643
+	 * @throws EE_Error
644
+	 * @throws InvalidArgumentException
645
+	 * @throws InvalidDataTypeException
646
+	 * @throws InvalidInterfaceException
647
+	 * @throws ModelConfigurationException
648
+	 * @throws ReflectionException
649
+	 * @throws RestException
650
+	 * @throws RestPasswordIncorrectException
651
+	 * @throws RestPasswordRequiredException
652
+	 * @throws UnexpectedEntityException
653
+	 */
654
+	public function createEntityFromWpdbResult(
655
+		EEM_Base $model,
656
+		array $db_row,
657
+		?WP_REST_Request $rest_request,
658
+		string $deprecated = null
659
+	): array {
660
+		if (! $rest_request instanceof WP_REST_Request) {
661
+			// ok so this was called in the old style, where the 3rd arg was
662
+			// $include, and the 4th arg was $context
663
+			// now setup the request just to avoid fatal errors, although we won't be able
664
+			// to truly make use of it because it's kinda devoid of info
665
+			$rest_request = new WP_REST_Request();
666
+			$rest_request->set_param('include', $rest_request);
667
+			$rest_request->set_param('caps', $deprecated);
668
+		}
669
+		if ($rest_request->get_param('caps') === null) {
670
+			$rest_request->set_param('caps', EEM_Base::caps_read);
671
+		}
672
+		$current_user_full_access_to_entity = $model->currentUserCan(
673
+			EEM_Base::caps_read_admin,
674
+			$model->deduce_fields_n_values_from_cols_n_values($db_row)
675
+		);
676
+		$entity_array                       = $this->createBareEntityFromWpdbResults($model, $db_row);
677
+		$entity_array                       = $this->addExtraFields($model, $db_row, $entity_array);
678
+		$entity_array['_links']             = $this->getEntityLinks($model, $db_row, $entity_array);
679
+		// when it's a regular read request for a model with a password and the password wasn't provided
680
+		// remove the password protected fields
681
+		$has_protected_fields = false;
682
+		try {
683
+			$this->checkPassword(
684
+				$model,
685
+				$db_row,
686
+				$model->alter_query_params_to_restrict_by_ID(
687
+					$model->get_index_primary_key_string(
688
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
689
+					)
690
+				),
691
+				$rest_request
692
+			);
693
+		} catch (RestPasswordRequiredException $e) {
694
+			if ($model->hasPassword()) {
695
+				// just remove protected fields
696
+				$has_protected_fields = true;
697
+				$entity_array         = Capabilities::filterOutPasswordProtectedFields(
698
+					$entity_array,
699
+					$model,
700
+					$this->getModelVersionInfo()
701
+				);
702
+			} else {
703
+				// that's a problem. None of this should be accessible if no password was provided
704
+				throw $e;
705
+			}
706
+		}
707
+
708
+		$entity_array['_calculated_fields'] = $this->getEntityCalculations(
709
+			$model,
710
+			$db_row,
711
+			$rest_request,
712
+			$has_protected_fields
713
+		);
714
+		$entity_array                       = apply_filters(
715
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
716
+			$entity_array,
717
+			$model,
718
+			$rest_request->get_param('caps'),
719
+			$rest_request,
720
+			$this
721
+		);
722
+		// add an empty protected property for now. If it's still around after we remove everything the request didn't
723
+		// want, we'll populate it then. k?
724
+		$entity_array['_protected'] = [];
725
+		// remove any properties the request didn't want. This way _protected won't bother mentioning them
726
+		$entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
727
+		$entity_array = $this->includeRequestedModels(
728
+			$model,
729
+			$rest_request,
730
+			$entity_array,
731
+			$db_row,
732
+			$has_protected_fields
733
+		);
734
+		// if they still wanted the _protected property, add it.
735
+		if (isset($entity_array['_protected'])) {
736
+			$entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
737
+		}
738
+		$entity_array = apply_filters(
739
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
740
+			$entity_array,
741
+			$model,
742
+			$rest_request->get_param('caps'),
743
+			$rest_request,
744
+			$this
745
+		);
746
+		if (! $current_user_full_access_to_entity) {
747
+			$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
748
+				$entity_array,
749
+				$model,
750
+				$rest_request->get_param('caps'),
751
+				$this->getModelVersionInfo()
752
+			);
753
+		} else {
754
+			$result_without_inaccessible_fields = $entity_array;
755
+		}
756
+		$this->setDebugInfo(
757
+			'inaccessible fields',
758
+			array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
759
+		);
760
+		return apply_filters(
761
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
762
+			$result_without_inaccessible_fields,
763
+			$model,
764
+			$rest_request->get_param('caps')
765
+		);
766
+	}
767
+
768
+
769
+	/**
770
+	 * Returns an array describing which fields can be protected, and which actually were removed this request
771
+	 *
772
+	 * @param EEM_Base $model
773
+	 * @param array    $results_so_far
774
+	 * @param bool     $protected
775
+	 * @return array results
776
+	 * @throws EE_Error
777
+	 * @since 4.9.74.p
778
+	 */
779
+	protected function addProtectedProperty(EEM_Base $model, array $results_so_far, bool $protected): array
780
+	{
781
+		if (! $protected || ! $model->hasPassword()) {
782
+			return $results_so_far;
783
+		}
784
+		$password_field  = $model->getPasswordField();
785
+		$all_protected   = array_merge(
786
+			[$password_field->get_name()],
787
+			$password_field->protectedFields()
788
+		);
789
+		$fields_included = array_keys($results_so_far);
790
+		$fields_included = array_intersect(
791
+			$all_protected,
792
+			$fields_included
793
+		);
794
+		foreach ($fields_included as $field_name) {
795
+			$results_so_far['_protected'][] = $field_name;
796
+		}
797
+		return $results_so_far;
798
+	}
799
+
800
+
801
+	/**
802
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
803
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
804
+	 * from $wpdb->get_row( $sql, ARRAY_A)
805
+	 *
806
+	 * @param EEM_Base $model
807
+	 * @param array    $db_row
808
+	 * @return array entity mostly ready for converting to JSON and sending in the response
809
+	 * @throws EE_Error
810
+	 * @throws ReflectionException
811
+	 * @throws RestException
812
+	 * @throws Exception
813
+	 */
814
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, array $db_row): array
815
+	{
816
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
817
+		$result = array_intersect_key(
818
+			$result,
819
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
820
+		);
821
+		// if this is a CPT, we need to set the global $post to it,
822
+		// otherwise shortcodes etc won't work properly while rendering it
823
+		if ($model instanceof EEM_CPT_Base) {
824
+			$do_chevy_shuffle = true;
825
+		} else {
826
+			$do_chevy_shuffle = false;
827
+		}
828
+		if ($do_chevy_shuffle) {
829
+			global $post;
830
+			$old_post = $post;
831
+			$post     = get_post($result[ $model->primary_key_name() ]);
832
+			if (! $post instanceof WP_Post) {
833
+				// well that's weird, because $result is what we JUST fetched from the database
834
+				throw new RestException(
835
+					'error_fetching_post_from_database_results',
836
+					esc_html__(
837
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
838
+						'event_espresso'
839
+					)
840
+				);
841
+			}
842
+			$model_object_classname          = 'EE_' . $model->get_this_model_name();
843
+			$post->{$model_object_classname} = EE_Registry::instance()->load_class(
844
+				$model_object_classname,
845
+				$result,
846
+				false,
847
+				false
848
+			);
849
+		}
850
+		foreach ($result as $field_name => $field_value) {
851
+			$field_obj = $model->field_settings_for($field_name);
852
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
853
+				unset($result[ $field_name ]);
854
+			} elseif (
855
+				$this->isSubclassOfOne(
856
+					$field_obj,
857
+					$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
858
+				)
859
+			) {
860
+				$result[ $field_name ] = [
861
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
862
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
863
+				];
864
+			} elseif (
865
+				$this->isSubclassOfOne(
866
+					$field_obj,
867
+					$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
868
+				)
869
+			) {
870
+				$result[ $field_name ] = [
871
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
872
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
873
+				];
874
+			} elseif ($field_obj instanceof EE_Datetime_Field) {
875
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
876
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
877
+				if (is_null($field_value)) {
878
+					$field_value = $field_obj->getDefaultDateTimeObj();
879
+				}
880
+				if (is_null($field_value)) {
881
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
882
+						$field_obj,
883
+						$field_value,
884
+						$this->getModelVersionInfo()->requestedVersion()
885
+					);
886
+				} else {
887
+					$timezone = $field_value->getTimezone();
888
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
889
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
890
+						$field_obj,
891
+						$field_value,
892
+						$this->getModelVersionInfo()->requestedVersion()
893
+					);
894
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
895
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
896
+						$field_obj,
897
+						$field_value,
898
+						$this->getModelVersionInfo()->requestedVersion()
899
+					);
900
+				}
901
+				$result[ $field_name . '_gmt' ] = $gmt_date;
902
+				$result[ $field_name ]          = $local_date;
903
+			} else {
904
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
905
+			}
906
+		}
907
+		if ($do_chevy_shuffle) {
908
+			$post = $old_post;
909
+		}
910
+		return $result;
911
+	}
912
+
913
+
914
+	/**
915
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
916
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
917
+	 * representation using $field_obj->prepare_for_set_from_db())
918
+	 *
919
+	 * @param EE_Model_Field_Base $field_obj
920
+	 * @param mixed               $value  as it's stored on a model object
921
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
922
+	 * @return array|int
923
+	 * @throws RestException if $value contains a PHP object
924
+	 * @throws EE_Error
925
+	 */
926
+	protected function prepareFieldObjValueForJson(
927
+		EE_Model_Field_Base $field_obj,
928
+		$value,
929
+		string $format = 'normal'
930
+	) {
931
+		$value = $field_obj->prepare_for_set_from_db($value);
932
+		switch ($format) {
933
+			case 'pretty':
934
+				$value = $field_obj->prepare_for_pretty_echoing($value);
935
+				break;
936
+			case 'normal':
937
+			default:
938
+				$value = $field_obj->prepare_for_get($value);
939
+				break;
940
+		}
941
+		return ModelDataTranslator::prepareFieldValuesForJson(
942
+			$field_obj,
943
+			$value,
944
+			$this->getModelVersionInfo()->requestedVersion()
945
+		);
946
+	}
947
+
948
+
949
+	/**
950
+	 * Adds a few extra fields to the entity response
951
+	 *
952
+	 * @param EEM_Base $model
953
+	 * @param array    $db_row
954
+	 * @param array    $entity_array
955
+	 * @return array modified entity
956
+	 * @throws EE_Error
957
+	 */
958
+	protected function addExtraFields(EEM_Base $model, array $db_row, array $entity_array): array
959
+	{
960
+		if ($model instanceof EEM_CPT_Base) {
961
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
962
+		}
963
+		return $entity_array;
964
+	}
965
+
966
+
967
+	/**
968
+	 * Gets links we want to add to the response
969
+	 *
970
+	 * @param EEM_Base        $model
971
+	 * @param array           $db_row
972
+	 * @param array           $entity_array
973
+	 * @return array the _links item in the entity
974
+	 * @throws EE_Error
975
+	 * @global WP_REST_Server $wp_rest_server
976
+	 */
977
+	protected function getEntityLinks(EEM_Base $model, array $db_row, array $entity_array): array
978
+	{
979
+		// add basic links
980
+		$links = [];
981
+		if ($model->has_primary_key_field()) {
982
+			$links['self'] = [
983
+				[
984
+					'href' => $this->getVersionedLinkTo(
985
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
986
+						. '/'
987
+						. $entity_array[ $model->primary_key_name() ]
988
+					),
989
+				],
990
+			];
991
+		}
992
+		$links['collection'] = [
993
+			[
994
+				'href' => $this->getVersionedLinkTo(
995
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
996
+				),
997
+			],
998
+		];
999
+		// add links to related models
1000
+		if ($model->has_primary_key_field()) {
1001
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
1002
+				$related_model_part                                                      =
1003
+					Read::getRelatedEntityName($relation_name, $relation_obj);
1004
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
1005
+					[
1006
+						'href'   => $this->getVersionedLinkTo(
1007
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
1008
+							. '/'
1009
+							. $entity_array[ $model->primary_key_name() ]
1010
+							. '/'
1011
+							. $related_model_part
1012
+						),
1013
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation,
1014
+					],
1015
+				];
1016
+			}
1017
+		}
1018
+		return $links;
1019
+	}
1020
+
1021
+
1022
+	/**
1023
+	 * Adds the included models indicated in the request to the entity provided
1024
+	 *
1025
+	 * @param EEM_Base        $model
1026
+	 * @param WP_REST_Request $rest_request
1027
+	 * @param array           $entity_array
1028
+	 * @param array           $db_row
1029
+	 * @param boolean         $included_items_protected if the original item is password protected, don't include any
1030
+	 *                                                  related models.
1031
+	 * @return array the modified entity
1032
+	 * @throws DomainException
1033
+	 * @throws EE_Error
1034
+	 * @throws InvalidArgumentException
1035
+	 * @throws InvalidDataTypeException
1036
+	 * @throws InvalidInterfaceException
1037
+	 * @throws ModelConfigurationException
1038
+	 * @throws ReflectionException
1039
+	 * @throws UnexpectedEntityException
1040
+	 */
1041
+	protected function includeRequestedModels(
1042
+		EEM_Base $model,
1043
+		WP_REST_Request $rest_request,
1044
+		array $entity_array,
1045
+		array $db_row = [],
1046
+		bool $included_items_protected = false
1047
+	): array {
1048
+		// if $db_row not included, hope the entity array has what we need
1049
+		if (! $db_row) {
1050
+			$db_row = $entity_array;
1051
+		}
1052
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
1053
+		foreach ($relation_settings as $relation_name => $relation_obj) {
1054
+			$related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1055
+				$rest_request->get_param('include'),
1056
+				$relation_name
1057
+			);
1058
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
1059
+				$rest_request->get_param('calculate'),
1060
+				$relation_name
1061
+			);
1062
+			// did they specify they wanted to include a related model, or
1063
+			// specific fields from a related model?
1064
+			// or did they specify to calculate a field from a related model?
1065
+			if ($related_fields_to_include || $related_fields_to_calculate) {
1066
+				// if so, we should include at least some part of the related model
1067
+				$pretend_related_request = new WP_REST_Request();
1068
+				$pretend_related_request->set_query_params(
1069
+					[
1070
+						'caps'      => $rest_request->get_param('caps'),
1071
+						'include'   => $related_fields_to_include,
1072
+						'calculate' => $related_fields_to_calculate,
1073
+						'password'  => $rest_request->get_param('password'),
1074
+					]
1075
+				);
1076
+				$pretend_related_request->add_header('no_rest_headers', true);
1077
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
1078
+					$model->get_index_primary_key_string(
1079
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
1080
+					)
1081
+				);
1082
+				if (! $included_items_protected) {
1083
+					try {
1084
+						$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1085
+							$primary_model_query_params,
1086
+							$relation_obj,
1087
+							$pretend_related_request
1088
+						);
1089
+					} catch (RestException $e) {
1090
+						$related_results = null;
1091
+					}
1092
+				} else {
1093
+					// they're protected, hide them.
1094
+					$related_results              = null;
1095
+					$entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
1096
+				}
1097
+				if ($related_results instanceof WP_Error || $related_results === null) {
1098
+					$related_results = $relation_obj instanceof EE_Belongs_To_Relation
1099
+							? null
1100
+							: [];
1101
+				}
1102
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1103
+			}
1104
+		}
1105
+		return $entity_array;
1106
+	}
1107
+
1108
+
1109
+	/**
1110
+	 * If the user has requested only specific properties (including meta properties like _links or _protected)
1111
+	 * remove everything else.
1112
+	 *
1113
+	 * @param EEM_Base        $model
1114
+	 * @param WP_REST_Request $rest_request
1115
+	 * @param                 $entity_array
1116
+	 * @return array
1117
+	 * @throws EE_Error
1118
+	 * @since 4.9.74.p
1119
+	 */
1120
+	protected function includeOnlyRequestedProperties(
1121
+		EEM_Base $model,
1122
+		WP_REST_Request $rest_request,
1123
+		$entity_array
1124
+	): array {
1125
+
1126
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1127
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
1128
+		// if they passed in * or didn't specify any includes, return everything
1129
+		if (! empty($includes_for_this_model) && ! in_array('*', $includes_for_this_model, true)) {
1130
+			if ($model->has_primary_key_field()) {
1131
+				// always include the primary key. ya just gotta know that at least
1132
+				$includes_for_this_model[] = $model->primary_key_name();
1133
+			}
1134
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1135
+				$includes_for_this_model[] = '_calculated_fields';
1136
+			}
1137
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1138
+		}
1139
+		return $entity_array;
1140
+	}
1141
+
1142
+
1143
+	/**
1144
+	 * Returns a new array with all the names of models removed. Eg
1145
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1146
+	 *
1147
+	 * @param array $array
1148
+	 * @return array
1149
+	 */
1150
+	private function removeModelNamesFromArray(array $array): array
1151
+	{
1152
+		return array_diff($array, array_keys(EE_Registry::instance()->non_abstract_db_models));
1153
+	}
1154
+
1155
+
1156
+	/**
1157
+	 * Gets the calculated fields for the response
1158
+	 *
1159
+	 * @param EEM_Base        $model
1160
+	 * @param array           $wpdb_row
1161
+	 * @param WP_REST_Request $rest_request
1162
+	 * @param bool            $row_is_protected whether this row is password protected or not
1163
+	 * @return stdClass the _calculations item in the entity
1164
+	 * @throws RestException if a default value has a PHP object, which should never do (and if we
1165
+	 *                                          did, let's know about it ASAP, so let the exception bubble up)
1166
+	 * @throws EE_Error
1167
+	 */
1168
+	protected function getEntityCalculations(
1169
+		EEM_Base $model,
1170
+		array $wpdb_row,
1171
+		WP_REST_Request $rest_request,
1172
+		bool $row_is_protected = false
1173
+	): stdClass {
1174
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1175
+			$rest_request->get_param('calculate'),
1176
+			''
1177
+		);
1178
+		// note: setting calculate=* doesn't do anything
1179
+		$calculated_fields_to_return = new stdClass();
1180
+		$protected_fields            = [];
1181
+		foreach ($calculated_fields as $field_to_calculate) {
1182
+			try {
1183
+				// it's password protected, so they shouldn't be able to read this. Remove the value
1184
+				$schema = $this->fields_calculator->getJsonSchemaForModel($model);
1185
+				if (
1186
+					$row_is_protected
1187
+					&& isset($schema['properties'][ $field_to_calculate ]['protected'])
1188
+					&& $schema['properties'][ $field_to_calculate ]['protected']
1189
+				) {
1190
+					$calculated_value   = null;
1191
+					$protected_fields[] = $field_to_calculate;
1192
+					if ($schema['properties'][ $field_to_calculate ]['type']) {
1193
+						switch ($schema['properties'][ $field_to_calculate ]['type']) {
1194
+							case 'boolean':
1195
+								$calculated_value = false;
1196
+								break;
1197
+							case 'integer':
1198
+								$calculated_value = 0;
1199
+								break;
1200
+							case 'string':
1201
+								$calculated_value = '';
1202
+								break;
1203
+							case 'array':
1204
+								$calculated_value = [];
1205
+								break;
1206
+							case 'object':
1207
+								$calculated_value = new stdClass();
1208
+								break;
1209
+						}
1210
+					}
1211
+				} else {
1212
+					$calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1213
+						null,
1214
+						$this->fields_calculator->retrieveCalculatedFieldValue(
1215
+							$model,
1216
+							$field_to_calculate,
1217
+							$wpdb_row,
1218
+							$rest_request,
1219
+							$this
1220
+						),
1221
+						$this->getModelVersionInfo()->requestedVersion()
1222
+					);
1223
+				}
1224
+				$calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1225
+			} catch (RestException $e) {
1226
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
1227
+				$this->setResponseHeader(
1228
+					'Notices-Field-Calculation-Errors['
1229
+					. $e->getStringCode()
1230
+					. ']['
1231
+					. $model->get_this_model_name()
1232
+					. ']['
1233
+					. $field_to_calculate
1234
+					. ']',
1235
+					$e->getMessage()
1236
+				);
1237
+			}
1238
+		}
1239
+		$calculated_fields_to_return->_protected = $protected_fields;
1240
+		return $calculated_fields_to_return;
1241
+	}
1242
+
1243
+
1244
+	/**
1245
+	 * Gets the full URL to the resource, taking the requested version into account
1246
+	 *
1247
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1248
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1249
+	 * @throws EE_Error
1250
+	 */
1251
+	public function getVersionedLinkTo(string $link_part_after_version_and_slash): string
1252
+	{
1253
+		return rest_url(
1254
+			EED_Core_Rest_Api::get_versioned_route_to(
1255
+				$link_part_after_version_and_slash,
1256
+				$this->getModelVersionInfo()->requestedVersion()
1257
+			)
1258
+		);
1259
+	}
1260
+
1261
+
1262
+	/**
1263
+	 * Gets the correct lowercase name for the relation in the API according
1264
+	 * to the relation's type
1265
+	 *
1266
+	 * @param string                 $relation_name
1267
+	 * @param EE_Model_Relation_Base $relation_obj
1268
+	 * @return string
1269
+	 */
1270
+	public static function getRelatedEntityName(string $relation_name, EE_Model_Relation_Base $relation_obj): string
1271
+	{
1272
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1273
+			return strtolower($relation_name);
1274
+		}
1275
+		return EEH_Inflector::pluralize_and_lower($relation_name);
1276
+	}
1277
+
1278
+
1279
+	/**
1280
+	 * Gets the one model object with the specified id for the specified model
1281
+	 *
1282
+	 * @param EEM_Base        $model
1283
+	 * @param WP_REST_Request $request
1284
+	 * @return array
1285
+	 * @throws EE_Error
1286
+	 * @throws InvalidArgumentException
1287
+	 * @throws InvalidDataTypeException
1288
+	 * @throws InvalidInterfaceException
1289
+	 * @throws ModelConfigurationException
1290
+	 * @throws ReflectionException
1291
+	 * @throws RestException
1292
+	 * @throws RestPasswordIncorrectException
1293
+	 * @throws RestPasswordRequiredException
1294
+	 * @throws UnexpectedEntityException
1295
+	 * @throws DomainException
1296
+	 */
1297
+	public function getEntityFromModel(EEM_Base $model, WP_REST_Request $request): array
1298
+	{
1299
+		$context = $this->validateContext($request->get_param('caps'));
1300
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1301
+	}
1302
+
1303
+
1304
+	/**
1305
+	 * If a context is provided which isn't valid, maybe it was added in a future
1306
+	 * version so just treat it as a default read
1307
+	 *
1308
+	 * @param string|null $context
1309
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1310
+	 */
1311
+	public function validateContext(?string $context): string
1312
+	{
1313
+		if (! $context) {
1314
+			$context = EEM_Base::caps_read;
1315
+		}
1316
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1317
+		if (in_array($context, $valid_contexts, true)) {
1318
+			return $context;
1319
+		}
1320
+		return EEM_Base::caps_read;
1321
+	}
1322
+
1323
+
1324
+	/**
1325
+	 * Verifies the passed in value is an allowable default where conditions value.
1326
+	 *
1327
+	 * @param string $default_where_conditions
1328
+	 * @return string
1329
+	 */
1330
+	public function validateDefaultQueryParams(string $default_where_conditions): string
1331
+	{
1332
+		$valid_default_where_conditions_for_api_calls = [
1333
+			EEM_Base::default_where_conditions_all,
1334
+			EEM_Base::default_where_conditions_minimum_all,
1335
+			EEM_Base::default_where_conditions_minimum_others,
1336
+		];
1337
+		if (! $default_where_conditions) {
1338
+			$default_where_conditions = EEM_Base::default_where_conditions_all;
1339
+		}
1340
+		if (
1341
+			in_array(
1342
+				$default_where_conditions,
1343
+				$valid_default_where_conditions_for_api_calls,
1344
+				true
1345
+			)
1346
+		) {
1347
+			return $default_where_conditions;
1348
+		}
1349
+		return EEM_Base::default_where_conditions_all;
1350
+	}
1351
+
1352
+
1353
+	/**
1354
+	 * Translates API filter get parameter into model query params @param EEM_Base $model
1355
+	 *
1356
+	 * @param array $query_params
1357
+	 * @return array model query params (@see
1358
+	 *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1359
+	 *               or FALSE to indicate that absolutely no results should be returned
1360
+	 * @throws EE_Error
1361
+	 * @throws InvalidArgumentException
1362
+	 * @throws InvalidDataTypeException
1363
+	 * @throws InvalidInterfaceException
1364
+	 * @throws RestException
1365
+	 * @throws DomainException
1366
+	 * @throws ReflectionException
1367
+	 * @see
1368
+	 *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1369
+	 *               Note: right now the query parameter keys for fields (and related fields) can be left as-is, but
1370
+	 *               it's quite possible this will change someday. Also, this method's contents might be candidate for
1371
+	 *               moving to Model_Data_Translator
1372
+	 *
1373
+	 */
1374
+	public function createModelQueryParams(EEM_Base $model, array $query_params): array
1375
+	{
1376
+		$model_query_params = [];
1377
+		if (isset($query_params['where'])) {
1378
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1379
+				$query_params['where'],
1380
+				$model,
1381
+				$this->getModelVersionInfo()->requestedVersion()
1382
+			);
1383
+		}
1384
+		if (isset($query_params['order_by'])) {
1385
+			$order_by = $query_params['order_by'];
1386
+		} elseif (isset($query_params['orderby'])) {
1387
+			$order_by = $query_params['orderby'];
1388
+		} else {
1389
+			$order_by = null;
1390
+		}
1391
+		if ($order_by !== null) {
1392
+			if (is_array($order_by)) {
1393
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1394
+			} else {
1395
+				// it's a single item
1396
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1397
+			}
1398
+			$model_query_params['order_by'] = $order_by;
1399
+		}
1400
+		if (isset($query_params['group_by'])) {
1401
+			$group_by = $query_params['group_by'];
1402
+		} elseif (isset($query_params['groupby'])) {
1403
+			$group_by = $query_params['groupby'];
1404
+		} else {
1405
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1406
+		}
1407
+		// make sure they're all real names
1408
+		if (is_array($group_by)) {
1409
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1410
+		}
1411
+		if ($group_by !== null) {
1412
+			$model_query_params['group_by'] = $group_by;
1413
+		}
1414
+		if (isset($query_params['having'])) {
1415
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1416
+				$query_params['having'],
1417
+				$model,
1418
+				$this->getModelVersionInfo()->requestedVersion()
1419
+			);
1420
+		}
1421
+		if (isset($query_params['order'])) {
1422
+			$model_query_params['order'] = $query_params['order'];
1423
+		}
1424
+		if (isset($query_params['mine'])) {
1425
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1426
+		}
1427
+		if (isset($query_params['limit'])) {
1428
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1429
+			if (! is_array($query_params['limit'])) {
1430
+				$limit_array = explode(',', (string) $query_params['limit']);
1431
+			} else {
1432
+				$limit_array = $query_params['limit'];
1433
+			}
1434
+			$sanitized_limit = [];
1435
+			foreach ($limit_array as $limit_part) {
1436
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1437
+					throw new EE_Error(
1438
+						sprintf(
1439
+							esc_html__(
1440
+							// @codingStandardsIgnoreStart
1441
+								'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.',
1442
+								// @codingStandardsIgnoreEnd
1443
+								'event_espresso'
1444
+							),
1445
+							wp_json_encode($query_params['limit'])
1446
+						)
1447
+					);
1448
+				}
1449
+				$sanitized_limit[] = (int) $limit_part;
1450
+			}
1451
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1452
+		} else {
1453
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1454
+		}
1455
+		if (isset($query_params['caps'])) {
1456
+			$model_query_params['caps'] = $this->validateContext($query_params['caps']);
1457
+		} else {
1458
+			$model_query_params['caps'] = EEM_Base::caps_read;
1459
+		}
1460
+		if (isset($query_params['default_where_conditions'])) {
1461
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1462
+				$query_params['default_where_conditions']
1463
+			);
1464
+		}
1465
+		// if this is a model protected by a password on another model, exclude the password protected
1466
+		// entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1467
+		// though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1468
+		if (
1469
+			$model_query_params['caps'] === EEM_Base::caps_read
1470
+			&& empty($query_params['password'])
1471
+			&& ! $model->hasPassword()
1472
+			&& $model->restrictedByRelatedModelPassword()
1473
+		) {
1474
+			$model_query_params['exclude_protected'] = true;
1475
+		}
1476
+
1477
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1478
+	}
1479
+
1480
+
1481
+	/**
1482
+	 * Changes the REST-style query params for use in the models
1483
+	 *
1484
+	 * @param EEM_Base $model
1485
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1486
+	 * @return array
1487
+	 * @deprecated
1488
+	 */
1489
+	public function prepareRestQueryParamsKeyForModels(EEM_Base $model, array $query_params): array
1490
+	{
1491
+		$model_ready_query_params = [];
1492
+		foreach ($query_params as $key => $value) {
1493
+			$model_ready_query_params[ $key ] = is_array($value)
1494
+				? $this->prepareRestQueryParamsKeyForModels($model, $value)
1495
+				: $value;
1496
+		}
1497
+		return $model_ready_query_params;
1498
+	}
1499
+
1500
+
1501
+	/**
1502
+	 * @param $model
1503
+	 * @param $query_params
1504
+	 * @return array
1505
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1506
+	 */
1507
+	public function prepareRestQueryParamsValuesForModels($model, $query_params): array
1508
+	{
1509
+		$model_ready_query_params = [];
1510
+		foreach ($query_params as $key => $value) {
1511
+			if (is_array($value)) {
1512
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1513
+			} else {
1514
+				$model_ready_query_params[ $key ] = $value;
1515
+			}
1516
+		}
1517
+		return $model_ready_query_params;
1518
+	}
1519
+
1520
+
1521
+	/**
1522
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1523
+	 * If no prefix is specified, returns items with no period.
1524
+	 *
1525
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1526
+	 * @param string       $prefix            "Event" or "foobar"
1527
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1528
+	 *                                        we only return strings starting with that and a period; if no prefix was
1529
+	 *                                        specified we return all items containing NO periods
1530
+	 */
1531
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, string $prefix): array
1532
+	{
1533
+		if (is_string($string_to_explode)) {
1534
+			$exploded_contents = explode(',', $string_to_explode);
1535
+		} elseif (is_array($string_to_explode)) {
1536
+			$exploded_contents = $string_to_explode;
1537
+		} else {
1538
+			$exploded_contents = [];
1539
+		}
1540
+		// if the string was empty, we want an empty array
1541
+		$exploded_contents    = array_filter($exploded_contents);
1542
+		$contents_with_prefix = [];
1543
+		foreach ($exploded_contents as $item) {
1544
+			$item = trim($item);
1545
+			// if no prefix was provided, so we look for items with no "." in them
1546
+			if (! $prefix) {
1547
+				// does this item have a period?
1548
+				if (strpos($item, '.') === false) {
1549
+					// if not, then its what we're looking for
1550
+					$contents_with_prefix[] = $item;
1551
+				}
1552
+			} elseif (strpos($item, $prefix . '.') === 0) {
1553
+				// this item has the prefix and a period, grab it
1554
+				$contents_with_prefix[] = substr(
1555
+					$item,
1556
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1557
+				);
1558
+			} elseif ($item === $prefix) {
1559
+				// this item is JUST the prefix
1560
+				// so let's grab everything after, which is a blank string
1561
+				$contents_with_prefix[] = '';
1562
+			}
1563
+		}
1564
+		return $contents_with_prefix;
1565
+	}
1566
+
1567
+
1568
+	/**
1569
+	 * @param string      $include_string @see Read:handle_request_get_all
1570
+	 * @param string|null $model_name
1571
+	 * @return array of fields for this model. If $model_name is provided, then
1572
+	 *                                    the fields for that model, with the model's name removed from each.
1573
+	 *                                    If $include_string was blank or '*' returns an empty array
1574
+	 * @throws EE_Error
1575
+	 * @throws EE_Error
1576
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1577
+	 *                                    Deprecated because its return values were really quite confusing- sometimes
1578
+	 *                                    it
1579
+	 *                                    returned an empty array (when the include string was blank or '*') or
1580
+	 *                                    sometimes it returned array('*') (when you provided a model and a model of
1581
+	 *                                    that kind was found). Parses the $include_string so we fetch all the field
1582
+	 *                                    names relating to THIS model
1583
+	 *                                    (ie have NO period in them), or for the provided model (ie start with the
1584
+	 *                                    model name and then a period).
1585
+	 */
1586
+	public function extractIncludesForThisModel(string $include_string, string $model_name = null): array
1587
+	{
1588
+		if (is_array($include_string)) {
1589
+			$include_string = implode(',', $include_string);
1590
+		}
1591
+		if ($include_string === '*' || $include_string === '') {
1592
+			return [];
1593
+		}
1594
+		$includes                    = explode(',', $include_string);
1595
+		$extracted_fields_to_include = [];
1596
+		if ($model_name) {
1597
+			foreach ($includes as $field_to_include) {
1598
+				$field_to_include = trim($field_to_include);
1599
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1600
+					// found the model name at the exact start
1601
+					$field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1602
+					$extracted_fields_to_include[] = $field_sans_model_name;
1603
+				} elseif ($field_to_include === $model_name) {
1604
+					$extracted_fields_to_include[] = '*';
1605
+				}
1606
+			}
1607
+		} else {
1608
+			// look for ones with no period
1609
+			foreach ($includes as $field_to_include) {
1610
+				$field_to_include = trim($field_to_include);
1611
+				if (
1612
+					strpos($field_to_include, '.') === false
1613
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1614
+				) {
1615
+					$extracted_fields_to_include[] = $field_to_include;
1616
+				}
1617
+			}
1618
+		}
1619
+		return $extracted_fields_to_include;
1620
+	}
1621
+
1622
+
1623
+	/**
1624
+	 * Gets the single item using the model according to the request in the context given, otherwise
1625
+	 * returns that it's inaccessible to the current user
1626
+	 *
1627
+	 * @param EEM_Base        $model
1628
+	 * @param WP_REST_Request $request
1629
+	 * @param null            $context
1630
+	 * @return array
1631
+	 * @throws EE_Error
1632
+	 * @throws ReflectionException
1633
+	 */
1634
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null): array
1635
+	{
1636
+		$query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1];
1637
+		if ($model instanceof EEM_Soft_Delete_Base) {
1638
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1639
+		}
1640
+		$restricted_query_params         = $query_params;
1641
+		$restricted_query_params['caps'] = $context;
1642
+		$this->setDebugInfo('model query params', $restricted_query_params);
1643
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1644
+		if (! empty($model_rows)) {
1645
+			return $this->createEntityFromWpdbResult(
1646
+				$model,
1647
+				reset($model_rows),
1648
+				$request
1649
+			);
1650
+		}
1651
+		// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1652
+		$lowercase_model_name = strtolower($model->get_this_model_name());
1653
+		if ($model->exists($query_params)) {
1654
+			// you got shafted- it existed but we didn't want to tell you!
1655
+			throw new RestException(
1656
+				'rest_user_cannot_' . $context,
1657
+				sprintf(
1658
+					__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1659
+					$context,
1660
+					$lowercase_model_name,
1661
+					Capabilities::getMissingPermissionsString(
1662
+						$model,
1663
+						$context
1664
+					)
1665
+				),
1666
+				['status' => 403]
1667
+			);
1668
+		}
1669
+		// it's not you. It just doesn't exist
1670
+		throw new RestException(
1671
+			sprintf('rest_%s_invalid_id', $lowercase_model_name),
1672
+			sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1673
+			['status' => 404]
1674
+		);
1675
+	}
1676
+
1677
+
1678
+	/**
1679
+	 * Checks that if this content requires a password to be read, that it's been provided and is correct.
1680
+	 *
1681
+	 * @param EEM_Base        $model
1682
+	 * @param array           $model_row
1683
+	 * @param array           $query_params Adds 'default_where_conditions' => 'minimum'
1684
+	 *                                      to ensure we don't confuse trashed with password protected.
1685
+	 * @param WP_REST_Request $request
1686
+	 * @throws EE_Error
1687
+	 * @throws InvalidArgumentException
1688
+	 * @throws InvalidDataTypeException
1689
+	 * @throws InvalidInterfaceException
1690
+	 * @throws RestPasswordRequiredException
1691
+	 * @throws RestPasswordIncorrectException
1692
+	 * @throws ModelConfigurationException
1693
+	 * @throws ReflectionException
1694
+	 * @since 4.9.74.p
1695
+	 */
1696
+	protected function checkPassword(EEM_Base $model, array $model_row, array $query_params, WP_REST_Request $request)
1697
+	{
1698
+		$query_params['default_where_conditions'] = 'minimum';
1699
+		// stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1700
+		// or you don't.
1701
+		$request_caps = $request->get_param('caps');
1702
+		if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1703
+			return;
1704
+		}
1705
+		// if this entity requires a password, they better give it and it better be right!
1706
+		if (
1707
+			$model->hasPassword()
1708
+			&& $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1709
+		) {
1710
+			if (empty($request['password'])) {
1711
+				throw new RestPasswordRequiredException();
1712
+			}
1713
+			if (
1714
+				! hash_equals(
1715
+					$model_row[ $model->getPasswordField()->get_qualified_column() ],
1716
+					$request['password']
1717
+				)
1718
+			) {
1719
+				throw new RestPasswordIncorrectException();
1720
+			}
1721
+		} elseif (
1722
+			// wait! maybe this content is password protected
1723
+			$model->restrictedByRelatedModelPassword()
1724
+			&& $request->get_param('caps') === EEM_Base::caps_read
1725
+		) {
1726
+			$password_supplied = $request->get_param('password');
1727
+			if (empty($password_supplied)) {
1728
+				$query_params['exclude_protected'] = true;
1729
+				if (! $model->exists($query_params)) {
1730
+					throw new RestPasswordRequiredException();
1731
+				}
1732
+			} else {
1733
+				$query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1734
+				if (! $model->exists($query_params)) {
1735
+					throw new RestPasswordIncorrectException();
1736
+				}
1737
+			}
1738
+		}
1739
+	}
1740 1740
 }
Please login to merge, or discard this patch.
core/services/helpers/datetime/AbstractHelper.php 2 patches
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -49,7 +49,7 @@  discard block
 block discarded – undo
49 49
             new DateTimeZone($timezone_string);
50 50
         } catch (Exception $e) {
51 51
             // sometimes we take exception to exceptions
52
-            if (! $throw_error) {
52
+            if ( ! $throw_error) {
53 53
                 return false;
54 54
             }
55 55
             throw new EE_Error(
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
     public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null)
102 102
     {
103 103
         $transition = $this->getTimezoneTransitions($date_time_zone, $time);
104
-        if (! isset($transition['offset'])) {
104
+        if ( ! isset($transition['offset'])) {
105 105
             throw new DomainException(
106 106
                 sprintf(
107 107
                     esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
     public function timezoneSelectInput($timezone_string = '')
124 124
     {
125 125
         // get WP date time format
126
-        $datetime_format = get_option('date_format') . ' ' . get_option('time_format');
126
+        $datetime_format = get_option('date_format').' '.get_option('time_format');
127 127
         // if passed a value, then use that, else get WP option
128 128
         $timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
129 129
         // check if the timezone is valid but don't throw any errors if it isn't
@@ -137,9 +137,9 @@  discard block
 block discarded – undo
137 137
             $timezone_string = 'UTC';
138 138
             $check_zone_info = false;
139 139
             if ($gmt_offset > 0) {
140
-                $timezone_string = 'UTC+' . $gmt_offset;
140
+                $timezone_string = 'UTC+'.$gmt_offset;
141 141
             } elseif ($gmt_offset < 0) {
142
-                $timezone_string = 'UTC' . $gmt_offset;
142
+                $timezone_string = 'UTC'.$gmt_offset;
143 143
             }
144 144
         }
145 145
         ?>
@@ -159,14 +159,14 @@  discard block
 block discarded – undo
159 159
                 esc_html__('%1$sUTC%2$s time is %3$s', 'event_espresso'),
160 160
                 '<abbr title="Coordinated Universal Time">',
161 161
                 '</abbr>',
162
-                '<code>' . date_i18n($datetime_format, false, true) . '</code>'
162
+                '<code>'.date_i18n($datetime_format, false, true).'</code>'
163 163
             );
164 164
             ?></span>
165 165
         <?php
166
-        if (! empty($timezone_string) || ! empty($gmt_offset)) : ?>
166
+        if ( ! empty($timezone_string) || ! empty($gmt_offset)) : ?>
167 167
         <br/>
168 168
         <span><?php
169
-        printf(esc_html__('Local time is %1$s', 'event_espresso'), '<code>' . date_i18n($datetime_format) . '</code>');
169
+        printf(esc_html__('Local time is %1$s', 'event_espresso'), '<code>'.date_i18n($datetime_format).'</code>');
170 170
         ?></span>
171 171
             <?php
172 172
         endif; ?>
@@ -207,7 +207,7 @@  discard block
 block discarded – undo
207 207
                     // transition time from date_i18n().
208 208
                     printf(
209 209
                         $message,
210
-                        '<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
210
+                        '<code >'.date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])).'</code >'
211 211
                     );
212 212
                 } else {
213 213
                     esc_html_e('This timezone does not observe daylight saving time.', 'event_espresso');
@@ -240,7 +240,7 @@  discard block
 block discarded – undo
240 240
         $unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
241 241
         $timezone_string = $this->getValidTimezoneString($timezone_string);
242 242
         $TimeZone        = new DateTimeZone($timezone_string);
243
-        $DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
243
+        $DateTime        = new DateTime('@'.$unix_timestamp, $TimeZone);
244 244
         $offset          = timezone_offset_get($TimeZone, $DateTime);
245 245
         return (int) $DateTime->format('U') + (int) $offset;
246 246
     }
Please login to merge, or discard this patch.
Indentation   +247 added lines, -247 removed lines patch added patch discarded remove patch
@@ -11,136 +11,136 @@  discard block
 block discarded – undo
11 11
 
12 12
 abstract class AbstractHelper implements HelperInterface
13 13
 {
14
-    /**
15
-     * Ensures that a valid timezone string is returned.
16
-     *
17
-     * @param string $timezone_string  When not provided then attempt to use the timezone_string set in the WP Time
18
-     *                                 settings (or derive from set UTC offset).
19
-     * @return string
20
-     * @throws EE_Error
21
-     */
22
-    public function getValidTimezoneString($timezone_string = '')
23
-    {
24
-        $timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
25
-        $timezone_string = ! empty($timezone_string)
26
-            ? $timezone_string
27
-            : $this->getTimezoneStringFromGmtOffset();
28
-        $this->validateTimezone($timezone_string);
29
-        return $timezone_string;
30
-    }
14
+	/**
15
+	 * Ensures that a valid timezone string is returned.
16
+	 *
17
+	 * @param string $timezone_string  When not provided then attempt to use the timezone_string set in the WP Time
18
+	 *                                 settings (or derive from set UTC offset).
19
+	 * @return string
20
+	 * @throws EE_Error
21
+	 */
22
+	public function getValidTimezoneString($timezone_string = '')
23
+	{
24
+		$timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
25
+		$timezone_string = ! empty($timezone_string)
26
+			? $timezone_string
27
+			: $this->getTimezoneStringFromGmtOffset();
28
+		$this->validateTimezone($timezone_string);
29
+		return $timezone_string;
30
+	}
31 31
 
32 32
 
33 33
 
34
-    /**
35
-     * The only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
36
-     *
37
-     * @param string $timezone_string
38
-     * @param bool   $throw_error
39
-     * @return bool
40
-     * @throws EE_Error
41
-     */
42
-    public function validateTimezone($timezone_string, $throw_error = true)
43
-    {
44
-        // easiest way to test a timezone string is just see if it throws an error when you try to create a
45
-        // DateTimeZone object with it
46
-        try {
47
-            new DateTimeZone($timezone_string);
48
-        } catch (Exception $e) {
49
-            // sometimes we take exception to exceptions
50
-            if (! $throw_error) {
51
-                return false;
52
-            }
53
-            throw new EE_Error(
54
-                sprintf(
55
-                    esc_html__(
56
-                        'The timezone given (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
57
-                        'event_espresso'
58
-                    ),
59
-                    $timezone_string,
60
-                    '<a href="http://www.php.net/manual/en/timezones.php">',
61
-                    '</a>'
62
-                )
63
-            );
64
-        }
65
-        return true;
66
-    }
34
+	/**
35
+	 * The only purpose for this static method is to validate that the incoming timezone is a valid php timezone.
36
+	 *
37
+	 * @param string $timezone_string
38
+	 * @param bool   $throw_error
39
+	 * @return bool
40
+	 * @throws EE_Error
41
+	 */
42
+	public function validateTimezone($timezone_string, $throw_error = true)
43
+	{
44
+		// easiest way to test a timezone string is just see if it throws an error when you try to create a
45
+		// DateTimeZone object with it
46
+		try {
47
+			new DateTimeZone($timezone_string);
48
+		} catch (Exception $e) {
49
+			// sometimes we take exception to exceptions
50
+			if (! $throw_error) {
51
+				return false;
52
+			}
53
+			throw new EE_Error(
54
+				sprintf(
55
+					esc_html__(
56
+						'The timezone given (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used',
57
+						'event_espresso'
58
+					),
59
+					$timezone_string,
60
+					'<a href="http://www.php.net/manual/en/timezones.php">',
61
+					'</a>'
62
+				)
63
+			);
64
+		}
65
+		return true;
66
+	}
67 67
 
68 68
 
69
-    /**
70
-     * Gets the site's GMT offset based on either the timezone string
71
-     * (in which case the gmt offset will vary depending on the location's
72
-     * observance of daylight savings time) or the gmt_offset wp option
73
-     *
74
-     * @return int  seconds offset
75
-     */
76
-    public function getSiteTimezoneGmtOffset()
77
-    {
78
-        $timezone_string = (string) get_option('timezone_string');
79
-        if ($timezone_string) {
80
-            try {
81
-                $timezone = new DateTimeZone($timezone_string);
82
-                return $timezone->getOffset(new DateTime()); // in WordPress DateTime defaults to UTC
83
-            } catch (Exception $e) {
84
-            }
85
-        }
86
-        $offset = get_option('gmt_offset');
87
-        return (int) ($offset * HOUR_IN_SECONDS);
88
-    }
69
+	/**
70
+	 * Gets the site's GMT offset based on either the timezone string
71
+	 * (in which case the gmt offset will vary depending on the location's
72
+	 * observance of daylight savings time) or the gmt_offset wp option
73
+	 *
74
+	 * @return int  seconds offset
75
+	 */
76
+	public function getSiteTimezoneGmtOffset()
77
+	{
78
+		$timezone_string = (string) get_option('timezone_string');
79
+		if ($timezone_string) {
80
+			try {
81
+				$timezone = new DateTimeZone($timezone_string);
82
+				return $timezone->getOffset(new DateTime()); // in WordPress DateTime defaults to UTC
83
+			} catch (Exception $e) {
84
+			}
85
+		}
86
+		$offset = get_option('gmt_offset');
87
+		return (int) ($offset * HOUR_IN_SECONDS);
88
+	}
89 89
 
90 90
 
91
-    /**
92
-     * Get Timezone offset for given timezone object
93
-     *
94
-     * @param DateTimeZone $date_time_zone
95
-     * @param null|int     $time
96
-     * @return int
97
-     * @throws DomainException
98
-     */
99
-    public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null)
100
-    {
101
-        $transition = $this->getTimezoneTransitions($date_time_zone, $time);
102
-        if (! isset($transition['offset'])) {
103
-            throw new DomainException(
104
-                sprintf(
105
-                    esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
106
-                    print_r($transition, true)
107
-                )
108
-            );
109
-        }
110
-        return $transition['offset'];
111
-    }
91
+	/**
92
+	 * Get Timezone offset for given timezone object
93
+	 *
94
+	 * @param DateTimeZone $date_time_zone
95
+	 * @param null|int     $time
96
+	 * @return int
97
+	 * @throws DomainException
98
+	 */
99
+	public function getTimezoneOffset(DateTimeZone $date_time_zone, $time = null)
100
+	{
101
+		$transition = $this->getTimezoneTransitions($date_time_zone, $time);
102
+		if (! isset($transition['offset'])) {
103
+			throw new DomainException(
104
+				sprintf(
105
+					esc_html__('An invalid timezone transition was received %1$s', 'event_espresso'),
106
+					print_r($transition, true)
107
+				)
108
+			);
109
+		}
110
+		return $transition['offset'];
111
+	}
112 112
 
113 113
 
114
-    /**
115
-     * Provide a timezone select input
116
-     *
117
-     * @param string $timezone_string
118
-     * @return string
119
-     * @throws EE_Error
120
-     */
121
-    public function timezoneSelectInput($timezone_string = '')
122
-    {
123
-        // get WP date time format
124
-        $datetime_format = get_option('date_format') . ' ' . get_option('time_format');
125
-        // if passed a value, then use that, else get WP option
126
-        $timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
127
-        // check if the timezone is valid but don't throw any errors if it isn't
128
-        $timezone_string = $this->validateTimezone($timezone_string, false)
129
-            ? $timezone_string
130
-            : '';
131
-        $gmt_offset      = get_option('gmt_offset');
132
-        $check_zone_info = true;
133
-        if (empty($timezone_string)) {
134
-            // Create a UTC+- zone if no timezone string exists
135
-            $timezone_string = 'UTC';
136
-            $check_zone_info = false;
137
-            if ($gmt_offset > 0) {
138
-                $timezone_string = 'UTC+' . $gmt_offset;
139
-            } elseif ($gmt_offset < 0) {
140
-                $timezone_string = 'UTC' . $gmt_offset;
141
-            }
142
-        }
143
-        ?>
114
+	/**
115
+	 * Provide a timezone select input
116
+	 *
117
+	 * @param string $timezone_string
118
+	 * @return string
119
+	 * @throws EE_Error
120
+	 */
121
+	public function timezoneSelectInput($timezone_string = '')
122
+	{
123
+		// get WP date time format
124
+		$datetime_format = get_option('date_format') . ' ' . get_option('time_format');
125
+		// if passed a value, then use that, else get WP option
126
+		$timezone_string = ! empty($timezone_string) ? $timezone_string : (string) get_option('timezone_string');
127
+		// check if the timezone is valid but don't throw any errors if it isn't
128
+		$timezone_string = $this->validateTimezone($timezone_string, false)
129
+			? $timezone_string
130
+			: '';
131
+		$gmt_offset      = get_option('gmt_offset');
132
+		$check_zone_info = true;
133
+		if (empty($timezone_string)) {
134
+			// Create a UTC+- zone if no timezone string exists
135
+			$timezone_string = 'UTC';
136
+			$check_zone_info = false;
137
+			if ($gmt_offset > 0) {
138
+				$timezone_string = 'UTC+' . $gmt_offset;
139
+			} elseif ($gmt_offset < 0) {
140
+				$timezone_string = 'UTC' . $gmt_offset;
141
+			}
142
+		}
143
+		?>
144 144
         <p>
145 145
             <label for="timezone_string"><?php esc_html_e('timezone', 'event_espresso'); ?></label>
146 146
             <select id="timezone_string" name="timezone_string">
@@ -153,153 +153,153 @@  discard block
 block discarded – undo
153 153
         <p>
154 154
         <span>
155 155
             <?php
156
-            printf(
157
-                esc_html__('%1$sUTC%2$s time is %3$s', 'event_espresso'),
158
-                '<abbr title="Coordinated Universal Time">',
159
-                '</abbr>',
160
-                '<code>' . date_i18n($datetime_format, false, true) . '</code>'
161
-            );
162
-            ?></span>
156
+			printf(
157
+				esc_html__('%1$sUTC%2$s time is %3$s', 'event_espresso'),
158
+				'<abbr title="Coordinated Universal Time">',
159
+				'</abbr>',
160
+				'<code>' . date_i18n($datetime_format, false, true) . '</code>'
161
+			);
162
+			?></span>
163 163
         <?php
164
-        if (! empty($timezone_string) || ! empty($gmt_offset)) : ?>
164
+		if (! empty($timezone_string) || ! empty($gmt_offset)) : ?>
165 165
         <br/>
166 166
         <span><?php
167
-        printf(esc_html__('Local time is %1$s', 'event_espresso'), '<code>' . date_i18n($datetime_format) . '</code>');
168
-        ?></span>
167
+		printf(esc_html__('Local time is %1$s', 'event_espresso'), '<code>' . date_i18n($datetime_format) . '</code>');
168
+		?></span>
169 169
             <?php
170
-        endif; ?>
170
+		endif; ?>
171 171
 
172 172
         <?php
173
-        if ($check_zone_info && $timezone_string) : ?>
173
+		if ($check_zone_info && $timezone_string) : ?>
174 174
         <br/>
175 175
         <span>
176 176
                 <?php
177
-                // Set TZ so localtime works.
178
-                date_default_timezone_set($timezone_string);
179
-                $now = localtime(time(), true);
180
-                if ($now['tm_isdst']) {
181
-                    esc_html_e('This timezone is currently in daylight saving time.', 'event_espresso');
182
-                } else {
183
-                    esc_html_e('This timezone is currently in standard time.', 'event_espresso');
184
-                }
185
-                ?>
177
+				// Set TZ so localtime works.
178
+				date_default_timezone_set($timezone_string);
179
+				$now = localtime(time(), true);
180
+				if ($now['tm_isdst']) {
181
+					esc_html_e('This timezone is currently in daylight saving time.', 'event_espresso');
182
+				} else {
183
+					esc_html_e('This timezone is currently in standard time.', 'event_espresso');
184
+				}
185
+				?>
186 186
             <br/>
187 187
             <?php
188
-            if (function_exists('timezone_transitions_get')) {
189
-                $found                   = false;
190
-                $date_time_zone_selected = new DateTimeZone($timezone_string);
191
-                $tz_offset               = timezone_offset_get($date_time_zone_selected, date_create());
192
-                $right_now               = time();
193
-                $tr['isdst']             = false;
194
-                foreach (timezone_transitions_get($date_time_zone_selected) as $tr) {
195
-                    if ($tr['ts'] > $right_now) {
196
-                        $found = true;
197
-                        break;
198
-                    }
199
-                }
200
-                if ($found) {
201
-                    $message = $tr['isdst']
202
-                        ? esc_html__(' Daylight saving time begins on: %s.', 'event_espresso')
203
-                        : esc_html__(' Standard time begins  on: %s.', 'event_espresso');
204
-                    // Add the difference between the current offset and the new offset to ts to get the correct
205
-                    // transition time from date_i18n().
206
-                    printf(
207
-                        $message,
208
-                        '<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
209
-                    );
210
-                } else {
211
-                    esc_html_e('This timezone does not observe daylight saving time.', 'event_espresso');
212
-                }
213
-            }
214
-            // Set back to UTC.
215
-            date_default_timezone_set('UTC');
216
-            ?>
188
+			if (function_exists('timezone_transitions_get')) {
189
+				$found                   = false;
190
+				$date_time_zone_selected = new DateTimeZone($timezone_string);
191
+				$tz_offset               = timezone_offset_get($date_time_zone_selected, date_create());
192
+				$right_now               = time();
193
+				$tr['isdst']             = false;
194
+				foreach (timezone_transitions_get($date_time_zone_selected) as $tr) {
195
+					if ($tr['ts'] > $right_now) {
196
+						$found = true;
197
+						break;
198
+					}
199
+				}
200
+				if ($found) {
201
+					$message = $tr['isdst']
202
+						? esc_html__(' Daylight saving time begins on: %s.', 'event_espresso')
203
+						: esc_html__(' Standard time begins  on: %s.', 'event_espresso');
204
+					// Add the difference between the current offset and the new offset to ts to get the correct
205
+					// transition time from date_i18n().
206
+					printf(
207
+						$message,
208
+						'<code >' . date_i18n($datetime_format, $tr['ts'] + ($tz_offset - $tr['offset'])) . '</code >'
209
+					);
210
+				} else {
211
+					esc_html_e('This timezone does not observe daylight saving time.', 'event_espresso');
212
+				}
213
+			}
214
+			// Set back to UTC.
215
+			date_default_timezone_set('UTC');
216
+			?>
217 217
         </span></p>
218 218
             <?php
219
-        endif;
220
-    }
219
+		endif;
220
+	}
221 221
 
222 222
 
223
-    /**
224
-     * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
225
-     * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
226
-     * the site is used.
227
-     * This is used typically when using a Unix timestamp any core WP functions that expect their specially
228
-     * computed timestamp (i.e. date_i18n() )
229
-     *
230
-     * @param int    $unix_timestamp  if 0, then time() will be used.
231
-     * @param string $timezone_string timezone_string. If empty, then the current set timezone for the
232
-     *                                site will be used.
233
-     * @return int      unix_timestamp value with the offset applied for the given timezone.
234
-     * @throws EE_Error
235
-     */
236
-    public function getTimestampWithOffset($unix_timestamp = 0, $timezone_string = '')
237
-    {
238
-        $unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
239
-        $timezone_string = $this->getValidTimezoneString($timezone_string);
240
-        $TimeZone        = new DateTimeZone($timezone_string);
241
-        $DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
242
-        $offset          = timezone_offset_get($TimeZone, $DateTime);
243
-        return (int) $DateTime->format('U') + (int) $offset;
244
-    }
223
+	/**
224
+	 * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string.
225
+	 * If no unix timestamp is given then time() is used.  If no timezone is given then the set timezone string for
226
+	 * the site is used.
227
+	 * This is used typically when using a Unix timestamp any core WP functions that expect their specially
228
+	 * computed timestamp (i.e. date_i18n() )
229
+	 *
230
+	 * @param int    $unix_timestamp  if 0, then time() will be used.
231
+	 * @param string $timezone_string timezone_string. If empty, then the current set timezone for the
232
+	 *                                site will be used.
233
+	 * @return int      unix_timestamp value with the offset applied for the given timezone.
234
+	 * @throws EE_Error
235
+	 */
236
+	public function getTimestampWithOffset($unix_timestamp = 0, $timezone_string = '')
237
+	{
238
+		$unix_timestamp  = $unix_timestamp === 0 ? time() : (int) $unix_timestamp;
239
+		$timezone_string = $this->getValidTimezoneString($timezone_string);
240
+		$TimeZone        = new DateTimeZone($timezone_string);
241
+		$DateTime        = new DateTime('@' . $unix_timestamp, $TimeZone);
242
+		$offset          = timezone_offset_get($TimeZone, $DateTime);
243
+		return (int) $DateTime->format('U') + (int) $offset;
244
+	}
245 245
 
246 246
 
247
-    /**
248
-     * Get Timezone Transitions
249
-     *
250
-     * @param DateTimeZone $date_time_zone
251
-     * @param int|null     $time
252
-     * @param bool         $first_only
253
-     * @return array|mixed
254
-     */
255
-    public function getTimezoneTransitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
256
-    {
257
-        $time        = is_int($time) || $time === null ? $time : (int) strtotime($time);
258
-        $time        = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
259
-        $transitions = $date_time_zone->getTransitions($time);
260
-        return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
261
-    }
247
+	/**
248
+	 * Get Timezone Transitions
249
+	 *
250
+	 * @param DateTimeZone $date_time_zone
251
+	 * @param int|null     $time
252
+	 * @param bool         $first_only
253
+	 * @return array|mixed
254
+	 */
255
+	public function getTimezoneTransitions(DateTimeZone $date_time_zone, $time = null, $first_only = true)
256
+	{
257
+		$time        = is_int($time) || $time === null ? $time : (int) strtotime($time);
258
+		$time        = preg_match(EE_Datetime_Field::unix_timestamp_regex, $time) ? $time : time();
259
+		$transitions = $date_time_zone->getTransitions($time);
260
+		return $first_only && ! isset($transitions['ts']) ? reset($transitions) : $transitions;
261
+	}
262 262
 
263 263
 
264 264
 
265
-    /**
266
-     * Default to just returning the provided $gmt_offset.  Children can override if adjustment needed.
267
-     *
268
-     * @param int $gmt_offset
269
-     * @return int
270
-     */
271
-    public function adjustInvalidGmtOffsets($gmt_offset = 0)
272
-    {
273
-        return $gmt_offset;
274
-    }
265
+	/**
266
+	 * Default to just returning the provided $gmt_offset.  Children can override if adjustment needed.
267
+	 *
268
+	 * @param int $gmt_offset
269
+	 * @return int
270
+	 */
271
+	public function adjustInvalidGmtOffsets($gmt_offset = 0)
272
+	{
273
+		return $gmt_offset;
274
+	}
275 275
 
276 276
 
277 277
 
278
-    /**
279
-     * This receives an incoming gmt_offset and santizes it.  If the provide value is an empty string, then this will
280
-     * attempt to get the offset from the timezone string.  If this returns a string, then a timezone string was
281
-     * successfully derived from existing timezone_string in the db.  If not, then a float is returned for the provided
282
-     * offset.
283
-     * @param  float|string $gmt_offset
284
-     * @return float|string
285
-     */
286
-    protected function sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset)
287
-    {
288
-        // if there is no incoming gmt_offset, then because WP hooks in on timezone_string, we need to see if that is
289
-        // set because it will override `gmt_offset` via `pre_get_option` filter.  If that's set, then let's just use
290
-        // that!  Otherwise we'll leave timezone_string at the default of 'UTC' before doing other logic.
291
-        if ($gmt_offset === '') {
292
-            // autoloaded so no need to set to a variable.  There will not be multiple hits to the db.
293
-            if (get_option('timezone_string')) {
294
-                return (string) get_option('timezone_string');
295
-            }
296
-        }
297
-        $gmt_offset = $gmt_offset !== '' ? $gmt_offset : (string) get_option('gmt_offset');
298
-        $gmt_offset = (float) $gmt_offset;
299
-        // if $gmt_offset is 0 or is still an empty string, then just return UTC
300
-        if ($gmt_offset === (float) 0) {
301
-            return 'UTC';
302
-        }
303
-        return $gmt_offset;
304
-    }
278
+	/**
279
+	 * This receives an incoming gmt_offset and santizes it.  If the provide value is an empty string, then this will
280
+	 * attempt to get the offset from the timezone string.  If this returns a string, then a timezone string was
281
+	 * successfully derived from existing timezone_string in the db.  If not, then a float is returned for the provided
282
+	 * offset.
283
+	 * @param  float|string $gmt_offset
284
+	 * @return float|string
285
+	 */
286
+	protected function sanitizeInitialIncomingGmtOffsetForGettingTimezoneString($gmt_offset)
287
+	{
288
+		// if there is no incoming gmt_offset, then because WP hooks in on timezone_string, we need to see if that is
289
+		// set because it will override `gmt_offset` via `pre_get_option` filter.  If that's set, then let's just use
290
+		// that!  Otherwise we'll leave timezone_string at the default of 'UTC' before doing other logic.
291
+		if ($gmt_offset === '') {
292
+			// autoloaded so no need to set to a variable.  There will not be multiple hits to the db.
293
+			if (get_option('timezone_string')) {
294
+				return (string) get_option('timezone_string');
295
+			}
296
+		}
297
+		$gmt_offset = $gmt_offset !== '' ? $gmt_offset : (string) get_option('gmt_offset');
298
+		$gmt_offset = (float) $gmt_offset;
299
+		// if $gmt_offset is 0 or is still an empty string, then just return UTC
300
+		if ($gmt_offset === (float) 0) {
301
+			return 'UTC';
302
+		}
303
+		return $gmt_offset;
304
+	}
305 305
 }
Please login to merge, or discard this patch.