Completed
Branch master (de4804)
by
unknown
34:50 queued 28:45
created
core/services/licensing/LicenseKeyData.php 2 patches
Indentation   +70 added lines, -70 removed lines patch added patch discarded remove patch
@@ -16,85 +16,85 @@
 block discarded – undo
16 16
  */
17 17
 class LicenseKeyData extends WordPressOption
18 18
 {
19
-    /**
20
-     * The name of the WordPress option where license data is stored.
21
-     */
22
-    const OPTION_NAME = 'event-espresso-license-keys';
19
+	/**
20
+	 * The name of the WordPress option where license data is stored.
21
+	 */
22
+	const OPTION_NAME = 'event-espresso-license-keys';
23 23
 
24
-    private static array $no_license = [
25
-        'item_id'     => false,
26
-        'item_name'   => '',
27
-        'license'     => 'none',
28
-        'license_key' => '',
29
-        'success'     => false,
30
-    ];
24
+	private static array $no_license = [
25
+		'item_id'     => false,
26
+		'item_name'   => '',
27
+		'license'     => 'none',
28
+		'license_key' => '',
29
+		'success'     => false,
30
+	];
31 31
 
32 32
 
33
-    public function __construct()
34
-    {
35
-        parent::__construct(LicenseKeyData::OPTION_NAME, [], true);
36
-    }
33
+	public function __construct()
34
+	{
35
+		parent::__construct(LicenseKeyData::OPTION_NAME, [], true);
36
+	}
37 37
 
38 38
 
39
-    /**
40
-     * Retrieves all stored license data for all plugins.
41
-     *
42
-     * @return array An associative array of all license data, keyed by plugin identifier.
43
-     */
44
-    public function getAllLicenses(): array
45
-    {
46
-        return $this->loadOption();
47
-    }
39
+	/**
40
+	 * Retrieves all stored license data for all plugins.
41
+	 *
42
+	 * @return array An associative array of all license data, keyed by plugin identifier.
43
+	 */
44
+	public function getAllLicenses(): array
45
+	{
46
+		return $this->loadOption();
47
+	}
48 48
 
49 49
 
50
-    /**
51
-     * Retrieves the license data for a specific plugin.
52
-     *
53
-     * @param string $plugin The plugin identifier.
54
-     * @return stdClass An object containing the license data for the specified plugin.
55
-     *                       Returns a default structure if no data exists.
56
-     */
57
-    public function getLicenseDataForPlugin(string $plugin): stdCLass
58
-    {
59
-        $licenses     = $this->loadOption();
60
-        $license_data = $licenses[ $plugin ] ?? LicenseKeyData::$no_license;
61
-        return (object) $license_data;
62
-    }
50
+	/**
51
+	 * Retrieves the license data for a specific plugin.
52
+	 *
53
+	 * @param string $plugin The plugin identifier.
54
+	 * @return stdClass An object containing the license data for the specified plugin.
55
+	 *                       Returns a default structure if no data exists.
56
+	 */
57
+	public function getLicenseDataForPlugin(string $plugin): stdCLass
58
+	{
59
+		$licenses     = $this->loadOption();
60
+		$license_data = $licenses[ $plugin ] ?? LicenseKeyData::$no_license;
61
+		return (object) $license_data;
62
+	}
63 63
 
64 64
 
65
-    /**
66
-     * Updates or adds the license data for a specific plugin.
67
-     *
68
-     * @param stdClass $license_data The new license data to store.
69
-     * @param string   $plugin       The plugin identifier.
70
-     * @param bool     $force_update Whether to force the update operation.
71
-     * @return int The result of the update operation.
72
-     */
73
-    public function updateLicenseDataForPlugin(stdCLass $license_data, string $plugin, bool $force_update = false): int
74
-    {
75
-        if (! isset($license_data->success) || (bool) $license_data->success !== true) {
76
-            return WordPressOption::UPDATE_NONE;
77
-        }
78
-        $licenses = $this->loadOption();
79
-        // convert objects to array and merge new data with old
80
-        $licenses[ $plugin ] = (array) $license_data;
81
-        // then sort by key and convert back to stdCLass
82
-        ksort($licenses[ $plugin ]);
83
-        $licenses[ $plugin ] = (object) $licenses[ $plugin ];
84
-        return $this->updateOption($licenses, $force_update);
85
-    }
65
+	/**
66
+	 * Updates or adds the license data for a specific plugin.
67
+	 *
68
+	 * @param stdClass $license_data The new license data to store.
69
+	 * @param string   $plugin       The plugin identifier.
70
+	 * @param bool     $force_update Whether to force the update operation.
71
+	 * @return int The result of the update operation.
72
+	 */
73
+	public function updateLicenseDataForPlugin(stdCLass $license_data, string $plugin, bool $force_update = false): int
74
+	{
75
+		if (! isset($license_data->success) || (bool) $license_data->success !== true) {
76
+			return WordPressOption::UPDATE_NONE;
77
+		}
78
+		$licenses = $this->loadOption();
79
+		// convert objects to array and merge new data with old
80
+		$licenses[ $plugin ] = (array) $license_data;
81
+		// then sort by key and convert back to stdCLass
82
+		ksort($licenses[ $plugin ]);
83
+		$licenses[ $plugin ] = (object) $licenses[ $plugin ];
84
+		return $this->updateOption($licenses, $force_update);
85
+	}
86 86
 
87 87
 
88
-    /**
89
-     * Removes the license data for a specific plugin.
90
-     *
91
-     * @param string $plugin The plugin identifier.
92
-     * @return int The result of the remove operation.
93
-     */
94
-    public function removeLicenseDataForPlugin(string $plugin): int
95
-    {
96
-        $licenses = $this->loadOption();
97
-        unset($licenses[ $plugin ]);
98
-        return $this->updateOption($licenses);
99
-    }
88
+	/**
89
+	 * Removes the license data for a specific plugin.
90
+	 *
91
+	 * @param string $plugin The plugin identifier.
92
+	 * @return int The result of the remove operation.
93
+	 */
94
+	public function removeLicenseDataForPlugin(string $plugin): int
95
+	{
96
+		$licenses = $this->loadOption();
97
+		unset($licenses[ $plugin ]);
98
+		return $this->updateOption($licenses);
99
+	}
100 100
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@  discard block
 block discarded – undo
57 57
     public function getLicenseDataForPlugin(string $plugin): stdCLass
58 58
     {
59 59
         $licenses     = $this->loadOption();
60
-        $license_data = $licenses[ $plugin ] ?? LicenseKeyData::$no_license;
60
+        $license_data = $licenses[$plugin] ?? LicenseKeyData::$no_license;
61 61
         return (object) $license_data;
62 62
     }
63 63
 
@@ -72,15 +72,15 @@  discard block
 block discarded – undo
72 72
      */
73 73
     public function updateLicenseDataForPlugin(stdCLass $license_data, string $plugin, bool $force_update = false): int
74 74
     {
75
-        if (! isset($license_data->success) || (bool) $license_data->success !== true) {
75
+        if ( ! isset($license_data->success) || (bool) $license_data->success !== true) {
76 76
             return WordPressOption::UPDATE_NONE;
77 77
         }
78 78
         $licenses = $this->loadOption();
79 79
         // convert objects to array and merge new data with old
80
-        $licenses[ $plugin ] = (array) $license_data;
80
+        $licenses[$plugin] = (array) $license_data;
81 81
         // then sort by key and convert back to stdCLass
82
-        ksort($licenses[ $plugin ]);
83
-        $licenses[ $plugin ] = (object) $licenses[ $plugin ];
82
+        ksort($licenses[$plugin]);
83
+        $licenses[$plugin] = (object) $licenses[$plugin];
84 84
         return $this->updateOption($licenses, $force_update);
85 85
     }
86 86
 
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
     public function removeLicenseDataForPlugin(string $plugin): int
95 95
     {
96 96
         $licenses = $this->loadOption();
97
-        unset($licenses[ $plugin ]);
97
+        unset($licenses[$plugin]);
98 98
         return $this->updateOption($licenses);
99 99
     }
100 100
 }
Please login to merge, or discard this patch.
core/services/licensing/PluginLicense.php 2 patches
Indentation   +367 added lines, -367 removed lines patch added patch discarded remove patch
@@ -17,371 +17,371 @@
 block discarded – undo
17 17
  */
18 18
 class PluginLicense
19 19
 {
20
-    private ?LicenseKeyData $license_key_data = null;
21
-
22
-    private ?PluginUpdater $updater = null;
23
-
24
-    private string $license_key = '';
25
-
26
-    private string $mainfile;
27
-
28
-    private string $min_core_version;
29
-
30
-    private string $plugin_id;
31
-
32
-    private string $plugin_name;
33
-
34
-    private string $plugin_slug;
35
-
36
-    private string $status = '';
37
-
38
-    private string $version;
39
-
40
-    private bool $beta;
41
-
42
-    private bool $initialized = false;
43
-
44
-    private bool $wp_override;
45
-
46
-    private static array $slug_prefixes = ['ee-', 'eea-', 'eep-', 'espresso-', 'ee_', 'eea_', 'eep_', 'espresso_'];
47
-
48
-
49
-    public function __construct(
50
-        string $mainfile,
51
-        string $plugin_id,
52
-        string $plugin_name,
53
-        string $plugin_slug,
54
-        string $version,
55
-        bool $beta = false,
56
-        bool $wp_override = false,
57
-        string $min_core_version = ''
58
-    ) {
59
-        $this->mainfile         = $mainfile;
60
-        $this->plugin_id        = $plugin_id;
61
-        $this->plugin_name      = $plugin_name;
62
-        $this->version          = $version;
63
-        $this->beta             = $beta;
64
-        $this->wp_override      = $wp_override;
65
-        $this->plugin_slug      = $this->removePluginSlugPrefixes($plugin_slug);
66
-        $this->min_core_version = $min_core_version;
67
-    }
68
-
69
-
70
-    public function setHooks(): void
71
-    {
72
-        // only set hooks ONCE!
73
-        if ($this->initialized) {
74
-            return;
75
-        }
76
-        add_action('init', [$this, 'loadPluginUpdater']);
77
-        add_action('admin_init', [$this, 'refreshPluginLicenseData'], 99);
78
-        add_action(
79
-            'AHEE__EventEspresso_core_services_licensing_PluginLicenseCollection__loadPluginLicenses',
80
-            [$this, 'loadPluginLicense']
81
-        );
82
-        add_filter(
83
-            'FHEE__LicenseKeysAdminForm__generate__form_subsections',
84
-            [$this, 'addLicenseKeyFormSection']
85
-        );
86
-        add_filter(
87
-            'edd_sl_plugin_updater_api_params',
88
-            [$this, 'addCustomApiParams'],
89
-            10,
90
-            2
91
-        );
92
-        $this->initialized = true;
93
-    }
94
-
95
-
96
-    /**
97
-     * removes unnecessary prefixes from plugin slugs
98
-     *
99
-     * @param string $plugin_slug
100
-     * @return string
101
-     */
102
-    private function removePluginSlugPrefixes(string $plugin_slug): string
103
-    {
104
-        foreach (self::$slug_prefixes as $slug_prefix) {
105
-            if (strpos($plugin_slug, $slug_prefix) === 0) {
106
-                $plugin_slug = str_replace($slug_prefix, '', $plugin_slug);
107
-            }
108
-        }
109
-        return $plugin_slug;
110
-    }
111
-
112
-
113
-    /**
114
-     * @return PluginUpdater|null
115
-     */
116
-    public function updater(): ?PluginUpdater
117
-    {
118
-        return $this->updater;
119
-    }
120
-
121
-
122
-    /**
123
-     * @return string
124
-     */
125
-    public function itemID(): string
126
-    {
127
-        return $this->plugin_id;
128
-    }
129
-
130
-
131
-    /**
132
-     * @return string
133
-     */
134
-    public function itemName(): string
135
-    {
136
-        return $this->plugin_name;
137
-    }
138
-
139
-
140
-    private function getLicenseKeyData(): stdClass
141
-    {
142
-        if (! $this->license_key_data instanceof LicenseKeyData) {
143
-            $this->license_key_data = LoaderFactory::getShared(LicenseKeyData::class);
144
-        }
145
-        return $this->license_key_data->getLicenseDataForPlugin($this->pluginSlug());
146
-    }
147
-
148
-
149
-    /**
150
-     * @return bool
151
-     */
152
-    public function hasLicenseKey(): bool
153
-    {
154
-        return ! empty($this->license_key);
155
-    }
156
-
157
-
158
-    /**
159
-     * @return bool
160
-     */
161
-    public function isMissingLicenseKey(): bool
162
-    {
163
-        return empty($this->license_key);
164
-    }
165
-
166
-
167
-    /**
168
-     * @return string
169
-     */
170
-    public function licenseKey(): string
171
-    {
172
-        return $this->license_key;
173
-    }
174
-
175
-
176
-    /**
177
-     * !!! IMPORTANT !!!
178
-     * This method only sets the license key for this plugin,
179
-     * it does not persist the change to the database.
180
-     * To persist the change, use LicenseKeyData::updateLicenseDataForPlugin(),
181
-     * or call one of the methods on LicenseManager
182
-     * which will also send the change to EDD on the server.
183
-     *
184
-     * @param string $license_key
185
-     */
186
-    public function setLicenseKey(string $license_key): void
187
-    {
188
-        $this->license_key = sanitize_text_field($license_key);
189
-    }
190
-
191
-
192
-    /**
193
-     * @return string
194
-     */
195
-    public function mainfile(): string
196
-    {
197
-        return $this->mainfile;
198
-    }
199
-
200
-
201
-    /**
202
-     * @return string
203
-     * @since 5.0.20.p
204
-     */
205
-    public function minCoreVersion(): string
206
-    {
207
-        return $this->min_core_version;
208
-    }
209
-
210
-
211
-    /**
212
-     * @return string
213
-     */
214
-    public function pluginSlug(): string
215
-    {
216
-        return $this->plugin_slug;
217
-    }
218
-
219
-
220
-    public function status(): string
221
-    {
222
-        return $this->status;
223
-    }
224
-
225
-
226
-    public function setStatus(string $status): void
227
-    {
228
-        $this->status = $status;
229
-    }
230
-
231
-
232
-    /**
233
-     * @return string
234
-     */
235
-    public function version(): string
236
-    {
237
-        return $this->version;
238
-    }
239
-
240
-
241
-    /**
242
-     * @return bool
243
-     */
244
-    public function isBeta(): bool
245
-    {
246
-        return $this->beta;
247
-    }
248
-
249
-
250
-    /**
251
-     * @return bool
252
-     */
253
-    public function isWpOverride(): bool
254
-    {
255
-        return $this->wp_override;
256
-    }
257
-
258
-
259
-    public function loadPluginUpdater()
260
-    {
261
-        // To support auto-updates, this needs to run during the wp_version_check cron job for privileged users.
262
-        if (! current_user_can('manage_options') && ! (defined('DOING_CRON') && DOING_CRON)) {
263
-            return;
264
-        }
265
-
266
-        $license_data = $this->getLicenseKeyData();
267
-        $license_key  = $license_data->license_key ?? '';
268
-        if ($license_key && $this->isMissingLicenseKey()) {
269
-            $this->setLicenseKey($license_key);
270
-        }
271
-
272
-        $this->updater = new PluginUpdater(
273
-            LicenseAPI::url(),
274
-            $this->mainfile(),
275
-            [
276
-                'author'      => LicenseAPI::AUTHOR,
277
-                'beta'        => $this->isBeta(),
278
-                'item_id'     => $this->itemID(),
279
-                'item_name'   => $this->itemName(),
280
-                'license'     => $this->licenseKey(),
281
-                'version'     => $this->version(),
282
-                'wp_override' => $this->isWpOverride(),
283
-            ]
284
-        );
285
-    }
286
-
287
-
288
-    public function loadPluginLicense(PluginLicenseCollection $plugin_license_collection)
289
-    {
290
-        $plugin_license_collection->add($this, $this->pluginSlug());
291
-    }
292
-
293
-
294
-    public function addLicenseKeyFormSection(array $license_keys_form_subsections): array
295
-    {
296
-        if (is_main_site()) {
297
-            $license_keys_form_subsections[ $this->pluginSlug() ] = LoaderFactory::getNew(
298
-                LicenseKeyFormInput::class,
299
-                [$this]
300
-            );
301
-        }
302
-        return $license_keys_form_subsections;
303
-    }
304
-
305
-
306
-    public function addCustomApiParams($api_params, $api_data)
307
-    {
308
-        if ($api_data['item_name'] === $this->itemName()) {
309
-            $api_params['event_espresso_core_version'] = EVENT_ESPRESSO_VERSION;
310
-            $core_license                              =
311
-                $this->license_key_data->getLicenseDataForPlugin(Domain::LICENSE_PLUGIN_SLUG);
312
-            if (! empty($core_license->license_key)) {
313
-                $api_params['event_espresso_core_license'] = $core_license->license_key;
314
-            }
315
-        }
316
-        return $api_params;
317
-    }
318
-
319
-
320
-    /**
321
-     * updates the license key and status for this plugin
322
-     * using the license data previously saved in the database
323
-     *
324
-     * @return void
325
-     * @since 5.0.40.p
326
-     */
327
-    public function refreshPluginLicenseData()
328
-    {
329
-        $license_data = $this->getLicenseKeyData();
330
-        $update       = ! isset($license_data->license) || $license_data->license === 'none';
331
-        $license_key  = $license_data->license_key ?? '';
332
-        if ($this->isMissingLicenseKey()) {
333
-            if (! $license_key) {
334
-                $core_license = $this->license_key_data->getLicenseDataForPlugin(Domain::LICENSE_PLUGIN_SLUG);
335
-                if ($core_license->license_key && $core_license->license === LicenseStatus::VALID) {
336
-                    $license_key = $core_license->license_key;
337
-                    $update      = true;
338
-                } else {
339
-                    $network_config = $this->getNetworkConfig();
340
-                    if (! empty($network_config->core->site_license_key)) {
341
-                        $license_key = $network_config->core->site_license_key;
342
-                        $update      = true;
343
-                    }
344
-                }
345
-            }
346
-            if ($license_key) {
347
-                $this->setLicenseKey($license_key);
348
-            }
349
-        }
350
-        $license_status = $license_data->license ?? '';
351
-        if ($license_status && empty($this->status)) {
352
-            $this->setStatus($license_status);
353
-        }
354
-        if ($update && $this->hasLicenseKey()) {
355
-            $licence_manager = $this->getLicenseManager();
356
-            $licence_manager->checkLicense(
357
-                $this->licenseKey(),
358
-                $this->itemID(),
359
-                $this->itemName(),
360
-                $this->pluginSlug(),
361
-                $this->version(),
362
-                $this->minCoreVersion(),
363
-                $this->status()
364
-            );
365
-        }
366
-    }
367
-
368
-
369
-    private function getNetworkConfig(): EE_Network_Config
370
-    {
371
-        static $network_config = null;
372
-        if (! $network_config instanceof EE_Network_Config) {
373
-            $network_config = LoaderFactory::getShared(EE_Network_Config::class);
374
-        }
375
-        return $network_config;
376
-    }
377
-
378
-
379
-    private function getLicenseManager(): LicenseManager
380
-    {
381
-        static $licence_manager = null;
382
-        if (! $licence_manager instanceof LicenseManager) {
383
-            $licence_manager = LoaderFactory::getShared(LicenseManager::class);
384
-        }
385
-        return $licence_manager;
386
-    }
20
+	private ?LicenseKeyData $license_key_data = null;
21
+
22
+	private ?PluginUpdater $updater = null;
23
+
24
+	private string $license_key = '';
25
+
26
+	private string $mainfile;
27
+
28
+	private string $min_core_version;
29
+
30
+	private string $plugin_id;
31
+
32
+	private string $plugin_name;
33
+
34
+	private string $plugin_slug;
35
+
36
+	private string $status = '';
37
+
38
+	private string $version;
39
+
40
+	private bool $beta;
41
+
42
+	private bool $initialized = false;
43
+
44
+	private bool $wp_override;
45
+
46
+	private static array $slug_prefixes = ['ee-', 'eea-', 'eep-', 'espresso-', 'ee_', 'eea_', 'eep_', 'espresso_'];
47
+
48
+
49
+	public function __construct(
50
+		string $mainfile,
51
+		string $plugin_id,
52
+		string $plugin_name,
53
+		string $plugin_slug,
54
+		string $version,
55
+		bool $beta = false,
56
+		bool $wp_override = false,
57
+		string $min_core_version = ''
58
+	) {
59
+		$this->mainfile         = $mainfile;
60
+		$this->plugin_id        = $plugin_id;
61
+		$this->plugin_name      = $plugin_name;
62
+		$this->version          = $version;
63
+		$this->beta             = $beta;
64
+		$this->wp_override      = $wp_override;
65
+		$this->plugin_slug      = $this->removePluginSlugPrefixes($plugin_slug);
66
+		$this->min_core_version = $min_core_version;
67
+	}
68
+
69
+
70
+	public function setHooks(): void
71
+	{
72
+		// only set hooks ONCE!
73
+		if ($this->initialized) {
74
+			return;
75
+		}
76
+		add_action('init', [$this, 'loadPluginUpdater']);
77
+		add_action('admin_init', [$this, 'refreshPluginLicenseData'], 99);
78
+		add_action(
79
+			'AHEE__EventEspresso_core_services_licensing_PluginLicenseCollection__loadPluginLicenses',
80
+			[$this, 'loadPluginLicense']
81
+		);
82
+		add_filter(
83
+			'FHEE__LicenseKeysAdminForm__generate__form_subsections',
84
+			[$this, 'addLicenseKeyFormSection']
85
+		);
86
+		add_filter(
87
+			'edd_sl_plugin_updater_api_params',
88
+			[$this, 'addCustomApiParams'],
89
+			10,
90
+			2
91
+		);
92
+		$this->initialized = true;
93
+	}
94
+
95
+
96
+	/**
97
+	 * removes unnecessary prefixes from plugin slugs
98
+	 *
99
+	 * @param string $plugin_slug
100
+	 * @return string
101
+	 */
102
+	private function removePluginSlugPrefixes(string $plugin_slug): string
103
+	{
104
+		foreach (self::$slug_prefixes as $slug_prefix) {
105
+			if (strpos($plugin_slug, $slug_prefix) === 0) {
106
+				$plugin_slug = str_replace($slug_prefix, '', $plugin_slug);
107
+			}
108
+		}
109
+		return $plugin_slug;
110
+	}
111
+
112
+
113
+	/**
114
+	 * @return PluginUpdater|null
115
+	 */
116
+	public function updater(): ?PluginUpdater
117
+	{
118
+		return $this->updater;
119
+	}
120
+
121
+
122
+	/**
123
+	 * @return string
124
+	 */
125
+	public function itemID(): string
126
+	{
127
+		return $this->plugin_id;
128
+	}
129
+
130
+
131
+	/**
132
+	 * @return string
133
+	 */
134
+	public function itemName(): string
135
+	{
136
+		return $this->plugin_name;
137
+	}
138
+
139
+
140
+	private function getLicenseKeyData(): stdClass
141
+	{
142
+		if (! $this->license_key_data instanceof LicenseKeyData) {
143
+			$this->license_key_data = LoaderFactory::getShared(LicenseKeyData::class);
144
+		}
145
+		return $this->license_key_data->getLicenseDataForPlugin($this->pluginSlug());
146
+	}
147
+
148
+
149
+	/**
150
+	 * @return bool
151
+	 */
152
+	public function hasLicenseKey(): bool
153
+	{
154
+		return ! empty($this->license_key);
155
+	}
156
+
157
+
158
+	/**
159
+	 * @return bool
160
+	 */
161
+	public function isMissingLicenseKey(): bool
162
+	{
163
+		return empty($this->license_key);
164
+	}
165
+
166
+
167
+	/**
168
+	 * @return string
169
+	 */
170
+	public function licenseKey(): string
171
+	{
172
+		return $this->license_key;
173
+	}
174
+
175
+
176
+	/**
177
+	 * !!! IMPORTANT !!!
178
+	 * This method only sets the license key for this plugin,
179
+	 * it does not persist the change to the database.
180
+	 * To persist the change, use LicenseKeyData::updateLicenseDataForPlugin(),
181
+	 * or call one of the methods on LicenseManager
182
+	 * which will also send the change to EDD on the server.
183
+	 *
184
+	 * @param string $license_key
185
+	 */
186
+	public function setLicenseKey(string $license_key): void
187
+	{
188
+		$this->license_key = sanitize_text_field($license_key);
189
+	}
190
+
191
+
192
+	/**
193
+	 * @return string
194
+	 */
195
+	public function mainfile(): string
196
+	{
197
+		return $this->mainfile;
198
+	}
199
+
200
+
201
+	/**
202
+	 * @return string
203
+	 * @since 5.0.20.p
204
+	 */
205
+	public function minCoreVersion(): string
206
+	{
207
+		return $this->min_core_version;
208
+	}
209
+
210
+
211
+	/**
212
+	 * @return string
213
+	 */
214
+	public function pluginSlug(): string
215
+	{
216
+		return $this->plugin_slug;
217
+	}
218
+
219
+
220
+	public function status(): string
221
+	{
222
+		return $this->status;
223
+	}
224
+
225
+
226
+	public function setStatus(string $status): void
227
+	{
228
+		$this->status = $status;
229
+	}
230
+
231
+
232
+	/**
233
+	 * @return string
234
+	 */
235
+	public function version(): string
236
+	{
237
+		return $this->version;
238
+	}
239
+
240
+
241
+	/**
242
+	 * @return bool
243
+	 */
244
+	public function isBeta(): bool
245
+	{
246
+		return $this->beta;
247
+	}
248
+
249
+
250
+	/**
251
+	 * @return bool
252
+	 */
253
+	public function isWpOverride(): bool
254
+	{
255
+		return $this->wp_override;
256
+	}
257
+
258
+
259
+	public function loadPluginUpdater()
260
+	{
261
+		// To support auto-updates, this needs to run during the wp_version_check cron job for privileged users.
262
+		if (! current_user_can('manage_options') && ! (defined('DOING_CRON') && DOING_CRON)) {
263
+			return;
264
+		}
265
+
266
+		$license_data = $this->getLicenseKeyData();
267
+		$license_key  = $license_data->license_key ?? '';
268
+		if ($license_key && $this->isMissingLicenseKey()) {
269
+			$this->setLicenseKey($license_key);
270
+		}
271
+
272
+		$this->updater = new PluginUpdater(
273
+			LicenseAPI::url(),
274
+			$this->mainfile(),
275
+			[
276
+				'author'      => LicenseAPI::AUTHOR,
277
+				'beta'        => $this->isBeta(),
278
+				'item_id'     => $this->itemID(),
279
+				'item_name'   => $this->itemName(),
280
+				'license'     => $this->licenseKey(),
281
+				'version'     => $this->version(),
282
+				'wp_override' => $this->isWpOverride(),
283
+			]
284
+		);
285
+	}
286
+
287
+
288
+	public function loadPluginLicense(PluginLicenseCollection $plugin_license_collection)
289
+	{
290
+		$plugin_license_collection->add($this, $this->pluginSlug());
291
+	}
292
+
293
+
294
+	public function addLicenseKeyFormSection(array $license_keys_form_subsections): array
295
+	{
296
+		if (is_main_site()) {
297
+			$license_keys_form_subsections[ $this->pluginSlug() ] = LoaderFactory::getNew(
298
+				LicenseKeyFormInput::class,
299
+				[$this]
300
+			);
301
+		}
302
+		return $license_keys_form_subsections;
303
+	}
304
+
305
+
306
+	public function addCustomApiParams($api_params, $api_data)
307
+	{
308
+		if ($api_data['item_name'] === $this->itemName()) {
309
+			$api_params['event_espresso_core_version'] = EVENT_ESPRESSO_VERSION;
310
+			$core_license                              =
311
+				$this->license_key_data->getLicenseDataForPlugin(Domain::LICENSE_PLUGIN_SLUG);
312
+			if (! empty($core_license->license_key)) {
313
+				$api_params['event_espresso_core_license'] = $core_license->license_key;
314
+			}
315
+		}
316
+		return $api_params;
317
+	}
318
+
319
+
320
+	/**
321
+	 * updates the license key and status for this plugin
322
+	 * using the license data previously saved in the database
323
+	 *
324
+	 * @return void
325
+	 * @since 5.0.40.p
326
+	 */
327
+	public function refreshPluginLicenseData()
328
+	{
329
+		$license_data = $this->getLicenseKeyData();
330
+		$update       = ! isset($license_data->license) || $license_data->license === 'none';
331
+		$license_key  = $license_data->license_key ?? '';
332
+		if ($this->isMissingLicenseKey()) {
333
+			if (! $license_key) {
334
+				$core_license = $this->license_key_data->getLicenseDataForPlugin(Domain::LICENSE_PLUGIN_SLUG);
335
+				if ($core_license->license_key && $core_license->license === LicenseStatus::VALID) {
336
+					$license_key = $core_license->license_key;
337
+					$update      = true;
338
+				} else {
339
+					$network_config = $this->getNetworkConfig();
340
+					if (! empty($network_config->core->site_license_key)) {
341
+						$license_key = $network_config->core->site_license_key;
342
+						$update      = true;
343
+					}
344
+				}
345
+			}
346
+			if ($license_key) {
347
+				$this->setLicenseKey($license_key);
348
+			}
349
+		}
350
+		$license_status = $license_data->license ?? '';
351
+		if ($license_status && empty($this->status)) {
352
+			$this->setStatus($license_status);
353
+		}
354
+		if ($update && $this->hasLicenseKey()) {
355
+			$licence_manager = $this->getLicenseManager();
356
+			$licence_manager->checkLicense(
357
+				$this->licenseKey(),
358
+				$this->itemID(),
359
+				$this->itemName(),
360
+				$this->pluginSlug(),
361
+				$this->version(),
362
+				$this->minCoreVersion(),
363
+				$this->status()
364
+			);
365
+		}
366
+	}
367
+
368
+
369
+	private function getNetworkConfig(): EE_Network_Config
370
+	{
371
+		static $network_config = null;
372
+		if (! $network_config instanceof EE_Network_Config) {
373
+			$network_config = LoaderFactory::getShared(EE_Network_Config::class);
374
+		}
375
+		return $network_config;
376
+	}
377
+
378
+
379
+	private function getLicenseManager(): LicenseManager
380
+	{
381
+		static $licence_manager = null;
382
+		if (! $licence_manager instanceof LicenseManager) {
383
+			$licence_manager = LoaderFactory::getShared(LicenseManager::class);
384
+		}
385
+		return $licence_manager;
386
+	}
387 387
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
 
140 140
     private function getLicenseKeyData(): stdClass
141 141
     {
142
-        if (! $this->license_key_data instanceof LicenseKeyData) {
142
+        if ( ! $this->license_key_data instanceof LicenseKeyData) {
143 143
             $this->license_key_data = LoaderFactory::getShared(LicenseKeyData::class);
144 144
         }
145 145
         return $this->license_key_data->getLicenseDataForPlugin($this->pluginSlug());
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
     public function loadPluginUpdater()
260 260
     {
261 261
         // To support auto-updates, this needs to run during the wp_version_check cron job for privileged users.
262
-        if (! current_user_can('manage_options') && ! (defined('DOING_CRON') && DOING_CRON)) {
262
+        if ( ! current_user_can('manage_options') && ! (defined('DOING_CRON') && DOING_CRON)) {
263 263
             return;
264 264
         }
265 265
 
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
     public function addLicenseKeyFormSection(array $license_keys_form_subsections): array
295 295
     {
296 296
         if (is_main_site()) {
297
-            $license_keys_form_subsections[ $this->pluginSlug() ] = LoaderFactory::getNew(
297
+            $license_keys_form_subsections[$this->pluginSlug()] = LoaderFactory::getNew(
298 298
                 LicenseKeyFormInput::class,
299 299
                 [$this]
300 300
             );
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
             $api_params['event_espresso_core_version'] = EVENT_ESPRESSO_VERSION;
310 310
             $core_license                              =
311 311
                 $this->license_key_data->getLicenseDataForPlugin(Domain::LICENSE_PLUGIN_SLUG);
312
-            if (! empty($core_license->license_key)) {
312
+            if ( ! empty($core_license->license_key)) {
313 313
                 $api_params['event_espresso_core_license'] = $core_license->license_key;
314 314
             }
315 315
         }
@@ -330,14 +330,14 @@  discard block
 block discarded – undo
330 330
         $update       = ! isset($license_data->license) || $license_data->license === 'none';
331 331
         $license_key  = $license_data->license_key ?? '';
332 332
         if ($this->isMissingLicenseKey()) {
333
-            if (! $license_key) {
333
+            if ( ! $license_key) {
334 334
                 $core_license = $this->license_key_data->getLicenseDataForPlugin(Domain::LICENSE_PLUGIN_SLUG);
335 335
                 if ($core_license->license_key && $core_license->license === LicenseStatus::VALID) {
336 336
                     $license_key = $core_license->license_key;
337 337
                     $update      = true;
338 338
                 } else {
339 339
                     $network_config = $this->getNetworkConfig();
340
-                    if (! empty($network_config->core->site_license_key)) {
340
+                    if ( ! empty($network_config->core->site_license_key)) {
341 341
                         $license_key = $network_config->core->site_license_key;
342 342
                         $update      = true;
343 343
                     }
@@ -369,7 +369,7 @@  discard block
 block discarded – undo
369 369
     private function getNetworkConfig(): EE_Network_Config
370 370
     {
371 371
         static $network_config = null;
372
-        if (! $network_config instanceof EE_Network_Config) {
372
+        if ( ! $network_config instanceof EE_Network_Config) {
373 373
             $network_config = LoaderFactory::getShared(EE_Network_Config::class);
374 374
         }
375 375
         return $network_config;
@@ -379,7 +379,7 @@  discard block
 block discarded – undo
379 379
     private function getLicenseManager(): LicenseManager
380 380
     {
381 381
         static $licence_manager = null;
382
-        if (! $licence_manager instanceof LicenseManager) {
382
+        if ( ! $licence_manager instanceof LicenseManager) {
383 383
             $licence_manager = LoaderFactory::getShared(LicenseManager::class);
384 384
         }
385 385
         return $licence_manager;
Please login to merge, or discard this patch.
core/services/licensing/LicenseManager.php 2 patches
Indentation   +159 added lines, -159 removed lines patch added patch discarded remove patch
@@ -6,163 +6,163 @@
 block discarded – undo
6 6
 
7 7
 class LicenseManager
8 8
 {
9
-    private LicenseAPI $license_api;
10
-
11
-    private LicenseKeyData $license_key_data;
12
-
13
-    private PluginLicenseCollection $plugin_license_collection;
14
-
15
-
16
-    public function __construct(
17
-        LicenseAPI $license_api,
18
-        LicenseKeyData $license_key_data,
19
-        PluginLicenseCollection $plugin_license_collection
20
-    ) {
21
-        $this->license_api               = $license_api;
22
-        $this->license_key_data          = $license_key_data;
23
-        $this->plugin_license_collection = $plugin_license_collection;
24
-    }
25
-
26
-
27
-    public function activateLicense(
28
-        string $license_key,
29
-        string $item_id,
30
-        string $item_name,
31
-        string $plugin_slug,
32
-        string $plugin_version,
33
-        string $min_core_version = ''
34
-    ): stdCLass {
35
-        $license_data = $this->license_api->postRequest(
36
-            LicenseAPI::ACTION_ACTIVATE,
37
-            $license_key,
38
-            $item_id,
39
-            $item_name,
40
-            $plugin_version,
41
-            $min_core_version
42
-        );
43
-        return $this->updateLicenseData(
44
-            $plugin_slug,
45
-            $license_key,
46
-            $license_data,
47
-            $license_data->license ?? '',
48
-            true
49
-        );
50
-    }
51
-
52
-
53
-    public function deactivateLicense(
54
-        string $license_key,
55
-        string $item_id,
56
-        string $item_name,
57
-        string $plugin_slug,
58
-        string $plugin_version,
59
-        string $min_core_version = ''
60
-    ): stdCLass {
61
-        $license_data = $this->license_api->postRequest(
62
-            LicenseAPI::ACTION_DEACTIVATE,
63
-            $license_key,
64
-            $item_id,
65
-            $item_name,
66
-            $plugin_version,
67
-            $min_core_version
68
-        );
69
-        $this->license_key_data->removeLicenseDataForPlugin($plugin_slug);
70
-        return $license_data;
71
-    }
72
-
73
-
74
-    public function resetLicenseKey(string $plugin_slug): stdCLass
75
-    {
76
-        $license_data              = $this->getLicenseData($plugin_slug);
77
-        $license_data->license_key = '';
78
-        $this->license_key_data->updateLicenseDataForPlugin($license_data, $plugin_slug, true);
79
-        return $license_data;
80
-    }
81
-
82
-
83
-    public function checkLicense(
84
-        string $license_key,
85
-        string $item_id,
86
-        string $item_name,
87
-        string $plugin_slug,
88
-        string $plugin_version,
89
-        string $min_core_version = '',
90
-        string $license_status = ''
91
-    ): stdCLass {
92
-        $license_data = $this->license_api->postRequest(
93
-            LicenseAPI::ACTION_CHECK,
94
-            $license_key,
95
-            $item_id,
96
-            $item_name,
97
-            $plugin_version,
98
-            $min_core_version
99
-        );
100
-        return $this->updateLicenseData(
101
-            $plugin_slug,
102
-            $license_key,
103
-            $license_data,
104
-            $license_status
105
-        );
106
-    }
107
-
108
-
109
-    public function getLicenseData(string $plugin_slug): stdClass
110
-    {
111
-        return $this->license_key_data->getLicenseDataForPlugin($plugin_slug);
112
-    }
113
-
114
-
115
-    public function getVersionInfo(): stdClass
116
-    {
117
-        $products = [];
118
-        foreach ($this->plugin_license_collection as $plugin_license) {
119
-            if (! $plugin_license instanceof PluginLicense) {
120
-                continue;
121
-            }
122
-            $products[ $plugin_license->pluginSlug() ] = [
123
-                'item_id' => $plugin_license->itemId(),
124
-                'license' => $plugin_license->licenseKey(),
125
-                'url'     => LicenseAPI::url(),
126
-            ];
127
-        }
128
-        return $this->license_api->getProductVersions($products);
129
-    }
130
-
131
-
132
-    /**
133
-     * @param string   $plugin_slug
134
-     * @param string   $license_key
135
-     * @param stdClass $license_data
136
-     * @param string   $license_status
137
-     * @param bool     $force_update    true for license activation requests
138
-     * @return stdClass
139
-     * @since 5.0.40.p
140
-     */
141
-    private function updateLicenseData(
142
-        string $plugin_slug,
143
-        string $license_key,
144
-        stdClass $license_data,
145
-        string $license_status = '',
146
-        bool $force_update = false
147
-    ): stdClass {
148
-        if (! isset($license_data->license_key)) {
149
-            $license_data->license_key = $license_key;
150
-        }
151
-        // if the license key or license status has changed, then update the license data
152
-        $success = $license_data->success ?? false;
153
-        if (
154
-            $success
155
-            && (
156
-                $force_update
157
-                || (
158
-                    (! empty($license_data->license_key) && $license_data->license_key !== $license_key)
159
-                    || (! empty($license_data->license) && $license_data->license !== $license_status)
160
-                )
161
-            )
162
-        ) {
163
-            $this->license_key_data->updateLicenseDataForPlugin($license_data, $plugin_slug);
164
-        }
165
-
166
-        return $license_data;
167
-    }
9
+	private LicenseAPI $license_api;
10
+
11
+	private LicenseKeyData $license_key_data;
12
+
13
+	private PluginLicenseCollection $plugin_license_collection;
14
+
15
+
16
+	public function __construct(
17
+		LicenseAPI $license_api,
18
+		LicenseKeyData $license_key_data,
19
+		PluginLicenseCollection $plugin_license_collection
20
+	) {
21
+		$this->license_api               = $license_api;
22
+		$this->license_key_data          = $license_key_data;
23
+		$this->plugin_license_collection = $plugin_license_collection;
24
+	}
25
+
26
+
27
+	public function activateLicense(
28
+		string $license_key,
29
+		string $item_id,
30
+		string $item_name,
31
+		string $plugin_slug,
32
+		string $plugin_version,
33
+		string $min_core_version = ''
34
+	): stdCLass {
35
+		$license_data = $this->license_api->postRequest(
36
+			LicenseAPI::ACTION_ACTIVATE,
37
+			$license_key,
38
+			$item_id,
39
+			$item_name,
40
+			$plugin_version,
41
+			$min_core_version
42
+		);
43
+		return $this->updateLicenseData(
44
+			$plugin_slug,
45
+			$license_key,
46
+			$license_data,
47
+			$license_data->license ?? '',
48
+			true
49
+		);
50
+	}
51
+
52
+
53
+	public function deactivateLicense(
54
+		string $license_key,
55
+		string $item_id,
56
+		string $item_name,
57
+		string $plugin_slug,
58
+		string $plugin_version,
59
+		string $min_core_version = ''
60
+	): stdCLass {
61
+		$license_data = $this->license_api->postRequest(
62
+			LicenseAPI::ACTION_DEACTIVATE,
63
+			$license_key,
64
+			$item_id,
65
+			$item_name,
66
+			$plugin_version,
67
+			$min_core_version
68
+		);
69
+		$this->license_key_data->removeLicenseDataForPlugin($plugin_slug);
70
+		return $license_data;
71
+	}
72
+
73
+
74
+	public function resetLicenseKey(string $plugin_slug): stdCLass
75
+	{
76
+		$license_data              = $this->getLicenseData($plugin_slug);
77
+		$license_data->license_key = '';
78
+		$this->license_key_data->updateLicenseDataForPlugin($license_data, $plugin_slug, true);
79
+		return $license_data;
80
+	}
81
+
82
+
83
+	public function checkLicense(
84
+		string $license_key,
85
+		string $item_id,
86
+		string $item_name,
87
+		string $plugin_slug,
88
+		string $plugin_version,
89
+		string $min_core_version = '',
90
+		string $license_status = ''
91
+	): stdCLass {
92
+		$license_data = $this->license_api->postRequest(
93
+			LicenseAPI::ACTION_CHECK,
94
+			$license_key,
95
+			$item_id,
96
+			$item_name,
97
+			$plugin_version,
98
+			$min_core_version
99
+		);
100
+		return $this->updateLicenseData(
101
+			$plugin_slug,
102
+			$license_key,
103
+			$license_data,
104
+			$license_status
105
+		);
106
+	}
107
+
108
+
109
+	public function getLicenseData(string $plugin_slug): stdClass
110
+	{
111
+		return $this->license_key_data->getLicenseDataForPlugin($plugin_slug);
112
+	}
113
+
114
+
115
+	public function getVersionInfo(): stdClass
116
+	{
117
+		$products = [];
118
+		foreach ($this->plugin_license_collection as $plugin_license) {
119
+			if (! $plugin_license instanceof PluginLicense) {
120
+				continue;
121
+			}
122
+			$products[ $plugin_license->pluginSlug() ] = [
123
+				'item_id' => $plugin_license->itemId(),
124
+				'license' => $plugin_license->licenseKey(),
125
+				'url'     => LicenseAPI::url(),
126
+			];
127
+		}
128
+		return $this->license_api->getProductVersions($products);
129
+	}
130
+
131
+
132
+	/**
133
+	 * @param string   $plugin_slug
134
+	 * @param string   $license_key
135
+	 * @param stdClass $license_data
136
+	 * @param string   $license_status
137
+	 * @param bool     $force_update    true for license activation requests
138
+	 * @return stdClass
139
+	 * @since 5.0.40.p
140
+	 */
141
+	private function updateLicenseData(
142
+		string $plugin_slug,
143
+		string $license_key,
144
+		stdClass $license_data,
145
+		string $license_status = '',
146
+		bool $force_update = false
147
+	): stdClass {
148
+		if (! isset($license_data->license_key)) {
149
+			$license_data->license_key = $license_key;
150
+		}
151
+		// if the license key or license status has changed, then update the license data
152
+		$success = $license_data->success ?? false;
153
+		if (
154
+			$success
155
+			&& (
156
+				$force_update
157
+				|| (
158
+					(! empty($license_data->license_key) && $license_data->license_key !== $license_key)
159
+					|| (! empty($license_data->license) && $license_data->license !== $license_status)
160
+				)
161
+			)
162
+		) {
163
+			$this->license_key_data->updateLicenseDataForPlugin($license_data, $plugin_slug);
164
+		}
165
+
166
+		return $license_data;
167
+	}
168 168
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -116,10 +116,10 @@  discard block
 block discarded – undo
116 116
     {
117 117
         $products = [];
118 118
         foreach ($this->plugin_license_collection as $plugin_license) {
119
-            if (! $plugin_license instanceof PluginLicense) {
119
+            if ( ! $plugin_license instanceof PluginLicense) {
120 120
                 continue;
121 121
             }
122
-            $products[ $plugin_license->pluginSlug() ] = [
122
+            $products[$plugin_license->pluginSlug()] = [
123 123
                 'item_id' => $plugin_license->itemId(),
124 124
                 'license' => $plugin_license->licenseKey(),
125 125
                 'url'     => LicenseAPI::url(),
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
         string $license_status = '',
146 146
         bool $force_update = false
147 147
     ): stdClass {
148
-        if (! isset($license_data->license_key)) {
148
+        if ( ! isset($license_data->license_key)) {
149 149
             $license_data->license_key = $license_key;
150 150
         }
151 151
         // if the license key or license status has changed, then update the license data
@@ -155,8 +155,8 @@  discard block
 block discarded – undo
155 155
             && (
156 156
                 $force_update
157 157
                 || (
158
-                    (! empty($license_data->license_key) && $license_data->license_key !== $license_key)
159
-                    || (! empty($license_data->license) && $license_data->license !== $license_status)
158
+                    ( ! empty($license_data->license_key) && $license_data->license_key !== $license_key)
159
+                    || ( ! empty($license_data->license) && $license_data->license !== $license_status)
160 160
                 )
161 161
             )
162 162
         ) {
Please login to merge, or discard this patch.
core/services/licensing/AddonLicense.php 2 patches
Indentation   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -18,64 +18,64 @@
 block discarded – undo
18 18
  */
19 19
 class AddonLicense
20 20
 {
21
-    public static function register(string $addon_name, array $license_data)
22
-    {
23
-        if (! $addon_name || ! $license_data) {
24
-            return;
25
-        }
26
-        // also bail if the feature flag is not enabled
27
-        $feature = LoaderFactory::getShared(FeatureFlags::class);
28
-        if (! $feature->allowed('use_edd_plugin_licensing')) {
29
-            return;
30
-        }
31
-        $main_file_path = $license_data['main_file_path'] ?? '';
32
-        $main_file_slug = AddonLicense::derivePluginSlugFromMainFile($main_file_path);
33
-        // use values from addon IF SET
34
-        $plugin_slug = $license_data['plugin_slug'] ?? '';
35
-        $plugin_id   =  $license_data['plugin_id'] ?? 0;
36
-        $plugin_name =  $license_data['plugin_name'] ?? '';
21
+	public static function register(string $addon_name, array $license_data)
22
+	{
23
+		if (! $addon_name || ! $license_data) {
24
+			return;
25
+		}
26
+		// also bail if the feature flag is not enabled
27
+		$feature = LoaderFactory::getShared(FeatureFlags::class);
28
+		if (! $feature->allowed('use_edd_plugin_licensing')) {
29
+			return;
30
+		}
31
+		$main_file_path = $license_data['main_file_path'] ?? '';
32
+		$main_file_slug = AddonLicense::derivePluginSlugFromMainFile($main_file_path);
33
+		// use values from addon IF SET
34
+		$plugin_slug = $license_data['plugin_slug'] ?? '';
35
+		$plugin_id   =  $license_data['plugin_id'] ?? 0;
36
+		$plugin_name =  $license_data['plugin_name'] ?? '';
37 37
 
38
-        // if the plugin ID has been set to ZERO, then we are using a pre-EDD plugin,
39
-        // so use the plugin slug derived from the main file path.
40
-        // also try to derive the plugin ID and name from the plugin slug.
41
-        // set the plugin name first else we can't check if plugin id is 0 !!!
42
-        $plugin_slug = $plugin_id && $plugin_slug ? $plugin_slug : $main_file_slug;
43
-        $plugin_name = $plugin_id && $plugin_name ? $plugin_name : AddonEddData::getPluginItemName($main_file_slug);
44
-        $plugin_id   = $plugin_id ?: AddonEddData::getPluginItemID($main_file_slug);
38
+		// if the plugin ID has been set to ZERO, then we are using a pre-EDD plugin,
39
+		// so use the plugin slug derived from the main file path.
40
+		// also try to derive the plugin ID and name from the plugin slug.
41
+		// set the plugin name first else we can't check if plugin id is 0 !!!
42
+		$plugin_slug = $plugin_id && $plugin_slug ? $plugin_slug : $main_file_slug;
43
+		$plugin_name = $plugin_id && $plugin_name ? $plugin_name : AddonEddData::getPluginItemName($main_file_slug);
44
+		$plugin_id   = $plugin_id ?: AddonEddData::getPluginItemID($main_file_slug);
45 45
 
46
-        // ensure defaults are set
47
-        $license_data = [
48
-            'beta'             => false,
49
-            'main_file_path'   => $license_data['main_file_path'] ?? '',
50
-            'min_core_version' => $license_data['min_core_version'] ?? '',
51
-            'plugin_id'        => $plugin_id,
52
-            'plugin_name'      => $plugin_name,
53
-            'plugin_slug'      => $plugin_slug,
54
-            'version'          => $license_data['version'],
55
-            'wp_override'      => false,
56
-        ];
46
+		// ensure defaults are set
47
+		$license_data = [
48
+			'beta'             => false,
49
+			'main_file_path'   => $license_data['main_file_path'] ?? '',
50
+			'min_core_version' => $license_data['min_core_version'] ?? '',
51
+			'plugin_id'        => $plugin_id,
52
+			'plugin_name'      => $plugin_name,
53
+			'plugin_slug'      => $plugin_slug,
54
+			'version'          => $license_data['version'],
55
+			'wp_override'      => false,
56
+		];
57 57
 
58
-        // Bail if we still don't have a plugin ID.
59
-        if (empty($license_data['plugin_id'])) {
60
-            return;
61
-        }
58
+		// Bail if we still don't have a plugin ID.
59
+		if (empty($license_data['plugin_id'])) {
60
+			return;
61
+		}
62 62
 
63
-        $addon_license = new PluginLicense(
64
-            $license_data['main_file_path'],
65
-            $license_data['plugin_id'],
66
-            $license_data['plugin_name'],
67
-            $license_data['plugin_slug'],
68
-            $license_data['version'],
69
-            $license_data['beta'],
70
-            $license_data['wp_override'],
71
-            $license_data['min_core_version']
72
-        );
73
-        $addon_license->setHooks();
74
-    }
63
+		$addon_license = new PluginLicense(
64
+			$license_data['main_file_path'],
65
+			$license_data['plugin_id'],
66
+			$license_data['plugin_name'],
67
+			$license_data['plugin_slug'],
68
+			$license_data['version'],
69
+			$license_data['beta'],
70
+			$license_data['wp_override'],
71
+			$license_data['min_core_version']
72
+		);
73
+		$addon_license->setHooks();
74
+	}
75 75
 
76 76
 
77
-    private static function derivePluginSlugFromMainFile(string $main_file_path): string
78
-    {
79
-        return wp_basename($main_file_path, '.php');
80
-    }
77
+	private static function derivePluginSlugFromMainFile(string $main_file_path): string
78
+	{
79
+		return wp_basename($main_file_path, '.php');
80
+	}
81 81
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -20,20 +20,20 @@
 block discarded – undo
20 20
 {
21 21
     public static function register(string $addon_name, array $license_data)
22 22
     {
23
-        if (! $addon_name || ! $license_data) {
23
+        if ( ! $addon_name || ! $license_data) {
24 24
             return;
25 25
         }
26 26
         // also bail if the feature flag is not enabled
27 27
         $feature = LoaderFactory::getShared(FeatureFlags::class);
28
-        if (! $feature->allowed('use_edd_plugin_licensing')) {
28
+        if ( ! $feature->allowed('use_edd_plugin_licensing')) {
29 29
             return;
30 30
         }
31 31
         $main_file_path = $license_data['main_file_path'] ?? '';
32 32
         $main_file_slug = AddonLicense::derivePluginSlugFromMainFile($main_file_path);
33 33
         // use values from addon IF SET
34 34
         $plugin_slug = $license_data['plugin_slug'] ?? '';
35
-        $plugin_id   =  $license_data['plugin_id'] ?? 0;
36
-        $plugin_name =  $license_data['plugin_name'] ?? '';
35
+        $plugin_id   = $license_data['plugin_id'] ?? 0;
36
+        $plugin_name = $license_data['plugin_name'] ?? '';
37 37
 
38 38
         // if the plugin ID has been set to ZERO, then we are using a pre-EDD plugin,
39 39
         // so use the plugin slug derived from the main file path.
Please login to merge, or discard this patch.
core/services/routing/Router.php 1 patch
Indentation   +225 added lines, -225 removed lines patch added patch discarded remove patch
@@ -30,249 +30,249 @@
 block discarded – undo
30 30
  */
31 31
 class Router
32 32
 {
33
-    protected EE_Dependency_Map $dependency_map;
33
+	protected EE_Dependency_Map $dependency_map;
34 34
 
35
-    protected LoaderInterface $loader;
35
+	protected LoaderInterface $loader;
36 36
 
37
-    protected RouteHandler $route_handler;
37
+	protected RouteHandler $route_handler;
38 38
 
39
-    protected string $route_request_type;
39
+	protected string $route_request_type;
40 40
 
41
-    protected array $routes_loaded;
41
+	protected array $routes_loaded;
42 42
 
43 43
 
44
-    /**
45
-     * RoutingSwitch constructor.
46
-     *
47
-     * @param EE_Dependency_Map $dependency_map
48
-     * @param LoaderInterface   $loader
49
-     * @param RouteHandler      $router
50
-     */
51
-    public function __construct(EE_Dependency_Map $dependency_map, LoaderInterface $loader, RouteHandler $router)
52
-    {
53
-        $this->dependency_map = $dependency_map;
54
-        $this->loader         = $loader;
55
-        $this->route_handler  = $router;
56
-    }
44
+	/**
45
+	 * RoutingSwitch constructor.
46
+	 *
47
+	 * @param EE_Dependency_Map $dependency_map
48
+	 * @param LoaderInterface   $loader
49
+	 * @param RouteHandler      $router
50
+	 */
51
+	public function __construct(EE_Dependency_Map $dependency_map, LoaderInterface $loader, RouteHandler $router)
52
+	{
53
+		$this->dependency_map = $dependency_map;
54
+		$this->loader         = $loader;
55
+		$this->route_handler  = $router;
56
+	}
57 57
 
58 58
 
59
-    /**
60
-     * @throws Exception|Throwable
61
-     */
62
-    public function loadPrimaryRoutes()
63
-    {
64
-        if (isset($this->routes_loaded[ __FUNCTION__ ])) {
65
-            return;
66
-        }
67
-        $this->dependency_map->registerDependencies(
68
-            'EventEspresso\core\domain\entities\routing\handlers\admin\ActivationRequests',
69
-            Route::getFullDependencies()
70
-        );
71
-        $this->dependency_map->registerDependencies(
72
-            'EventEspresso\core\domain\entities\routing\handlers\shared\RegularRequests',
73
-            Route::getFullDependencies()
74
-        );
75
-        // now load and prep all primary Routes
76
-        $this->route_handler->addRoute('EventEspresso\core\domain\entities\routing\handlers\admin\ActivationRequests');
77
-        $this->route_handler->addRoute('EventEspresso\core\domain\entities\routing\handlers\shared\RegularRequests');
78
-        $this->route_request_type = $this->route_handler->getRouteRequestType();
79
-        do_action(
80
-            'AHEE__EventEspresso_core_services_routing_Router__loadPrimaryRoutes',
81
-            $this->route_handler,
82
-            $this->route_request_type,
83
-            $this->dependency_map
84
-        );
85
-        $this->routes_loaded[ __FUNCTION__ ] = true;
86
-    }
59
+	/**
60
+	 * @throws Exception|Throwable
61
+	 */
62
+	public function loadPrimaryRoutes()
63
+	{
64
+		if (isset($this->routes_loaded[ __FUNCTION__ ])) {
65
+			return;
66
+		}
67
+		$this->dependency_map->registerDependencies(
68
+			'EventEspresso\core\domain\entities\routing\handlers\admin\ActivationRequests',
69
+			Route::getFullDependencies()
70
+		);
71
+		$this->dependency_map->registerDependencies(
72
+			'EventEspresso\core\domain\entities\routing\handlers\shared\RegularRequests',
73
+			Route::getFullDependencies()
74
+		);
75
+		// now load and prep all primary Routes
76
+		$this->route_handler->addRoute('EventEspresso\core\domain\entities\routing\handlers\admin\ActivationRequests');
77
+		$this->route_handler->addRoute('EventEspresso\core\domain\entities\routing\handlers\shared\RegularRequests');
78
+		$this->route_request_type = $this->route_handler->getRouteRequestType();
79
+		do_action(
80
+			'AHEE__EventEspresso_core_services_routing_Router__loadPrimaryRoutes',
81
+			$this->route_handler,
82
+			$this->route_request_type,
83
+			$this->dependency_map
84
+		);
85
+		$this->routes_loaded[ __FUNCTION__ ] = true;
86
+	}
87 87
 
88 88
 
89
-    /**
90
-     * @throws Exception|Throwable
91
-     */
92
-    public function registerShortcodesModulesAndWidgets()
93
-    {
94
-        if (isset($this->routes_loaded[ __FUNCTION__ ])) {
95
-            return;
96
-        }
97
-        do_action(
98
-            'AHEE__EventEspresso_core_services_routing_Router__registerShortcodesModulesAndWidgets',
99
-            $this->route_handler,
100
-            $this->route_request_type,
101
-            $this->dependency_map
102
-        );
89
+	/**
90
+	 * @throws Exception|Throwable
91
+	 */
92
+	public function registerShortcodesModulesAndWidgets()
93
+	{
94
+		if (isset($this->routes_loaded[ __FUNCTION__ ])) {
95
+			return;
96
+		}
97
+		do_action(
98
+			'AHEE__EventEspresso_core_services_routing_Router__registerShortcodesModulesAndWidgets',
99
+			$this->route_handler,
100
+			$this->route_request_type,
101
+			$this->dependency_map
102
+		);
103 103
 
104
-        /** @var LegacyModulesManager $legacy_modules_manager */
105
-        $legacy_modules_manager = $this->loader->getShared(LegacyModulesManager::class);
106
-        $legacy_modules_manager->setHooks();
104
+		/** @var LegacyModulesManager $legacy_modules_manager */
105
+		$legacy_modules_manager = $this->loader->getShared(LegacyModulesManager::class);
106
+		$legacy_modules_manager->setHooks();
107 107
 
108
-        switch ($this->route_request_type) {
109
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
110
-                break;
111
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
112
-                $this->route_handler->addRoute(
113
-                    'EventEspresso\core\domain\entities\routing\handlers\frontend\ShortcodeRequests'
114
-                );
115
-                /** @var LegacyWidgetsManager $legacy_widgets_manager */
116
-                $legacy_widgets_manager = $this->loader->getShared(LegacyWidgetsManager::class);
117
-                $legacy_widgets_manager->setHooks();
118
-                break;
119
-        }
120
-        $this->routes_loaded[ __FUNCTION__ ] = true;
121
-    }
108
+		switch ($this->route_request_type) {
109
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
110
+				break;
111
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
112
+				$this->route_handler->addRoute(
113
+					'EventEspresso\core\domain\entities\routing\handlers\frontend\ShortcodeRequests'
114
+				);
115
+				/** @var LegacyWidgetsManager $legacy_widgets_manager */
116
+				$legacy_widgets_manager = $this->loader->getShared(LegacyWidgetsManager::class);
117
+				$legacy_widgets_manager->setHooks();
118
+				break;
119
+		}
120
+		$this->routes_loaded[ __FUNCTION__ ] = true;
121
+	}
122 122
 
123 123
 
124
-    /**
125
-     * @throws Exception|Throwable
126
-     */
127
-    public function brewEspresso()
128
-    {
129
-        if (isset($this->routes_loaded[ __FUNCTION__ ])) {
130
-            return;
131
-        }
132
-        do_action(
133
-            'AHEE__EventEspresso_core_services_routing_Router__brewEspresso',
134
-            $this->route_handler,
135
-            $this->route_request_type,
136
-            $this->dependency_map
137
-        );
138
-        switch ($this->route_request_type) {
139
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
140
-                break;
141
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
142
-                $this->route_handler->addRoute(
143
-                    'EventEspresso\core\domain\entities\routing\handlers\shared\GQLRequests'
144
-                );
145
-                $this->route_handler->addRoute(
146
-                    'EventEspresso\core\domain\entities\routing\handlers\shared\RestApiRequests'
147
-                );
148
-                break;
149
-        }
150
-        $this->routes_loaded[ __FUNCTION__ ] = true;
151
-    }
124
+	/**
125
+	 * @throws Exception|Throwable
126
+	 */
127
+	public function brewEspresso()
128
+	{
129
+		if (isset($this->routes_loaded[ __FUNCTION__ ])) {
130
+			return;
131
+		}
132
+		do_action(
133
+			'AHEE__EventEspresso_core_services_routing_Router__brewEspresso',
134
+			$this->route_handler,
135
+			$this->route_request_type,
136
+			$this->dependency_map
137
+		);
138
+		switch ($this->route_request_type) {
139
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
140
+				break;
141
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
142
+				$this->route_handler->addRoute(
143
+					'EventEspresso\core\domain\entities\routing\handlers\shared\GQLRequests'
144
+				);
145
+				$this->route_handler->addRoute(
146
+					'EventEspresso\core\domain\entities\routing\handlers\shared\RestApiRequests'
147
+				);
148
+				break;
149
+		}
150
+		$this->routes_loaded[ __FUNCTION__ ] = true;
151
+	}
152 152
 
153 153
 
154
-    /**
155
-     * @throws Exception|Throwable
156
-     */
157
-    public function loadControllers()
158
-    {
159
-        if (isset($this->routes_loaded[ __FUNCTION__ ])) {
160
-            return;
161
-        }
162
-        do_action(
163
-            'AHEE__EventEspresso_core_services_routing_Router__loadControllers',
164
-            $this->route_handler,
165
-            $this->route_request_type,
166
-            $this->dependency_map
167
-        );
168
-        $this->route_handler->addRoute(
169
-            'EventEspresso\core\domain\entities\routing\handlers\admin\AdminRoute'
170
-        );
171
-        switch ($this->route_request_type) {
172
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
173
-                $this->route_handler->addRoute(
174
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPluginsPage'
175
-                );
176
-                $this->route_handler->addRoute(
177
-                    'EventEspresso\core\domain\services\licensing\LicenseKeyActivationRoute'
178
-                );
179
-                break;
180
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
181
-                $this->route_handler->addRoute(
182
-                    'EventEspresso\core\domain\entities\routing\handlers\frontend\FrontendRequests'
183
-                );
184
-                $this->route_handler->addRoute(
185
-                    'EventEspresso\core\domain\entities\routing\handlers\frontend\RegistrationCheckoutRequests'
186
-                );
187
-                $this->route_handler->addRoute(
188
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoLegacyAdmin'
189
-                );
190
-                $this->route_handler->addRoute(
191
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoEventsAdmin'
192
-                );
193
-                $this->route_handler->addRoute(
194
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoEventEditor'
195
-                );
196
-                $this->route_handler->addRoute(
197
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\GutenbergEditor'
198
-                );
199
-                $this->route_handler->addRoute(
200
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\NonEspressoAdminAjax'
201
-                );
202
-                $this->route_handler->addRoute(
203
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPluginsPage'
204
-                );
205
-                $this->route_handler->addRoute(
206
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressProfilePage'
207
-                );
208
-                $this->route_handler->addRoute(
209
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPostsPage'
210
-                );
211
-                $this->route_handler->addRoute(
212
-                    'EventEspresso\core\domain\entities\routing\handlers\shared\WordPressHeartbeat'
213
-                );
214
-                $this->route_handler->addRoute(
215
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoBatchJob'
216
-                );
217
-                break;
218
-        }
219
-        $this->routes_loaded[ __FUNCTION__ ] = true;
220
-    }
154
+	/**
155
+	 * @throws Exception|Throwable
156
+	 */
157
+	public function loadControllers()
158
+	{
159
+		if (isset($this->routes_loaded[ __FUNCTION__ ])) {
160
+			return;
161
+		}
162
+		do_action(
163
+			'AHEE__EventEspresso_core_services_routing_Router__loadControllers',
164
+			$this->route_handler,
165
+			$this->route_request_type,
166
+			$this->dependency_map
167
+		);
168
+		$this->route_handler->addRoute(
169
+			'EventEspresso\core\domain\entities\routing\handlers\admin\AdminRoute'
170
+		);
171
+		switch ($this->route_request_type) {
172
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
173
+				$this->route_handler->addRoute(
174
+					'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPluginsPage'
175
+				);
176
+				$this->route_handler->addRoute(
177
+					'EventEspresso\core\domain\services\licensing\LicenseKeyActivationRoute'
178
+				);
179
+				break;
180
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
181
+				$this->route_handler->addRoute(
182
+					'EventEspresso\core\domain\entities\routing\handlers\frontend\FrontendRequests'
183
+				);
184
+				$this->route_handler->addRoute(
185
+					'EventEspresso\core\domain\entities\routing\handlers\frontend\RegistrationCheckoutRequests'
186
+				);
187
+				$this->route_handler->addRoute(
188
+					'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoLegacyAdmin'
189
+				);
190
+				$this->route_handler->addRoute(
191
+					'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoEventsAdmin'
192
+				);
193
+				$this->route_handler->addRoute(
194
+					'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoEventEditor'
195
+				);
196
+				$this->route_handler->addRoute(
197
+					'EventEspresso\core\domain\entities\routing\handlers\admin\GutenbergEditor'
198
+				);
199
+				$this->route_handler->addRoute(
200
+					'EventEspresso\core\domain\entities\routing\handlers\admin\NonEspressoAdminAjax'
201
+				);
202
+				$this->route_handler->addRoute(
203
+					'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPluginsPage'
204
+				);
205
+				$this->route_handler->addRoute(
206
+					'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressProfilePage'
207
+				);
208
+				$this->route_handler->addRoute(
209
+					'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPostsPage'
210
+				);
211
+				$this->route_handler->addRoute(
212
+					'EventEspresso\core\domain\entities\routing\handlers\shared\WordPressHeartbeat'
213
+				);
214
+				$this->route_handler->addRoute(
215
+					'EventEspresso\core\domain\entities\routing\handlers\admin\EspressoBatchJob'
216
+				);
217
+				break;
218
+		}
219
+		$this->routes_loaded[ __FUNCTION__ ] = true;
220
+	}
221 221
 
222 222
 
223
-    /**
224
-     * @throws Exception|Throwable
225
-     */
226
-    public function coreLoadedAndReady()
227
-    {
228
-        if (isset($this->routes_loaded[ __FUNCTION__ ])) {
229
-            return;
230
-        }
231
-        do_action(
232
-            'AHEE__EventEspresso_core_services_routing_Router__coreLoadedAndReady',
233
-            $this->route_handler,
234
-            $this->route_request_type,
235
-            $this->dependency_map
236
-        );
237
-        switch ($this->route_request_type) {
238
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
239
-                break;
240
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
241
-                $this->route_handler->addRoute(
242
-                    'EventEspresso\core\domain\entities\routing\handlers\shared\AssetRequests'
243
-                );
244
-                $this->route_handler->addRoute(
245
-                    'EventEspresso\core\domain\entities\routing\handlers\shared\SessionRequests'
246
-                );
247
-                break;
248
-        }
249
-        $this->routes_loaded[ __FUNCTION__ ] = true;
250
-    }
223
+	/**
224
+	 * @throws Exception|Throwable
225
+	 */
226
+	public function coreLoadedAndReady()
227
+	{
228
+		if (isset($this->routes_loaded[ __FUNCTION__ ])) {
229
+			return;
230
+		}
231
+		do_action(
232
+			'AHEE__EventEspresso_core_services_routing_Router__coreLoadedAndReady',
233
+			$this->route_handler,
234
+			$this->route_request_type,
235
+			$this->dependency_map
236
+		);
237
+		switch ($this->route_request_type) {
238
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
239
+				break;
240
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
241
+				$this->route_handler->addRoute(
242
+					'EventEspresso\core\domain\entities\routing\handlers\shared\AssetRequests'
243
+				);
244
+				$this->route_handler->addRoute(
245
+					'EventEspresso\core\domain\entities\routing\handlers\shared\SessionRequests'
246
+				);
247
+				break;
248
+		}
249
+		$this->routes_loaded[ __FUNCTION__ ] = true;
250
+	}
251 251
 
252 252
 
253
-    /**
254
-     * @throws Exception|Throwable
255
-     */
256
-    public function initializeLast()
257
-    {
258
-        if (isset($this->routes_loaded[ __FUNCTION__ ])) {
259
-            return;
260
-        }
261
-        do_action(
262
-            'AHEE__EventEspresso_core_services_routing_Router__initializeLast',
263
-            $this->route_handler,
264
-            $this->route_request_type,
265
-            $this->dependency_map
266
-        );
267
-        switch ($this->route_request_type) {
268
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
269
-                break;
270
-            case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
271
-                $this->route_handler->addRoute(
272
-                    'EventEspresso\core\domain\entities\routing\handlers\admin\PersonalDataRequests'
273
-                );
274
-                break;
275
-        }
276
-        $this->routes_loaded[ __FUNCTION__ ] = true;
277
-    }
253
+	/**
254
+	 * @throws Exception|Throwable
255
+	 */
256
+	public function initializeLast()
257
+	{
258
+		if (isset($this->routes_loaded[ __FUNCTION__ ])) {
259
+			return;
260
+		}
261
+		do_action(
262
+			'AHEE__EventEspresso_core_services_routing_Router__initializeLast',
263
+			$this->route_handler,
264
+			$this->route_request_type,
265
+			$this->dependency_map
266
+		);
267
+		switch ($this->route_request_type) {
268
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION:
269
+				break;
270
+			case PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR:
271
+				$this->route_handler->addRoute(
272
+					'EventEspresso\core\domain\entities\routing\handlers\admin\PersonalDataRequests'
273
+				);
274
+				break;
275
+		}
276
+		$this->routes_loaded[ __FUNCTION__ ] = true;
277
+	}
278 278
 }
Please login to merge, or discard this patch.
core/services/payments/PaymentProcessorFees.php 1 patch
Indentation   +158 added lines, -158 removed lines patch added patch discarded remove patch
@@ -28,162 +28,162 @@
 block discarded – undo
28 28
  */
29 29
 class PaymentProcessorFees
30 30
 {
31
-    public const  GATEWAY_PAYPAL  = 'PayPal Commerce';
32
-
33
-    public const  GATEWAY_SQUARE  = 'Square';
34
-
35
-    public const  GATEWAY_STRIPE  = 'Stripe';
36
-
37
-    private GracePeriod $grace_period;
38
-
39
-    private LicenseData $license_data;
40
-
41
-    /**
42
-     * @var float[][] $gateway_fees
43
-     */
44
-    private array $gateway_fees = [
45
-        LicenseStatus::ACTIVE  => [
46
-            PaymentProcessorFees::GATEWAY_PAYPAL => 0.00,
47
-            PaymentProcessorFees::GATEWAY_SQUARE => 0.00,
48
-            PaymentProcessorFees::GATEWAY_STRIPE => 0.00,
49
-        ],
50
-        LicenseStatus::EXPIRED => [
51
-            PaymentProcessorFees::GATEWAY_PAYPAL => 3.00,
52
-            PaymentProcessorFees::GATEWAY_SQUARE => 2.50,
53
-            PaymentProcessorFees::GATEWAY_STRIPE => 3.00,
54
-        ],
55
-        LicenseStatus::DECAF   => [
56
-            PaymentProcessorFees::GATEWAY_PAYPAL => 3.00,
57
-            PaymentProcessorFees::GATEWAY_SQUARE => 2.50,
58
-            PaymentProcessorFees::GATEWAY_STRIPE => 3.00,
59
-        ],
60
-    ];
61
-
62
-    private array $partner_gateways = [
63
-        PaymentProcessorFees::GATEWAY_PAYPAL,
64
-        PaymentProcessorFees::GATEWAY_SQUARE,
65
-        PaymentProcessorFees::GATEWAY_STRIPE,
66
-    ];
67
-
68
-
69
-    /**
70
-     * @param GracePeriod $grace_period
71
-     * @param LicenseData $license_data
72
-     */
73
-    public function __construct(GracePeriod $grace_period, LicenseData $license_data)
74
-    {
75
-        $this->grace_period = $grace_period;
76
-        $this->license_data = $license_data;
77
-    }
78
-
79
-
80
-    /**
81
-     * @param EE_Transaction $transaction
82
-     * @param string         $payment_method_name
83
-     * @param float          $amount
84
-     * @return float
85
-     * @throws EE_Error|ReflectionException|RuntimeException
86
-     * @throws Exception
87
-     */
88
-    public function applyGatewayPartnerFees(
89
-        EE_Transaction $transaction,
90
-        string $payment_method_name,
91
-        float $amount = 0.00
92
-    ): float {
93
-        $processing_fee = $this->forPaymentMethod($payment_method_name);
94
-        if ($processing_fee <= 0.00) {
95
-            return $amount;
96
-        }
97
-        $grand_total = $transaction->total_line_item(false);
98
-        if (
99
-            ! $grand_total instanceof EE_Line_Item
100
-            || ! $grand_total->is_total()
101
-            || $grand_total->TXN_ID() !== $transaction->ID()
102
-        ) {
103
-            // throw RuntimeException if total_line_item is not a total line item
104
-            throw new RuntimeException(
105
-                sprintf(
106
-                    esc_html__(
107
-                        'Invalid or missing grand total line item for transaction %1$d.',
108
-                        'event_espresso'
109
-                    ),
110
-                    $transaction->ID()
111
-                )
112
-            );
113
-        }
114
-        $line_item = EEH_Line_Item::add_percentage_based_item(
115
-            EEH_Line_Item::get_pre_tax_subtotal($grand_total),
116
-            esc_html__('Payment Processing Fee', 'event_espresso'),
117
-            $processing_fee,
118
-            '',
119
-            false,
120
-            sanitize_key(
121
-                sprintf(
122
-                    '%1$s-fee-%2$d',
123
-                    $payment_method_name,
124
-                    $transaction->ID()
125
-                )
126
-            ),
127
-            true
128
-        );
129
-        $line_item->save();
130
-        return $grand_total->recalculate_total_including_taxes();
131
-    }
132
-
133
-
134
-    /**
135
-     * Returns the fee for a specific payment method based on the license status.
136
-     *
137
-     * @param string $payment_method_name
138
-     * @return float
139
-     * @throws Exception|OutOfBoundsException|RuntimeException
140
-     */
141
-    public function forPaymentMethod(string $payment_method_name): float
142
-    {
143
-        if (! $this->isPartnerGateway($payment_method_name)) {
144
-            return 0.0;
145
-        }
146
-        $license_status = $this->license_data->licenseStatus();
147
-        $license_expires = $this->license_data->licenseExpiry();
148
-        // decaf, new activations, or expired licenses are allowed a grace period
149
-        if ($this->grace_period->withinGracePeriod($license_status, $license_expires)) {
150
-            return 0.0;
151
-        }
152
-        return $this->getGatewayFee($payment_method_name, $license_status);
153
-    }
154
-
155
-
156
-    /**
157
-     * Checks if a gateway is a partner gateway.
158
-     *
159
-     * @param string $payment_method_name
160
-     * @return bool
161
-     */
162
-    private function isPartnerGateway(string $payment_method_name): bool
163
-    {
164
-        return in_array($payment_method_name, $this->partner_gateways, true);
165
-    }
166
-
167
-
168
-    /**
169
-     * Returns the fee for a specific payment method based on the license status.
170
-     *
171
-     * @param string $payment_method_name
172
-     * @param string $license_status
173
-     * @return float
174
-     * @throws OutOfBoundsException
175
-     */
176
-    private function getGatewayFee(string $payment_method_name, string $license_status): float
177
-    {
178
-        if (isset($this->gateway_fees[ $license_status ][ $payment_method_name ])) {
179
-            return $this->gateway_fees[ $license_status ][ $payment_method_name ];
180
-        }
181
-        throw new OutOfBoundsException(
182
-            sprintf(
183
-                esc_html__('A partner fee for %1$s with %2$s license is not defined.', 'event_espresso'),
184
-                $payment_method_name,
185
-                $license_status
186
-            )
187
-        );
188
-    }
31
+	public const  GATEWAY_PAYPAL  = 'PayPal Commerce';
32
+
33
+	public const  GATEWAY_SQUARE  = 'Square';
34
+
35
+	public const  GATEWAY_STRIPE  = 'Stripe';
36
+
37
+	private GracePeriod $grace_period;
38
+
39
+	private LicenseData $license_data;
40
+
41
+	/**
42
+	 * @var float[][] $gateway_fees
43
+	 */
44
+	private array $gateway_fees = [
45
+		LicenseStatus::ACTIVE  => [
46
+			PaymentProcessorFees::GATEWAY_PAYPAL => 0.00,
47
+			PaymentProcessorFees::GATEWAY_SQUARE => 0.00,
48
+			PaymentProcessorFees::GATEWAY_STRIPE => 0.00,
49
+		],
50
+		LicenseStatus::EXPIRED => [
51
+			PaymentProcessorFees::GATEWAY_PAYPAL => 3.00,
52
+			PaymentProcessorFees::GATEWAY_SQUARE => 2.50,
53
+			PaymentProcessorFees::GATEWAY_STRIPE => 3.00,
54
+		],
55
+		LicenseStatus::DECAF   => [
56
+			PaymentProcessorFees::GATEWAY_PAYPAL => 3.00,
57
+			PaymentProcessorFees::GATEWAY_SQUARE => 2.50,
58
+			PaymentProcessorFees::GATEWAY_STRIPE => 3.00,
59
+		],
60
+	];
61
+
62
+	private array $partner_gateways = [
63
+		PaymentProcessorFees::GATEWAY_PAYPAL,
64
+		PaymentProcessorFees::GATEWAY_SQUARE,
65
+		PaymentProcessorFees::GATEWAY_STRIPE,
66
+	];
67
+
68
+
69
+	/**
70
+	 * @param GracePeriod $grace_period
71
+	 * @param LicenseData $license_data
72
+	 */
73
+	public function __construct(GracePeriod $grace_period, LicenseData $license_data)
74
+	{
75
+		$this->grace_period = $grace_period;
76
+		$this->license_data = $license_data;
77
+	}
78
+
79
+
80
+	/**
81
+	 * @param EE_Transaction $transaction
82
+	 * @param string         $payment_method_name
83
+	 * @param float          $amount
84
+	 * @return float
85
+	 * @throws EE_Error|ReflectionException|RuntimeException
86
+	 * @throws Exception
87
+	 */
88
+	public function applyGatewayPartnerFees(
89
+		EE_Transaction $transaction,
90
+		string $payment_method_name,
91
+		float $amount = 0.00
92
+	): float {
93
+		$processing_fee = $this->forPaymentMethod($payment_method_name);
94
+		if ($processing_fee <= 0.00) {
95
+			return $amount;
96
+		}
97
+		$grand_total = $transaction->total_line_item(false);
98
+		if (
99
+			! $grand_total instanceof EE_Line_Item
100
+			|| ! $grand_total->is_total()
101
+			|| $grand_total->TXN_ID() !== $transaction->ID()
102
+		) {
103
+			// throw RuntimeException if total_line_item is not a total line item
104
+			throw new RuntimeException(
105
+				sprintf(
106
+					esc_html__(
107
+						'Invalid or missing grand total line item for transaction %1$d.',
108
+						'event_espresso'
109
+					),
110
+					$transaction->ID()
111
+				)
112
+			);
113
+		}
114
+		$line_item = EEH_Line_Item::add_percentage_based_item(
115
+			EEH_Line_Item::get_pre_tax_subtotal($grand_total),
116
+			esc_html__('Payment Processing Fee', 'event_espresso'),
117
+			$processing_fee,
118
+			'',
119
+			false,
120
+			sanitize_key(
121
+				sprintf(
122
+					'%1$s-fee-%2$d',
123
+					$payment_method_name,
124
+					$transaction->ID()
125
+				)
126
+			),
127
+			true
128
+		);
129
+		$line_item->save();
130
+		return $grand_total->recalculate_total_including_taxes();
131
+	}
132
+
133
+
134
+	/**
135
+	 * Returns the fee for a specific payment method based on the license status.
136
+	 *
137
+	 * @param string $payment_method_name
138
+	 * @return float
139
+	 * @throws Exception|OutOfBoundsException|RuntimeException
140
+	 */
141
+	public function forPaymentMethod(string $payment_method_name): float
142
+	{
143
+		if (! $this->isPartnerGateway($payment_method_name)) {
144
+			return 0.0;
145
+		}
146
+		$license_status = $this->license_data->licenseStatus();
147
+		$license_expires = $this->license_data->licenseExpiry();
148
+		// decaf, new activations, or expired licenses are allowed a grace period
149
+		if ($this->grace_period->withinGracePeriod($license_status, $license_expires)) {
150
+			return 0.0;
151
+		}
152
+		return $this->getGatewayFee($payment_method_name, $license_status);
153
+	}
154
+
155
+
156
+	/**
157
+	 * Checks if a gateway is a partner gateway.
158
+	 *
159
+	 * @param string $payment_method_name
160
+	 * @return bool
161
+	 */
162
+	private function isPartnerGateway(string $payment_method_name): bool
163
+	{
164
+		return in_array($payment_method_name, $this->partner_gateways, true);
165
+	}
166
+
167
+
168
+	/**
169
+	 * Returns the fee for a specific payment method based on the license status.
170
+	 *
171
+	 * @param string $payment_method_name
172
+	 * @param string $license_status
173
+	 * @return float
174
+	 * @throws OutOfBoundsException
175
+	 */
176
+	private function getGatewayFee(string $payment_method_name, string $license_status): float
177
+	{
178
+		if (isset($this->gateway_fees[ $license_status ][ $payment_method_name ])) {
179
+			return $this->gateway_fees[ $license_status ][ $payment_method_name ];
180
+		}
181
+		throw new OutOfBoundsException(
182
+			sprintf(
183
+				esc_html__('A partner fee for %1$s with %2$s license is not defined.', 'event_espresso'),
184
+				$payment_method_name,
185
+				$license_status
186
+			)
187
+		);
188
+	}
189 189
 }
Please login to merge, or discard this patch.
core/services/request/RequestStackCoreApp.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -30,91 +30,91 @@
 block discarded – undo
30 30
  */
31 31
 class RequestStackCoreApp implements RequestDecoratorInterface, RequestStackCoreAppInterface
32 32
 {
33
-    protected RequestInterface $request;
33
+	protected RequestInterface $request;
34 34
 
35
-    protected ResponseInterface $response;
35
+	protected ResponseInterface $response;
36 36
 
37 37
 
38
-    /**
39
-     * handle
40
-     * sets hooks for running rest of system
41
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
42
-     * starting EE Addons from any other point may lead to problems
43
-     *
44
-     * @param RequestInterface  $request
45
-     * @param ResponseInterface $response
46
-     * @return ResponseInterface
47
-     * @throws InvalidClassException
48
-     * @throws EE_Error
49
-     * @throws InvalidDataTypeException
50
-     * @throws InvalidInterfaceException
51
-     * @throws InvalidArgumentException
52
-     */
53
-    public function handleRequest(RequestInterface $request, ResponseInterface $response): ResponseInterface
54
-    {
55
-        $this->request  = $request;
56
-        $this->response = $response;
57
-        espresso_load_required('EE_Base', EE_CORE . 'EE_Base.core.php');
58
-        DeprecationManager::loadDeprecations();
59
-        // workarounds for PHP < 5.3
60
-        espresso_load_required('EEH_Class_Tools', EE_HELPERS . 'EEH_Class_Tools.helper.php');
61
-        do_action(
62
-            'EE_EventEspresso_core_services_request_RequestStackCoreApp__handle_request__initialize_core_loading'
63
-        );
64
-        // legacy action for backwards compatibility
65
-        do_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading');
66
-        $this->setupFramework();
67
-        $capabilities_checker = LoaderFactory::getShared(CapabilitiesChecker::class, [EE_Capabilities::instance()]);
68
-        LoaderFactory::getShared(PersistentAdminNoticeManager::class, [$capabilities_checker, $request]);
69
-        // needed
70
-        LoaderFactory::getShared(EE_Maintenance_Mode::class);
71
-        // load legacy Cron Tasks and new Cron Manager
72
-        LoaderFactory::getShared(EE_Cron_Tasks::class);
73
-        /** @var CronManager $cron_manager */
74
-        $cron_manager = LoaderFactory::getShared(CronManager::class, [LoaderFactory::getLoader()]);
75
-        $cron_manager->initialize();
76
-        LoaderFactory::getShared(EE_System::class);
77
-        return $this->response;
78
-    }
38
+	/**
39
+	 * handle
40
+	 * sets hooks for running rest of system
41
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
42
+	 * starting EE Addons from any other point may lead to problems
43
+	 *
44
+	 * @param RequestInterface  $request
45
+	 * @param ResponseInterface $response
46
+	 * @return ResponseInterface
47
+	 * @throws InvalidClassException
48
+	 * @throws EE_Error
49
+	 * @throws InvalidDataTypeException
50
+	 * @throws InvalidInterfaceException
51
+	 * @throws InvalidArgumentException
52
+	 */
53
+	public function handleRequest(RequestInterface $request, ResponseInterface $response): ResponseInterface
54
+	{
55
+		$this->request  = $request;
56
+		$this->response = $response;
57
+		espresso_load_required('EE_Base', EE_CORE . 'EE_Base.core.php');
58
+		DeprecationManager::loadDeprecations();
59
+		// workarounds for PHP < 5.3
60
+		espresso_load_required('EEH_Class_Tools', EE_HELPERS . 'EEH_Class_Tools.helper.php');
61
+		do_action(
62
+			'EE_EventEspresso_core_services_request_RequestStackCoreApp__handle_request__initialize_core_loading'
63
+		);
64
+		// legacy action for backwards compatibility
65
+		do_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading');
66
+		$this->setupFramework();
67
+		$capabilities_checker = LoaderFactory::getShared(CapabilitiesChecker::class, [EE_Capabilities::instance()]);
68
+		LoaderFactory::getShared(PersistentAdminNoticeManager::class, [$capabilities_checker, $request]);
69
+		// needed
70
+		LoaderFactory::getShared(EE_Maintenance_Mode::class);
71
+		// load legacy Cron Tasks and new Cron Manager
72
+		LoaderFactory::getShared(EE_Cron_Tasks::class);
73
+		/** @var CronManager $cron_manager */
74
+		$cron_manager = LoaderFactory::getShared(CronManager::class, [LoaderFactory::getLoader()]);
75
+		$cron_manager->initialize();
76
+		LoaderFactory::getShared(EE_System::class);
77
+		return $this->response;
78
+	}
79 79
 
80 80
 
81
-    /**
82
-     * set framework for the rest of EE to hook into when loading
83
-     *
84
-     * @throws EE_Error
85
-     */
86
-    private function setupFramework()
87
-    {
88
-        espresso_load_required('EE_Bootstrap', EE_CORE . 'EE_Bootstrap.core.php');
89
-        add_action('plugins_loaded', ['EE_Bootstrap', 'load_espresso_addons'], 1);
90
-        add_action('plugins_loaded', ['EE_Bootstrap', 'detect_activations_or_upgrades'], 3);
91
-        add_action('plugins_loaded', ['EE_Bootstrap', 'load_core_configuration'], 5);
92
-        add_action('plugins_loaded', ['EE_Bootstrap', 'register_shortcodes_modules_and_widgets'], 7);
93
-        add_action('plugins_loaded', ['EE_Bootstrap', 'brew_espresso'], 9);
94
-    }
81
+	/**
82
+	 * set framework for the rest of EE to hook into when loading
83
+	 *
84
+	 * @throws EE_Error
85
+	 */
86
+	private function setupFramework()
87
+	{
88
+		espresso_load_required('EE_Bootstrap', EE_CORE . 'EE_Bootstrap.core.php');
89
+		add_action('plugins_loaded', ['EE_Bootstrap', 'load_espresso_addons'], 1);
90
+		add_action('plugins_loaded', ['EE_Bootstrap', 'detect_activations_or_upgrades'], 3);
91
+		add_action('plugins_loaded', ['EE_Bootstrap', 'load_core_configuration'], 5);
92
+		add_action('plugins_loaded', ['EE_Bootstrap', 'register_shortcodes_modules_and_widgets'], 7);
93
+		add_action('plugins_loaded', ['EE_Bootstrap', 'brew_espresso'], 9);
94
+	}
95 95
 
96 96
 
97
-    /**
98
-     * called after the request stack has been fully processed
99
-     * if any of the middleware apps has requested the plugin be deactivated, then we do that now
100
-     *
101
-     * @param RequestInterface  $request
102
-     * @param ResponseInterface $response
103
-     */
104
-    public function handleResponse(RequestInterface $request, ResponseInterface $response)
105
-    {
106
-        if ($response->pluginDeactivated()) {
107
-            espresso_deactivate_plugin(EE_PLUGIN_BASENAME);
108
-        }
109
-        $request_headers = $response->requestHeaders();
110
-        if ($request_headers) {
111
-            foreach ($request_headers as $request_header) {
112
-                header($request_header);
113
-            }
114
-            // headers set AND request terminated? then kill the current request
115
-            if ($response->requestTerminated()) {
116
-                exit;
117
-            }
118
-        }
119
-    }
97
+	/**
98
+	 * called after the request stack has been fully processed
99
+	 * if any of the middleware apps has requested the plugin be deactivated, then we do that now
100
+	 *
101
+	 * @param RequestInterface  $request
102
+	 * @param ResponseInterface $response
103
+	 */
104
+	public function handleResponse(RequestInterface $request, ResponseInterface $response)
105
+	{
106
+		if ($response->pluginDeactivated()) {
107
+			espresso_deactivate_plugin(EE_PLUGIN_BASENAME);
108
+		}
109
+		$request_headers = $response->requestHeaders();
110
+		if ($request_headers) {
111
+			foreach ($request_headers as $request_header) {
112
+				header($request_header);
113
+			}
114
+			// headers set AND request terminated? then kill the current request
115
+			if ($response->requestTerminated()) {
116
+				exit;
117
+			}
118
+		}
119
+	}
120 120
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Read.php 2 patches
Indentation   +1686 added lines, -1686 removed lines patch added patch discarded remove patch
@@ -52,1690 +52,1690 @@
 block discarded – undo
52 52
  */
53 53
 class Read extends Base
54 54
 {
55
-    protected CalculatedModelFields $fields_calculator;
56
-
57
-
58
-    /**
59
-     * Read constructor.
60
-     *
61
-     * @param CalculatedModelFields $fields_calculator
62
-     */
63
-    public function __construct(CalculatedModelFields $fields_calculator)
64
-    {
65
-        parent::__construct();
66
-        $this->fields_calculator = $fields_calculator;
67
-    }
68
-
69
-
70
-    /**
71
-     * @return Read
72
-     */
73
-    private static function getReadController(): Read
74
-    {
75
-        return LoaderFactory::getLoader()->getNew(Read::class);
76
-    }
77
-
78
-
79
-    /**
80
-     * Handles requests to get all (or a filtered subset) of entities for a particular model
81
-     *
82
-     * @param WP_REST_Request $request
83
-     * @param string          $version
84
-     * @param string          $model_name
85
-     * @return WP_REST_Response
86
-     * @throws InvalidArgumentException
87
-     * @throws InvalidDataTypeException
88
-     * @throws InvalidInterfaceException
89
-     */
90
-    public static function handleRequestGetAll(
91
-        WP_REST_Request $request,
92
-        string $version,
93
-        string $model_name
94
-    ): WP_REST_Response {
95
-        $controller = self::getReadController();
96
-        try {
97
-            $controller->setRequestedVersion($version);
98
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
99
-                return $controller->sendResponse(
100
-                    new WP_Error(
101
-                        'endpoint_parsing_error',
102
-                        sprintf(
103
-                            esc_html__(
104
-                                'There is no model for endpoint %s. Please contact event espresso support',
105
-                                'event_espresso'
106
-                            ),
107
-                            $model_name
108
-                        )
109
-                    )
110
-                );
111
-            }
112
-            return $controller->sendResponse(
113
-                $controller->getEntitiesFromModel(
114
-                    $controller->getModelVersionInfo()->loadModel($model_name),
115
-                    $request
116
-                )
117
-            );
118
-        } catch (Exception $e) {
119
-            return $controller->sendResponse($e);
120
-        }
121
-    }
122
-
123
-
124
-    /**
125
-     * Prepares and returns schema for any OPTIONS request.
126
-     *
127
-     * @param string $version    The API endpoint version being used.
128
-     * @param string $model_name Something like `Event` or `Registration`
129
-     * @return array
130
-     * @throws InvalidArgumentException
131
-     * @throws InvalidDataTypeException
132
-     * @throws InvalidInterfaceException
133
-     */
134
-    public static function handleSchemaRequest(string $version, string $model_name): array
135
-    {
136
-        $controller = self::getReadController();
137
-        try {
138
-            $controller->setRequestedVersion($version);
139
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
140
-                return [];
141
-            }
142
-            // get the model for this version
143
-            $model        = $controller->getModelVersionInfo()->loadModel($model_name);
144
-            $model_schema = new JsonModelSchema(
145
-                $model,
146
-                LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields')
147
-            );
148
-            return $model_schema->getModelSchemaForRelations(
149
-                $controller->getModelVersionInfo()->relationSettings($model),
150
-                $controller->customizeSchemaForRestResponse(
151
-                    $model,
152
-                    $model_schema->getModelSchemaForFields(
153
-                        $controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
154
-                        $model_schema->getInitialSchemaStructure()
155
-                    )
156
-                )
157
-            );
158
-        } catch (Exception $e) {
159
-            error_log($e->getMessage());
160
-            return [];
161
-        }
162
-    }
163
-
164
-
165
-    /**
166
-     * This loops through each field in the given schema for the model and does the following:
167
-     * - add any extra fields that are REST API specific and related to existing fields.
168
-     * - transform default values into the correct format for a REST API response.
169
-     *
170
-     * @param EEM_Base $model
171
-     * @param array    $schema
172
-     * @return array  The final schema.
173
-     * @throws EE_Error
174
-     */
175
-    public function customizeSchemaForRestResponse(EEM_Base $model, array $schema): array
176
-    {
177
-        foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
178
-            $schema = $this->translateDefaultsForRestResponse(
179
-                $field_name,
180
-                $field,
181
-                $this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
182
-            );
183
-        }
184
-        return $schema;
185
-    }
186
-
187
-
188
-    /**
189
-     * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
190
-     * response.
191
-     *
192
-     * @param                      $field_name
193
-     * @param EE_Model_Field_Base  $field
194
-     * @param array                $schema
195
-     * @return array
196
-     * @throws RestException  if a default value has a PHP object, which we should never do
197
-     *                                  (but if we did, let's know about it ASAP, so let the exception bubble up)
198
-     * @throws EE_Error
199
-     *
200
-     */
201
-    protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema): array
202
-    {
203
-        if (isset($schema['properties'][ $field_name ]['default'])) {
204
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
205
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
206
-                    if ($default_key === 'raw') {
207
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
208
-                            ModelDataTranslator::prepareFieldValueForJson(
209
-                                $field,
210
-                                $default_value,
211
-                                $this->getModelVersionInfo()->requestedVersion()
212
-                            );
213
-                    }
214
-                }
215
-            } else {
216
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
217
-                    $field,
218
-                    $schema['properties'][ $field_name ]['default'],
219
-                    $this->getModelVersionInfo()->requestedVersion()
220
-                );
221
-            }
222
-        }
223
-        return $schema;
224
-    }
225
-
226
-
227
-    /**
228
-     * Adds additional fields to the schema
229
-     * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
230
-     * needs to be added to the schema.
231
-     *
232
-     * @param                      $field_name
233
-     * @param EE_Model_Field_Base  $field
234
-     * @param array                $schema
235
-     * @return array
236
-     */
237
-    protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema): array
238
-    {
239
-        if ($field instanceof EE_Datetime_Field) {
240
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
241
-            // modify the description
242
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
243
-                esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
244
-                wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
245
-            );
246
-        }
247
-        return $schema;
248
-    }
249
-
250
-
251
-    /**
252
-     * Used to figure out the route from the request when a `WP_REST_Request` object is not available
253
-     *
254
-     * @return string
255
-     */
256
-    protected function getRouteFromRequest(): string
257
-    {
258
-        if (
259
-            isset($GLOBALS['wp'])
260
-            && $GLOBALS['wp'] instanceof WP
261
-            && isset($GLOBALS['wp']->query_vars['rest_route'])
262
-        ) {
263
-            return $GLOBALS['wp']->query_vars['rest_route'];
264
-        }
265
-        /** @var RequestInterface $request */
266
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
267
-        return $request->serverParamIsSet('PATH_INFO')
268
-            ? $request->getServerParam('PATH_INFO')
269
-            : '/';
270
-    }
271
-
272
-
273
-    /**
274
-     * Gets a single entity related to the model indicated in the path and its id
275
-     *
276
-     * @param WP_REST_Request $request
277
-     * @param string          $version
278
-     * @param string          $model_name
279
-     * @return WP_REST_Response
280
-     * @throws InvalidDataTypeException
281
-     * @throws InvalidInterfaceException
282
-     * @throws InvalidArgumentException
283
-     */
284
-    public static function handleRequestGetOne(
285
-        WP_REST_Request $request,
286
-        string $version,
287
-        string $model_name
288
-    ): WP_REST_Response {
289
-        $controller = self::getReadController();
290
-        try {
291
-            $controller->setRequestedVersion($version);
292
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
293
-                return $controller->sendResponse(
294
-                    new WP_Error(
295
-                        'endpoint_parsing_error',
296
-                        sprintf(
297
-                            esc_html__(
298
-                                'There is no model for endpoint %s. Please contact event espresso support',
299
-                                'event_espresso'
300
-                            ),
301
-                            $model_name
302
-                        )
303
-                    )
304
-                );
305
-            }
306
-            return $controller->sendResponse(
307
-                $controller->getEntityFromModel(
308
-                    $controller->getModelVersionInfo()->loadModel($model_name),
309
-                    $request
310
-                )
311
-            );
312
-        } catch (Exception $e) {
313
-            return $controller->sendResponse($e);
314
-        }
315
-    }
316
-
317
-
318
-    /**
319
-     * Gets all the related entities (or if its a belongs-to relation just the one)
320
-     * to the item with the given id
321
-     *
322
-     * @param WP_REST_Request $request
323
-     * @param string          $version
324
-     * @param string          $model_name
325
-     * @param string          $related_model_name
326
-     * @return WP_REST_Response
327
-     * @throws InvalidDataTypeException
328
-     * @throws InvalidInterfaceException
329
-     * @throws InvalidArgumentException
330
-     */
331
-    public static function handleRequestGetRelated(
332
-        WP_REST_Request $request,
333
-        string $version,
334
-        string $model_name,
335
-        string $related_model_name
336
-    ): WP_REST_Response {
337
-        $controller = self::getReadController();
338
-        try {
339
-            $controller->setRequestedVersion($version);
340
-            $main_model = $controller->validateModel($model_name);
341
-            $controller->validateModel($related_model_name);
342
-            return $controller->sendResponse(
343
-                $controller->getEntitiesFromRelation(
344
-                    $request->get_param('id'),
345
-                    $main_model->related_settings_for($related_model_name),
346
-                    $request
347
-                )
348
-            );
349
-        } catch (Exception $e) {
350
-            return $controller->sendResponse($e);
351
-        }
352
-    }
353
-
354
-
355
-    /**
356
-     * Gets a collection for the given model and filters
357
-     *
358
-     * @param EEM_Base        $model
359
-     * @param WP_REST_Request $request
360
-     * @return array
361
-     * @throws DomainException
362
-     * @throws EE_Error
363
-     * @throws InvalidArgumentException
364
-     * @throws InvalidDataTypeException
365
-     * @throws InvalidInterfaceException
366
-     * @throws ModelConfigurationException
367
-     * @throws ReflectionException
368
-     * @throws RestException
369
-     * @throws RestPasswordIncorrectException
370
-     * @throws RestPasswordRequiredException
371
-     * @throws UnexpectedEntityException
372
-     */
373
-    public function getEntitiesFromModel(EEM_Base $model, WP_REST_Request $request): array
374
-    {
375
-        $query_params = $this->createModelQueryParams($model, $request->get_params());
376
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
377
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
378
-            throw new RestException(
379
-                sprintf('rest_%s_cannot_list', $model_name_plural),
380
-                sprintf(
381
-                    esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
382
-                    $model_name_plural,
383
-                    Capabilities::getMissingPermissionsString($model, $query_params['caps'])
384
-                ),
385
-                ['status' => 403]
386
-            );
387
-        }
388
-        if (! $request->get_header('no_rest_headers')) {
389
-            $this->setHeadersFromQueryParams($model, $query_params);
390
-        }
391
-        /** @type array $results */
392
-        $results      = $model->get_all_wpdb_results($query_params);
393
-        $nice_results = [];
394
-        foreach ($results as $result) {
395
-            $nice_results[] = $this->createEntityFromWpdbResult(
396
-                $model,
397
-                $result,
398
-                $request
399
-            );
400
-        }
401
-        return $nice_results;
402
-    }
403
-
404
-
405
-    /**
406
-     * Gets the collection for given relation object
407
-     * The same as Read::get_entities_from_model(), except if the relation
408
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
409
-     * the join-model-object into the results
410
-     *
411
-     * @param array                  $primary_model_query_params  query params for finding the item from which
412
-     *                                                            relations will be based
413
-     * @param EE_Model_Relation_Base $relation
414
-     * @param WP_REST_Request        $request
415
-     * @return array|null
416
-     * @throws DomainException
417
-     * @throws EE_Error
418
-     * @throws InvalidArgumentException
419
-     * @throws InvalidDataTypeException
420
-     * @throws InvalidInterfaceException
421
-     * @throws ModelConfigurationException
422
-     * @throws ReflectionException
423
-     * @throws RestException
424
-     * @throws ModelConfigurationException
425
-     * @throws UnexpectedEntityException
426
-     * @throws Exception
427
-     */
428
-    protected function getEntitiesFromRelationUsingModelQueryParams(
429
-        array $primary_model_query_params,
430
-        EE_Model_Relation_Base $relation,
431
-        WP_REST_Request $request
432
-    ): ?array {
433
-        $context       = $this->validateContext($request->get_param('caps'));
434
-        $model         = $relation->get_this_model();
435
-        $related_model = $relation->get_other_model();
436
-        if (! isset($primary_model_query_params[0])) {
437
-            $primary_model_query_params[0] = [];
438
-        }
439
-        // check if they can access the 1st model object
440
-        $primary_model_query_params = [
441
-            0       => $primary_model_query_params[0],
442
-            'limit' => 1,
443
-        ];
444
-        if ($model instanceof EEM_Soft_Delete_Base) {
445
-            $primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
446
-                $primary_model_query_params
447
-            );
448
-        }
449
-        $restricted_query_params          = $primary_model_query_params;
450
-        $restricted_query_params['caps']  = $context;
451
-        $restricted_query_params['limit'] = 1;
452
-        $this->setDebugInfo('main model query params', $restricted_query_params);
453
-        $this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
454
-        $primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
455
-        $primary_model_row  = null;
456
-        if (is_array($primary_model_rows)) {
457
-            $primary_model_row = reset($primary_model_rows);
458
-        }
459
-        if (
460
-            ! (
461
-                $primary_model_row
462
-                && Capabilities::currentUserHasPartialAccessTo($related_model, $context)
463
-            )
464
-        ) {
465
-            if ($relation instanceof EE_Belongs_To_Relation) {
466
-                $related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
467
-            } else {
468
-                $related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
469
-                    $related_model->get_this_model_name()
470
-                );
471
-            }
472
-            throw new RestException(
473
-                sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
474
-                sprintf(
475
-                    esc_html__(
476
-                        'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
477
-                        'event_espresso'
478
-                    ),
479
-                    $related_model_name_maybe_plural,
480
-                    $relation->get_this_model()->get_this_model_name(),
481
-                    implode(
482
-                        ',',
483
-                        array_keys(
484
-                            Capabilities::getMissingPermissions($related_model, $context)
485
-                        )
486
-                    )
487
-                ),
488
-                ['status' => 403]
489
-            );
490
-        }
491
-
492
-        $this->checkPassword(
493
-            $model,
494
-            $primary_model_row,
495
-            $restricted_query_params,
496
-            $request
497
-        );
498
-        $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
499
-        foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
500
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
501
-                              . '.'
502
-                              . $where_condition_key ] = $where_condition_value;
503
-        }
504
-        $query_params['default_where_conditions'] = 'none';
505
-        $query_params['caps']                     = $context;
506
-        if (! $request->get_header('no_rest_headers')) {
507
-            $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
508
-        }
509
-        /** @type array $results */
510
-        $results      = $relation->get_other_model()->get_all_wpdb_results($query_params);
511
-        $nice_results = [];
512
-        foreach ($results as $result) {
513
-            $nice_result = $this->createEntityFromWpdbResult(
514
-                $relation->get_other_model(),
515
-                $result,
516
-                $request
517
-            );
518
-            if ($relation instanceof EE_HABTM_Relation) {
519
-                // put the unusual stuff (properties from the HABTM relation) first, and make sure
520
-                // if there are conflicts we prefer the properties from the main model
521
-                $join_model_result = $this->createEntityFromWpdbResult(
522
-                    $relation->get_join_model(),
523
-                    $result,
524
-                    $request
525
-                );
526
-                $joined_result     = array_merge($join_model_result, $nice_result);
527
-                // but keep the meta stuff from the main model
528
-                if (isset($nice_result['meta'])) {
529
-                    $joined_result['meta'] = $nice_result['meta'];
530
-                }
531
-                $nice_result = $joined_result;
532
-            }
533
-            $nice_results[] = $nice_result;
534
-        }
535
-        if ($relation instanceof EE_Belongs_To_Relation) {
536
-            return array_shift($nice_results);
537
-        } else {
538
-            return $nice_results;
539
-        }
540
-    }
541
-
542
-
543
-    /**
544
-     * Gets the collection for given relation object
545
-     * The same as Read::get_entities_from_model(), except if the relation
546
-     * is a HABTM relation, in which case it merges any non-foreign-key fields from
547
-     * the join-model-object into the results
548
-     *
549
-     * @param int|string             $id the ID of the thing we are fetching related stuff from
550
-     * @param EE_Model_Relation_Base $relation
551
-     * @param WP_REST_Request        $request
552
-     * @return array
553
-     * @throws DomainException
554
-     * @throws EE_Error
555
-     * @throws InvalidArgumentException
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidInterfaceException
558
-     * @throws ReflectionException
559
-     * @throws RestException
560
-     * @throws ModelConfigurationException
561
-     * @throws UnexpectedEntityException
562
-     * @throws Exception
563
-     */
564
-    public function getEntitiesFromRelation($id, EE_Model_Relation_Base $relation, WP_REST_Request $request): array
565
-    {
566
-        if (! $relation->get_this_model()->has_primary_key_field()) {
567
-            throw new EE_Error(
568
-                sprintf(
569
-                    esc_html__(
570
-                    // @codingStandardsIgnoreStart
571
-                        'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
572
-                        // @codingStandardsIgnoreEnd
573
-                        'event_espresso'
574
-                    ),
575
-                    $relation->get_this_model()->get_this_model_name()
576
-                )
577
-            );
578
-        }
579
-        // can we edit that main item?
580
-        // if not, show nothing but an error
581
-        // otherwise, please proceed
582
-        return $this->getEntitiesFromRelationUsingModelQueryParams(
583
-            [
584
-                [
585
-                    $relation->get_this_model()->primary_key_name() => $id,
586
-                ],
587
-            ],
588
-            $relation,
589
-            $request
590
-        );
591
-    }
592
-
593
-
594
-    /**
595
-     * Sets the headers that are based on the model and query params,
596
-     * like the total records. This should only be called on the original request
597
-     * from the client, not on subsequent internal
598
-     *
599
-     * @param EEM_Base $model
600
-     * @param array    $query_params
601
-     * @return void
602
-     * @throws EE_Error
603
-     * @throws ReflectionException
604
-     */
605
-    protected function setHeadersFromQueryParams(EEM_Base $model, array $query_params)
606
-    {
607
-        $this->setDebugInfo('model query params', $query_params);
608
-        $this->setDebugInfo(
609
-            'missing caps',
610
-            Capabilities::getMissingPermissionsString($model, $query_params['caps'])
611
-        );
612
-        // normally the limit to a 2-part array, where the 2nd item is the limit
613
-        if (! isset($query_params['limit'])) {
614
-            $query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
615
-        }
616
-        if (is_array($query_params['limit'])) {
617
-            $limit_parts = $query_params['limit'];
618
-        } else {
619
-            $limit_parts = explode(',', $query_params['limit']);
620
-            if (count($limit_parts) === 1) {
621
-                $limit_parts = [0, $limit_parts[0]];
622
-            }
623
-        }
624
-        // remove the group by and having parts of the query, as those will
625
-        // make the sql query return an array of values, instead of just a single value
626
-        unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
627
-        $count = $model->count($query_params, null, true);
628
-        $pages = $count / $limit_parts[1];
629
-        $this->setResponseHeader('Total', $count, false);
630
-        $this->setResponseHeader('PageSize', $limit_parts[1], false);
631
-        $this->setResponseHeader('TotalPages', ceil($pages), false);
632
-    }
633
-
634
-
635
-    /**
636
-     * Changes database results into REST API entities
637
-     *
638
-     * @param EEM_Base             $model
639
-     * @param array                $db_row     like results from $wpdb->get_results()
640
-     * @param WP_REST_Request|null $rest_request
641
-     * @param string|null          $deprecated no longer used
642
-     * @return array ready for being converted into json for sending to client
643
-     * @throws DomainException
644
-     * @throws EE_Error
645
-     * @throws InvalidArgumentException
646
-     * @throws InvalidDataTypeException
647
-     * @throws InvalidInterfaceException
648
-     * @throws ModelConfigurationException
649
-     * @throws ReflectionException
650
-     * @throws RestException
651
-     * @throws RestPasswordIncorrectException
652
-     * @throws RestPasswordRequiredException
653
-     * @throws UnexpectedEntityException
654
-     */
655
-    public function createEntityFromWpdbResult(
656
-        EEM_Base $model,
657
-        array $db_row,
658
-        ?WP_REST_Request $rest_request,
659
-        string $deprecated = null
660
-    ): array {
661
-        if (! $rest_request instanceof WP_REST_Request) {
662
-            // ok so this was called in the old style, where the 3rd arg was
663
-            // $include, and the 4th arg was $context
664
-            // now setup the request just to avoid fatal errors, although we won't be able
665
-            // to truly make use of it because it's kinda devoid of info
666
-            $rest_request = new WP_REST_Request();
667
-            $rest_request->set_param('include', $rest_request);
668
-            $rest_request->set_param('caps', $deprecated);
669
-        }
670
-        if ($rest_request->get_param('caps') === null) {
671
-            $rest_request->set_param('caps', EEM_Base::caps_read);
672
-        }
673
-        $current_user_full_access_to_entity = $model->currentUserCan(
674
-            EEM_Base::caps_read_admin,
675
-            $model->deduce_fields_n_values_from_cols_n_values($db_row)
676
-        );
677
-        $entity_array                       = $this->createBareEntityFromWpdbResults($model, $db_row);
678
-        $entity_array                       = $this->addExtraFields($model, $db_row, $entity_array);
679
-        $entity_array['_links']             = $this->getEntityLinks($model, $db_row, $entity_array);
680
-        // when it's a regular read request for a model with a password and the password wasn't provided
681
-        // remove the password protected fields
682
-        $has_protected_fields = false;
683
-        try {
684
-            $this->checkPassword(
685
-                $model,
686
-                $db_row,
687
-                $model->alter_query_params_to_restrict_by_ID(
688
-                    $model->get_index_primary_key_string(
689
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
690
-                    )
691
-                ),
692
-                $rest_request
693
-            );
694
-        } catch (RestPasswordRequiredException $e) {
695
-            if ($model->hasPassword()) {
696
-                // just remove protected fields
697
-                $has_protected_fields = true;
698
-                $entity_array         = Capabilities::filterOutPasswordProtectedFields(
699
-                    $entity_array,
700
-                    $model,
701
-                    $this->getModelVersionInfo()
702
-                );
703
-            } else {
704
-                // that's a problem. None of this should be accessible if no password was provided
705
-                throw $e;
706
-            }
707
-        }
708
-
709
-        $entity_array['_calculated_fields'] = $this->getEntityCalculations(
710
-            $model,
711
-            $db_row,
712
-            $rest_request,
713
-            $has_protected_fields
714
-        );
715
-        $entity_array                       = apply_filters(
716
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
717
-            $entity_array,
718
-            $model,
719
-            $rest_request->get_param('caps'),
720
-            $rest_request,
721
-            $this
722
-        );
723
-        // add an empty protected property for now. If it's still around after we remove everything the request didn't
724
-        // want, we'll populate it then. k?
725
-        $entity_array['_protected'] = [];
726
-        // remove any properties the request didn't want. This way _protected won't bother mentioning them
727
-        $entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
728
-        $entity_array = $this->includeRequestedModels(
729
-            $model,
730
-            $rest_request,
731
-            $entity_array,
732
-            $db_row,
733
-            $has_protected_fields
734
-        );
735
-        // if they still wanted the _protected property, add it.
736
-        if (isset($entity_array['_protected'])) {
737
-            $entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
738
-        }
739
-        $entity_array = apply_filters(
740
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
741
-            $entity_array,
742
-            $model,
743
-            $rest_request->get_param('caps'),
744
-            $rest_request,
745
-            $this
746
-        );
747
-        if (! $current_user_full_access_to_entity) {
748
-            $result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
749
-                $entity_array,
750
-                $model,
751
-                $rest_request->get_param('caps'),
752
-                $this->getModelVersionInfo()
753
-            );
754
-        } else {
755
-            $result_without_inaccessible_fields = $entity_array;
756
-        }
757
-        $this->setDebugInfo(
758
-            'inaccessible fields',
759
-            array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
760
-        );
761
-        return apply_filters(
762
-            'FHEE__Read__create_entity_from_wpdb_results__entity_return',
763
-            $result_without_inaccessible_fields,
764
-            $model,
765
-            $rest_request->get_param('caps')
766
-        );
767
-    }
768
-
769
-
770
-    /**
771
-     * Returns an array describing which fields can be protected, and which actually were removed this request
772
-     *
773
-     * @param EEM_Base $model
774
-     * @param array    $results_so_far
775
-     * @param bool     $protected
776
-     * @return array results
777
-     * @throws EE_Error
778
-     * @since 4.9.74.p
779
-     */
780
-    protected function addProtectedProperty(EEM_Base $model, array $results_so_far, bool $protected): array
781
-    {
782
-        if (! $protected || ! $model->hasPassword()) {
783
-            return $results_so_far;
784
-        }
785
-        $password_field  = $model->getPasswordField();
786
-        $all_protected   = array_merge(
787
-            [$password_field->get_name()],
788
-            $password_field->protectedFields()
789
-        );
790
-        $fields_included = array_keys($results_so_far);
791
-        $fields_included = array_intersect(
792
-            $all_protected,
793
-            $fields_included
794
-        );
795
-        foreach ($fields_included as $field_name) {
796
-            $results_so_far['_protected'][] = $field_name;
797
-        }
798
-        return $results_so_far;
799
-    }
800
-
801
-
802
-    /**
803
-     * Creates a REST entity array (JSON object we're going to return in the response, but
804
-     * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
805
-     * from $wpdb->get_row( $sql, ARRAY_A)
806
-     *
807
-     * @param EEM_Base $model
808
-     * @param array    $db_row
809
-     * @return array entity mostly ready for converting to JSON and sending in the response
810
-     * @throws EE_Error
811
-     * @throws ReflectionException
812
-     * @throws RestException
813
-     * @throws Exception
814
-     */
815
-    protected function createBareEntityFromWpdbResults(EEM_Base $model, array $db_row): array
816
-    {
817
-        $result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
818
-        $result = array_intersect_key(
819
-            $result,
820
-            $this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
821
-        );
822
-        // if this is a CPT, we need to set the global $post to it,
823
-        // otherwise shortcodes etc won't work properly while rendering it
824
-        if ($model instanceof EEM_CPT_Base) {
825
-            $do_chevy_shuffle = true;
826
-        } else {
827
-            $do_chevy_shuffle = false;
828
-        }
829
-        if ($do_chevy_shuffle) {
830
-            global $post;
831
-            $old_post = $post;
832
-            $post     = get_post($result[ $model->primary_key_name() ]);
833
-            if (! $post instanceof WP_Post) {
834
-                // well that's weird, because $result is what we JUST fetched from the database
835
-                throw new RestException(
836
-                    'error_fetching_post_from_database_results',
837
-                    esc_html__(
838
-                        'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
839
-                        'event_espresso'
840
-                    )
841
-                );
842
-            }
843
-            $model_object_classname          = 'EE_' . $model->get_this_model_name();
844
-            $post->{$model_object_classname} = EE_Registry::instance()->load_class(
845
-                $model_object_classname,
846
-                $result,
847
-                false,
848
-                false
849
-            );
850
-        }
851
-        foreach ($result as $field_name => $field_value) {
852
-            $field_obj = $model->field_settings_for($field_name);
853
-            if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
854
-                unset($result[ $field_name ]);
855
-            } elseif (
856
-                $this->isSubclassOfOne(
857
-                    $field_obj,
858
-                    $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
859
-                )
860
-            ) {
861
-                $result[ $field_name ] = [
862
-                    'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
863
-                    'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
864
-                ];
865
-            } elseif (
866
-                $this->isSubclassOfOne(
867
-                    $field_obj,
868
-                    $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
869
-                )
870
-            ) {
871
-                $result[ $field_name ] = [
872
-                    'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
873
-                    'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
874
-                ];
875
-            } elseif ($field_obj instanceof EE_Datetime_Field) {
876
-                $field_value = $field_obj->prepare_for_set_from_db($field_value);
877
-                // if the value is null, but we're not supposed to permit null, then set to the field's default
878
-                if (is_null($field_value)) {
879
-                    $field_value = $field_obj->getDefaultDateTimeObj();
880
-                }
881
-                if (is_null($field_value)) {
882
-                    $gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
883
-                        $field_obj,
884
-                        $field_value,
885
-                        $this->getModelVersionInfo()->requestedVersion()
886
-                    );
887
-                } else {
888
-                    $timezone = $field_value->getTimezone();
889
-                    EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
890
-                    $gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
891
-                        $field_obj,
892
-                        $field_value,
893
-                        $this->getModelVersionInfo()->requestedVersion()
894
-                    );
895
-                    EEH_DTT_Helper::setTimezone($field_value, $timezone);
896
-                    $local_date = ModelDataTranslator::prepareFieldValuesForJson(
897
-                        $field_obj,
898
-                        $field_value,
899
-                        $this->getModelVersionInfo()->requestedVersion()
900
-                    );
901
-                }
902
-                $result[ $field_name . '_gmt' ] = $gmt_date;
903
-                $result[ $field_name ]          = $local_date;
904
-            } else {
905
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
906
-            }
907
-        }
908
-        if ($do_chevy_shuffle) {
909
-            $post = $old_post;
910
-        }
911
-        return $result;
912
-    }
913
-
914
-
915
-    /**
916
-     * Takes a value all the way from the DB representation, to the model object's representation, to the
917
-     * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
918
-     * representation using $field_obj->prepare_for_set_from_db())
919
-     *
920
-     * @param EE_Model_Field_Base $field_obj
921
-     * @param mixed               $value  as it's stored on a model object
922
-     * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
923
-     * @return array|int
924
-     * @throws RestException if $value contains a PHP object
925
-     * @throws EE_Error
926
-     */
927
-    protected function prepareFieldObjValueForJson(
928
-        EE_Model_Field_Base $field_obj,
929
-        $value,
930
-        string $format = 'normal'
931
-    ) {
932
-        $value = $field_obj->prepare_for_set_from_db($value);
933
-        switch ($format) {
934
-            case 'pretty':
935
-                $value = $field_obj->prepare_for_pretty_echoing($value);
936
-                break;
937
-            case 'normal':
938
-            default:
939
-                $value = $field_obj->prepare_for_get($value);
940
-                break;
941
-        }
942
-        return ModelDataTranslator::prepareFieldValuesForJson(
943
-            $field_obj,
944
-            $value,
945
-            $this->getModelVersionInfo()->requestedVersion()
946
-        );
947
-    }
948
-
949
-
950
-    /**
951
-     * Adds a few extra fields to the entity response
952
-     *
953
-     * @param EEM_Base $model
954
-     * @param array    $db_row
955
-     * @param array    $entity_array
956
-     * @return array modified entity
957
-     * @throws EE_Error
958
-     */
959
-    protected function addExtraFields(EEM_Base $model, array $db_row, array $entity_array): array
960
-    {
961
-        if ($model instanceof EEM_CPT_Base) {
962
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
963
-        }
964
-        return $entity_array;
965
-    }
966
-
967
-
968
-    /**
969
-     * Gets links we want to add to the response
970
-     *
971
-     * @param EEM_Base        $model
972
-     * @param array           $db_row
973
-     * @param array           $entity_array
974
-     * @return array the _links item in the entity
975
-     * @throws EE_Error
976
-     * @global WP_REST_Server $wp_rest_server
977
-     */
978
-    protected function getEntityLinks(EEM_Base $model, array $db_row, array $entity_array): array
979
-    {
980
-        // add basic links
981
-        $links = [];
982
-        if ($model->has_primary_key_field()) {
983
-            $links['self'] = [
984
-                [
985
-                    'href' => $this->getVersionedLinkTo(
986
-                        EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
987
-                        . '/'
988
-                        . $entity_array[ $model->primary_key_name() ]
989
-                    ),
990
-                ],
991
-            ];
992
-        }
993
-        $links['collection'] = [
994
-            [
995
-                'href' => $this->getVersionedLinkTo(
996
-                    EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
997
-                ),
998
-            ],
999
-        ];
1000
-        // add links to related models
1001
-        if ($model->has_primary_key_field()) {
1002
-            foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
1003
-                $related_model_part                                                      =
1004
-                    Read::getRelatedEntityName($relation_name, $relation_obj);
1005
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
1006
-                    [
1007
-                        'href'   => $this->getVersionedLinkTo(
1008
-                            EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
1009
-                            . '/'
1010
-                            . $entity_array[ $model->primary_key_name() ]
1011
-                            . '/'
1012
-                            . $related_model_part
1013
-                        ),
1014
-                        'single' => $relation_obj instanceof EE_Belongs_To_Relation,
1015
-                    ],
1016
-                ];
1017
-            }
1018
-        }
1019
-        return $links;
1020
-    }
1021
-
1022
-
1023
-    /**
1024
-     * Adds the included models indicated in the request to the entity provided
1025
-     *
1026
-     * @param EEM_Base        $model
1027
-     * @param WP_REST_Request $rest_request
1028
-     * @param array           $entity_array
1029
-     * @param array           $db_row
1030
-     * @param boolean         $included_items_protected if the original item is password protected, don't include any
1031
-     *                                                  related models.
1032
-     * @return array the modified entity
1033
-     * @throws DomainException
1034
-     * @throws EE_Error
1035
-     * @throws InvalidArgumentException
1036
-     * @throws InvalidDataTypeException
1037
-     * @throws InvalidInterfaceException
1038
-     * @throws ModelConfigurationException
1039
-     * @throws ReflectionException
1040
-     * @throws UnexpectedEntityException
1041
-     */
1042
-    protected function includeRequestedModels(
1043
-        EEM_Base $model,
1044
-        WP_REST_Request $rest_request,
1045
-        array $entity_array,
1046
-        array $db_row = [],
1047
-        bool $included_items_protected = false
1048
-    ): array {
1049
-        // if $db_row not included, hope the entity array has what we need
1050
-        if (! $db_row) {
1051
-            $db_row = $entity_array;
1052
-        }
1053
-        $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
1054
-        foreach ($relation_settings as $relation_name => $relation_obj) {
1055
-            $related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1056
-                $rest_request->get_param('include'),
1057
-                $relation_name
1058
-            );
1059
-            $related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
1060
-                $rest_request->get_param('calculate'),
1061
-                $relation_name
1062
-            );
1063
-            // did they specify they wanted to include a related model, or
1064
-            // specific fields from a related model?
1065
-            // or did they specify to calculate a field from a related model?
1066
-            if ($related_fields_to_include || $related_fields_to_calculate) {
1067
-                // if so, we should include at least some part of the related model
1068
-                $pretend_related_request = new WP_REST_Request();
1069
-                $pretend_related_request->set_query_params(
1070
-                    [
1071
-                        'caps'      => $rest_request->get_param('caps'),
1072
-                        'include'   => $related_fields_to_include,
1073
-                        'calculate' => $related_fields_to_calculate,
1074
-                        'password'  => $rest_request->get_param('password'),
1075
-                    ]
1076
-                );
1077
-                $pretend_related_request->add_header('no_rest_headers', true);
1078
-                $primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
1079
-                    $model->get_index_primary_key_string(
1080
-                        $model->deduce_fields_n_values_from_cols_n_values($db_row)
1081
-                    )
1082
-                );
1083
-                if (! $included_items_protected) {
1084
-                    try {
1085
-                        $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1086
-                            $primary_model_query_params,
1087
-                            $relation_obj,
1088
-                            $pretend_related_request
1089
-                        );
1090
-                    } catch (RestException $e) {
1091
-                        $related_results = null;
1092
-                    }
1093
-                } else {
1094
-                    // they're protected, hide them.
1095
-                    $related_results              = null;
1096
-                    $entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
1097
-                }
1098
-                if ($related_results instanceof WP_Error || $related_results === null) {
1099
-                    $related_results = $relation_obj instanceof EE_Belongs_To_Relation
1100
-                            ? null
1101
-                            : [];
1102
-                }
1103
-                $entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1104
-            }
1105
-        }
1106
-        return $entity_array;
1107
-    }
1108
-
1109
-
1110
-    /**
1111
-     * If the user has requested only specific properties (including meta properties like _links or _protected)
1112
-     * remove everything else.
1113
-     *
1114
-     * @param EEM_Base        $model
1115
-     * @param WP_REST_Request $rest_request
1116
-     * @param                 $entity_array
1117
-     * @return array
1118
-     * @throws EE_Error
1119
-     * @since 4.9.74.p
1120
-     */
1121
-    protected function includeOnlyRequestedProperties(
1122
-        EEM_Base $model,
1123
-        WP_REST_Request $rest_request,
1124
-        $entity_array
1125
-    ): array {
1126
-
1127
-        $includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1128
-        $includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
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)) {
1131
-            if ($model->has_primary_key_field()) {
1132
-                // always include the primary key. ya just gotta know that at least
1133
-                $includes_for_this_model[] = $model->primary_key_name();
1134
-            }
1135
-            if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1136
-                $includes_for_this_model[] = '_calculated_fields';
1137
-            }
1138
-            $entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1139
-        }
1140
-        return $entity_array;
1141
-    }
1142
-
1143
-
1144
-    /**
1145
-     * Returns a new array with all the names of models removed. Eg
1146
-     * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1147
-     *
1148
-     * @param array $array
1149
-     * @return array
1150
-     */
1151
-    private function removeModelNamesFromArray(array $array): array
1152
-    {
1153
-        return array_diff($array, array_keys(EE_Registry::instance()->non_abstract_db_models));
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * Gets the calculated fields for the response
1159
-     *
1160
-     * @param EEM_Base        $model
1161
-     * @param array           $wpdb_row
1162
-     * @param WP_REST_Request $rest_request
1163
-     * @param bool            $row_is_protected whether this row is password protected or not
1164
-     * @return stdClass the _calculations item in the entity
1165
-     * @throws RestException if a default value has a PHP object, which should never do (and if we
1166
-     *                                          did, let's know about it ASAP, so let the exception bubble up)
1167
-     * @throws EE_Error
1168
-     */
1169
-    protected function getEntityCalculations(
1170
-        EEM_Base $model,
1171
-        array $wpdb_row,
1172
-        WP_REST_Request $rest_request,
1173
-        bool $row_is_protected = false
1174
-    ): stdClass {
1175
-        $calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1176
-            $rest_request->get_param('calculate'),
1177
-            ''
1178
-        );
1179
-        // note: setting calculate=* doesn't do anything
1180
-        $calculated_fields_to_return = new stdClass();
1181
-        $protected_fields            = [];
1182
-        foreach ($calculated_fields as $field_to_calculate) {
1183
-            try {
1184
-                // it's password protected, so they shouldn't be able to read this. Remove the value
1185
-                $schema = $this->fields_calculator->getJsonSchemaForModel($model);
1186
-                if (
1187
-                    $row_is_protected
1188
-                    && isset($schema['properties'][ $field_to_calculate ]['protected'])
1189
-                    && $schema['properties'][ $field_to_calculate ]['protected']
1190
-                ) {
1191
-                    $calculated_value   = null;
1192
-                    $protected_fields[] = $field_to_calculate;
1193
-                    if ($schema['properties'][ $field_to_calculate ]['type']) {
1194
-                        switch ($schema['properties'][ $field_to_calculate ]['type']) {
1195
-                            case 'boolean':
1196
-                                $calculated_value = false;
1197
-                                break;
1198
-                            case 'integer':
1199
-                                $calculated_value = 0;
1200
-                                break;
1201
-                            case 'string':
1202
-                                $calculated_value = '';
1203
-                                break;
1204
-                            case 'array':
1205
-                                $calculated_value = [];
1206
-                                break;
1207
-                            case 'object':
1208
-                                $calculated_value = new stdClass();
1209
-                                break;
1210
-                        }
1211
-                    }
1212
-                } else {
1213
-                    $calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1214
-                        null,
1215
-                        $this->fields_calculator->retrieveCalculatedFieldValue(
1216
-                            $model,
1217
-                            $field_to_calculate,
1218
-                            $wpdb_row,
1219
-                            $rest_request,
1220
-                            $this
1221
-                        ),
1222
-                        $this->getModelVersionInfo()->requestedVersion()
1223
-                    );
1224
-                }
1225
-                $calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1226
-            } catch (RestException $e) {
1227
-                // if we don't have permission to read it, just leave it out. but let devs know about the problem
1228
-                $this->setResponseHeader(
1229
-                    'Notices-Field-Calculation-Errors['
1230
-                    . $e->getStringCode()
1231
-                    . ']['
1232
-                    . $model->get_this_model_name()
1233
-                    . ']['
1234
-                    . $field_to_calculate
1235
-                    . ']',
1236
-                    $e->getMessage()
1237
-                );
1238
-            }
1239
-        }
1240
-        $calculated_fields_to_return->_protected = $protected_fields;
1241
-        return $calculated_fields_to_return;
1242
-    }
1243
-
1244
-
1245
-    /**
1246
-     * Gets the full URL to the resource, taking the requested version into account
1247
-     *
1248
-     * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1249
-     * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1250
-     * @throws EE_Error
1251
-     */
1252
-    public function getVersionedLinkTo(string $link_part_after_version_and_slash): string
1253
-    {
1254
-        return rest_url(
1255
-            EED_Core_Rest_Api::get_versioned_route_to(
1256
-                $link_part_after_version_and_slash,
1257
-                $this->getModelVersionInfo()->requestedVersion()
1258
-            )
1259
-        );
1260
-    }
1261
-
1262
-
1263
-    /**
1264
-     * Gets the correct lowercase name for the relation in the API according
1265
-     * to the relation's type
1266
-     *
1267
-     * @param string                 $relation_name
1268
-     * @param EE_Model_Relation_Base $relation_obj
1269
-     * @return string
1270
-     */
1271
-    public static function getRelatedEntityName(string $relation_name, EE_Model_Relation_Base $relation_obj): string
1272
-    {
1273
-        if ($relation_obj instanceof EE_Belongs_To_Relation) {
1274
-            return strtolower($relation_name);
1275
-        }
1276
-        return EEH_Inflector::pluralize_and_lower($relation_name);
1277
-    }
1278
-
1279
-
1280
-    /**
1281
-     * Gets the one model object with the specified id for the specified model
1282
-     *
1283
-     * @param EEM_Base        $model
1284
-     * @param WP_REST_Request $request
1285
-     * @return array
1286
-     * @throws EE_Error
1287
-     * @throws InvalidArgumentException
1288
-     * @throws InvalidDataTypeException
1289
-     * @throws InvalidInterfaceException
1290
-     * @throws ModelConfigurationException
1291
-     * @throws ReflectionException
1292
-     * @throws RestException
1293
-     * @throws RestPasswordIncorrectException
1294
-     * @throws RestPasswordRequiredException
1295
-     * @throws UnexpectedEntityException
1296
-     * @throws DomainException
1297
-     */
1298
-    public function getEntityFromModel(EEM_Base $model, WP_REST_Request $request): array
1299
-    {
1300
-        $context = $this->validateContext($request->get_param('caps'));
1301
-        return $this->getOneOrReportPermissionError($model, $request, $context);
1302
-    }
1303
-
1304
-
1305
-    /**
1306
-     * If a context is provided which isn't valid, maybe it was added in a future
1307
-     * version so just treat it as a default read
1308
-     *
1309
-     * @param string|null $context
1310
-     * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1311
-     */
1312
-    public function validateContext(?string $context): string
1313
-    {
1314
-        if (! $context) {
1315
-            $context = EEM_Base::caps_read;
1316
-        }
1317
-        $valid_contexts = EEM_Base::valid_cap_contexts();
1318
-        if (in_array($context, $valid_contexts, true)) {
1319
-            return $context;
1320
-        }
1321
-        return EEM_Base::caps_read;
1322
-    }
1323
-
1324
-
1325
-    /**
1326
-     * Verifies the passed in value is an allowable default where conditions value.
1327
-     *
1328
-     * @param string $default_where_conditions
1329
-     * @return string
1330
-     */
1331
-    public function validateDefaultQueryParams(string $default_where_conditions): string
1332
-    {
1333
-        $valid_default_where_conditions_for_api_calls = [
1334
-            EE_Default_Where_Conditions::ALL,
1335
-            EE_Default_Where_Conditions::MINIMUM_ALL,
1336
-            EE_Default_Where_Conditions::MINIMUM_OTHERS,
1337
-        ];
1338
-        if (! $default_where_conditions) {
1339
-            $default_where_conditions = EE_Default_Where_Conditions::ALL;
1340
-        }
1341
-        if (
1342
-            in_array(
1343
-                $default_where_conditions,
1344
-                $valid_default_where_conditions_for_api_calls,
1345
-                true
1346
-            )
1347
-        ) {
1348
-            return $default_where_conditions;
1349
-        }
1350
-        return EE_Default_Where_Conditions::ALL;
1351
-    }
1352
-
1353
-
1354
-    /**
1355
-     * Translates API filter get parameter into model query params @param EEM_Base $model
1356
-     *
1357
-     * @param array $query_params
1358
-     * @return array model query params (@see
1359
-     *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1360
-     *               or FALSE to indicate that absolutely no results should be returned
1361
-     * @throws EE_Error
1362
-     * @throws InvalidArgumentException
1363
-     * @throws InvalidDataTypeException
1364
-     * @throws InvalidInterfaceException
1365
-     * @throws RestException
1366
-     * @throws DomainException
1367
-     * @throws ReflectionException
1368
-     * @see
1369
-     *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1370
-     *               Note: right now the query parameter keys for fields (and related fields) can be left as-is, but
1371
-     *               it's quite possible this will change someday. Also, this method's contents might be candidate for
1372
-     *               moving to Model_Data_Translator
1373
-     *
1374
-     */
1375
-    public function createModelQueryParams(EEM_Base $model, array $query_params): array
1376
-    {
1377
-        $model_query_params = [];
1378
-        if (isset($query_params['where'])) {
1379
-            $model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1380
-                $query_params['where'],
1381
-                $model,
1382
-                $this->getModelVersionInfo()->requestedVersion()
1383
-            );
1384
-        }
1385
-        if (isset($query_params['order_by'])) {
1386
-            $order_by = $query_params['order_by'];
1387
-        } elseif (isset($query_params['orderby'])) {
1388
-            $order_by = $query_params['orderby'];
1389
-        } else {
1390
-            $order_by = null;
1391
-        }
1392
-        if ($order_by !== null) {
1393
-            if (is_array($order_by)) {
1394
-                $order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1395
-            } else {
1396
-                // it's a single item
1397
-                $order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1398
-            }
1399
-            $model_query_params['order_by'] = $order_by;
1400
-        }
1401
-        if (isset($query_params['group_by'])) {
1402
-            $group_by = $query_params['group_by'];
1403
-        } elseif (isset($query_params['groupby'])) {
1404
-            $group_by = $query_params['groupby'];
1405
-        } else {
1406
-            $group_by = array_keys($model->get_combined_primary_key_fields());
1407
-        }
1408
-        // make sure they're all real names
1409
-        if (is_array($group_by)) {
1410
-            $group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1411
-        }
1412
-        if ($group_by !== null) {
1413
-            $model_query_params['group_by'] = $group_by;
1414
-        }
1415
-        if (isset($query_params['having'])) {
1416
-            $model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1417
-                $query_params['having'],
1418
-                $model,
1419
-                $this->getModelVersionInfo()->requestedVersion()
1420
-            );
1421
-        }
1422
-        if (isset($query_params['order'])) {
1423
-            $model_query_params['order'] = $query_params['order'];
1424
-        }
1425
-        if (isset($query_params['mine'])) {
1426
-            $model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1427
-        }
1428
-        if (isset($query_params['limit'])) {
1429
-            // limit should be either a string like '23' or '23,43', or an array with two items in it
1430
-            if (! is_array($query_params['limit'])) {
1431
-                $limit_array = explode(',', (string) $query_params['limit']);
1432
-            } else {
1433
-                $limit_array = $query_params['limit'];
1434
-            }
1435
-            $sanitized_limit = [];
1436
-            foreach ($limit_array as $limit_part) {
1437
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1438
-                    throw new EE_Error(
1439
-                        sprintf(
1440
-                            esc_html__(
1441
-                            // @codingStandardsIgnoreStart
1442
-                                '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.',
1443
-                                // @codingStandardsIgnoreEnd
1444
-                                'event_espresso'
1445
-                            ),
1446
-                            wp_json_encode($query_params['limit'])
1447
-                        )
1448
-                    );
1449
-                }
1450
-                $sanitized_limit[] = (int) $limit_part;
1451
-            }
1452
-            $model_query_params['limit'] = implode(',', $sanitized_limit);
1453
-        } else {
1454
-            $model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1455
-        }
1456
-        if (isset($query_params['caps'])) {
1457
-            $model_query_params['caps'] = $this->validateContext($query_params['caps']);
1458
-        } else {
1459
-            $model_query_params['caps'] = EEM_Base::caps_read;
1460
-        }
1461
-        if (isset($query_params['default_where_conditions'])) {
1462
-            $model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1463
-                $query_params['default_where_conditions']
1464
-            );
1465
-        }
1466
-        // if this is a model protected by a password on another model, exclude the password protected
1467
-        // entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1468
-        // though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1469
-        if (
1470
-            $model_query_params['caps'] === EEM_Base::caps_read
1471
-            && empty($query_params['password'])
1472
-            && ! $model->hasPassword()
1473
-            && $model->restrictedByRelatedModelPassword()
1474
-        ) {
1475
-            $model_query_params['exclude_protected'] = true;
1476
-        }
1477
-
1478
-        return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1479
-    }
1480
-
1481
-
1482
-    /**
1483
-     * Changes the REST-style query params for use in the models
1484
-     *
1485
-     * @param EEM_Base $model
1486
-     * @param array    $query_params sub-array from @see EEM_Base::get_all()
1487
-     * @return array
1488
-     * @deprecated
1489
-     */
1490
-    public function prepareRestQueryParamsKeyForModels(EEM_Base $model, array $query_params): array
1491
-    {
1492
-        $model_ready_query_params = [];
1493
-        foreach ($query_params as $key => $value) {
1494
-            $model_ready_query_params[ $key ] = is_array($value)
1495
-                ? $this->prepareRestQueryParamsKeyForModels($model, $value)
1496
-                : $value;
1497
-        }
1498
-        return $model_ready_query_params;
1499
-    }
1500
-
1501
-
1502
-    /**
1503
-     * @param $model
1504
-     * @param $query_params
1505
-     * @return array
1506
-     * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1507
-     */
1508
-    public function prepareRestQueryParamsValuesForModels($model, $query_params): array
1509
-    {
1510
-        $model_ready_query_params = [];
1511
-        foreach ($query_params as $key => $value) {
1512
-            if (is_array($value)) {
1513
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1514
-            } else {
1515
-                $model_ready_query_params[ $key ] = $value;
1516
-            }
1517
-        }
1518
-        return $model_ready_query_params;
1519
-    }
1520
-
1521
-
1522
-    /**
1523
-     * Explodes the string on commas, and only returns items with $prefix followed by a period.
1524
-     * If no prefix is specified, returns items with no period.
1525
-     *
1526
-     * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1527
-     * @param string       $prefix            "Event" or "foobar"
1528
-     * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1529
-     *                                        we only return strings starting with that and a period; if no prefix was
1530
-     *                                        specified we return all items containing NO periods
1531
-     */
1532
-    public function explodeAndGetItemsPrefixedWith($string_to_explode, string $prefix): array
1533
-    {
1534
-        if (is_string($string_to_explode)) {
1535
-            $exploded_contents = explode(',', $string_to_explode);
1536
-        } elseif (is_array($string_to_explode)) {
1537
-            $exploded_contents = $string_to_explode;
1538
-        } else {
1539
-            $exploded_contents = [];
1540
-        }
1541
-        // if the string was empty, we want an empty array
1542
-        $exploded_contents    = array_filter($exploded_contents);
1543
-        $contents_with_prefix = [];
1544
-        foreach ($exploded_contents as $item) {
1545
-            $item = trim($item);
1546
-            // if no prefix was provided, so we look for items with no "." in them
1547
-            if (! $prefix) {
1548
-                // does this item have a period?
1549
-                if (strpos($item, '.') === false) {
1550
-                    // if not, then its what we're looking for
1551
-                    $contents_with_prefix[] = $item;
1552
-                }
1553
-            } elseif (strpos($item, $prefix . '.') === 0) {
1554
-                // this item has the prefix and a period, grab it
1555
-                $contents_with_prefix[] = substr(
1556
-                    $item,
1557
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1558
-                );
1559
-            } elseif ($item === $prefix) {
1560
-                // this item is JUST the prefix
1561
-                // so let's grab everything after, which is a blank string
1562
-                $contents_with_prefix[] = '';
1563
-            }
1564
-        }
1565
-        return $contents_with_prefix;
1566
-    }
1567
-
1568
-
1569
-    /**
1570
-     * @param string      $include_string @see Read:handle_request_get_all
1571
-     * @param string|null $model_name
1572
-     * @return array of fields for this model. If $model_name is provided, then
1573
-     *                                    the fields for that model, with the model's name removed from each.
1574
-     *                                    If $include_string was blank or '*' returns an empty array
1575
-     * @throws EE_Error
1576
-     * @throws EE_Error
1577
-     * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1578
-     *                                    Deprecated because its return values were really quite confusing- sometimes
1579
-     *                                    it
1580
-     *                                    returned an empty array (when the include string was blank or '*') or
1581
-     *                                    sometimes it returned array('*') (when you provided a model and a model of
1582
-     *                                    that kind was found). Parses the $include_string so we fetch all the field
1583
-     *                                    names relating to THIS model
1584
-     *                                    (ie have NO period in them), or for the provided model (ie start with the
1585
-     *                                    model name and then a period).
1586
-     */
1587
-    public function extractIncludesForThisModel(string $include_string, string $model_name = null): array
1588
-    {
1589
-        if (is_array($include_string)) {
1590
-            $include_string = implode(',', $include_string);
1591
-        }
1592
-        if ($include_string === '*' || $include_string === '') {
1593
-            return [];
1594
-        }
1595
-        $includes                    = explode(',', $include_string);
1596
-        $extracted_fields_to_include = [];
1597
-        if ($model_name) {
1598
-            foreach ($includes as $field_to_include) {
1599
-                $field_to_include = trim($field_to_include);
1600
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1601
-                    // found the model name at the exact start
1602
-                    $field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1603
-                    $extracted_fields_to_include[] = $field_sans_model_name;
1604
-                } elseif ($field_to_include === $model_name) {
1605
-                    $extracted_fields_to_include[] = '*';
1606
-                }
1607
-            }
1608
-        } else {
1609
-            // look for ones with no period
1610
-            foreach ($includes as $field_to_include) {
1611
-                $field_to_include = trim($field_to_include);
1612
-                if (
1613
-                    strpos($field_to_include, '.') === false
1614
-                    && ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1615
-                ) {
1616
-                    $extracted_fields_to_include[] = $field_to_include;
1617
-                }
1618
-            }
1619
-        }
1620
-        return $extracted_fields_to_include;
1621
-    }
1622
-
1623
-
1624
-    /**
1625
-     * Gets the single item using the model according to the request in the context given, otherwise
1626
-     * returns that it's inaccessible to the current user
1627
-     *
1628
-     * @param EEM_Base        $model
1629
-     * @param WP_REST_Request $request
1630
-     * @param null            $context
1631
-     * @return array
1632
-     * @throws EE_Error
1633
-     * @throws ReflectionException
1634
-     */
1635
-    public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null): array
1636
-    {
1637
-        $query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1];
1638
-        if ($model instanceof EEM_Soft_Delete_Base) {
1639
-            $query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1640
-        }
1641
-        $restricted_query_params         = $query_params;
1642
-        $restricted_query_params['caps'] = $context;
1643
-        $this->setDebugInfo('model query params', $restricted_query_params);
1644
-        $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1645
-        if (! empty($model_rows)) {
1646
-            return $this->createEntityFromWpdbResult(
1647
-                $model,
1648
-                reset($model_rows),
1649
-                $request
1650
-            );
1651
-        }
1652
-        // ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1653
-        $lowercase_model_name = strtolower($model->get_this_model_name());
1654
-        if ($model->exists($query_params)) {
1655
-            // you got shafted- it existed but we didn't want to tell you!
1656
-            throw new RestException(
1657
-                'rest_user_cannot_' . $context,
1658
-                sprintf(
1659
-                    __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1660
-                    $context,
1661
-                    $lowercase_model_name,
1662
-                    Capabilities::getMissingPermissionsString(
1663
-                        $model,
1664
-                        $context
1665
-                    )
1666
-                ),
1667
-                ['status' => 403]
1668
-            );
1669
-        }
1670
-        // it's not you. It just doesn't exist
1671
-        throw new RestException(
1672
-            sprintf('rest_%s_invalid_id', $lowercase_model_name),
1673
-            sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1674
-            ['status' => 404]
1675
-        );
1676
-    }
1677
-
1678
-
1679
-    /**
1680
-     * Checks that if this content requires a password to be read, that it's been provided and is correct.
1681
-     *
1682
-     * @param EEM_Base        $model
1683
-     * @param array           $model_row
1684
-     * @param array           $query_params Adds 'default_where_conditions' => 'minimum'
1685
-     *                                      to ensure we don't confuse trashed with password protected.
1686
-     * @param WP_REST_Request $request
1687
-     * @throws EE_Error
1688
-     * @throws InvalidArgumentException
1689
-     * @throws InvalidDataTypeException
1690
-     * @throws InvalidInterfaceException
1691
-     * @throws RestPasswordRequiredException
1692
-     * @throws RestPasswordIncorrectException
1693
-     * @throws ModelConfigurationException
1694
-     * @throws ReflectionException
1695
-     * @since 4.9.74.p
1696
-     */
1697
-    protected function checkPassword(EEM_Base $model, array $model_row, array $query_params, WP_REST_Request $request)
1698
-    {
1699
-        $query_params['default_where_conditions'] = 'minimum';
1700
-        // stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1701
-        // or you don't.
1702
-        $request_caps = $request->get_param('caps');
1703
-        if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1704
-            return;
1705
-        }
1706
-        // if this entity requires a password, they better give it and it better be right!
1707
-        if (
1708
-            $model->hasPassword()
1709
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1710
-        ) {
1711
-            if (empty($request['password'])) {
1712
-                throw new RestPasswordRequiredException();
1713
-            }
1714
-            if (
1715
-                ! hash_equals(
1716
-                    $model_row[ $model->getPasswordField()->get_qualified_column() ],
1717
-                    $request['password']
1718
-                )
1719
-            ) {
1720
-                throw new RestPasswordIncorrectException();
1721
-            }
1722
-        } elseif (
1723
-            // wait! maybe this content is password protected
1724
-            $model->restrictedByRelatedModelPassword()
1725
-            && $request->get_param('caps') === EEM_Base::caps_read
1726
-        ) {
1727
-            $password_supplied = $request->get_param('password');
1728
-            if (empty($password_supplied)) {
1729
-                $query_params['exclude_protected'] = true;
1730
-                if (! $model->exists($query_params)) {
1731
-                    throw new RestPasswordRequiredException();
1732
-                }
1733
-            } else {
1734
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1735
-                if (! $model->exists($query_params)) {
1736
-                    throw new RestPasswordIncorrectException();
1737
-                }
1738
-            }
1739
-        }
1740
-    }
55
+	protected CalculatedModelFields $fields_calculator;
56
+
57
+
58
+	/**
59
+	 * Read constructor.
60
+	 *
61
+	 * @param CalculatedModelFields $fields_calculator
62
+	 */
63
+	public function __construct(CalculatedModelFields $fields_calculator)
64
+	{
65
+		parent::__construct();
66
+		$this->fields_calculator = $fields_calculator;
67
+	}
68
+
69
+
70
+	/**
71
+	 * @return Read
72
+	 */
73
+	private static function getReadController(): Read
74
+	{
75
+		return LoaderFactory::getLoader()->getNew(Read::class);
76
+	}
77
+
78
+
79
+	/**
80
+	 * Handles requests to get all (or a filtered subset) of entities for a particular model
81
+	 *
82
+	 * @param WP_REST_Request $request
83
+	 * @param string          $version
84
+	 * @param string          $model_name
85
+	 * @return WP_REST_Response
86
+	 * @throws InvalidArgumentException
87
+	 * @throws InvalidDataTypeException
88
+	 * @throws InvalidInterfaceException
89
+	 */
90
+	public static function handleRequestGetAll(
91
+		WP_REST_Request $request,
92
+		string $version,
93
+		string $model_name
94
+	): WP_REST_Response {
95
+		$controller = self::getReadController();
96
+		try {
97
+			$controller->setRequestedVersion($version);
98
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
99
+				return $controller->sendResponse(
100
+					new WP_Error(
101
+						'endpoint_parsing_error',
102
+						sprintf(
103
+							esc_html__(
104
+								'There is no model for endpoint %s. Please contact event espresso support',
105
+								'event_espresso'
106
+							),
107
+							$model_name
108
+						)
109
+					)
110
+				);
111
+			}
112
+			return $controller->sendResponse(
113
+				$controller->getEntitiesFromModel(
114
+					$controller->getModelVersionInfo()->loadModel($model_name),
115
+					$request
116
+				)
117
+			);
118
+		} catch (Exception $e) {
119
+			return $controller->sendResponse($e);
120
+		}
121
+	}
122
+
123
+
124
+	/**
125
+	 * Prepares and returns schema for any OPTIONS request.
126
+	 *
127
+	 * @param string $version    The API endpoint version being used.
128
+	 * @param string $model_name Something like `Event` or `Registration`
129
+	 * @return array
130
+	 * @throws InvalidArgumentException
131
+	 * @throws InvalidDataTypeException
132
+	 * @throws InvalidInterfaceException
133
+	 */
134
+	public static function handleSchemaRequest(string $version, string $model_name): array
135
+	{
136
+		$controller = self::getReadController();
137
+		try {
138
+			$controller->setRequestedVersion($version);
139
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
140
+				return [];
141
+			}
142
+			// get the model for this version
143
+			$model        = $controller->getModelVersionInfo()->loadModel($model_name);
144
+			$model_schema = new JsonModelSchema(
145
+				$model,
146
+				LoaderFactory::getLoader()->getShared('EventEspresso\core\libraries\rest_api\CalculatedModelFields')
147
+			);
148
+			return $model_schema->getModelSchemaForRelations(
149
+				$controller->getModelVersionInfo()->relationSettings($model),
150
+				$controller->customizeSchemaForRestResponse(
151
+					$model,
152
+					$model_schema->getModelSchemaForFields(
153
+						$controller->getModelVersionInfo()->fieldsOnModelInThisVersion($model),
154
+						$model_schema->getInitialSchemaStructure()
155
+					)
156
+				)
157
+			);
158
+		} catch (Exception $e) {
159
+			error_log($e->getMessage());
160
+			return [];
161
+		}
162
+	}
163
+
164
+
165
+	/**
166
+	 * This loops through each field in the given schema for the model and does the following:
167
+	 * - add any extra fields that are REST API specific and related to existing fields.
168
+	 * - transform default values into the correct format for a REST API response.
169
+	 *
170
+	 * @param EEM_Base $model
171
+	 * @param array    $schema
172
+	 * @return array  The final schema.
173
+	 * @throws EE_Error
174
+	 */
175
+	public function customizeSchemaForRestResponse(EEM_Base $model, array $schema): array
176
+	{
177
+		foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field) {
178
+			$schema = $this->translateDefaultsForRestResponse(
179
+				$field_name,
180
+				$field,
181
+				$this->maybeAddExtraFieldsToSchema($field_name, $field, $schema)
182
+			);
183
+		}
184
+		return $schema;
185
+	}
186
+
187
+
188
+	/**
189
+	 * This is used to ensure that the 'default' value set in the schema response is formatted correctly for the REST
190
+	 * response.
191
+	 *
192
+	 * @param                      $field_name
193
+	 * @param EE_Model_Field_Base  $field
194
+	 * @param array                $schema
195
+	 * @return array
196
+	 * @throws RestException  if a default value has a PHP object, which we should never do
197
+	 *                                  (but if we did, let's know about it ASAP, so let the exception bubble up)
198
+	 * @throws EE_Error
199
+	 *
200
+	 */
201
+	protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema): array
202
+	{
203
+		if (isset($schema['properties'][ $field_name ]['default'])) {
204
+			if (is_array($schema['properties'][ $field_name ]['default'])) {
205
+				foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
206
+					if ($default_key === 'raw') {
207
+						$schema['properties'][ $field_name ]['default'][ $default_key ] =
208
+							ModelDataTranslator::prepareFieldValueForJson(
209
+								$field,
210
+								$default_value,
211
+								$this->getModelVersionInfo()->requestedVersion()
212
+							);
213
+					}
214
+				}
215
+			} else {
216
+				$schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
217
+					$field,
218
+					$schema['properties'][ $field_name ]['default'],
219
+					$this->getModelVersionInfo()->requestedVersion()
220
+				);
221
+			}
222
+		}
223
+		return $schema;
224
+	}
225
+
226
+
227
+	/**
228
+	 * Adds additional fields to the schema
229
+	 * The REST API returns a GMT value field for each datetime field in the resource.  Thus the description about this
230
+	 * needs to be added to the schema.
231
+	 *
232
+	 * @param                      $field_name
233
+	 * @param EE_Model_Field_Base  $field
234
+	 * @param array                $schema
235
+	 * @return array
236
+	 */
237
+	protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema): array
238
+	{
239
+		if ($field instanceof EE_Datetime_Field) {
240
+			$schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
241
+			// modify the description
242
+			$schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
243
+				esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
244
+				wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
245
+			);
246
+		}
247
+		return $schema;
248
+	}
249
+
250
+
251
+	/**
252
+	 * Used to figure out the route from the request when a `WP_REST_Request` object is not available
253
+	 *
254
+	 * @return string
255
+	 */
256
+	protected function getRouteFromRequest(): string
257
+	{
258
+		if (
259
+			isset($GLOBALS['wp'])
260
+			&& $GLOBALS['wp'] instanceof WP
261
+			&& isset($GLOBALS['wp']->query_vars['rest_route'])
262
+		) {
263
+			return $GLOBALS['wp']->query_vars['rest_route'];
264
+		}
265
+		/** @var RequestInterface $request */
266
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
267
+		return $request->serverParamIsSet('PATH_INFO')
268
+			? $request->getServerParam('PATH_INFO')
269
+			: '/';
270
+	}
271
+
272
+
273
+	/**
274
+	 * Gets a single entity related to the model indicated in the path and its id
275
+	 *
276
+	 * @param WP_REST_Request $request
277
+	 * @param string          $version
278
+	 * @param string          $model_name
279
+	 * @return WP_REST_Response
280
+	 * @throws InvalidDataTypeException
281
+	 * @throws InvalidInterfaceException
282
+	 * @throws InvalidArgumentException
283
+	 */
284
+	public static function handleRequestGetOne(
285
+		WP_REST_Request $request,
286
+		string $version,
287
+		string $model_name
288
+	): WP_REST_Response {
289
+		$controller = self::getReadController();
290
+		try {
291
+			$controller->setRequestedVersion($version);
292
+			if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
293
+				return $controller->sendResponse(
294
+					new WP_Error(
295
+						'endpoint_parsing_error',
296
+						sprintf(
297
+							esc_html__(
298
+								'There is no model for endpoint %s. Please contact event espresso support',
299
+								'event_espresso'
300
+							),
301
+							$model_name
302
+						)
303
+					)
304
+				);
305
+			}
306
+			return $controller->sendResponse(
307
+				$controller->getEntityFromModel(
308
+					$controller->getModelVersionInfo()->loadModel($model_name),
309
+					$request
310
+				)
311
+			);
312
+		} catch (Exception $e) {
313
+			return $controller->sendResponse($e);
314
+		}
315
+	}
316
+
317
+
318
+	/**
319
+	 * Gets all the related entities (or if its a belongs-to relation just the one)
320
+	 * to the item with the given id
321
+	 *
322
+	 * @param WP_REST_Request $request
323
+	 * @param string          $version
324
+	 * @param string          $model_name
325
+	 * @param string          $related_model_name
326
+	 * @return WP_REST_Response
327
+	 * @throws InvalidDataTypeException
328
+	 * @throws InvalidInterfaceException
329
+	 * @throws InvalidArgumentException
330
+	 */
331
+	public static function handleRequestGetRelated(
332
+		WP_REST_Request $request,
333
+		string $version,
334
+		string $model_name,
335
+		string $related_model_name
336
+	): WP_REST_Response {
337
+		$controller = self::getReadController();
338
+		try {
339
+			$controller->setRequestedVersion($version);
340
+			$main_model = $controller->validateModel($model_name);
341
+			$controller->validateModel($related_model_name);
342
+			return $controller->sendResponse(
343
+				$controller->getEntitiesFromRelation(
344
+					$request->get_param('id'),
345
+					$main_model->related_settings_for($related_model_name),
346
+					$request
347
+				)
348
+			);
349
+		} catch (Exception $e) {
350
+			return $controller->sendResponse($e);
351
+		}
352
+	}
353
+
354
+
355
+	/**
356
+	 * Gets a collection for the given model and filters
357
+	 *
358
+	 * @param EEM_Base        $model
359
+	 * @param WP_REST_Request $request
360
+	 * @return array
361
+	 * @throws DomainException
362
+	 * @throws EE_Error
363
+	 * @throws InvalidArgumentException
364
+	 * @throws InvalidDataTypeException
365
+	 * @throws InvalidInterfaceException
366
+	 * @throws ModelConfigurationException
367
+	 * @throws ReflectionException
368
+	 * @throws RestException
369
+	 * @throws RestPasswordIncorrectException
370
+	 * @throws RestPasswordRequiredException
371
+	 * @throws UnexpectedEntityException
372
+	 */
373
+	public function getEntitiesFromModel(EEM_Base $model, WP_REST_Request $request): array
374
+	{
375
+		$query_params = $this->createModelQueryParams($model, $request->get_params());
376
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
377
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
378
+			throw new RestException(
379
+				sprintf('rest_%s_cannot_list', $model_name_plural),
380
+				sprintf(
381
+					esc_html__('Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso'),
382
+					$model_name_plural,
383
+					Capabilities::getMissingPermissionsString($model, $query_params['caps'])
384
+				),
385
+				['status' => 403]
386
+			);
387
+		}
388
+		if (! $request->get_header('no_rest_headers')) {
389
+			$this->setHeadersFromQueryParams($model, $query_params);
390
+		}
391
+		/** @type array $results */
392
+		$results      = $model->get_all_wpdb_results($query_params);
393
+		$nice_results = [];
394
+		foreach ($results as $result) {
395
+			$nice_results[] = $this->createEntityFromWpdbResult(
396
+				$model,
397
+				$result,
398
+				$request
399
+			);
400
+		}
401
+		return $nice_results;
402
+	}
403
+
404
+
405
+	/**
406
+	 * Gets the collection for given relation object
407
+	 * The same as Read::get_entities_from_model(), except if the relation
408
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
409
+	 * the join-model-object into the results
410
+	 *
411
+	 * @param array                  $primary_model_query_params  query params for finding the item from which
412
+	 *                                                            relations will be based
413
+	 * @param EE_Model_Relation_Base $relation
414
+	 * @param WP_REST_Request        $request
415
+	 * @return array|null
416
+	 * @throws DomainException
417
+	 * @throws EE_Error
418
+	 * @throws InvalidArgumentException
419
+	 * @throws InvalidDataTypeException
420
+	 * @throws InvalidInterfaceException
421
+	 * @throws ModelConfigurationException
422
+	 * @throws ReflectionException
423
+	 * @throws RestException
424
+	 * @throws ModelConfigurationException
425
+	 * @throws UnexpectedEntityException
426
+	 * @throws Exception
427
+	 */
428
+	protected function getEntitiesFromRelationUsingModelQueryParams(
429
+		array $primary_model_query_params,
430
+		EE_Model_Relation_Base $relation,
431
+		WP_REST_Request $request
432
+	): ?array {
433
+		$context       = $this->validateContext($request->get_param('caps'));
434
+		$model         = $relation->get_this_model();
435
+		$related_model = $relation->get_other_model();
436
+		if (! isset($primary_model_query_params[0])) {
437
+			$primary_model_query_params[0] = [];
438
+		}
439
+		// check if they can access the 1st model object
440
+		$primary_model_query_params = [
441
+			0       => $primary_model_query_params[0],
442
+			'limit' => 1,
443
+		];
444
+		if ($model instanceof EEM_Soft_Delete_Base) {
445
+			$primary_model_query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included(
446
+				$primary_model_query_params
447
+			);
448
+		}
449
+		$restricted_query_params          = $primary_model_query_params;
450
+		$restricted_query_params['caps']  = $context;
451
+		$restricted_query_params['limit'] = 1;
452
+		$this->setDebugInfo('main model query params', $restricted_query_params);
453
+		$this->setDebugInfo('missing caps', Capabilities::getMissingPermissionsString($related_model, $context));
454
+		$primary_model_rows = $model->get_all_wpdb_results($restricted_query_params);
455
+		$primary_model_row  = null;
456
+		if (is_array($primary_model_rows)) {
457
+			$primary_model_row = reset($primary_model_rows);
458
+		}
459
+		if (
460
+			! (
461
+				$primary_model_row
462
+				&& Capabilities::currentUserHasPartialAccessTo($related_model, $context)
463
+			)
464
+		) {
465
+			if ($relation instanceof EE_Belongs_To_Relation) {
466
+				$related_model_name_maybe_plural = strtolower($related_model->get_this_model_name());
467
+			} else {
468
+				$related_model_name_maybe_plural = EEH_Inflector::pluralize_and_lower(
469
+					$related_model->get_this_model_name()
470
+				);
471
+			}
472
+			throw new RestException(
473
+				sprintf('rest_%s_cannot_list', $related_model_name_maybe_plural),
474
+				sprintf(
475
+					esc_html__(
476
+						'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s',
477
+						'event_espresso'
478
+					),
479
+					$related_model_name_maybe_plural,
480
+					$relation->get_this_model()->get_this_model_name(),
481
+					implode(
482
+						',',
483
+						array_keys(
484
+							Capabilities::getMissingPermissions($related_model, $context)
485
+						)
486
+					)
487
+				),
488
+				['status' => 403]
489
+			);
490
+		}
491
+
492
+		$this->checkPassword(
493
+			$model,
494
+			$primary_model_row,
495
+			$restricted_query_params,
496
+			$request
497
+		);
498
+		$query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
499
+		foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
500
+			$query_params[0][ $relation->get_this_model()->get_this_model_name()
501
+							  . '.'
502
+							  . $where_condition_key ] = $where_condition_value;
503
+		}
504
+		$query_params['default_where_conditions'] = 'none';
505
+		$query_params['caps']                     = $context;
506
+		if (! $request->get_header('no_rest_headers')) {
507
+			$this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
508
+		}
509
+		/** @type array $results */
510
+		$results      = $relation->get_other_model()->get_all_wpdb_results($query_params);
511
+		$nice_results = [];
512
+		foreach ($results as $result) {
513
+			$nice_result = $this->createEntityFromWpdbResult(
514
+				$relation->get_other_model(),
515
+				$result,
516
+				$request
517
+			);
518
+			if ($relation instanceof EE_HABTM_Relation) {
519
+				// put the unusual stuff (properties from the HABTM relation) first, and make sure
520
+				// if there are conflicts we prefer the properties from the main model
521
+				$join_model_result = $this->createEntityFromWpdbResult(
522
+					$relation->get_join_model(),
523
+					$result,
524
+					$request
525
+				);
526
+				$joined_result     = array_merge($join_model_result, $nice_result);
527
+				// but keep the meta stuff from the main model
528
+				if (isset($nice_result['meta'])) {
529
+					$joined_result['meta'] = $nice_result['meta'];
530
+				}
531
+				$nice_result = $joined_result;
532
+			}
533
+			$nice_results[] = $nice_result;
534
+		}
535
+		if ($relation instanceof EE_Belongs_To_Relation) {
536
+			return array_shift($nice_results);
537
+		} else {
538
+			return $nice_results;
539
+		}
540
+	}
541
+
542
+
543
+	/**
544
+	 * Gets the collection for given relation object
545
+	 * The same as Read::get_entities_from_model(), except if the relation
546
+	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
547
+	 * the join-model-object into the results
548
+	 *
549
+	 * @param int|string             $id the ID of the thing we are fetching related stuff from
550
+	 * @param EE_Model_Relation_Base $relation
551
+	 * @param WP_REST_Request        $request
552
+	 * @return array
553
+	 * @throws DomainException
554
+	 * @throws EE_Error
555
+	 * @throws InvalidArgumentException
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidInterfaceException
558
+	 * @throws ReflectionException
559
+	 * @throws RestException
560
+	 * @throws ModelConfigurationException
561
+	 * @throws UnexpectedEntityException
562
+	 * @throws Exception
563
+	 */
564
+	public function getEntitiesFromRelation($id, EE_Model_Relation_Base $relation, WP_REST_Request $request): array
565
+	{
566
+		if (! $relation->get_this_model()->has_primary_key_field()) {
567
+			throw new EE_Error(
568
+				sprintf(
569
+					esc_html__(
570
+					// @codingStandardsIgnoreStart
571
+						'Read::get_entities_from_relation should only be called from a model with a primary key, it was called from %1$s',
572
+						// @codingStandardsIgnoreEnd
573
+						'event_espresso'
574
+					),
575
+					$relation->get_this_model()->get_this_model_name()
576
+				)
577
+			);
578
+		}
579
+		// can we edit that main item?
580
+		// if not, show nothing but an error
581
+		// otherwise, please proceed
582
+		return $this->getEntitiesFromRelationUsingModelQueryParams(
583
+			[
584
+				[
585
+					$relation->get_this_model()->primary_key_name() => $id,
586
+				],
587
+			],
588
+			$relation,
589
+			$request
590
+		);
591
+	}
592
+
593
+
594
+	/**
595
+	 * Sets the headers that are based on the model and query params,
596
+	 * like the total records. This should only be called on the original request
597
+	 * from the client, not on subsequent internal
598
+	 *
599
+	 * @param EEM_Base $model
600
+	 * @param array    $query_params
601
+	 * @return void
602
+	 * @throws EE_Error
603
+	 * @throws ReflectionException
604
+	 */
605
+	protected function setHeadersFromQueryParams(EEM_Base $model, array $query_params)
606
+	{
607
+		$this->setDebugInfo('model query params', $query_params);
608
+		$this->setDebugInfo(
609
+			'missing caps',
610
+			Capabilities::getMissingPermissionsString($model, $query_params['caps'])
611
+		);
612
+		// normally the limit to a 2-part array, where the 2nd item is the limit
613
+		if (! isset($query_params['limit'])) {
614
+			$query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
615
+		}
616
+		if (is_array($query_params['limit'])) {
617
+			$limit_parts = $query_params['limit'];
618
+		} else {
619
+			$limit_parts = explode(',', $query_params['limit']);
620
+			if (count($limit_parts) === 1) {
621
+				$limit_parts = [0, $limit_parts[0]];
622
+			}
623
+		}
624
+		// remove the group by and having parts of the query, as those will
625
+		// make the sql query return an array of values, instead of just a single value
626
+		unset($query_params['group_by'], $query_params['having'], $query_params['limit']);
627
+		$count = $model->count($query_params, null, true);
628
+		$pages = $count / $limit_parts[1];
629
+		$this->setResponseHeader('Total', $count, false);
630
+		$this->setResponseHeader('PageSize', $limit_parts[1], false);
631
+		$this->setResponseHeader('TotalPages', ceil($pages), false);
632
+	}
633
+
634
+
635
+	/**
636
+	 * Changes database results into REST API entities
637
+	 *
638
+	 * @param EEM_Base             $model
639
+	 * @param array                $db_row     like results from $wpdb->get_results()
640
+	 * @param WP_REST_Request|null $rest_request
641
+	 * @param string|null          $deprecated no longer used
642
+	 * @return array ready for being converted into json for sending to client
643
+	 * @throws DomainException
644
+	 * @throws EE_Error
645
+	 * @throws InvalidArgumentException
646
+	 * @throws InvalidDataTypeException
647
+	 * @throws InvalidInterfaceException
648
+	 * @throws ModelConfigurationException
649
+	 * @throws ReflectionException
650
+	 * @throws RestException
651
+	 * @throws RestPasswordIncorrectException
652
+	 * @throws RestPasswordRequiredException
653
+	 * @throws UnexpectedEntityException
654
+	 */
655
+	public function createEntityFromWpdbResult(
656
+		EEM_Base $model,
657
+		array $db_row,
658
+		?WP_REST_Request $rest_request,
659
+		string $deprecated = null
660
+	): array {
661
+		if (! $rest_request instanceof WP_REST_Request) {
662
+			// ok so this was called in the old style, where the 3rd arg was
663
+			// $include, and the 4th arg was $context
664
+			// now setup the request just to avoid fatal errors, although we won't be able
665
+			// to truly make use of it because it's kinda devoid of info
666
+			$rest_request = new WP_REST_Request();
667
+			$rest_request->set_param('include', $rest_request);
668
+			$rest_request->set_param('caps', $deprecated);
669
+		}
670
+		if ($rest_request->get_param('caps') === null) {
671
+			$rest_request->set_param('caps', EEM_Base::caps_read);
672
+		}
673
+		$current_user_full_access_to_entity = $model->currentUserCan(
674
+			EEM_Base::caps_read_admin,
675
+			$model->deduce_fields_n_values_from_cols_n_values($db_row)
676
+		);
677
+		$entity_array                       = $this->createBareEntityFromWpdbResults($model, $db_row);
678
+		$entity_array                       = $this->addExtraFields($model, $db_row, $entity_array);
679
+		$entity_array['_links']             = $this->getEntityLinks($model, $db_row, $entity_array);
680
+		// when it's a regular read request for a model with a password and the password wasn't provided
681
+		// remove the password protected fields
682
+		$has_protected_fields = false;
683
+		try {
684
+			$this->checkPassword(
685
+				$model,
686
+				$db_row,
687
+				$model->alter_query_params_to_restrict_by_ID(
688
+					$model->get_index_primary_key_string(
689
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
690
+					)
691
+				),
692
+				$rest_request
693
+			);
694
+		} catch (RestPasswordRequiredException $e) {
695
+			if ($model->hasPassword()) {
696
+				// just remove protected fields
697
+				$has_protected_fields = true;
698
+				$entity_array         = Capabilities::filterOutPasswordProtectedFields(
699
+					$entity_array,
700
+					$model,
701
+					$this->getModelVersionInfo()
702
+				);
703
+			} else {
704
+				// that's a problem. None of this should be accessible if no password was provided
705
+				throw $e;
706
+			}
707
+		}
708
+
709
+		$entity_array['_calculated_fields'] = $this->getEntityCalculations(
710
+			$model,
711
+			$db_row,
712
+			$rest_request,
713
+			$has_protected_fields
714
+		);
715
+		$entity_array                       = apply_filters(
716
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
717
+			$entity_array,
718
+			$model,
719
+			$rest_request->get_param('caps'),
720
+			$rest_request,
721
+			$this
722
+		);
723
+		// add an empty protected property for now. If it's still around after we remove everything the request didn't
724
+		// want, we'll populate it then. k?
725
+		$entity_array['_protected'] = [];
726
+		// remove any properties the request didn't want. This way _protected won't bother mentioning them
727
+		$entity_array = $this->includeOnlyRequestedProperties($model, $rest_request, $entity_array);
728
+		$entity_array = $this->includeRequestedModels(
729
+			$model,
730
+			$rest_request,
731
+			$entity_array,
732
+			$db_row,
733
+			$has_protected_fields
734
+		);
735
+		// if they still wanted the _protected property, add it.
736
+		if (isset($entity_array['_protected'])) {
737
+			$entity_array = $this->addProtectedProperty($model, $entity_array, $has_protected_fields);
738
+		}
739
+		$entity_array = apply_filters(
740
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
741
+			$entity_array,
742
+			$model,
743
+			$rest_request->get_param('caps'),
744
+			$rest_request,
745
+			$this
746
+		);
747
+		if (! $current_user_full_access_to_entity) {
748
+			$result_without_inaccessible_fields = Capabilities::filterOutInaccessibleEntityFields(
749
+				$entity_array,
750
+				$model,
751
+				$rest_request->get_param('caps'),
752
+				$this->getModelVersionInfo()
753
+			);
754
+		} else {
755
+			$result_without_inaccessible_fields = $entity_array;
756
+		}
757
+		$this->setDebugInfo(
758
+			'inaccessible fields',
759
+			array_keys(array_diff_key((array) $entity_array, (array) $result_without_inaccessible_fields))
760
+		);
761
+		return apply_filters(
762
+			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
763
+			$result_without_inaccessible_fields,
764
+			$model,
765
+			$rest_request->get_param('caps')
766
+		);
767
+	}
768
+
769
+
770
+	/**
771
+	 * Returns an array describing which fields can be protected, and which actually were removed this request
772
+	 *
773
+	 * @param EEM_Base $model
774
+	 * @param array    $results_so_far
775
+	 * @param bool     $protected
776
+	 * @return array results
777
+	 * @throws EE_Error
778
+	 * @since 4.9.74.p
779
+	 */
780
+	protected function addProtectedProperty(EEM_Base $model, array $results_so_far, bool $protected): array
781
+	{
782
+		if (! $protected || ! $model->hasPassword()) {
783
+			return $results_so_far;
784
+		}
785
+		$password_field  = $model->getPasswordField();
786
+		$all_protected   = array_merge(
787
+			[$password_field->get_name()],
788
+			$password_field->protectedFields()
789
+		);
790
+		$fields_included = array_keys($results_so_far);
791
+		$fields_included = array_intersect(
792
+			$all_protected,
793
+			$fields_included
794
+		);
795
+		foreach ($fields_included as $field_name) {
796
+			$results_so_far['_protected'][] = $field_name;
797
+		}
798
+		return $results_so_far;
799
+	}
800
+
801
+
802
+	/**
803
+	 * Creates a REST entity array (JSON object we're going to return in the response, but
804
+	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
805
+	 * from $wpdb->get_row( $sql, ARRAY_A)
806
+	 *
807
+	 * @param EEM_Base $model
808
+	 * @param array    $db_row
809
+	 * @return array entity mostly ready for converting to JSON and sending in the response
810
+	 * @throws EE_Error
811
+	 * @throws ReflectionException
812
+	 * @throws RestException
813
+	 * @throws Exception
814
+	 */
815
+	protected function createBareEntityFromWpdbResults(EEM_Base $model, array $db_row): array
816
+	{
817
+		$result = $model->deduce_fields_n_values_from_cols_n_values($db_row);
818
+		$result = array_intersect_key(
819
+			$result,
820
+			$this->getModelVersionInfo()->fieldsOnModelInThisVersion($model)
821
+		);
822
+		// if this is a CPT, we need to set the global $post to it,
823
+		// otherwise shortcodes etc won't work properly while rendering it
824
+		if ($model instanceof EEM_CPT_Base) {
825
+			$do_chevy_shuffle = true;
826
+		} else {
827
+			$do_chevy_shuffle = false;
828
+		}
829
+		if ($do_chevy_shuffle) {
830
+			global $post;
831
+			$old_post = $post;
832
+			$post     = get_post($result[ $model->primary_key_name() ]);
833
+			if (! $post instanceof WP_Post) {
834
+				// well that's weird, because $result is what we JUST fetched from the database
835
+				throw new RestException(
836
+					'error_fetching_post_from_database_results',
837
+					esc_html__(
838
+						'An item was retrieved from the database but it\'s not a WP_Post like it should be.',
839
+						'event_espresso'
840
+					)
841
+				);
842
+			}
843
+			$model_object_classname          = 'EE_' . $model->get_this_model_name();
844
+			$post->{$model_object_classname} = EE_Registry::instance()->load_class(
845
+				$model_object_classname,
846
+				$result,
847
+				false,
848
+				false
849
+			);
850
+		}
851
+		foreach ($result as $field_name => $field_value) {
852
+			$field_obj = $model->field_settings_for($field_name);
853
+			if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
854
+				unset($result[ $field_name ]);
855
+			} elseif (
856
+				$this->isSubclassOfOne(
857
+					$field_obj,
858
+					$this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
859
+				)
860
+			) {
861
+				$result[ $field_name ] = [
862
+					'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
863
+					'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
864
+				];
865
+			} elseif (
866
+				$this->isSubclassOfOne(
867
+					$field_obj,
868
+					$this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
869
+				)
870
+			) {
871
+				$result[ $field_name ] = [
872
+					'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
873
+					'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
874
+				];
875
+			} elseif ($field_obj instanceof EE_Datetime_Field) {
876
+				$field_value = $field_obj->prepare_for_set_from_db($field_value);
877
+				// if the value is null, but we're not supposed to permit null, then set to the field's default
878
+				if (is_null($field_value)) {
879
+					$field_value = $field_obj->getDefaultDateTimeObj();
880
+				}
881
+				if (is_null($field_value)) {
882
+					$gmt_date = $local_date = ModelDataTranslator::prepareFieldValuesForJson(
883
+						$field_obj,
884
+						$field_value,
885
+						$this->getModelVersionInfo()->requestedVersion()
886
+					);
887
+				} else {
888
+					$timezone = $field_value->getTimezone();
889
+					EEH_DTT_Helper::setTimezone($field_value, new DateTimeZone('UTC'));
890
+					$gmt_date = ModelDataTranslator::prepareFieldValuesForJson(
891
+						$field_obj,
892
+						$field_value,
893
+						$this->getModelVersionInfo()->requestedVersion()
894
+					);
895
+					EEH_DTT_Helper::setTimezone($field_value, $timezone);
896
+					$local_date = ModelDataTranslator::prepareFieldValuesForJson(
897
+						$field_obj,
898
+						$field_value,
899
+						$this->getModelVersionInfo()->requestedVersion()
900
+					);
901
+				}
902
+				$result[ $field_name . '_gmt' ] = $gmt_date;
903
+				$result[ $field_name ]          = $local_date;
904
+			} else {
905
+				$result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
906
+			}
907
+		}
908
+		if ($do_chevy_shuffle) {
909
+			$post = $old_post;
910
+		}
911
+		return $result;
912
+	}
913
+
914
+
915
+	/**
916
+	 * Takes a value all the way from the DB representation, to the model object's representation, to the
917
+	 * user-facing PHP representation, to the REST API representation. (Assumes you've already taken from the DB
918
+	 * representation using $field_obj->prepare_for_set_from_db())
919
+	 *
920
+	 * @param EE_Model_Field_Base $field_obj
921
+	 * @param mixed               $value  as it's stored on a model object
922
+	 * @param string              $format valid values are 'normal' (default), 'pretty', 'datetime_obj'
923
+	 * @return array|int
924
+	 * @throws RestException if $value contains a PHP object
925
+	 * @throws EE_Error
926
+	 */
927
+	protected function prepareFieldObjValueForJson(
928
+		EE_Model_Field_Base $field_obj,
929
+		$value,
930
+		string $format = 'normal'
931
+	) {
932
+		$value = $field_obj->prepare_for_set_from_db($value);
933
+		switch ($format) {
934
+			case 'pretty':
935
+				$value = $field_obj->prepare_for_pretty_echoing($value);
936
+				break;
937
+			case 'normal':
938
+			default:
939
+				$value = $field_obj->prepare_for_get($value);
940
+				break;
941
+		}
942
+		return ModelDataTranslator::prepareFieldValuesForJson(
943
+			$field_obj,
944
+			$value,
945
+			$this->getModelVersionInfo()->requestedVersion()
946
+		);
947
+	}
948
+
949
+
950
+	/**
951
+	 * Adds a few extra fields to the entity response
952
+	 *
953
+	 * @param EEM_Base $model
954
+	 * @param array    $db_row
955
+	 * @param array    $entity_array
956
+	 * @return array modified entity
957
+	 * @throws EE_Error
958
+	 */
959
+	protected function addExtraFields(EEM_Base $model, array $db_row, array $entity_array): array
960
+	{
961
+		if ($model instanceof EEM_CPT_Base) {
962
+			$entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
963
+		}
964
+		return $entity_array;
965
+	}
966
+
967
+
968
+	/**
969
+	 * Gets links we want to add to the response
970
+	 *
971
+	 * @param EEM_Base        $model
972
+	 * @param array           $db_row
973
+	 * @param array           $entity_array
974
+	 * @return array the _links item in the entity
975
+	 * @throws EE_Error
976
+	 * @global WP_REST_Server $wp_rest_server
977
+	 */
978
+	protected function getEntityLinks(EEM_Base $model, array $db_row, array $entity_array): array
979
+	{
980
+		// add basic links
981
+		$links = [];
982
+		if ($model->has_primary_key_field()) {
983
+			$links['self'] = [
984
+				[
985
+					'href' => $this->getVersionedLinkTo(
986
+						EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
987
+						. '/'
988
+						. $entity_array[ $model->primary_key_name() ]
989
+					),
990
+				],
991
+			];
992
+		}
993
+		$links['collection'] = [
994
+			[
995
+				'href' => $this->getVersionedLinkTo(
996
+					EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
997
+				),
998
+			],
999
+		];
1000
+		// add links to related models
1001
+		if ($model->has_primary_key_field()) {
1002
+			foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
1003
+				$related_model_part                                                      =
1004
+					Read::getRelatedEntityName($relation_name, $relation_obj);
1005
+				$links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
1006
+					[
1007
+						'href'   => $this->getVersionedLinkTo(
1008
+							EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
1009
+							. '/'
1010
+							. $entity_array[ $model->primary_key_name() ]
1011
+							. '/'
1012
+							. $related_model_part
1013
+						),
1014
+						'single' => $relation_obj instanceof EE_Belongs_To_Relation,
1015
+					],
1016
+				];
1017
+			}
1018
+		}
1019
+		return $links;
1020
+	}
1021
+
1022
+
1023
+	/**
1024
+	 * Adds the included models indicated in the request to the entity provided
1025
+	 *
1026
+	 * @param EEM_Base        $model
1027
+	 * @param WP_REST_Request $rest_request
1028
+	 * @param array           $entity_array
1029
+	 * @param array           $db_row
1030
+	 * @param boolean         $included_items_protected if the original item is password protected, don't include any
1031
+	 *                                                  related models.
1032
+	 * @return array the modified entity
1033
+	 * @throws DomainException
1034
+	 * @throws EE_Error
1035
+	 * @throws InvalidArgumentException
1036
+	 * @throws InvalidDataTypeException
1037
+	 * @throws InvalidInterfaceException
1038
+	 * @throws ModelConfigurationException
1039
+	 * @throws ReflectionException
1040
+	 * @throws UnexpectedEntityException
1041
+	 */
1042
+	protected function includeRequestedModels(
1043
+		EEM_Base $model,
1044
+		WP_REST_Request $rest_request,
1045
+		array $entity_array,
1046
+		array $db_row = [],
1047
+		bool $included_items_protected = false
1048
+	): array {
1049
+		// if $db_row not included, hope the entity array has what we need
1050
+		if (! $db_row) {
1051
+			$db_row = $entity_array;
1052
+		}
1053
+		$relation_settings = $this->getModelVersionInfo()->relationSettings($model);
1054
+		foreach ($relation_settings as $relation_name => $relation_obj) {
1055
+			$related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1056
+				$rest_request->get_param('include'),
1057
+				$relation_name
1058
+			);
1059
+			$related_fields_to_calculate = $this->explodeAndGetItemsPrefixedWith(
1060
+				$rest_request->get_param('calculate'),
1061
+				$relation_name
1062
+			);
1063
+			// did they specify they wanted to include a related model, or
1064
+			// specific fields from a related model?
1065
+			// or did they specify to calculate a field from a related model?
1066
+			if ($related_fields_to_include || $related_fields_to_calculate) {
1067
+				// if so, we should include at least some part of the related model
1068
+				$pretend_related_request = new WP_REST_Request();
1069
+				$pretend_related_request->set_query_params(
1070
+					[
1071
+						'caps'      => $rest_request->get_param('caps'),
1072
+						'include'   => $related_fields_to_include,
1073
+						'calculate' => $related_fields_to_calculate,
1074
+						'password'  => $rest_request->get_param('password'),
1075
+					]
1076
+				);
1077
+				$pretend_related_request->add_header('no_rest_headers', true);
1078
+				$primary_model_query_params = $model->alter_query_params_to_restrict_by_ID(
1079
+					$model->get_index_primary_key_string(
1080
+						$model->deduce_fields_n_values_from_cols_n_values($db_row)
1081
+					)
1082
+				);
1083
+				if (! $included_items_protected) {
1084
+					try {
1085
+						$related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1086
+							$primary_model_query_params,
1087
+							$relation_obj,
1088
+							$pretend_related_request
1089
+						);
1090
+					} catch (RestException $e) {
1091
+						$related_results = null;
1092
+					}
1093
+				} else {
1094
+					// they're protected, hide them.
1095
+					$related_results              = null;
1096
+					$entity_array['_protected'][] = Read::getRelatedEntityName($relation_name, $relation_obj);
1097
+				}
1098
+				if ($related_results instanceof WP_Error || $related_results === null) {
1099
+					$related_results = $relation_obj instanceof EE_Belongs_To_Relation
1100
+							? null
1101
+							: [];
1102
+				}
1103
+				$entity_array[ Read::getRelatedEntityName($relation_name, $relation_obj) ] = $related_results;
1104
+			}
1105
+		}
1106
+		return $entity_array;
1107
+	}
1108
+
1109
+
1110
+	/**
1111
+	 * If the user has requested only specific properties (including meta properties like _links or _protected)
1112
+	 * remove everything else.
1113
+	 *
1114
+	 * @param EEM_Base        $model
1115
+	 * @param WP_REST_Request $rest_request
1116
+	 * @param                 $entity_array
1117
+	 * @return array
1118
+	 * @throws EE_Error
1119
+	 * @since 4.9.74.p
1120
+	 */
1121
+	protected function includeOnlyRequestedProperties(
1122
+		EEM_Base $model,
1123
+		WP_REST_Request $rest_request,
1124
+		$entity_array
1125
+	): array {
1126
+
1127
+		$includes_for_this_model = $this->explodeAndGetItemsPrefixedWith($rest_request->get_param('include'), '');
1128
+		$includes_for_this_model = $this->removeModelNamesFromArray($includes_for_this_model);
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)) {
1131
+			if ($model->has_primary_key_field()) {
1132
+				// always include the primary key. ya just gotta know that at least
1133
+				$includes_for_this_model[] = $model->primary_key_name();
1134
+			}
1135
+			if ($this->explodeAndGetItemsPrefixedWith($rest_request->get_param('calculate'), '')) {
1136
+				$includes_for_this_model[] = '_calculated_fields';
1137
+			}
1138
+			$entity_array = array_intersect_key($entity_array, array_flip($includes_for_this_model));
1139
+		}
1140
+		return $entity_array;
1141
+	}
1142
+
1143
+
1144
+	/**
1145
+	 * Returns a new array with all the names of models removed. Eg
1146
+	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
1147
+	 *
1148
+	 * @param array $array
1149
+	 * @return array
1150
+	 */
1151
+	private function removeModelNamesFromArray(array $array): array
1152
+	{
1153
+		return array_diff($array, array_keys(EE_Registry::instance()->non_abstract_db_models));
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * Gets the calculated fields for the response
1159
+	 *
1160
+	 * @param EEM_Base        $model
1161
+	 * @param array           $wpdb_row
1162
+	 * @param WP_REST_Request $rest_request
1163
+	 * @param bool            $row_is_protected whether this row is password protected or not
1164
+	 * @return stdClass the _calculations item in the entity
1165
+	 * @throws RestException if a default value has a PHP object, which should never do (and if we
1166
+	 *                                          did, let's know about it ASAP, so let the exception bubble up)
1167
+	 * @throws EE_Error
1168
+	 */
1169
+	protected function getEntityCalculations(
1170
+		EEM_Base $model,
1171
+		array $wpdb_row,
1172
+		WP_REST_Request $rest_request,
1173
+		bool $row_is_protected = false
1174
+	): stdClass {
1175
+		$calculated_fields = $this->explodeAndGetItemsPrefixedWith(
1176
+			$rest_request->get_param('calculate'),
1177
+			''
1178
+		);
1179
+		// note: setting calculate=* doesn't do anything
1180
+		$calculated_fields_to_return = new stdClass();
1181
+		$protected_fields            = [];
1182
+		foreach ($calculated_fields as $field_to_calculate) {
1183
+			try {
1184
+				// it's password protected, so they shouldn't be able to read this. Remove the value
1185
+				$schema = $this->fields_calculator->getJsonSchemaForModel($model);
1186
+				if (
1187
+					$row_is_protected
1188
+					&& isset($schema['properties'][ $field_to_calculate ]['protected'])
1189
+					&& $schema['properties'][ $field_to_calculate ]['protected']
1190
+				) {
1191
+					$calculated_value   = null;
1192
+					$protected_fields[] = $field_to_calculate;
1193
+					if ($schema['properties'][ $field_to_calculate ]['type']) {
1194
+						switch ($schema['properties'][ $field_to_calculate ]['type']) {
1195
+							case 'boolean':
1196
+								$calculated_value = false;
1197
+								break;
1198
+							case 'integer':
1199
+								$calculated_value = 0;
1200
+								break;
1201
+							case 'string':
1202
+								$calculated_value = '';
1203
+								break;
1204
+							case 'array':
1205
+								$calculated_value = [];
1206
+								break;
1207
+							case 'object':
1208
+								$calculated_value = new stdClass();
1209
+								break;
1210
+						}
1211
+					}
1212
+				} else {
1213
+					$calculated_value = ModelDataTranslator::prepareFieldValueForJson(
1214
+						null,
1215
+						$this->fields_calculator->retrieveCalculatedFieldValue(
1216
+							$model,
1217
+							$field_to_calculate,
1218
+							$wpdb_row,
1219
+							$rest_request,
1220
+							$this
1221
+						),
1222
+						$this->getModelVersionInfo()->requestedVersion()
1223
+					);
1224
+				}
1225
+				$calculated_fields_to_return->{$field_to_calculate} = $calculated_value;
1226
+			} catch (RestException $e) {
1227
+				// if we don't have permission to read it, just leave it out. but let devs know about the problem
1228
+				$this->setResponseHeader(
1229
+					'Notices-Field-Calculation-Errors['
1230
+					. $e->getStringCode()
1231
+					. ']['
1232
+					. $model->get_this_model_name()
1233
+					. ']['
1234
+					. $field_to_calculate
1235
+					. ']',
1236
+					$e->getMessage()
1237
+				);
1238
+			}
1239
+		}
1240
+		$calculated_fields_to_return->_protected = $protected_fields;
1241
+		return $calculated_fields_to_return;
1242
+	}
1243
+
1244
+
1245
+	/**
1246
+	 * Gets the full URL to the resource, taking the requested version into account
1247
+	 *
1248
+	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
1249
+	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
1250
+	 * @throws EE_Error
1251
+	 */
1252
+	public function getVersionedLinkTo(string $link_part_after_version_and_slash): string
1253
+	{
1254
+		return rest_url(
1255
+			EED_Core_Rest_Api::get_versioned_route_to(
1256
+				$link_part_after_version_and_slash,
1257
+				$this->getModelVersionInfo()->requestedVersion()
1258
+			)
1259
+		);
1260
+	}
1261
+
1262
+
1263
+	/**
1264
+	 * Gets the correct lowercase name for the relation in the API according
1265
+	 * to the relation's type
1266
+	 *
1267
+	 * @param string                 $relation_name
1268
+	 * @param EE_Model_Relation_Base $relation_obj
1269
+	 * @return string
1270
+	 */
1271
+	public static function getRelatedEntityName(string $relation_name, EE_Model_Relation_Base $relation_obj): string
1272
+	{
1273
+		if ($relation_obj instanceof EE_Belongs_To_Relation) {
1274
+			return strtolower($relation_name);
1275
+		}
1276
+		return EEH_Inflector::pluralize_and_lower($relation_name);
1277
+	}
1278
+
1279
+
1280
+	/**
1281
+	 * Gets the one model object with the specified id for the specified model
1282
+	 *
1283
+	 * @param EEM_Base        $model
1284
+	 * @param WP_REST_Request $request
1285
+	 * @return array
1286
+	 * @throws EE_Error
1287
+	 * @throws InvalidArgumentException
1288
+	 * @throws InvalidDataTypeException
1289
+	 * @throws InvalidInterfaceException
1290
+	 * @throws ModelConfigurationException
1291
+	 * @throws ReflectionException
1292
+	 * @throws RestException
1293
+	 * @throws RestPasswordIncorrectException
1294
+	 * @throws RestPasswordRequiredException
1295
+	 * @throws UnexpectedEntityException
1296
+	 * @throws DomainException
1297
+	 */
1298
+	public function getEntityFromModel(EEM_Base $model, WP_REST_Request $request): array
1299
+	{
1300
+		$context = $this->validateContext($request->get_param('caps'));
1301
+		return $this->getOneOrReportPermissionError($model, $request, $context);
1302
+	}
1303
+
1304
+
1305
+	/**
1306
+	 * If a context is provided which isn't valid, maybe it was added in a future
1307
+	 * version so just treat it as a default read
1308
+	 *
1309
+	 * @param string|null $context
1310
+	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
1311
+	 */
1312
+	public function validateContext(?string $context): string
1313
+	{
1314
+		if (! $context) {
1315
+			$context = EEM_Base::caps_read;
1316
+		}
1317
+		$valid_contexts = EEM_Base::valid_cap_contexts();
1318
+		if (in_array($context, $valid_contexts, true)) {
1319
+			return $context;
1320
+		}
1321
+		return EEM_Base::caps_read;
1322
+	}
1323
+
1324
+
1325
+	/**
1326
+	 * Verifies the passed in value is an allowable default where conditions value.
1327
+	 *
1328
+	 * @param string $default_where_conditions
1329
+	 * @return string
1330
+	 */
1331
+	public function validateDefaultQueryParams(string $default_where_conditions): string
1332
+	{
1333
+		$valid_default_where_conditions_for_api_calls = [
1334
+			EE_Default_Where_Conditions::ALL,
1335
+			EE_Default_Where_Conditions::MINIMUM_ALL,
1336
+			EE_Default_Where_Conditions::MINIMUM_OTHERS,
1337
+		];
1338
+		if (! $default_where_conditions) {
1339
+			$default_where_conditions = EE_Default_Where_Conditions::ALL;
1340
+		}
1341
+		if (
1342
+			in_array(
1343
+				$default_where_conditions,
1344
+				$valid_default_where_conditions_for_api_calls,
1345
+				true
1346
+			)
1347
+		) {
1348
+			return $default_where_conditions;
1349
+		}
1350
+		return EE_Default_Where_Conditions::ALL;
1351
+	}
1352
+
1353
+
1354
+	/**
1355
+	 * Translates API filter get parameter into model query params @param EEM_Base $model
1356
+	 *
1357
+	 * @param array $query_params
1358
+	 * @return array model query params (@see
1359
+	 *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions)
1360
+	 *               or FALSE to indicate that absolutely no results should be returned
1361
+	 * @throws EE_Error
1362
+	 * @throws InvalidArgumentException
1363
+	 * @throws InvalidDataTypeException
1364
+	 * @throws InvalidInterfaceException
1365
+	 * @throws RestException
1366
+	 * @throws DomainException
1367
+	 * @throws ReflectionException
1368
+	 * @see
1369
+	 *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions.
1370
+	 *               Note: right now the query parameter keys for fields (and related fields) can be left as-is, but
1371
+	 *               it's quite possible this will change someday. Also, this method's contents might be candidate for
1372
+	 *               moving to Model_Data_Translator
1373
+	 *
1374
+	 */
1375
+	public function createModelQueryParams(EEM_Base $model, array $query_params): array
1376
+	{
1377
+		$model_query_params = [];
1378
+		if (isset($query_params['where'])) {
1379
+			$model_query_params[0] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1380
+				$query_params['where'],
1381
+				$model,
1382
+				$this->getModelVersionInfo()->requestedVersion()
1383
+			);
1384
+		}
1385
+		if (isset($query_params['order_by'])) {
1386
+			$order_by = $query_params['order_by'];
1387
+		} elseif (isset($query_params['orderby'])) {
1388
+			$order_by = $query_params['orderby'];
1389
+		} else {
1390
+			$order_by = null;
1391
+		}
1392
+		if ($order_by !== null) {
1393
+			if (is_array($order_by)) {
1394
+				$order_by = ModelDataTranslator::prepareFieldNamesInArrayKeysFromJson($order_by);
1395
+			} else {
1396
+				// it's a single item
1397
+				$order_by = ModelDataTranslator::prepareFieldNameFromJson($order_by);
1398
+			}
1399
+			$model_query_params['order_by'] = $order_by;
1400
+		}
1401
+		if (isset($query_params['group_by'])) {
1402
+			$group_by = $query_params['group_by'];
1403
+		} elseif (isset($query_params['groupby'])) {
1404
+			$group_by = $query_params['groupby'];
1405
+		} else {
1406
+			$group_by = array_keys($model->get_combined_primary_key_fields());
1407
+		}
1408
+		// make sure they're all real names
1409
+		if (is_array($group_by)) {
1410
+			$group_by = ModelDataTranslator::prepareFieldNamesFromJson($group_by);
1411
+		}
1412
+		if ($group_by !== null) {
1413
+			$model_query_params['group_by'] = $group_by;
1414
+		}
1415
+		if (isset($query_params['having'])) {
1416
+			$model_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
1417
+				$query_params['having'],
1418
+				$model,
1419
+				$this->getModelVersionInfo()->requestedVersion()
1420
+			);
1421
+		}
1422
+		if (isset($query_params['order'])) {
1423
+			$model_query_params['order'] = $query_params['order'];
1424
+		}
1425
+		if (isset($query_params['mine'])) {
1426
+			$model_query_params = $model->alter_query_params_to_only_include_mine($model_query_params);
1427
+		}
1428
+		if (isset($query_params['limit'])) {
1429
+			// limit should be either a string like '23' or '23,43', or an array with two items in it
1430
+			if (! is_array($query_params['limit'])) {
1431
+				$limit_array = explode(',', (string) $query_params['limit']);
1432
+			} else {
1433
+				$limit_array = $query_params['limit'];
1434
+			}
1435
+			$sanitized_limit = [];
1436
+			foreach ($limit_array as $limit_part) {
1437
+				if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1438
+					throw new EE_Error(
1439
+						sprintf(
1440
+							esc_html__(
1441
+							// @codingStandardsIgnoreStart
1442
+								'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.',
1443
+								// @codingStandardsIgnoreEnd
1444
+								'event_espresso'
1445
+							),
1446
+							wp_json_encode($query_params['limit'])
1447
+						)
1448
+					);
1449
+				}
1450
+				$sanitized_limit[] = (int) $limit_part;
1451
+			}
1452
+			$model_query_params['limit'] = implode(',', $sanitized_limit);
1453
+		} else {
1454
+			$model_query_params['limit'] = EED_Core_Rest_Api::get_default_query_limit();
1455
+		}
1456
+		if (isset($query_params['caps'])) {
1457
+			$model_query_params['caps'] = $this->validateContext($query_params['caps']);
1458
+		} else {
1459
+			$model_query_params['caps'] = EEM_Base::caps_read;
1460
+		}
1461
+		if (isset($query_params['default_where_conditions'])) {
1462
+			$model_query_params['default_where_conditions'] = $this->validateDefaultQueryParams(
1463
+				$query_params['default_where_conditions']
1464
+			);
1465
+		}
1466
+		// if this is a model protected by a password on another model, exclude the password protected
1467
+		// entities by default. But if they passed in a password, try to show them all. If the password is wrong,
1468
+		// though, they'll get an error (see Read::createEntityFromWpdbResult() which calls Read::checkPassword)
1469
+		if (
1470
+			$model_query_params['caps'] === EEM_Base::caps_read
1471
+			&& empty($query_params['password'])
1472
+			&& ! $model->hasPassword()
1473
+			&& $model->restrictedByRelatedModelPassword()
1474
+		) {
1475
+			$model_query_params['exclude_protected'] = true;
1476
+		}
1477
+
1478
+		return apply_filters('FHEE__Read__create_model_query_params', $model_query_params, $query_params, $model);
1479
+	}
1480
+
1481
+
1482
+	/**
1483
+	 * Changes the REST-style query params for use in the models
1484
+	 *
1485
+	 * @param EEM_Base $model
1486
+	 * @param array    $query_params sub-array from @see EEM_Base::get_all()
1487
+	 * @return array
1488
+	 * @deprecated
1489
+	 */
1490
+	public function prepareRestQueryParamsKeyForModels(EEM_Base $model, array $query_params): array
1491
+	{
1492
+		$model_ready_query_params = [];
1493
+		foreach ($query_params as $key => $value) {
1494
+			$model_ready_query_params[ $key ] = is_array($value)
1495
+				? $this->prepareRestQueryParamsKeyForModels($model, $value)
1496
+				: $value;
1497
+		}
1498
+		return $model_ready_query_params;
1499
+	}
1500
+
1501
+
1502
+	/**
1503
+	 * @param $model
1504
+	 * @param $query_params
1505
+	 * @return array
1506
+	 * @deprecated instead use ModelDataTranslator::prepareFieldValuesFromJson()
1507
+	 */
1508
+	public function prepareRestQueryParamsValuesForModels($model, $query_params): array
1509
+	{
1510
+		$model_ready_query_params = [];
1511
+		foreach ($query_params as $key => $value) {
1512
+			if (is_array($value)) {
1513
+				$model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1514
+			} else {
1515
+				$model_ready_query_params[ $key ] = $value;
1516
+			}
1517
+		}
1518
+		return $model_ready_query_params;
1519
+	}
1520
+
1521
+
1522
+	/**
1523
+	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
1524
+	 * If no prefix is specified, returns items with no period.
1525
+	 *
1526
+	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blah, blah" or array('jibba', 'jabba' )
1527
+	 * @param string       $prefix            "Event" or "foobar"
1528
+	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
1529
+	 *                                        we only return strings starting with that and a period; if no prefix was
1530
+	 *                                        specified we return all items containing NO periods
1531
+	 */
1532
+	public function explodeAndGetItemsPrefixedWith($string_to_explode, string $prefix): array
1533
+	{
1534
+		if (is_string($string_to_explode)) {
1535
+			$exploded_contents = explode(',', $string_to_explode);
1536
+		} elseif (is_array($string_to_explode)) {
1537
+			$exploded_contents = $string_to_explode;
1538
+		} else {
1539
+			$exploded_contents = [];
1540
+		}
1541
+		// if the string was empty, we want an empty array
1542
+		$exploded_contents    = array_filter($exploded_contents);
1543
+		$contents_with_prefix = [];
1544
+		foreach ($exploded_contents as $item) {
1545
+			$item = trim($item);
1546
+			// if no prefix was provided, so we look for items with no "." in them
1547
+			if (! $prefix) {
1548
+				// does this item have a period?
1549
+				if (strpos($item, '.') === false) {
1550
+					// if not, then its what we're looking for
1551
+					$contents_with_prefix[] = $item;
1552
+				}
1553
+			} elseif (strpos($item, $prefix . '.') === 0) {
1554
+				// this item has the prefix and a period, grab it
1555
+				$contents_with_prefix[] = substr(
1556
+					$item,
1557
+					strpos($item, $prefix . '.') + strlen($prefix . '.')
1558
+				);
1559
+			} elseif ($item === $prefix) {
1560
+				// this item is JUST the prefix
1561
+				// so let's grab everything after, which is a blank string
1562
+				$contents_with_prefix[] = '';
1563
+			}
1564
+		}
1565
+		return $contents_with_prefix;
1566
+	}
1567
+
1568
+
1569
+	/**
1570
+	 * @param string      $include_string @see Read:handle_request_get_all
1571
+	 * @param string|null $model_name
1572
+	 * @return array of fields for this model. If $model_name is provided, then
1573
+	 *                                    the fields for that model, with the model's name removed from each.
1574
+	 *                                    If $include_string was blank or '*' returns an empty array
1575
+	 * @throws EE_Error
1576
+	 * @throws EE_Error
1577
+	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
1578
+	 *                                    Deprecated because its return values were really quite confusing- sometimes
1579
+	 *                                    it
1580
+	 *                                    returned an empty array (when the include string was blank or '*') or
1581
+	 *                                    sometimes it returned array('*') (when you provided a model and a model of
1582
+	 *                                    that kind was found). Parses the $include_string so we fetch all the field
1583
+	 *                                    names relating to THIS model
1584
+	 *                                    (ie have NO period in them), or for the provided model (ie start with the
1585
+	 *                                    model name and then a period).
1586
+	 */
1587
+	public function extractIncludesForThisModel(string $include_string, string $model_name = null): array
1588
+	{
1589
+		if (is_array($include_string)) {
1590
+			$include_string = implode(',', $include_string);
1591
+		}
1592
+		if ($include_string === '*' || $include_string === '') {
1593
+			return [];
1594
+		}
1595
+		$includes                    = explode(',', $include_string);
1596
+		$extracted_fields_to_include = [];
1597
+		if ($model_name) {
1598
+			foreach ($includes as $field_to_include) {
1599
+				$field_to_include = trim($field_to_include);
1600
+				if (strpos($field_to_include, $model_name . '.') === 0) {
1601
+					// found the model name at the exact start
1602
+					$field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1603
+					$extracted_fields_to_include[] = $field_sans_model_name;
1604
+				} elseif ($field_to_include === $model_name) {
1605
+					$extracted_fields_to_include[] = '*';
1606
+				}
1607
+			}
1608
+		} else {
1609
+			// look for ones with no period
1610
+			foreach ($includes as $field_to_include) {
1611
+				$field_to_include = trim($field_to_include);
1612
+				if (
1613
+					strpos($field_to_include, '.') === false
1614
+					&& ! $this->getModelVersionInfo()->isModelNameInThisVersion($field_to_include)
1615
+				) {
1616
+					$extracted_fields_to_include[] = $field_to_include;
1617
+				}
1618
+			}
1619
+		}
1620
+		return $extracted_fields_to_include;
1621
+	}
1622
+
1623
+
1624
+	/**
1625
+	 * Gets the single item using the model according to the request in the context given, otherwise
1626
+	 * returns that it's inaccessible to the current user
1627
+	 *
1628
+	 * @param EEM_Base        $model
1629
+	 * @param WP_REST_Request $request
1630
+	 * @param null            $context
1631
+	 * @return array
1632
+	 * @throws EE_Error
1633
+	 * @throws ReflectionException
1634
+	 */
1635
+	public function getOneOrReportPermissionError(EEM_Base $model, WP_REST_Request $request, $context = null): array
1636
+	{
1637
+		$query_params = [[$model->primary_key_name() => $request->get_param('id')], 'limit' => 1];
1638
+		if ($model instanceof EEM_Soft_Delete_Base) {
1639
+			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
1640
+		}
1641
+		$restricted_query_params         = $query_params;
1642
+		$restricted_query_params['caps'] = $context;
1643
+		$this->setDebugInfo('model query params', $restricted_query_params);
1644
+		$model_rows = $model->get_all_wpdb_results($restricted_query_params);
1645
+		if (! empty($model_rows)) {
1646
+			return $this->createEntityFromWpdbResult(
1647
+				$model,
1648
+				reset($model_rows),
1649
+				$request
1650
+			);
1651
+		}
1652
+		// ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
1653
+		$lowercase_model_name = strtolower($model->get_this_model_name());
1654
+		if ($model->exists($query_params)) {
1655
+			// you got shafted- it existed but we didn't want to tell you!
1656
+			throw new RestException(
1657
+				'rest_user_cannot_' . $context,
1658
+				sprintf(
1659
+					__('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1660
+					$context,
1661
+					$lowercase_model_name,
1662
+					Capabilities::getMissingPermissionsString(
1663
+						$model,
1664
+						$context
1665
+					)
1666
+				),
1667
+				['status' => 403]
1668
+			);
1669
+		}
1670
+		// it's not you. It just doesn't exist
1671
+		throw new RestException(
1672
+			sprintf('rest_%s_invalid_id', $lowercase_model_name),
1673
+			sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
1674
+			['status' => 404]
1675
+		);
1676
+	}
1677
+
1678
+
1679
+	/**
1680
+	 * Checks that if this content requires a password to be read, that it's been provided and is correct.
1681
+	 *
1682
+	 * @param EEM_Base        $model
1683
+	 * @param array           $model_row
1684
+	 * @param array           $query_params Adds 'default_where_conditions' => 'minimum'
1685
+	 *                                      to ensure we don't confuse trashed with password protected.
1686
+	 * @param WP_REST_Request $request
1687
+	 * @throws EE_Error
1688
+	 * @throws InvalidArgumentException
1689
+	 * @throws InvalidDataTypeException
1690
+	 * @throws InvalidInterfaceException
1691
+	 * @throws RestPasswordRequiredException
1692
+	 * @throws RestPasswordIncorrectException
1693
+	 * @throws ModelConfigurationException
1694
+	 * @throws ReflectionException
1695
+	 * @since 4.9.74.p
1696
+	 */
1697
+	protected function checkPassword(EEM_Base $model, array $model_row, array $query_params, WP_REST_Request $request)
1698
+	{
1699
+		$query_params['default_where_conditions'] = 'minimum';
1700
+		// stuff is only "protected" for front-end requests. Elsewhere, you either get full permission to access the object
1701
+		// or you don't.
1702
+		$request_caps = $request->get_param('caps');
1703
+		if (isset($request_caps) && $request_caps !== EEM_Base::caps_read) {
1704
+			return;
1705
+		}
1706
+		// if this entity requires a password, they better give it and it better be right!
1707
+		if (
1708
+			$model->hasPassword()
1709
+			&& $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1710
+		) {
1711
+			if (empty($request['password'])) {
1712
+				throw new RestPasswordRequiredException();
1713
+			}
1714
+			if (
1715
+				! hash_equals(
1716
+					$model_row[ $model->getPasswordField()->get_qualified_column() ],
1717
+					$request['password']
1718
+				)
1719
+			) {
1720
+				throw new RestPasswordIncorrectException();
1721
+			}
1722
+		} elseif (
1723
+			// wait! maybe this content is password protected
1724
+			$model->restrictedByRelatedModelPassword()
1725
+			&& $request->get_param('caps') === EEM_Base::caps_read
1726
+		) {
1727
+			$password_supplied = $request->get_param('password');
1728
+			if (empty($password_supplied)) {
1729
+				$query_params['exclude_protected'] = true;
1730
+				if (! $model->exists($query_params)) {
1731
+					throw new RestPasswordRequiredException();
1732
+				}
1733
+			} else {
1734
+				$query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1735
+				if (! $model->exists($query_params)) {
1736
+					throw new RestPasswordIncorrectException();
1737
+				}
1738
+			}
1739
+		}
1740
+	}
1741 1741
 }
Please login to merge, or discard this patch.
Spacing   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
         $controller = self::getReadController();
96 96
         try {
97 97
             $controller->setRequestedVersion($version);
98
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
98
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
99 99
                 return $controller->sendResponse(
100 100
                     new WP_Error(
101 101
                         'endpoint_parsing_error',
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
         $controller = self::getReadController();
137 137
         try {
138 138
             $controller->setRequestedVersion($version);
139
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
139
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
140 140
                 return [];
141 141
             }
142 142
             // get the model for this version
@@ -200,11 +200,11 @@  discard block
 block discarded – undo
200 200
      */
201 201
     protected function translateDefaultsForRestResponse($field_name, EE_Model_Field_Base $field, array $schema): array
202 202
     {
203
-        if (isset($schema['properties'][ $field_name ]['default'])) {
204
-            if (is_array($schema['properties'][ $field_name ]['default'])) {
205
-                foreach ($schema['properties'][ $field_name ]['default'] as $default_key => $default_value) {
203
+        if (isset($schema['properties'][$field_name]['default'])) {
204
+            if (is_array($schema['properties'][$field_name]['default'])) {
205
+                foreach ($schema['properties'][$field_name]['default'] as $default_key => $default_value) {
206 206
                     if ($default_key === 'raw') {
207
-                        $schema['properties'][ $field_name ]['default'][ $default_key ] =
207
+                        $schema['properties'][$field_name]['default'][$default_key] =
208 208
                             ModelDataTranslator::prepareFieldValueForJson(
209 209
                                 $field,
210 210
                                 $default_value,
@@ -213,9 +213,9 @@  discard block
 block discarded – undo
213 213
                     }
214 214
                 }
215 215
             } else {
216
-                $schema['properties'][ $field_name ]['default'] = ModelDataTranslator::prepareFieldValueForJson(
216
+                $schema['properties'][$field_name]['default'] = ModelDataTranslator::prepareFieldValueForJson(
217 217
                     $field,
218
-                    $schema['properties'][ $field_name ]['default'],
218
+                    $schema['properties'][$field_name]['default'],
219 219
                     $this->getModelVersionInfo()->requestedVersion()
220 220
                 );
221 221
             }
@@ -237,9 +237,9 @@  discard block
 block discarded – undo
237 237
     protected function maybeAddExtraFieldsToSchema($field_name, EE_Model_Field_Base $field, array $schema): array
238 238
     {
239 239
         if ($field instanceof EE_Datetime_Field) {
240
-            $schema['properties'][ $field_name . '_gmt' ] = $field->getSchema();
240
+            $schema['properties'][$field_name.'_gmt'] = $field->getSchema();
241 241
             // modify the description
242
-            $schema['properties'][ $field_name . '_gmt' ]['description'] = sprintf(
242
+            $schema['properties'][$field_name.'_gmt']['description'] = sprintf(
243 243
                 esc_html__('%s - the value for this field is in GMT.', 'event_espresso'),
244 244
                 wp_specialchars_decode($field->get_nicename(), ENT_QUOTES)
245 245
             );
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
         $controller = self::getReadController();
290 290
         try {
291 291
             $controller->setRequestedVersion($version);
292
-            if (! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
292
+            if ( ! $controller->getModelVersionInfo()->isModelNameInThisVersion($model_name)) {
293 293
                 return $controller->sendResponse(
294 294
                     new WP_Error(
295 295
                         'endpoint_parsing_error',
@@ -373,7 +373,7 @@  discard block
 block discarded – undo
373 373
     public function getEntitiesFromModel(EEM_Base $model, WP_REST_Request $request): array
374 374
     {
375 375
         $query_params = $this->createModelQueryParams($model, $request->get_params());
376
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
376
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $query_params['caps'])) {
377 377
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
378 378
             throw new RestException(
379 379
                 sprintf('rest_%s_cannot_list', $model_name_plural),
@@ -385,7 +385,7 @@  discard block
 block discarded – undo
385 385
                 ['status' => 403]
386 386
             );
387 387
         }
388
-        if (! $request->get_header('no_rest_headers')) {
388
+        if ( ! $request->get_header('no_rest_headers')) {
389 389
             $this->setHeadersFromQueryParams($model, $query_params);
390 390
         }
391 391
         /** @type array $results */
@@ -433,7 +433,7 @@  discard block
 block discarded – undo
433 433
         $context       = $this->validateContext($request->get_param('caps'));
434 434
         $model         = $relation->get_this_model();
435 435
         $related_model = $relation->get_other_model();
436
-        if (! isset($primary_model_query_params[0])) {
436
+        if ( ! isset($primary_model_query_params[0])) {
437 437
             $primary_model_query_params[0] = [];
438 438
         }
439 439
         // check if they can access the 1st model object
@@ -497,13 +497,13 @@  discard block
 block discarded – undo
497 497
         );
498 498
         $query_params = $this->createModelQueryParams($relation->get_other_model(), $request->get_params());
499 499
         foreach ($primary_model_query_params[0] as $where_condition_key => $where_condition_value) {
500
-            $query_params[0][ $relation->get_this_model()->get_this_model_name()
500
+            $query_params[0][$relation->get_this_model()->get_this_model_name()
501 501
                               . '.'
502
-                              . $where_condition_key ] = $where_condition_value;
502
+                              . $where_condition_key] = $where_condition_value;
503 503
         }
504 504
         $query_params['default_where_conditions'] = 'none';
505 505
         $query_params['caps']                     = $context;
506
-        if (! $request->get_header('no_rest_headers')) {
506
+        if ( ! $request->get_header('no_rest_headers')) {
507 507
             $this->setHeadersFromQueryParams($relation->get_other_model(), $query_params);
508 508
         }
509 509
         /** @type array $results */
@@ -523,7 +523,7 @@  discard block
 block discarded – undo
523 523
                     $result,
524 524
                     $request
525 525
                 );
526
-                $joined_result     = array_merge($join_model_result, $nice_result);
526
+                $joined_result = array_merge($join_model_result, $nice_result);
527 527
                 // but keep the meta stuff from the main model
528 528
                 if (isset($nice_result['meta'])) {
529 529
                     $joined_result['meta'] = $nice_result['meta'];
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
      */
564 564
     public function getEntitiesFromRelation($id, EE_Model_Relation_Base $relation, WP_REST_Request $request): array
565 565
     {
566
-        if (! $relation->get_this_model()->has_primary_key_field()) {
566
+        if ( ! $relation->get_this_model()->has_primary_key_field()) {
567 567
             throw new EE_Error(
568 568
                 sprintf(
569 569
                     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();
@@ -829,8 +829,8 @@  discard block
 block discarded – undo
829 829
         if ($do_chevy_shuffle) {
830 830
             global $post;
831 831
             $old_post = $post;
832
-            $post     = get_post($result[ $model->primary_key_name() ]);
833
-            if (! $post instanceof WP_Post) {
832
+            $post     = get_post($result[$model->primary_key_name()]);
833
+            if ( ! $post instanceof WP_Post) {
834 834
                 // well that's weird, because $result is what we JUST fetched from the database
835 835
                 throw new RestException(
836 836
                     'error_fetching_post_from_database_results',
@@ -840,7 +840,7 @@  discard block
 block discarded – undo
840 840
                     )
841 841
                 );
842 842
             }
843
-            $model_object_classname          = 'EE_' . $model->get_this_model_name();
843
+            $model_object_classname          = 'EE_'.$model->get_this_model_name();
844 844
             $post->{$model_object_classname} = EE_Registry::instance()->load_class(
845 845
                 $model_object_classname,
846 846
                 $result,
@@ -851,14 +851,14 @@  discard block
 block discarded – undo
851 851
         foreach ($result as $field_name => $field_value) {
852 852
             $field_obj = $model->field_settings_for($field_name);
853 853
             if ($this->isSubclassOfOne($field_obj, $this->getModelVersionInfo()->fieldsIgnored())) {
854
-                unset($result[ $field_name ]);
854
+                unset($result[$field_name]);
855 855
             } elseif (
856 856
                 $this->isSubclassOfOne(
857 857
                     $field_obj,
858 858
                     $this->getModelVersionInfo()->fieldsThatHaveRenderedFormat()
859 859
                 )
860 860
             ) {
861
-                $result[ $field_name ] = [
861
+                $result[$field_name] = [
862 862
                     'raw'      => $this->prepareFieldObjValueForJson($field_obj, $field_value),
863 863
                     'rendered' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
864 864
                 ];
@@ -868,7 +868,7 @@  discard block
 block discarded – undo
868 868
                     $this->getModelVersionInfo()->fieldsThatHavePrettyFormat()
869 869
                 )
870 870
             ) {
871
-                $result[ $field_name ] = [
871
+                $result[$field_name] = [
872 872
                     'raw'    => $this->prepareFieldObjValueForJson($field_obj, $field_value),
873 873
                     'pretty' => $this->prepareFieldObjValueForJson($field_obj, $field_value, 'pretty'),
874 874
                 ];
@@ -899,10 +899,10 @@  discard block
 block discarded – undo
899 899
                         $this->getModelVersionInfo()->requestedVersion()
900 900
                     );
901 901
                 }
902
-                $result[ $field_name . '_gmt' ] = $gmt_date;
903
-                $result[ $field_name ]          = $local_date;
902
+                $result[$field_name.'_gmt'] = $gmt_date;
903
+                $result[$field_name]          = $local_date;
904 904
             } else {
905
-                $result[ $field_name ] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
905
+                $result[$field_name] = $this->prepareFieldObjValueForJson($field_obj, $field_value);
906 906
             }
907 907
         }
908 908
         if ($do_chevy_shuffle) {
@@ -959,7 +959,7 @@  discard block
 block discarded – undo
959 959
     protected function addExtraFields(EEM_Base $model, array $db_row, array $entity_array): array
960 960
     {
961 961
         if ($model instanceof EEM_CPT_Base) {
962
-            $entity_array['link'] = get_permalink($db_row[ $model->get_primary_key_field()->get_qualified_column() ]);
962
+            $entity_array['link'] = get_permalink($db_row[$model->get_primary_key_field()->get_qualified_column()]);
963 963
         }
964 964
         return $entity_array;
965 965
     }
@@ -985,7 +985,7 @@  discard block
 block discarded – undo
985 985
                     'href' => $this->getVersionedLinkTo(
986 986
                         EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
987 987
                         . '/'
988
-                        . $entity_array[ $model->primary_key_name() ]
988
+                        . $entity_array[$model->primary_key_name()]
989 989
                     ),
990 990
                 ],
991 991
             ];
@@ -1002,12 +1002,12 @@  discard block
 block discarded – undo
1002 1002
             foreach ($this->getModelVersionInfo()->relationSettings($model) as $relation_name => $relation_obj) {
1003 1003
                 $related_model_part                                                      =
1004 1004
                     Read::getRelatedEntityName($relation_name, $relation_obj);
1005
-                $links[ EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = [
1005
+                $links[EED_Core_Rest_Api::ee_api_link_namespace.$related_model_part] = [
1006 1006
                     [
1007 1007
                         'href'   => $this->getVersionedLinkTo(
1008 1008
                             EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
1009 1009
                             . '/'
1010
-                            . $entity_array[ $model->primary_key_name() ]
1010
+                            . $entity_array[$model->primary_key_name()]
1011 1011
                             . '/'
1012 1012
                             . $related_model_part
1013 1013
                         ),
@@ -1047,12 +1047,12 @@  discard block
 block discarded – undo
1047 1047
         bool $included_items_protected = false
1048 1048
     ): array {
1049 1049
         // if $db_row not included, hope the entity array has what we need
1050
-        if (! $db_row) {
1050
+        if ( ! $db_row) {
1051 1051
             $db_row = $entity_array;
1052 1052
         }
1053 1053
         $relation_settings = $this->getModelVersionInfo()->relationSettings($model);
1054 1054
         foreach ($relation_settings as $relation_name => $relation_obj) {
1055
-            $related_fields_to_include   = $this->explodeAndGetItemsPrefixedWith(
1055
+            $related_fields_to_include = $this->explodeAndGetItemsPrefixedWith(
1056 1056
                 $rest_request->get_param('include'),
1057 1057
                 $relation_name
1058 1058
             );
@@ -1080,7 +1080,7 @@  discard block
 block discarded – undo
1080 1080
                         $model->deduce_fields_n_values_from_cols_n_values($db_row)
1081 1081
                     )
1082 1082
                 );
1083
-                if (! $included_items_protected) {
1083
+                if ( ! $included_items_protected) {
1084 1084
                     try {
1085 1085
                         $related_results = $this->getEntitiesFromRelationUsingModelQueryParams(
1086 1086
                             $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
             EE_Default_Where_Conditions::MINIMUM_ALL,
1336 1336
             EE_Default_Where_Conditions::MINIMUM_OTHERS,
1337 1337
         ];
1338
-        if (! $default_where_conditions) {
1338
+        if ( ! $default_where_conditions) {
1339 1339
             $default_where_conditions = EE_Default_Where_Conditions::ALL;
1340 1340
         }
1341 1341
         if (
@@ -1427,14 +1427,14 @@  discard block
 block discarded – undo
1427 1427
         }
1428 1428
         if (isset($query_params['limit'])) {
1429 1429
             // limit should be either a string like '23' or '23,43', or an array with two items in it
1430
-            if (! is_array($query_params['limit'])) {
1430
+            if ( ! is_array($query_params['limit'])) {
1431 1431
                 $limit_array = explode(',', (string) $query_params['limit']);
1432 1432
             } else {
1433 1433
                 $limit_array = $query_params['limit'];
1434 1434
             }
1435 1435
             $sanitized_limit = [];
1436 1436
             foreach ($limit_array as $limit_part) {
1437
-                if ($this->debug_mode && (! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1437
+                if ($this->debug_mode && ( ! is_numeric($limit_part) || count($sanitized_limit) > 2)) {
1438 1438
                     throw new EE_Error(
1439 1439
                         sprintf(
1440 1440
                             esc_html__(
@@ -1491,7 +1491,7 @@  discard block
 block discarded – undo
1491 1491
     {
1492 1492
         $model_ready_query_params = [];
1493 1493
         foreach ($query_params as $key => $value) {
1494
-            $model_ready_query_params[ $key ] = is_array($value)
1494
+            $model_ready_query_params[$key] = is_array($value)
1495 1495
                 ? $this->prepareRestQueryParamsKeyForModels($model, $value)
1496 1496
                 : $value;
1497 1497
         }
@@ -1510,9 +1510,9 @@  discard block
 block discarded – undo
1510 1510
         $model_ready_query_params = [];
1511 1511
         foreach ($query_params as $key => $value) {
1512 1512
             if (is_array($value)) {
1513
-                $model_ready_query_params[ $key ] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1513
+                $model_ready_query_params[$key] = $this->prepareRestQueryParamsValuesForModels($model, $value);
1514 1514
             } else {
1515
-                $model_ready_query_params[ $key ] = $value;
1515
+                $model_ready_query_params[$key] = $value;
1516 1516
             }
1517 1517
         }
1518 1518
         return $model_ready_query_params;
@@ -1544,17 +1544,17 @@  discard block
 block discarded – undo
1544 1544
         foreach ($exploded_contents as $item) {
1545 1545
             $item = trim($item);
1546 1546
             // if no prefix was provided, so we look for items with no "." in them
1547
-            if (! $prefix) {
1547
+            if ( ! $prefix) {
1548 1548
                 // does this item have a period?
1549 1549
                 if (strpos($item, '.') === false) {
1550 1550
                     // if not, then its what we're looking for
1551 1551
                     $contents_with_prefix[] = $item;
1552 1552
                 }
1553
-            } elseif (strpos($item, $prefix . '.') === 0) {
1553
+            } elseif (strpos($item, $prefix.'.') === 0) {
1554 1554
                 // this item has the prefix and a period, grab it
1555 1555
                 $contents_with_prefix[] = substr(
1556 1556
                     $item,
1557
-                    strpos($item, $prefix . '.') + strlen($prefix . '.')
1557
+                    strpos($item, $prefix.'.') + strlen($prefix.'.')
1558 1558
                 );
1559 1559
             } elseif ($item === $prefix) {
1560 1560
                 // this item is JUST the prefix
@@ -1597,9 +1597,9 @@  discard block
 block discarded – undo
1597 1597
         if ($model_name) {
1598 1598
             foreach ($includes as $field_to_include) {
1599 1599
                 $field_to_include = trim($field_to_include);
1600
-                if (strpos($field_to_include, $model_name . '.') === 0) {
1600
+                if (strpos($field_to_include, $model_name.'.') === 0) {
1601 1601
                     // found the model name at the exact start
1602
-                    $field_sans_model_name         = str_replace($model_name . '.', '', $field_to_include);
1602
+                    $field_sans_model_name         = str_replace($model_name.'.', '', $field_to_include);
1603 1603
                     $extracted_fields_to_include[] = $field_sans_model_name;
1604 1604
                 } elseif ($field_to_include === $model_name) {
1605 1605
                     $extracted_fields_to_include[] = '*';
@@ -1642,7 +1642,7 @@  discard block
 block discarded – undo
1642 1642
         $restricted_query_params['caps'] = $context;
1643 1643
         $this->setDebugInfo('model query params', $restricted_query_params);
1644 1644
         $model_rows = $model->get_all_wpdb_results($restricted_query_params);
1645
-        if (! empty($model_rows)) {
1645
+        if ( ! empty($model_rows)) {
1646 1646
             return $this->createEntityFromWpdbResult(
1647 1647
                 $model,
1648 1648
                 reset($model_rows),
@@ -1654,7 +1654,7 @@  discard block
 block discarded – undo
1654 1654
         if ($model->exists($query_params)) {
1655 1655
             // you got shafted- it existed but we didn't want to tell you!
1656 1656
             throw new RestException(
1657
-                'rest_user_cannot_' . $context,
1657
+                'rest_user_cannot_'.$context,
1658 1658
                 sprintf(
1659 1659
                     __('Sorry, you cannot %1$s this %2$s. Missing permissions are: %3$s', 'event_espresso'),
1660 1660
                     $context,
@@ -1706,14 +1706,14 @@  discard block
 block discarded – undo
1706 1706
         // if this entity requires a password, they better give it and it better be right!
1707 1707
         if (
1708 1708
             $model->hasPassword()
1709
-            && $model_row[ $model->getPasswordField()->get_qualified_column() ] !== ''
1709
+            && $model_row[$model->getPasswordField()->get_qualified_column()] !== ''
1710 1710
         ) {
1711 1711
             if (empty($request['password'])) {
1712 1712
                 throw new RestPasswordRequiredException();
1713 1713
             }
1714 1714
             if (
1715 1715
                 ! hash_equals(
1716
-                    $model_row[ $model->getPasswordField()->get_qualified_column() ],
1716
+                    $model_row[$model->getPasswordField()->get_qualified_column()],
1717 1717
                     $request['password']
1718 1718
                 )
1719 1719
             ) {
@@ -1727,12 +1727,12 @@  discard block
 block discarded – undo
1727 1727
             $password_supplied = $request->get_param('password');
1728 1728
             if (empty($password_supplied)) {
1729 1729
                 $query_params['exclude_protected'] = true;
1730
-                if (! $model->exists($query_params)) {
1730
+                if ( ! $model->exists($query_params)) {
1731 1731
                     throw new RestPasswordRequiredException();
1732 1732
                 }
1733 1733
             } else {
1734
-                $query_params[0][ $model->modelChainAndPassword() ] = $password_supplied;
1735
-                if (! $model->exists($query_params)) {
1734
+                $query_params[0][$model->modelChainAndPassword()] = $password_supplied;
1735
+                if ( ! $model->exists($query_params)) {
1736 1736
                     throw new RestPasswordIncorrectException();
1737 1737
                 }
1738 1738
             }
Please login to merge, or discard this patch.
core/libraries/rest_api/calculations/Registration.php 1 patch
Indentation   +94 added lines, -94 removed lines patch added patch discarded remove patch
@@ -25,104 +25,104 @@
 block discarded – undo
25 25
  */
26 26
 class Registration extends RegistrationCalculationBase
27 27
 {
28
-    protected EEM_Registration $registration_model;
28
+	protected EEM_Registration $registration_model;
29 29
 
30
-    /**
31
-     * Registration constructor.
32
-     * @param EEM_Registration $registration_model
33
-     */
34
-    public function __construct(EEM_Registration $registration_model)
35
-    {
36
-        $this->registration_model = $registration_model;
37
-    }
30
+	/**
31
+	 * Registration constructor.
32
+	 * @param EEM_Registration $registration_model
33
+	 */
34
+	public function __construct(EEM_Registration $registration_model)
35
+	{
36
+		$this->registration_model = $registration_model;
37
+	}
38 38
 
39 39
 
40
-    /**
41
-     * Calculates the checkin status for each datetime this registration has access to
42
-     *
43
-     * @param array                      $wpdb_row
44
-     * @param WP_REST_Request            $request
45
-     * @param RegistrationControllerBase $controller
46
-     * @return array
47
-     * @throws EE_Error
48
-     * @throws InvalidDataTypeException
49
-     * @throws InvalidInterfaceException
50
-     * @throws InvalidArgumentException
51
-     * @throws ReflectionException
52
-     */
53
-    public function datetimeCheckinStati($wpdb_row, $request, $controller): array
54
-    {
55
-        $registration = is_array($wpdb_row) && isset($wpdb_row['Registration.REG_ID'])
56
-            ? $this->registration_model->get_one_by_ID($wpdb_row['Registration.REG_ID'])
57
-            : null;
40
+	/**
41
+	 * Calculates the checkin status for each datetime this registration has access to
42
+	 *
43
+	 * @param array                      $wpdb_row
44
+	 * @param WP_REST_Request            $request
45
+	 * @param RegistrationControllerBase $controller
46
+	 * @return array
47
+	 * @throws EE_Error
48
+	 * @throws InvalidDataTypeException
49
+	 * @throws InvalidInterfaceException
50
+	 * @throws InvalidArgumentException
51
+	 * @throws ReflectionException
52
+	 */
53
+	public function datetimeCheckinStati($wpdb_row, $request, $controller): array
54
+	{
55
+		$registration = is_array($wpdb_row) && isset($wpdb_row['Registration.REG_ID'])
56
+			? $this->registration_model->get_one_by_ID($wpdb_row['Registration.REG_ID'])
57
+			: null;
58 58
 
59
-        if (! $registration instanceof EE_Registration) {
60
-            throw new EE_Error(
61
-                sprintf(
62
-                    esc_html__(
63
-                    // @codingStandardsIgnoreStart
64
-                        'Cannot calculate datetime_checkin_stati because the registration with ID %1$s (from database row %2$s) was not found',
65
-                        // @codingStandardsIgnoreEnd
66
-                        'event_espresso'
67
-                    ),
68
-                    $wpdb_row['Registration.REG_ID'],
69
-                    print_r($wpdb_row, true)
70
-                )
71
-            );
72
-        }
73
-        $datetime_ids = EEM_Datetime::instance()->get_col(
74
-            [
75
-                [
76
-                    'Ticket.TKT_ID' => $registration->ticket_ID(),
77
-                ],
78
-                'default_where_conditions' => EE_Default_Where_Conditions::MINIMUM_ALL,
79
-            ]
80
-        );
81
-        $checkin_stati = [];
82
-        foreach ($datetime_ids as $datetime_id) {
83
-            $status = $registration->check_in_status_for_datetime($datetime_id);
84
-            switch ($status) {
85
-                case EE_Checkin::status_checked_out:
86
-                    $status_pretty = 'OUT';
87
-                    break;
88
-                case EE_Checkin::status_checked_in:
89
-                    $status_pretty = 'IN';
90
-                    break;
91
-                case EE_Checkin::status_checked_never:
92
-                default:
93
-                    $status_pretty = 'NEVER';
94
-            }
95
-            $checkin_stati[ $datetime_id ] = $status_pretty;
96
-        }
97
-        return $checkin_stati;
98
-    }
59
+		if (! $registration instanceof EE_Registration) {
60
+			throw new EE_Error(
61
+				sprintf(
62
+					esc_html__(
63
+					// @codingStandardsIgnoreStart
64
+						'Cannot calculate datetime_checkin_stati because the registration with ID %1$s (from database row %2$s) was not found',
65
+						// @codingStandardsIgnoreEnd
66
+						'event_espresso'
67
+					),
68
+					$wpdb_row['Registration.REG_ID'],
69
+					print_r($wpdb_row, true)
70
+				)
71
+			);
72
+		}
73
+		$datetime_ids = EEM_Datetime::instance()->get_col(
74
+			[
75
+				[
76
+					'Ticket.TKT_ID' => $registration->ticket_ID(),
77
+				],
78
+				'default_where_conditions' => EE_Default_Where_Conditions::MINIMUM_ALL,
79
+			]
80
+		);
81
+		$checkin_stati = [];
82
+		foreach ($datetime_ids as $datetime_id) {
83
+			$status = $registration->check_in_status_for_datetime($datetime_id);
84
+			switch ($status) {
85
+				case EE_Checkin::status_checked_out:
86
+					$status_pretty = 'OUT';
87
+					break;
88
+				case EE_Checkin::status_checked_in:
89
+					$status_pretty = 'IN';
90
+					break;
91
+				case EE_Checkin::status_checked_never:
92
+				default:
93
+					$status_pretty = 'NEVER';
94
+			}
95
+			$checkin_stati[ $datetime_id ] = $status_pretty;
96
+		}
97
+		return $checkin_stati;
98
+	}
99 99
 
100 100
 
101
-    /**
102
-     * Provides an array for all the calculations possible that outlines a json schema for those calculations.
103
-     * Array is indexed by calculation (snake case) and value is the schema for that calculation.
104
-     *
105
-     * @since 4.9.68.p
106
-     * @return array
107
-     */
108
-    public function schemaForCalculations()
109
-    {
110
-        return array(
111
-            'datetime_checkin_stati' => array(
112
-                'description' => esc_html__(
113
-                    'Returns the checkin status for each datetime this registration has access to.',
114
-                    'event_espresso'
115
-                ),
116
-                'type' => 'object',
117
-                'properties' => array(),
118
-                'additionalProperties' => array(
119
-                    'description' => esc_html__(
120
-                        'Keys are date-time ids and values are the check-in status',
121
-                        'event_espresso'
122
-                    ),
123
-                    'type' => 'string'
124
-                ),
125
-            ),
126
-        );
127
-    }
101
+	/**
102
+	 * Provides an array for all the calculations possible that outlines a json schema for those calculations.
103
+	 * Array is indexed by calculation (snake case) and value is the schema for that calculation.
104
+	 *
105
+	 * @since 4.9.68.p
106
+	 * @return array
107
+	 */
108
+	public function schemaForCalculations()
109
+	{
110
+		return array(
111
+			'datetime_checkin_stati' => array(
112
+				'description' => esc_html__(
113
+					'Returns the checkin status for each datetime this registration has access to.',
114
+					'event_espresso'
115
+				),
116
+				'type' => 'object',
117
+				'properties' => array(),
118
+				'additionalProperties' => array(
119
+					'description' => esc_html__(
120
+						'Keys are date-time ids and values are the check-in status',
121
+						'event_espresso'
122
+					),
123
+					'type' => 'string'
124
+				),
125
+			),
126
+		);
127
+	}
128 128
 }
Please login to merge, or discard this patch.