Completed
Branch Gutenberg/switch-eventespresso... (7adb18)
by
unknown
16:22 queued 14:31
created
core/libraries/rest_api/controllers/config/Read.php 1 patch
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -20,85 +20,85 @@
 block discarded – undo
20 20
 class Read
21 21
 {
22 22
 
23
-    /**
24
-     * @param WP_REST_Request $request
25
-     * @param string          $version
26
-     * @return EE_Config|WP_Error
27
-     */
28
-    public static function handleRequest(WP_REST_Request $request, $version)
29
-    {
30
-        $cap = EE_Restriction_Generator_Base::get_default_restrictions_cap();
31
-        if (EE_Capabilities::instance()->current_user_can($cap, 'read_over_api')) {
32
-            return EE_Config::instance();
33
-        } else {
34
-            return new WP_Error(
35
-                'cannot_read_config',
36
-                sprintf(
37
-                    __(
38
-                        'You do not have the necessary capabilities (%s) to read Event Espresso Configuration data',
39
-                        'event_espresso'
40
-                    ),
41
-                    $cap
42
-                ),
43
-                array('status' => 403)
44
-            );
45
-        }
46
-    }
23
+	/**
24
+	 * @param WP_REST_Request $request
25
+	 * @param string          $version
26
+	 * @return EE_Config|WP_Error
27
+	 */
28
+	public static function handleRequest(WP_REST_Request $request, $version)
29
+	{
30
+		$cap = EE_Restriction_Generator_Base::get_default_restrictions_cap();
31
+		if (EE_Capabilities::instance()->current_user_can($cap, 'read_over_api')) {
32
+			return EE_Config::instance();
33
+		} else {
34
+			return new WP_Error(
35
+				'cannot_read_config',
36
+				sprintf(
37
+					__(
38
+						'You do not have the necessary capabilities (%s) to read Event Espresso Configuration data',
39
+						'event_espresso'
40
+					),
41
+					$cap
42
+				),
43
+				array('status' => 403)
44
+			);
45
+		}
46
+	}
47 47
 
48 48
 
49
-    /**
50
-     * Handles the request for public site info
51
-     *
52
-     * @global                 $wp_json_basic_auth_success       boolean set by the basic auth plugin, indicates if the
53
-     *                                                           current user could be authenticated using basic auth
54
-     *                                                           data
55
-     * @global                 $wp_json_basic_auth_received_data boolean set by the basic auth plugin, indicates if
56
-     *                                                           basic auth data was somehow received
57
-     * @param WP_REST_Request  $request
58
-     * @param string           $version
59
-     * @return array|WP_Error
60
-     */
61
-    public static function handleRequestSiteInfo(WP_REST_Request $request, $version)
62
-    {
63
-        global $wp_json_basic_auth_success, $wp_json_basic_auth_received_data;
64
-        $insecure_usage_of_basic_auth = apply_filters(
65
-        // @codingStandardsIgnoreStart
66
-            'EventEspresso__core__libraries__rest_api__controllers__config__handle_request_site_info__insecure_usage_of_basic_auth',
67
-            // @codingStandardsIgnoreEnd
68
-            $wp_json_basic_auth_success && ! is_ssl(),
69
-            $request
70
-        );
71
-        if ($insecure_usage_of_basic_auth) {
72
-            $warning = sprintf(
73
-                esc_html__(
74
-                // @codingStandardsIgnoreStart
75
-                    'Notice: We strongly recommend installing an SSL Certificate on your website to keep your data secure. %1$sPlease see our recommendations.%2$s',
76
-                    // @codingStandardsIgnoreEnd
77
-                    'event_espresso'
78
-                ),
79
-                '<a href="https://eventespresso.com/wiki/rest-api-security-recommendations/">',
80
-                '</a>'
81
-            );
82
-        } else {
83
-            $warning = '';
84
-        }
85
-        return apply_filters(
86
-            'FHEE__EventEspresso_core_libraries_rest_api_controllers_config__handleRequestSiteInfo__return_val',
87
-            array(
88
-                'default_timezone' => array(
89
-                    'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
90
-                    'string' => get_option('timezone_string'),
91
-                    'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
92
-                ),
93
-                'default_currency' => EE_Config::instance()->currency,
94
-                'authentication'   => array(
95
-                    'received_basic_auth_data'     => (bool) $wp_json_basic_auth_received_data,
96
-                    'insecure_usage_of_basic_auth' => (bool) $insecure_usage_of_basic_auth,
97
-                    'warning'                      => $warning,
98
-                ),
99
-            )
100
-        );
101
-    }
49
+	/**
50
+	 * Handles the request for public site info
51
+	 *
52
+	 * @global                 $wp_json_basic_auth_success       boolean set by the basic auth plugin, indicates if the
53
+	 *                                                           current user could be authenticated using basic auth
54
+	 *                                                           data
55
+	 * @global                 $wp_json_basic_auth_received_data boolean set by the basic auth plugin, indicates if
56
+	 *                                                           basic auth data was somehow received
57
+	 * @param WP_REST_Request  $request
58
+	 * @param string           $version
59
+	 * @return array|WP_Error
60
+	 */
61
+	public static function handleRequestSiteInfo(WP_REST_Request $request, $version)
62
+	{
63
+		global $wp_json_basic_auth_success, $wp_json_basic_auth_received_data;
64
+		$insecure_usage_of_basic_auth = apply_filters(
65
+		// @codingStandardsIgnoreStart
66
+			'EventEspresso__core__libraries__rest_api__controllers__config__handle_request_site_info__insecure_usage_of_basic_auth',
67
+			// @codingStandardsIgnoreEnd
68
+			$wp_json_basic_auth_success && ! is_ssl(),
69
+			$request
70
+		);
71
+		if ($insecure_usage_of_basic_auth) {
72
+			$warning = sprintf(
73
+				esc_html__(
74
+				// @codingStandardsIgnoreStart
75
+					'Notice: We strongly recommend installing an SSL Certificate on your website to keep your data secure. %1$sPlease see our recommendations.%2$s',
76
+					// @codingStandardsIgnoreEnd
77
+					'event_espresso'
78
+				),
79
+				'<a href="https://eventespresso.com/wiki/rest-api-security-recommendations/">',
80
+				'</a>'
81
+			);
82
+		} else {
83
+			$warning = '';
84
+		}
85
+		return apply_filters(
86
+			'FHEE__EventEspresso_core_libraries_rest_api_controllers_config__handleRequestSiteInfo__return_val',
87
+			array(
88
+				'default_timezone' => array(
89
+					'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
90
+					'string' => get_option('timezone_string'),
91
+					'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
92
+				),
93
+				'default_currency' => EE_Config::instance()->currency,
94
+				'authentication'   => array(
95
+					'received_basic_auth_data'     => (bool) $wp_json_basic_auth_received_data,
96
+					'insecure_usage_of_basic_auth' => (bool) $insecure_usage_of_basic_auth,
97
+					'warning'                      => $warning,
98
+				),
99
+			)
100
+		);
101
+	}
102 102
 }
103 103
 
104 104
 // End of file Read.php
Please login to merge, or discard this patch.
core/libraries/rest_api/controllers/model/Meta.php 2 patches
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -23,122 +23,122 @@
 block discarded – undo
23 23
 {
24 24
 
25 25
 
26
-    /**
27
-     * @param \WP_REST_Request $request
28
-     * @param string           $version
29
-     * @return array|\WP_REST_Response
30
-     */
31
-    public static function handleRequestModelsMeta(\WP_REST_Request $request, $version)
32
-    {
33
-        $controller = new Meta();
34
-        try {
35
-            $controller->setRequestedVersion($version);
36
-            return $controller->sendResponse($controller->getModelsMetadataEntity());
37
-        } catch (Exception $e) {
38
-            return $controller->sendResponse($e);
39
-        }
40
-    }
26
+	/**
27
+	 * @param \WP_REST_Request $request
28
+	 * @param string           $version
29
+	 * @return array|\WP_REST_Response
30
+	 */
31
+	public static function handleRequestModelsMeta(\WP_REST_Request $request, $version)
32
+	{
33
+		$controller = new Meta();
34
+		try {
35
+			$controller->setRequestedVersion($version);
36
+			return $controller->sendResponse($controller->getModelsMetadataEntity());
37
+		} catch (Exception $e) {
38
+			return $controller->sendResponse($e);
39
+		}
40
+	}
41 41
 
42 42
 
43
-    /*
43
+	/*
44 44
      * Gets the model metadata resource entity
45 45
      * @return array for JSON response, describing all the models available in teh requested version
46 46
      */
47
-    protected function getModelsMetadataEntity()
48
-    {
49
-        $response = array();
50
-        foreach ($this->getModelVersionInfo()->modelsForRequestedVersion() as $model_name => $model_classname) {
51
-            $model = $this->getModelVersionInfo()->loadModel($model_name);
52
-            $fields_json = array();
53
-            foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field_obj) {
54
-                if ($this->getModelVersionInfo()->fieldIsIgnored($field_obj)) {
55
-                    continue;
56
-                }
57
-                if ($field_obj instanceof EE_Boolean_Field) {
58
-                    $datatype = 'Boolean';
59
-                } elseif ($field_obj->get_wpdb_data_type() == '%d') {
60
-                    $datatype = 'Number';
61
-                } elseif ($field_name instanceof EE_Serialized_Text_Field) {
62
-                    $datatype = 'Object';
63
-                } else {
64
-                    $datatype = 'String';
65
-                }
66
-                $default_value = ModelDataTranslator::prepareFieldValueForJson(
67
-                    $field_obj,
68
-                    $field_obj->get_default_value(),
69
-                    $this->getModelVersionInfo()->requestedVersion()
70
-                );
71
-                $field_json = array(
72
-                    'name'                => $field_name,
73
-                    'nicename'            => wp_specialchars_decode($field_obj->get_nicename(), ENT_QUOTES),
74
-                    'has_rendered_format' => $this->getModelVersionInfo()->fieldHasRenderedFormat($field_obj),
75
-                    'has_pretty_format'   => $this->getModelVersionInfo()->fieldHasPrettyFormat($field_obj),
76
-                    'type'                => str_replace('EE_', '', get_class($field_obj)),
77
-                    'datatype'            => $datatype,
78
-                    'nullable'            => $field_obj->is_nullable(),
79
-                    'default'             => $default_value,
80
-                    'table_alias'         => $field_obj->get_table_alias(),
81
-                    'table_column'        => $field_obj->get_table_column(),
82
-                );
83
-                $fields_json[ $field_json['name'] ] = $field_json;
84
-            }
85
-            $fields_json = array_merge(
86
-                $fields_json,
87
-                $this->getModelVersionInfo()->extraResourcePropertiesForModel($model)
88
-            );
89
-            $response[ $model_name ]['fields'] = apply_filters(
90
-                'FHEE__Meta__handle_request_models_meta__fields',
91
-                $fields_json,
92
-                $model
93
-            );
94
-            $relations_json = array();
95
-            foreach ($model->relation_settings() as $relation_name => $relation_obj) {
96
-                $relation_json = array(
97
-                    'name'   => $relation_name,
98
-                    'type'   => str_replace('EE_', '', get_class($relation_obj)),
99
-                    'single' => $relation_obj instanceof \EE_Belongs_To_Relation ? true : false,
100
-                );
101
-                $relations_json[ $relation_name ] = $relation_json;
102
-            }
103
-            $response[ $model_name ]['relations'] = apply_filters(
104
-                'FHEE__Meta__handle_request_models_meta__relations',
105
-                $relations_json,
106
-                $model
107
-            );
108
-        }
109
-        return $response;
110
-    }
47
+	protected function getModelsMetadataEntity()
48
+	{
49
+		$response = array();
50
+		foreach ($this->getModelVersionInfo()->modelsForRequestedVersion() as $model_name => $model_classname) {
51
+			$model = $this->getModelVersionInfo()->loadModel($model_name);
52
+			$fields_json = array();
53
+			foreach ($this->getModelVersionInfo()->fieldsOnModelInThisVersion($model) as $field_name => $field_obj) {
54
+				if ($this->getModelVersionInfo()->fieldIsIgnored($field_obj)) {
55
+					continue;
56
+				}
57
+				if ($field_obj instanceof EE_Boolean_Field) {
58
+					$datatype = 'Boolean';
59
+				} elseif ($field_obj->get_wpdb_data_type() == '%d') {
60
+					$datatype = 'Number';
61
+				} elseif ($field_name instanceof EE_Serialized_Text_Field) {
62
+					$datatype = 'Object';
63
+				} else {
64
+					$datatype = 'String';
65
+				}
66
+				$default_value = ModelDataTranslator::prepareFieldValueForJson(
67
+					$field_obj,
68
+					$field_obj->get_default_value(),
69
+					$this->getModelVersionInfo()->requestedVersion()
70
+				);
71
+				$field_json = array(
72
+					'name'                => $field_name,
73
+					'nicename'            => wp_specialchars_decode($field_obj->get_nicename(), ENT_QUOTES),
74
+					'has_rendered_format' => $this->getModelVersionInfo()->fieldHasRenderedFormat($field_obj),
75
+					'has_pretty_format'   => $this->getModelVersionInfo()->fieldHasPrettyFormat($field_obj),
76
+					'type'                => str_replace('EE_', '', get_class($field_obj)),
77
+					'datatype'            => $datatype,
78
+					'nullable'            => $field_obj->is_nullable(),
79
+					'default'             => $default_value,
80
+					'table_alias'         => $field_obj->get_table_alias(),
81
+					'table_column'        => $field_obj->get_table_column(),
82
+				);
83
+				$fields_json[ $field_json['name'] ] = $field_json;
84
+			}
85
+			$fields_json = array_merge(
86
+				$fields_json,
87
+				$this->getModelVersionInfo()->extraResourcePropertiesForModel($model)
88
+			);
89
+			$response[ $model_name ]['fields'] = apply_filters(
90
+				'FHEE__Meta__handle_request_models_meta__fields',
91
+				$fields_json,
92
+				$model
93
+			);
94
+			$relations_json = array();
95
+			foreach ($model->relation_settings() as $relation_name => $relation_obj) {
96
+				$relation_json = array(
97
+					'name'   => $relation_name,
98
+					'type'   => str_replace('EE_', '', get_class($relation_obj)),
99
+					'single' => $relation_obj instanceof \EE_Belongs_To_Relation ? true : false,
100
+				);
101
+				$relations_json[ $relation_name ] = $relation_json;
102
+			}
103
+			$response[ $model_name ]['relations'] = apply_filters(
104
+				'FHEE__Meta__handle_request_models_meta__relations',
105
+				$relations_json,
106
+				$model
107
+			);
108
+		}
109
+		return $response;
110
+	}
111 111
 
112 112
 
113
-    /**
114
-     * Adds EE metadata to the index
115
-     *
116
-     * @param \WP_REST_Response $rest_response_obj
117
-     * @return \WP_REST_Response
118
-     */
119
-    public static function filterEeMetadataIntoIndex(\WP_REST_Response $rest_response_obj)
120
-    {
121
-        $response_data = $rest_response_obj->get_data();
122
-        $addons = array();
123
-        foreach (EE_Registry::instance()->addons as $addon) {
124
-            $addon_json = array(
125
-                'name'    => $addon->name(),
126
-                'version' => $addon->version(),
127
-            );
128
-            $addons[ $addon_json['name'] ] = $addon_json;
129
-        }
130
-        $response_data['ee'] = array(
131
-            'version'              => EEM_System_Status::instance()->get_ee_version(),
132
-            // @codingStandardsIgnoreStart
133
-            'documentation_url'    => 'https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API',
134
-            // @codingStandardsIgnoreEnd
135
-            'addons'               => $addons,
136
-            'maintenance_mode'     => EE_Maintenance_Mode::instance()->real_level(),
137
-            'served_core_versions' => array_keys(EED_Core_Rest_Api::versions_served()),
138
-        );
139
-        $rest_response_obj->set_data($response_data);
140
-        return $rest_response_obj;
141
-    }
113
+	/**
114
+	 * Adds EE metadata to the index
115
+	 *
116
+	 * @param \WP_REST_Response $rest_response_obj
117
+	 * @return \WP_REST_Response
118
+	 */
119
+	public static function filterEeMetadataIntoIndex(\WP_REST_Response $rest_response_obj)
120
+	{
121
+		$response_data = $rest_response_obj->get_data();
122
+		$addons = array();
123
+		foreach (EE_Registry::instance()->addons as $addon) {
124
+			$addon_json = array(
125
+				'name'    => $addon->name(),
126
+				'version' => $addon->version(),
127
+			);
128
+			$addons[ $addon_json['name'] ] = $addon_json;
129
+		}
130
+		$response_data['ee'] = array(
131
+			'version'              => EEM_System_Status::instance()->get_ee_version(),
132
+			// @codingStandardsIgnoreStart
133
+			'documentation_url'    => 'https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API',
134
+			// @codingStandardsIgnoreEnd
135
+			'addons'               => $addons,
136
+			'maintenance_mode'     => EE_Maintenance_Mode::instance()->real_level(),
137
+			'served_core_versions' => array_keys(EED_Core_Rest_Api::versions_served()),
138
+		);
139
+		$rest_response_obj->set_data($response_data);
140
+		return $rest_response_obj;
141
+	}
142 142
 }
143 143
 
144 144
 
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -80,13 +80,13 @@  discard block
 block discarded – undo
80 80
                     'table_alias'         => $field_obj->get_table_alias(),
81 81
                     'table_column'        => $field_obj->get_table_column(),
82 82
                 );
83
-                $fields_json[ $field_json['name'] ] = $field_json;
83
+                $fields_json[$field_json['name']] = $field_json;
84 84
             }
85 85
             $fields_json = array_merge(
86 86
                 $fields_json,
87 87
                 $this->getModelVersionInfo()->extraResourcePropertiesForModel($model)
88 88
             );
89
-            $response[ $model_name ]['fields'] = apply_filters(
89
+            $response[$model_name]['fields'] = apply_filters(
90 90
                 'FHEE__Meta__handle_request_models_meta__fields',
91 91
                 $fields_json,
92 92
                 $model
@@ -98,9 +98,9 @@  discard block
 block discarded – undo
98 98
                     'type'   => str_replace('EE_', '', get_class($relation_obj)),
99 99
                     'single' => $relation_obj instanceof \EE_Belongs_To_Relation ? true : false,
100 100
                 );
101
-                $relations_json[ $relation_name ] = $relation_json;
101
+                $relations_json[$relation_name] = $relation_json;
102 102
             }
103
-            $response[ $model_name ]['relations'] = apply_filters(
103
+            $response[$model_name]['relations'] = apply_filters(
104 104
                 'FHEE__Meta__handle_request_models_meta__relations',
105 105
                 $relations_json,
106 106
                 $model
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
                 'name'    => $addon->name(),
126 126
                 'version' => $addon->version(),
127 127
             );
128
-            $addons[ $addon_json['name'] ] = $addon_json;
128
+            $addons[$addon_json['name']] = $addon_json;
129 129
         }
130 130
         $response_data['ee'] = array(
131 131
             'version'              => EEM_System_Status::instance()->get_ee_version(),
Please login to merge, or discard this patch.
core/libraries/rest_api/changes/ChangesInBase.php 2 patches
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -35,74 +35,74 @@
 block discarded – undo
35 35
 abstract class ChangesInBase
36 36
 {
37 37
 
38
-    /**
39
-     * The version that these changes happened
40
-     *
41
-     * @var string
42
-     */
43
-    protected $version = null;
38
+	/**
39
+	 * The version that these changes happened
40
+	 *
41
+	 * @var string
42
+	 */
43
+	protected $version = null;
44 44
 
45 45
 
46
-    /**
47
-     * Called when an EE4 REST API request is made to an earlier version than
48
-     * what is indicated in this class' name.
49
-     * Uses WordPress' add_filter and add_action to modify the EE4 REST API's response
50
-     * so that regardless of what version of EE4 core is running, API clients
51
-     * will have a consistent response
52
-     *
53
-     * @return void
54
-     */
55
-    abstract public function setHooks();
46
+	/**
47
+	 * Called when an EE4 REST API request is made to an earlier version than
48
+	 * what is indicated in this class' name.
49
+	 * Uses WordPress' add_filter and add_action to modify the EE4 REST API's response
50
+	 * so that regardless of what version of EE4 core is running, API clients
51
+	 * will have a consistent response
52
+	 *
53
+	 * @return void
54
+	 */
55
+	abstract public function setHooks();
56 56
 
57 57
 
58
-    /**
59
-     * Returns whether or not this class' name indicates its hooks should
60
-     * apply when a request comes in for $requested_version. A class can use
61
-     * other conditions when determining whether to perform their callbacks or not,
62
-     * but this will typically be enough
63
-     *
64
-     * @param string $requested_version eg "4.8.33"
65
-     * @return boolean true: this class' name indicates its filters and actions
66
-     *                                  should take effect. False: this class' name indicates it shouldn't do anything
67
-     */
68
-    public function appliesToVersion($requested_version)
69
-    {
70
-        if ($this->version() > $requested_version) {
71
-            return true;
72
-        }
73
-        return false;
74
-    }
58
+	/**
59
+	 * Returns whether or not this class' name indicates its hooks should
60
+	 * apply when a request comes in for $requested_version. A class can use
61
+	 * other conditions when determining whether to perform their callbacks or not,
62
+	 * but this will typically be enough
63
+	 *
64
+	 * @param string $requested_version eg "4.8.33"
65
+	 * @return boolean true: this class' name indicates its filters and actions
66
+	 *                                  should take effect. False: this class' name indicates it shouldn't do anything
67
+	 */
68
+	public function appliesToVersion($requested_version)
69
+	{
70
+		if ($this->version() > $requested_version) {
71
+			return true;
72
+		}
73
+		return false;
74
+	}
75 75
 
76 76
 
77
-    /**
78
-     * Gets the EE core version when this changes were made to the rest api.
79
-     * Any requests to earlier versions should have modifications made to them
80
-     * by the callbacks of this class.
81
-     *
82
-     * @return string eg "4.8.33"
83
-     * @throws EE_Error
84
-     */
85
-    public function version()
86
-    {
87
-        if ($this->version === null) {
88
-            $matches = array();
89
-            $regex = '~ChangesIn(\d)(\d\d)(\d\d)$~';
90
-            $success = preg_match(
91
-                $regex,
92
-                get_class($this),
93
-                $matches
94
-            );
95
-            if (! $success) {
96
-                throw new EE_Error(
97
-                    sprintf(
98
-                        __('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'),
99
-                        get_class($this),
100
-                        $regex
101
-                    )
102
-                );
103
-            }
104
-            $this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3];
105
-        }
106
-        return $this->version;
107
-    }
77
+	/**
78
+	 * Gets the EE core version when this changes were made to the rest api.
79
+	 * Any requests to earlier versions should have modifications made to them
80
+	 * by the callbacks of this class.
81
+	 *
82
+	 * @return string eg "4.8.33"
83
+	 * @throws EE_Error
84
+	 */
85
+	public function version()
86
+	{
87
+		if ($this->version === null) {
88
+			$matches = array();
89
+			$regex = '~ChangesIn(\d)(\d\d)(\d\d)$~';
90
+			$success = preg_match(
91
+				$regex,
92
+				get_class($this),
93
+				$matches
94
+			);
95
+			if (! $success) {
96
+				throw new EE_Error(
97
+					sprintf(
98
+						__('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'),
99
+						get_class($this),
100
+						$regex
101
+					)
102
+				);
103
+			}
104
+			$this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3];
105
+		}
106
+		return $this->version;
107
+	}
108 108
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
                 get_class($this),
93 93
                 $matches
94 94
             );
95
-            if (! $success) {
95
+            if ( ! $success) {
96 96
                 throw new EE_Error(
97 97
                     sprintf(
98 98
                         __('The class %1$s was misnamed. It name should match the regex "%2$s"', 'event_espresso'),
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
                     )
102 102
                 );
103 103
             }
104
-            $this->version = (int) $matches[1] . '.' . (int) $matches[2] . '.' . (int) $matches[3];
104
+            $this->version = (int) $matches[1].'.'.(int) $matches[2].'.'.(int) $matches[3];
105 105
         }
106 106
         return $this->version;
107 107
     }
Please login to merge, or discard this patch.
core/libraries/rest_api/changes/ChangesIn40836.php 2 patches
Indentation   +160 added lines, -160 removed lines patch added patch discarded remove patch
@@ -14,174 +14,174 @@
 block discarded – undo
14 14
 class ChangesIn40836 extends ChangesInBase
15 15
 {
16 16
 
17
-    /**
18
-     * Adds hooks so requests to 4.8.29 don't have the checkin endpoints
19
-     */
20
-    public function setHooks()
21
-    {
22
-        // set a hook to remove the "calculate" query param
23
-        add_filter(
24
-            'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
25
-            array($this, 'removeCalculateQueryParam'),
26
-            10,
27
-            3
28
-        );
29
-        // don't add the _calculated_fields either
30
-        add_filter(
31
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
32
-            array($this, 'removeCalculatedFieldsFromResponse'),
33
-            10,
34
-            5
35
-        );
36
-        // and also don't add the count headers
37
-        add_filter(
38
-            'FHEE__EventEspresso\core\libraries\rest_api\controllers\Base___get_response_headers',
39
-            array($this, 'removeHeadersNewInThisVersion'),
40
-            10,
41
-            3
42
-        );
43
-        // remove the old featured_image part of the response...
44
-        add_filter(
45
-            'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
46
-            array($this, 'addOldFeaturedImagePartOfCptEntities'),
47
-            10,
48
-            5
49
-        );
50
-        // assuming ticket 9425's change gets pushed with 9406, we don't need to
51
-        // remove it from the calculated fields on older requests (because this will
52
-        // be the first version with calculated fields)
53
-        // before this, infinity was -1, now it's null
54
-        add_filter(
55
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
56
-            array($this, 'useNegativeOneForInfinityBeforeThisVersion'),
57
-            10,
58
-            4
59
-        );
60
-    }
17
+	/**
18
+	 * Adds hooks so requests to 4.8.29 don't have the checkin endpoints
19
+	 */
20
+	public function setHooks()
21
+	{
22
+		// set a hook to remove the "calculate" query param
23
+		add_filter(
24
+			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
25
+			array($this, 'removeCalculateQueryParam'),
26
+			10,
27
+			3
28
+		);
29
+		// don't add the _calculated_fields either
30
+		add_filter(
31
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
32
+			array($this, 'removeCalculatedFieldsFromResponse'),
33
+			10,
34
+			5
35
+		);
36
+		// and also don't add the count headers
37
+		add_filter(
38
+			'FHEE__EventEspresso\core\libraries\rest_api\controllers\Base___get_response_headers',
39
+			array($this, 'removeHeadersNewInThisVersion'),
40
+			10,
41
+			3
42
+		);
43
+		// remove the old featured_image part of the response...
44
+		add_filter(
45
+			'FHEE__Read__create_entity_from_wpdb_results__entity_before_including_requested_models',
46
+			array($this, 'addOldFeaturedImagePartOfCptEntities'),
47
+			10,
48
+			5
49
+		);
50
+		// assuming ticket 9425's change gets pushed with 9406, we don't need to
51
+		// remove it from the calculated fields on older requests (because this will
52
+		// be the first version with calculated fields)
53
+		// before this, infinity was -1, now it's null
54
+		add_filter(
55
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
56
+			array($this, 'useNegativeOneForInfinityBeforeThisVersion'),
57
+			10,
58
+			4
59
+		);
60
+	}
61 61
 
62 62
 
63
-    /**
64
-     * Don't show "calculate" as an query param option in the index
65
-     *
66
-     * @param array    $query_params
67
-     * @param EEM_Base $model
68
-     * @param string   $version
69
-     * @return array
70
-     */
71
-    public function removeCalculateQueryParam($query_params, EEM_Base $model, $version)
72
-    {
73
-        if ($this->appliesToVersion($version)) {
74
-            unset($query_params['calculate']);
75
-        }
76
-        return $query_params;
77
-    }
63
+	/**
64
+	 * Don't show "calculate" as an query param option in the index
65
+	 *
66
+	 * @param array    $query_params
67
+	 * @param EEM_Base $model
68
+	 * @param string   $version
69
+	 * @return array
70
+	 */
71
+	public function removeCalculateQueryParam($query_params, EEM_Base $model, $version)
72
+	{
73
+		if ($this->appliesToVersion($version)) {
74
+			unset($query_params['calculate']);
75
+		}
76
+		return $query_params;
77
+	}
78 78
 
79 79
 
80
-    /**
81
-     * Removes the "_calculate_fields" part of entity responses before 4.8.36
82
-     *
83
-     * @param array           $entity_response_array
84
-     * @param EEM_Base        $model
85
-     * @param string          $request_context
86
-     * @param WP_REST_Request $request
87
-     * @param Read            $controller
88
-     * @return array
89
-     */
90
-    public function removeCalculatedFieldsFromResponse(
91
-        $entity_response_array,
92
-        EEM_Base $model,
93
-        $request_context,
94
-        WP_REST_Request $request,
95
-        Read $controller
96
-    ) {
97
-        if ($this->appliesToVersion($controller->getModelVersionInfo()->requestedVersion())) {
98
-            unset($entity_response_array['_calculated_fields']);
99
-        }
100
-        return $entity_response_array;
101
-    }
80
+	/**
81
+	 * Removes the "_calculate_fields" part of entity responses before 4.8.36
82
+	 *
83
+	 * @param array           $entity_response_array
84
+	 * @param EEM_Base        $model
85
+	 * @param string          $request_context
86
+	 * @param WP_REST_Request $request
87
+	 * @param Read            $controller
88
+	 * @return array
89
+	 */
90
+	public function removeCalculatedFieldsFromResponse(
91
+		$entity_response_array,
92
+		EEM_Base $model,
93
+		$request_context,
94
+		WP_REST_Request $request,
95
+		Read $controller
96
+	) {
97
+		if ($this->appliesToVersion($controller->getModelVersionInfo()->requestedVersion())) {
98
+			unset($entity_response_array['_calculated_fields']);
99
+		}
100
+		return $entity_response_array;
101
+	}
102 102
 
103 103
 
104
-    /**
105
-     * Removes the new headers for requests before 4.8.36
106
-     *
107
-     * @param array           $headers
108
-     * @param Controller_Base $controller
109
-     * @param string          $version
110
-     * @return array
111
-     */
112
-    public function removeHeadersNewInThisVersion(
113
-        $headers,
114
-        Controller_Base $controller,
115
-        $version
116
-    ) {
117
-        if ($this->appliesToVersion($version)) {
118
-            $headers = array_diff_key(
119
-                $headers,
120
-                array_flip(
121
-                    array(
122
-                        Base::HEADER_PREFIX_FOR_WP . 'Total',
123
-                        Base::HEADER_PREFIX_FOR_WP . 'TotalPages',
124
-                        Base::HEADER_PREFIX_FOR_WP . 'PageSize',
125
-                    )
126
-                )
127
-            );
128
-        }
129
-        return $headers;
130
-    }
104
+	/**
105
+	 * Removes the new headers for requests before 4.8.36
106
+	 *
107
+	 * @param array           $headers
108
+	 * @param Controller_Base $controller
109
+	 * @param string          $version
110
+	 * @return array
111
+	 */
112
+	public function removeHeadersNewInThisVersion(
113
+		$headers,
114
+		Controller_Base $controller,
115
+		$version
116
+	) {
117
+		if ($this->appliesToVersion($version)) {
118
+			$headers = array_diff_key(
119
+				$headers,
120
+				array_flip(
121
+					array(
122
+						Base::HEADER_PREFIX_FOR_WP . 'Total',
123
+						Base::HEADER_PREFIX_FOR_WP . 'TotalPages',
124
+						Base::HEADER_PREFIX_FOR_WP . 'PageSize',
125
+					)
126
+				)
127
+			);
128
+		}
129
+		return $headers;
130
+	}
131 131
 
132 132
 
133
-    /**
134
-     * Puts the 'featured_image_url' back in for responses before 4.8.36.
135
-     *
136
-     * @param array           $entity_response_array
137
-     * @param EEM_Base        $model
138
-     * @param string          $request_context
139
-     * @param WP_REST_Request $request
140
-     * @param Read            $controller
141
-     * @return array
142
-     */
143
-    public function addOldFeaturedImagePartOfCptEntities(
144
-        $entity_response_array,
145
-        EEM_Base $model,
146
-        $request_context,
147
-        WP_REST_Request $request,
148
-        Read $controller
149
-    ) {
150
-        if ($this->appliesToVersion($controller->getModelVersionInfo()->requestedVersion())
151
-            && $model instanceof \EEM_CPT_Base
152
-        ) {
153
-            $attachment = wp_get_attachment_image_src(
154
-                get_post_thumbnail_id($entity_response_array[ $model->primary_key_name() ]),
155
-                'full'
156
-            );
157
-            $entity_response_array['featured_image_url'] = ! empty($attachment) ? $attachment[0] : null;
158
-        }
159
-        return $entity_response_array;
160
-    }
133
+	/**
134
+	 * Puts the 'featured_image_url' back in for responses before 4.8.36.
135
+	 *
136
+	 * @param array           $entity_response_array
137
+	 * @param EEM_Base        $model
138
+	 * @param string          $request_context
139
+	 * @param WP_REST_Request $request
140
+	 * @param Read            $controller
141
+	 * @return array
142
+	 */
143
+	public function addOldFeaturedImagePartOfCptEntities(
144
+		$entity_response_array,
145
+		EEM_Base $model,
146
+		$request_context,
147
+		WP_REST_Request $request,
148
+		Read $controller
149
+	) {
150
+		if ($this->appliesToVersion($controller->getModelVersionInfo()->requestedVersion())
151
+			&& $model instanceof \EEM_CPT_Base
152
+		) {
153
+			$attachment = wp_get_attachment_image_src(
154
+				get_post_thumbnail_id($entity_response_array[ $model->primary_key_name() ]),
155
+				'full'
156
+			);
157
+			$entity_response_array['featured_image_url'] = ! empty($attachment) ? $attachment[0] : null;
158
+		}
159
+		return $entity_response_array;
160
+	}
161 161
 
162 162
 
163
-    /**
164
-     * If the value was infinity, we now use null in our JSON responses,
165
-     * but before this version we used -1.
166
-     *
167
-     * @param mixed                $new_value
168
-     * @param \EE_Model_Field_Base $field_obj
169
-     * @param mixed                $original_value
170
-     * @param string               $requested_value
171
-     * @return mixed
172
-     */
173
-    public function useNegativeOneForInfinityBeforeThisVersion(
174
-        $new_value,
175
-        $field_obj,
176
-        $original_value,
177
-        $requested_value
178
-    ) {
179
-        if ($this->appliesToVersion($requested_value)
180
-            && $original_value === EE_INF
181
-        ) {
182
-            // return the old representation of infinity in the JSON
183
-            return -1;
184
-        }
185
-        return $new_value;
186
-    }
163
+	/**
164
+	 * If the value was infinity, we now use null in our JSON responses,
165
+	 * but before this version we used -1.
166
+	 *
167
+	 * @param mixed                $new_value
168
+	 * @param \EE_Model_Field_Base $field_obj
169
+	 * @param mixed                $original_value
170
+	 * @param string               $requested_value
171
+	 * @return mixed
172
+	 */
173
+	public function useNegativeOneForInfinityBeforeThisVersion(
174
+		$new_value,
175
+		$field_obj,
176
+		$original_value,
177
+		$requested_value
178
+	) {
179
+		if ($this->appliesToVersion($requested_value)
180
+			&& $original_value === EE_INF
181
+		) {
182
+			// return the old representation of infinity in the JSON
183
+			return -1;
184
+		}
185
+		return $new_value;
186
+	}
187 187
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -119,9 +119,9 @@  discard block
 block discarded – undo
119 119
                 $headers,
120 120
                 array_flip(
121 121
                     array(
122
-                        Base::HEADER_PREFIX_FOR_WP . 'Total',
123
-                        Base::HEADER_PREFIX_FOR_WP . 'TotalPages',
124
-                        Base::HEADER_PREFIX_FOR_WP . 'PageSize',
122
+                        Base::HEADER_PREFIX_FOR_WP.'Total',
123
+                        Base::HEADER_PREFIX_FOR_WP.'TotalPages',
124
+                        Base::HEADER_PREFIX_FOR_WP.'PageSize',
125 125
                     )
126 126
                 )
127 127
             );
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
             && $model instanceof \EEM_CPT_Base
152 152
         ) {
153 153
             $attachment = wp_get_attachment_image_src(
154
-                get_post_thumbnail_id($entity_response_array[ $model->primary_key_name() ]),
154
+                get_post_thumbnail_id($entity_response_array[$model->primary_key_name()]),
155 155
                 'full'
156 156
             );
157 157
             $entity_response_array['featured_image_url'] = ! empty($attachment) ? $attachment[0] : null;
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelDataTranslator.php 2 patches
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -60,7 +60,7 @@  discard block
 block discarded – undo
60 60
         ) {
61 61
             $new_value_maybe_array = array();
62 62
             foreach ($original_value_maybe_array as $array_key => $array_item) {
63
-                $new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
63
+                $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson(
64 64
                     $field_obj,
65 65
                     $array_item,
66 66
                     $requested_version,
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
         if (is_array($original_value_maybe_array)) {
93 93
             $new_value = array();
94 94
             foreach ($original_value_maybe_array as $key => $value) {
95
-                $new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
95
+                $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson(
96 96
                     $field_obj,
97 97
                     $value,
98 98
                     $request_version
@@ -225,7 +225,7 @@  discard block
 block discarded – undo
225 225
                 '0',
226 226
                 STR_PAD_LEFT
227 227
             );
228
-        return $original_timestamp . $offset_sign . $offset_string;
228
+        return $original_timestamp.$offset_sign.$offset_string;
229 229
     }
230 230
 
231 231
 
@@ -302,7 +302,7 @@  discard block
 block discarded – undo
302 302
                     // first, check if its a MySQL timestamp in GMT
303 303
                     $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
304 304
                 }
305
-                if (! $datetime_obj instanceof \DateTime) {
305
+                if ( ! $datetime_obj instanceof \DateTime) {
306 306
                     // so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
307 307
                     $datetime_obj = $field_obj->prepare_for_set($original_value);
308 308
                 }
@@ -328,7 +328,7 @@  discard block
 block discarded – undo
328 328
                         $original_value,
329 329
                         $field_obj->get_name(),
330 330
                         $field_obj->get_model_name(),
331
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
331
+                        $field_obj->get_time_format().' '.$field_obj->get_time_format()
332 332
                     )
333 333
                 );
334 334
             }
@@ -338,7 +338,7 @@  discard block
 block discarded – undo
338 338
         }
339 339
         // are we about to send an object? just don't. We have no good way to represent it in JSON.
340 340
         // can't just check using is_object() because that missed PHP incomplete objects
341
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
341
+        if ( ! ModelDataTranslator::isRepresentableInJson($new_value)) {
342 342
             $new_value = array(
343 343
                 'error_code'    => 'php_object_not_return',
344 344
                 'error_message' => esc_html__(
@@ -391,7 +391,7 @@  discard block
 block discarded – undo
391 391
                 $model
392 392
             );
393 393
             // double-check is it a *_gmt field?
394
-            if (! $field instanceof EE_Model_Field_Base
394
+            if ( ! $field instanceof EE_Model_Field_Base
395 395
                 && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
396 396
             ) {
397 397
                 // yep, take off '_gmt', and find the field
@@ -410,8 +410,8 @@  discard block
 block discarded – undo
410 410
                 $timezone = $model->get_timezone();
411 411
             }
412 412
             if ($field instanceof EE_Model_Field_Base) {
413
-                if (! $writing && is_array($query_param_value)) {
414
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
413
+                if ( ! $writing && is_array($query_param_value)) {
414
+                    if ( ! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
415 415
                         if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
416 416
                             throw new RestException(
417 417
                                 'numerically_indexed_array_of_values_only',
@@ -430,7 +430,7 @@  discard block
 block discarded – undo
430 430
                     }
431 431
                     // did they specify an operator?
432 432
                     if (isset($query_param_value[0])
433
-                        && isset($valid_operators[ $query_param_value[0] ])
433
+                        && isset($valid_operators[$query_param_value[0]])
434 434
                     ) {
435 435
                         $op = $query_param_value[0];
436 436
                         $translated_value = array($op);
@@ -539,7 +539,7 @@  discard block
 block discarded – undo
539 539
                         $timezone
540 540
                     );
541 541
                 }
542
-                if ((isset($query_param_for_models[ $query_param_key ]) && $is_gmt_datetime_field)
542
+                if ((isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field)
543 543
                     || $translated_value === null
544 544
                 ) {
545 545
                     // they have already provided a non-gmt field, ignore the gmt one. That's what WP core
@@ -547,7 +547,7 @@  discard block
 block discarded – undo
547 547
                     // OR we couldn't create a translated value from their input
548 548
                     continue;
549 549
                 }
550
-                $query_param_for_models[ $query_param_key ] = $translated_value;
550
+                $query_param_for_models[$query_param_key] = $translated_value;
551 551
             } else {
552 552
                 // so this param doesn't correspond to a field eh?
553 553
                 if ($writing) {
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
                         $query_param_sans_stars,
567 567
                         $model->logic_query_param_keys()
568 568
                     )) {
569
-                        $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
569
+                        $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
570 570
                             $query_param_value,
571 571
                             $model,
572 572
                             $requested_version
@@ -620,7 +620,7 @@  discard block
 block discarded – undo
620 620
      */
621 621
     public static function removeGmtFromFieldName($field_name)
622 622
     {
623
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
623
+        if ( ! ModelDataTranslator::isGmtDateFieldName($field_name)) {
624 624
             return $field_name;
625 625
         }
626 626
         $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
@@ -663,7 +663,7 @@  discard block
 block discarded – undo
663 663
     {
664 664
         $new_array = array();
665 665
         foreach ($field_names as $key => $field_name) {
666
-            $new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
666
+            $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
667 667
         }
668 668
         return $new_array;
669 669
     }
@@ -680,7 +680,7 @@  discard block
 block discarded – undo
680 680
     {
681 681
         $new_array = array();
682 682
         foreach ($field_names_as_keys as $field_name => $value) {
683
-            $new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
683
+            $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value;
684 684
         }
685 685
         return $new_array;
686 686
     }
@@ -773,10 +773,10 @@  discard block
 block discarded – undo
773 773
                         $requested_version
774 774
                     );
775 775
                 }
776
-                $query_param_for_models[ $query_param_key ] = $translated_value;
776
+                $query_param_for_models[$query_param_key] = $translated_value;
777 777
             } else {
778 778
                 // so it's not for a field, assume it's a logic query param key
779
-                $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
779
+                $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
780 780
                     $query_param_value,
781 781
                     $model,
782 782
                     $requested_version
@@ -828,13 +828,13 @@  discard block
 block discarded – undo
828 828
             );
829 829
         }
830 830
         $number_of_parts = count($query_param_parts);
831
-        $last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
831
+        $last_query_param_part = $query_param_parts[count($query_param_parts) - 1];
832 832
         if ($number_of_parts === 1) {
833 833
             $field_name = $last_query_param_part;
834 834
         } else {// $number_of_parts >= 2
835 835
             // the last part is the column name, and there are only 2parts. therefore...
836 836
             $field_name = $last_query_param_part;
837
-            $model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
837
+            $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]);
838 838
         }
839 839
         try {
840 840
             return $model->field_settings_for($field_name, false);
Please login to merge, or discard this patch.
Indentation   +832 added lines, -832 removed lines patch added patch discarded remove patch
@@ -32,836 +32,836 @@
 block discarded – undo
32 32
 class ModelDataTranslator
33 33
 {
34 34
 
35
-    /**
36
-     * We used to use -1 for infinity in the rest api, but that's ambiguous for
37
-     * fields that COULD contain -1; so we use null
38
-     */
39
-    const EE_INF_IN_REST = null;
40
-
41
-
42
-    /**
43
-     * Prepares a possible array of input values from JSON for use by the models
44
-     *
45
-     * @param EE_Model_Field_Base $field_obj
46
-     * @param mixed               $original_value_maybe_array
47
-     * @param string              $requested_version
48
-     * @param string              $timezone_string treat values as being in this timezone
49
-     * @return mixed
50
-     * @throws RestException
51
-     */
52
-    public static function prepareFieldValuesFromJson(
53
-        $field_obj,
54
-        $original_value_maybe_array,
55
-        $requested_version,
56
-        $timezone_string = 'UTC'
57
-    ) {
58
-        if (is_array($original_value_maybe_array)
59
-            && ! $field_obj instanceof EE_Serialized_Text_Field
60
-        ) {
61
-            $new_value_maybe_array = array();
62
-            foreach ($original_value_maybe_array as $array_key => $array_item) {
63
-                $new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
64
-                    $field_obj,
65
-                    $array_item,
66
-                    $requested_version,
67
-                    $timezone_string
68
-                );
69
-            }
70
-        } else {
71
-            $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
72
-                $field_obj,
73
-                $original_value_maybe_array,
74
-                $requested_version,
75
-                $timezone_string
76
-            );
77
-        }
78
-        return $new_value_maybe_array;
79
-    }
80
-
81
-
82
-    /**
83
-     * Prepares an array of field values FOR use in JSON/REST API
84
-     *
85
-     * @param EE_Model_Field_Base $field_obj
86
-     * @param mixed               $original_value_maybe_array
87
-     * @param string              $request_version (eg 4.8.36)
88
-     * @return array
89
-     */
90
-    public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
91
-    {
92
-        if (is_array($original_value_maybe_array)) {
93
-            $new_value = array();
94
-            foreach ($original_value_maybe_array as $key => $value) {
95
-                $new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
96
-                    $field_obj,
97
-                    $value,
98
-                    $request_version
99
-                );
100
-            }
101
-        } else {
102
-            $new_value = ModelDataTranslator::prepareFieldValueForJson(
103
-                $field_obj,
104
-                $original_value_maybe_array,
105
-                $request_version
106
-            );
107
-        }
108
-        return $new_value;
109
-    }
110
-
111
-
112
-    /**
113
-     * Prepares incoming data from the json or $_REQUEST parameters for the models'
114
-     * "$query_params".
115
-     *
116
-     * @param EE_Model_Field_Base $field_obj
117
-     * @param mixed               $original_value
118
-     * @param string              $requested_version
119
-     * @param string              $timezone_string treat values as being in this timezone
120
-     * @return mixed
121
-     * @throws RestException
122
-     * @throws DomainException
123
-     * @throws EE_Error
124
-     */
125
-    public static function prepareFieldValueFromJson(
126
-        $field_obj,
127
-        $original_value,
128
-        $requested_version,
129
-        $timezone_string = 'UTC' // UTC
130
-    ) {
131
-        // check if they accidentally submitted an error value. If so throw an exception
132
-        if (is_array($original_value)
133
-            && isset($original_value['error_code'], $original_value['error_message'])) {
134
-            throw new RestException(
135
-                'rest_submitted_error_value',
136
-                sprintf(
137
-                    esc_html__(
138
-                        'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
139
-                        'event_espresso'
140
-                    ),
141
-                    $field_obj->get_name()
142
-                ),
143
-                array(
144
-                    'status' => 400,
145
-                )
146
-            );
147
-        }
148
-        // double-check for serialized PHP. We never accept serialized PHP. No way Jose.
149
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
150
-        $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
151
-        $new_value = null;
152
-        // walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
153
-        // way Jose.
154
-        ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
155
-        if ($field_obj instanceof EE_Infinite_Integer_Field
156
-            && in_array($original_value, array(null, ''), true)
157
-        ) {
158
-            $new_value = EE_INF;
159
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
160
-            $new_value = rest_parse_date(
161
-                self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
162
-            );
163
-            if ($new_value === false) {
164
-                throw new RestException(
165
-                    'invalid_format_for_timestamp',
166
-                    sprintf(
167
-                        esc_html__(
168
-                            'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
169
-                            'event_espresso'
170
-                        ),
171
-                        'RFC3339',
172
-                        'ISO8601',
173
-                        $original_value
174
-                    ),
175
-                    array(
176
-                        'status' => 400,
177
-                    )
178
-                );
179
-            }
180
-        } else {
181
-            $new_value = $original_value;
182
-        }
183
-        return $new_value;
184
-    }
185
-
186
-
187
-    /**
188
-     * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
189
-     * information via details obtained from the host site.
190
-     *
191
-     * @param string            $original_timestamp
192
-     * @param EE_Datetime_Field $datetime_field
193
-     * @param                   $timezone_string
194
-     * @return string
195
-     * @throws DomainException
196
-     */
197
-    private static function getTimestampWithTimezoneOffset(
198
-        $original_timestamp,
199
-        EE_Datetime_Field $datetime_field,
200
-        $timezone_string
201
-    ) {
202
-        // already have timezone information?
203
-        if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
204
-            // yes, we're ignoring the timezone.
205
-            return $original_timestamp;
206
-        }
207
-        // need to append timezone
208
-        list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
209
-            $datetime_field->get_timezone_offset(
210
-                new \DateTimeZone($timezone_string),
211
-                $original_timestamp
212
-            )
213
-        );
214
-        $offset_string =
215
-            str_pad(
216
-                floor($offset_secs / HOUR_IN_SECONDS),
217
-                2,
218
-                '0',
219
-                STR_PAD_LEFT
220
-            )
221
-            . ':'
222
-            . str_pad(
223
-                ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
224
-                2,
225
-                '0',
226
-                STR_PAD_LEFT
227
-            );
228
-        return $original_timestamp . $offset_sign . $offset_string;
229
-    }
230
-
231
-
232
-    /**
233
-     * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
234
-     * think that can happen). If $data is an array, recurses into its keys and values
235
-     *
236
-     * @param mixed $data
237
-     * @throws RestException
238
-     * @return void
239
-     */
240
-    public static function throwExceptionIfContainsSerializedData($data)
241
-    {
242
-        if (is_array($data)) {
243
-            foreach ($data as $key => $value) {
244
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
245
-                ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
246
-            }
247
-        } else {
248
-            if (is_serialized($data) || is_object($data)) {
249
-                throw new RestException(
250
-                    'serialized_data_submission_prohibited',
251
-                    esc_html__(
252
-                    // @codingStandardsIgnoreStart
253
-                        'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
254
-                        // @codingStandardsIgnoreEnd
255
-                        'event_espresso'
256
-                    )
257
-                );
258
-            }
259
-        }
260
-    }
261
-
262
-
263
-    /**
264
-     * determines what's going on with them timezone strings
265
-     *
266
-     * @param int $timezone_offset
267
-     * @return array
268
-     */
269
-    private static function parseTimezoneOffset($timezone_offset)
270
-    {
271
-        $first_char = substr((string) $timezone_offset, 0, 1);
272
-        if ($first_char === '+' || $first_char === '-') {
273
-            $offset_sign = $first_char;
274
-            $offset_secs = substr((string) $timezone_offset, 1);
275
-        } else {
276
-            $offset_sign = '+';
277
-            $offset_secs = $timezone_offset;
278
-        }
279
-        return array($offset_sign, $offset_secs);
280
-    }
281
-
282
-
283
-    /**
284
-     * Prepares a field's value for display in the API
285
-     *
286
-     * @param EE_Model_Field_Base $field_obj
287
-     * @param mixed               $original_value
288
-     * @param string              $requested_version
289
-     * @return mixed
290
-     */
291
-    public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
292
-    {
293
-        if ($original_value === EE_INF) {
294
-            $new_value = ModelDataTranslator::EE_INF_IN_REST;
295
-        } elseif ($field_obj instanceof EE_Datetime_Field) {
296
-            if (is_string($original_value)) {
297
-                // did they submit a string of a unix timestamp?
298
-                if (is_numeric($original_value)) {
299
-                    $datetime_obj = new \DateTime();
300
-                    $datetime_obj->setTimestamp((int) $original_value);
301
-                } else {
302
-                    // first, check if its a MySQL timestamp in GMT
303
-                    $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
304
-                }
305
-                if (! $datetime_obj instanceof \DateTime) {
306
-                    // so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
307
-                    $datetime_obj = $field_obj->prepare_for_set($original_value);
308
-                }
309
-                $original_value = $datetime_obj;
310
-            }
311
-            if ($original_value instanceof \DateTime) {
312
-                $new_value = $original_value->format('Y-m-d H:i:s');
313
-            } elseif (is_int($original_value) || is_float($original_value)) {
314
-                $new_value = date('Y-m-d H:i:s', $original_value);
315
-            } elseif ($original_value === null || $original_value === '') {
316
-                $new_value = null;
317
-            } else {
318
-                // so it's not a datetime object, unix timestamp (as string or int),
319
-                // MySQL timestamp, or even a string in the field object's format. So no idea what it is
320
-                throw new \EE_Error(
321
-                    sprintf(
322
-                        esc_html__(
323
-                        // @codingStandardsIgnoreStart
324
-                            'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
325
-                            // @codingStandardsIgnoreEnd
326
-                            'event_espresso'
327
-                        ),
328
-                        $original_value,
329
-                        $field_obj->get_name(),
330
-                        $field_obj->get_model_name(),
331
-                        $field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
332
-                    )
333
-                );
334
-            }
335
-            if ($new_value !== null) {
336
-                $new_value = mysql_to_rfc3339($new_value);
337
-            }
338
-        } else {
339
-            $new_value = $original_value;
340
-        }
341
-        // are we about to send an object? just don't. We have no good way to represent it in JSON.
342
-        // can't just check using is_object() because that missed PHP incomplete objects
343
-        if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
344
-            $new_value = array(
345
-                'error_code'    => 'php_object_not_return',
346
-                'error_message' => esc_html__(
347
-                    'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
348
-                    'event_espresso'
349
-                ),
350
-            );
351
-        }
352
-        return apply_filters(
353
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
354
-            $new_value,
355
-            $field_obj,
356
-            $original_value,
357
-            $requested_version
358
-        );
359
-    }
360
-
361
-
362
-    /**
363
-     * Prepares condition-query-parameters (like what's in where and having) from
364
-     * the format expected in the API to use in the models
365
-     *
366
-     * @param array    $inputted_query_params_of_this_type
367
-     * @param EEM_Base $model
368
-     * @param string   $requested_version
369
-     * @param boolean  $writing whether this data will be written to the DB, or if we're just building a query.
370
-     *                          If we're writing to the DB, we don't expect any operators, or any logic query
371
-     *                          parameters, and we also won't accept serialized data unless the current user has
372
-     *                          unfiltered_html.
373
-     * @return array
374
-     * @throws DomainException
375
-     * @throws RestException
376
-     * @throws EE_Error
377
-     */
378
-    public static function prepareConditionsQueryParamsForModels(
379
-        $inputted_query_params_of_this_type,
380
-        EEM_Base $model,
381
-        $requested_version,
382
-        $writing = false
383
-    ) {
384
-        $query_param_for_models = array();
385
-        $valid_operators = $model->valid_operators();
386
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
387
-            $is_gmt_datetime_field = false;
388
-            $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
389
-                $query_param_key
390
-            );
391
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
392
-                $query_param_sans_stars,
393
-                $model
394
-            );
395
-            // double-check is it a *_gmt field?
396
-            if (! $field instanceof EE_Model_Field_Base
397
-                && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
398
-            ) {
399
-                // yep, take off '_gmt', and find the field
400
-                $query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
401
-                $field = ModelDataTranslator::deduceFieldFromQueryParam(
402
-                    $query_param_key,
403
-                    $model
404
-                );
405
-                $timezone = 'UTC';
406
-                $is_gmt_datetime_field = true;
407
-            } elseif ($field instanceof EE_Datetime_Field) {
408
-                // so it's not a GMT field. Set the timezone on the model to the default
409
-                $timezone = \EEH_DTT_Helper::get_valid_timezone_string();
410
-            } else {
411
-                // just keep using what's already set for the timezone
412
-                $timezone = $model->get_timezone();
413
-            }
414
-            if ($field instanceof EE_Model_Field_Base) {
415
-                if (! $writing && is_array($query_param_value)) {
416
-                    if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
417
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
418
-                            throw new RestException(
419
-                                'numerically_indexed_array_of_values_only',
420
-                                sprintf(
421
-                                    esc_html__(
422
-                                        'The array provided for the parameter "%1$s" should be numerically indexed.',
423
-                                        'event_espresso'
424
-                                    ),
425
-                                    $query_param_key
426
-                                ),
427
-                                array(
428
-                                    'status' => 400,
429
-                                )
430
-                            );
431
-                        }
432
-                    }
433
-                    // did they specify an operator?
434
-                    if (isset($query_param_value[0])
435
-                        && isset($valid_operators[ $query_param_value[0] ])
436
-                    ) {
437
-                        $op = $query_param_value[0];
438
-                        $translated_value = array($op);
439
-                        if (array_key_exists($op, $model->valid_in_style_operators())
440
-                            && isset($query_param_value[1])
441
-                            && ! isset($query_param_value[2])
442
-                        ) {
443
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
444
-                                $field,
445
-                                $query_param_value[1],
446
-                                $requested_version,
447
-                                $timezone
448
-                            );
449
-                        } elseif (array_key_exists($op, $model->valid_between_style_operators())
450
-                                  && isset($query_param_value[1])
451
-                                  && is_array($query_param_value[1])
452
-                                  && isset($query_param_key[1][0], $query_param_value[1][1])
453
-                                  && ! isset($query_param_value[1][2])
454
-                                  && ! isset($query_param_value[2])
455
-                        ) {
456
-                            $translated_value[] = array(
457
-                                ModelDataTranslator::prepareFieldValuesFromJson(
458
-                                    $field,
459
-                                    $query_param_value[1][0],
460
-                                    $requested_version,
461
-                                    $timezone
462
-                                ),
463
-                                ModelDataTranslator::prepareFieldValuesFromJson(
464
-                                    $field,
465
-                                    $query_param_value[1][1],
466
-                                    $requested_version,
467
-                                    $timezone
468
-                                )
469
-                            );
470
-                        } elseif (array_key_exists($op, $model->valid_like_style_operators())
471
-                                  && isset($query_param_value[1])
472
-                                  && ! isset($query_param_value[2])
473
-                        ) {
474
-                            // we want to leave this value mostly-as-is (eg don't force it to be a float
475
-                            // or a boolean or an enum value. Leave it as-is with wildcards etc)
476
-                            // but do verify it at least doesn't have any serialized data
477
-                            ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
478
-                            $translated_value[] = $query_param_value[1];
479
-                        } elseif (array_key_exists($op, $model->valid_null_style_operators())
480
-                                  && ! isset($query_param_value[1])) {
481
-                            // no arguments should have been provided, so don't look for any
482
-                        } elseif (isset($query_param_value[1])
483
-                                  && ! isset($query_param_value[2])
484
-                                  && ! array_key_exists(
485
-                                      $op,
486
-                                      array_merge(
487
-                                          $model->valid_in_style_operators(),
488
-                                          $model->valid_null_style_operators(),
489
-                                          $model->valid_like_style_operators(),
490
-                                          $model->valid_between_style_operators()
491
-                                      )
492
-                                  )
493
-                        ) {
494
-                            // it's a valid operator, but none of the exceptions. Treat it normally.
495
-                            $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
496
-                                $field,
497
-                                $query_param_value[1],
498
-                                $requested_version,
499
-                                $timezone
500
-                            );
501
-                        } else {
502
-                            // so they provided a valid operator, but wrong number of arguments
503
-                            if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
504
-                                throw new RestException(
505
-                                    'wrong_number_of_arguments',
506
-                                    sprintf(
507
-                                        esc_html__(
508
-                                            'The operator you provided, "%1$s" had the wrong number of arguments',
509
-                                            'event_espresso'
510
-                                        ),
511
-                                        $op
512
-                                    ),
513
-                                    array(
514
-                                        'status' => 400,
515
-                                    )
516
-                                );
517
-                            }
518
-                            $translated_value = null;
519
-                        }
520
-                    } else {
521
-                        // so they didn't provide a valid operator
522
-                        if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
523
-                            throw new RestException(
524
-                                'invalid_operator',
525
-                                sprintf(
526
-                                    esc_html__(
527
-                                        'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
528
-                                        'event_espresso'
529
-                                    ),
530
-                                    $query_param_key,
531
-                                    $query_param_value
532
-                                ),
533
-                                array(
534
-                                    'status' => 400,
535
-                                )
536
-                            );
537
-                        }
538
-                        // if we aren't in debug mode, then just try our best to fulfill the user's request
539
-                        $translated_value = null;
540
-                    }
541
-                } else {
542
-                    $translated_value = ModelDataTranslator::prepareFieldValueFromJson(
543
-                        $field,
544
-                        $query_param_value,
545
-                        $requested_version,
546
-                        $timezone
547
-                    );
548
-                }
549
-                if ((isset($query_param_for_models[ $query_param_key ]) && $is_gmt_datetime_field)
550
-                    || $translated_value === null
551
-                ) {
552
-                    // they have already provided a non-gmt field, ignore the gmt one. That's what WP core
553
-                    // currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
554
-                    // OR we couldn't create a translated value from their input
555
-                    continue;
556
-                }
557
-                $query_param_for_models[ $query_param_key ] = $translated_value;
558
-            } else {
559
-                // so this param doesn't correspond to a field eh?
560
-                if ($writing) {
561
-                    // always tell API clients about invalid parameters when they're creating data. Otherwise,
562
-                    // they are probably going to create invalid data
563
-                    throw new RestException(
564
-                        'invalid_field',
565
-                        sprintf(
566
-                            esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
567
-                            $query_param_key
568
-                        )
569
-                    );
570
-                } else {
571
-                    // so it's not for a field, is it a logic query param key?
572
-                    if (in_array(
573
-                        $query_param_sans_stars,
574
-                        $model->logic_query_param_keys()
575
-                    )) {
576
-                        $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
577
-                            $query_param_value,
578
-                            $model,
579
-                            $requested_version
580
-                        );
581
-                    } elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
582
-                        // only tell API clients they got it wrong if we're in debug mode
583
-                        // otherwise try our best ot fulfill their request by ignoring this invalid data
584
-                        throw new RestException(
585
-                            'invalid_parameter',
586
-                            sprintf(
587
-                                esc_html__(
588
-                                    'You provided an invalid parameter, with key "%1$s"',
589
-                                    'event_espresso'
590
-                                ),
591
-                                $query_param_sans_stars
592
-                            ),
593
-                            array(
594
-                                'status' => 400,
595
-                            )
596
-                        );
597
-                    }
598
-                }
599
-            }
600
-        }
601
-        return $query_param_for_models;
602
-    }
603
-
604
-
605
-    /**
606
-     * Mostly checks if the last 4 characters are "_gmt", indicating its a
607
-     * gmt date field name
608
-     *
609
-     * @param string $field_name
610
-     * @return boolean
611
-     */
612
-    public static function isGmtDateFieldName($field_name)
613
-    {
614
-        return substr(
615
-            ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
616
-            -4,
617
-            4
618
-        ) === '_gmt';
619
-    }
620
-
621
-
622
-    /**
623
-     * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
624
-     *
625
-     * @param string $field_name
626
-     * @return string
627
-     */
628
-    public static function removeGmtFromFieldName($field_name)
629
-    {
630
-        if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
631
-            return $field_name;
632
-        }
633
-        $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
634
-            $field_name
635
-        );
636
-        $query_param_sans_gmt_and_sans_stars = substr(
637
-            $query_param_sans_stars,
638
-            0,
639
-            strrpos(
640
-                $field_name,
641
-                '_gmt'
642
-            )
643
-        );
644
-        return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
645
-    }
646
-
647
-
648
-    /**
649
-     * Takes a field name from the REST API and prepares it for the model querying
650
-     *
651
-     * @param string $field_name
652
-     * @return string
653
-     */
654
-    public static function prepareFieldNameFromJson($field_name)
655
-    {
656
-        if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
657
-            return ModelDataTranslator::removeGmtFromFieldName($field_name);
658
-        }
659
-        return $field_name;
660
-    }
661
-
662
-
663
-    /**
664
-     * Takes array of field names from REST API and prepares for models
665
-     *
666
-     * @param array $field_names
667
-     * @return array of field names (possibly include model prefixes)
668
-     */
669
-    public static function prepareFieldNamesFromJson(array $field_names)
670
-    {
671
-        $new_array = array();
672
-        foreach ($field_names as $key => $field_name) {
673
-            $new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
674
-        }
675
-        return $new_array;
676
-    }
677
-
678
-
679
-    /**
680
-     * Takes array where array keys are field names (possibly with model path prefixes)
681
-     * from the REST API and prepares them for model querying
682
-     *
683
-     * @param array $field_names_as_keys
684
-     * @return array
685
-     */
686
-    public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
687
-    {
688
-        $new_array = array();
689
-        foreach ($field_names_as_keys as $field_name => $value) {
690
-            $new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
691
-        }
692
-        return $new_array;
693
-    }
694
-
695
-
696
-    /**
697
-     * Prepares an array of model query params for use in the REST API
698
-     *
699
-     * @param array    $model_query_params
700
-     * @param EEM_Base $model
701
-     * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
702
-     *                                     REST API
703
-     * @return array which can be passed into the EE4 REST API when querying a model resource
704
-     * @throws EE_Error
705
-     */
706
-    public static function prepareQueryParamsForRestApi(
707
-        array $model_query_params,
708
-        EEM_Base $model,
709
-        $requested_version = null
710
-    ) {
711
-        if ($requested_version === null) {
712
-            $requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
713
-        }
714
-        $rest_query_params = $model_query_params;
715
-        if (isset($model_query_params[0])) {
716
-            $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
717
-                $model_query_params[0],
718
-                $model,
719
-                $requested_version
720
-            );
721
-            unset($rest_query_params[0]);
722
-        }
723
-        if (isset($model_query_params['having'])) {
724
-            $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
725
-                $model_query_params['having'],
726
-                $model,
727
-                $requested_version
728
-            );
729
-        }
730
-        return apply_filters(
731
-            'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
732
-            $rest_query_params,
733
-            $model_query_params,
734
-            $model,
735
-            $requested_version
736
-        );
737
-    }
738
-
739
-
740
-    /**
741
-     * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
742
-     *
743
-     * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
744
-     *                                                      passed into EEM_Base::get_all()
745
-     * @param EEM_Base $model
746
-     * @param string   $requested_version                   eg "4.8.36"
747
-     * @return array ready for use in the rest api query params
748
-     * @throws EE_Error
749
-     * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
750
-     *                                                      (which would be really unusual)
751
-     */
752
-    public static function prepareConditionsQueryParamsForRestApi(
753
-        $inputted_query_params_of_this_type,
754
-        EEM_Base $model,
755
-        $requested_version
756
-    ) {
757
-        $query_param_for_models = array();
758
-        foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
759
-            $field = ModelDataTranslator::deduceFieldFromQueryParam(
760
-                ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
761
-                $model
762
-            );
763
-            if ($field instanceof EE_Model_Field_Base) {
764
-                // did they specify an operator?
765
-                if (is_array($query_param_value)) {
766
-                    $op = $query_param_value[0];
767
-                    $translated_value = array($op);
768
-                    if (isset($query_param_value[1])) {
769
-                        $value = $query_param_value[1];
770
-                        $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
771
-                            $field,
772
-                            $value,
773
-                            $requested_version
774
-                        );
775
-                    }
776
-                } else {
777
-                    $translated_value = ModelDataTranslator::prepareFieldValueForJson(
778
-                        $field,
779
-                        $query_param_value,
780
-                        $requested_version
781
-                    );
782
-                }
783
-                $query_param_for_models[ $query_param_key ] = $translated_value;
784
-            } else {
785
-                // so it's not for a field, assume it's a logic query param key
786
-                $query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
787
-                    $query_param_value,
788
-                    $model,
789
-                    $requested_version
790
-                );
791
-            }
792
-        }
793
-        return $query_param_for_models;
794
-    }
795
-
796
-
797
-    /**
798
-     * @param $condition_query_param_key
799
-     * @return string
800
-     */
801
-    public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
802
-    {
803
-        $pos_of_star = strpos($condition_query_param_key, '*');
804
-        if ($pos_of_star === false) {
805
-            return $condition_query_param_key;
806
-        } else {
807
-            $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
808
-            return $condition_query_param_sans_star;
809
-        }
810
-    }
811
-
812
-
813
-    /**
814
-     * Takes the input parameter and finds the model field that it indicates.
815
-     *
816
-     * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
817
-     * @param EEM_Base $model
818
-     * @return EE_Model_Field_Base
819
-     * @throws EE_Error
820
-     */
821
-    public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
822
-    {
823
-        // ok, now proceed with deducing which part is the model's name, and which is the field's name
824
-        // which will help us find the database table and column
825
-        $query_param_parts = explode('.', $query_param_name);
826
-        if (empty($query_param_parts)) {
827
-            throw new EE_Error(
828
-                sprintf(
829
-                    __(
830
-                        '_extract_column_name is empty when trying to extract column and table name from %s',
831
-                        'event_espresso'
832
-                    ),
833
-                    $query_param_name
834
-                )
835
-            );
836
-        }
837
-        $number_of_parts = count($query_param_parts);
838
-        $last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
839
-        if ($number_of_parts === 1) {
840
-            $field_name = $last_query_param_part;
841
-        } else {// $number_of_parts >= 2
842
-            // the last part is the column name, and there are only 2parts. therefore...
843
-            $field_name = $last_query_param_part;
844
-            $model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
845
-        }
846
-        try {
847
-            return $model->field_settings_for($field_name, false);
848
-        } catch (EE_Error $e) {
849
-            return null;
850
-        }
851
-    }
852
-
853
-
854
-    /**
855
-     * Returns true if $data can be easily represented in JSON.
856
-     * Basically, objects and resources can't be represented in JSON easily.
857
-     *
858
-     * @param mixed $data
859
-     * @return bool
860
-     */
861
-    protected static function isRepresentableInJson($data)
862
-    {
863
-        return is_scalar($data)
864
-               || is_array($data)
865
-               || is_null($data);
866
-    }
35
+	/**
36
+	 * We used to use -1 for infinity in the rest api, but that's ambiguous for
37
+	 * fields that COULD contain -1; so we use null
38
+	 */
39
+	const EE_INF_IN_REST = null;
40
+
41
+
42
+	/**
43
+	 * Prepares a possible array of input values from JSON for use by the models
44
+	 *
45
+	 * @param EE_Model_Field_Base $field_obj
46
+	 * @param mixed               $original_value_maybe_array
47
+	 * @param string              $requested_version
48
+	 * @param string              $timezone_string treat values as being in this timezone
49
+	 * @return mixed
50
+	 * @throws RestException
51
+	 */
52
+	public static function prepareFieldValuesFromJson(
53
+		$field_obj,
54
+		$original_value_maybe_array,
55
+		$requested_version,
56
+		$timezone_string = 'UTC'
57
+	) {
58
+		if (is_array($original_value_maybe_array)
59
+			&& ! $field_obj instanceof EE_Serialized_Text_Field
60
+		) {
61
+			$new_value_maybe_array = array();
62
+			foreach ($original_value_maybe_array as $array_key => $array_item) {
63
+				$new_value_maybe_array[ $array_key ] = ModelDataTranslator::prepareFieldValueFromJson(
64
+					$field_obj,
65
+					$array_item,
66
+					$requested_version,
67
+					$timezone_string
68
+				);
69
+			}
70
+		} else {
71
+			$new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson(
72
+				$field_obj,
73
+				$original_value_maybe_array,
74
+				$requested_version,
75
+				$timezone_string
76
+			);
77
+		}
78
+		return $new_value_maybe_array;
79
+	}
80
+
81
+
82
+	/**
83
+	 * Prepares an array of field values FOR use in JSON/REST API
84
+	 *
85
+	 * @param EE_Model_Field_Base $field_obj
86
+	 * @param mixed               $original_value_maybe_array
87
+	 * @param string              $request_version (eg 4.8.36)
88
+	 * @return array
89
+	 */
90
+	public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version)
91
+	{
92
+		if (is_array($original_value_maybe_array)) {
93
+			$new_value = array();
94
+			foreach ($original_value_maybe_array as $key => $value) {
95
+				$new_value[ $key ] = ModelDataTranslator::prepareFieldValuesForJson(
96
+					$field_obj,
97
+					$value,
98
+					$request_version
99
+				);
100
+			}
101
+		} else {
102
+			$new_value = ModelDataTranslator::prepareFieldValueForJson(
103
+				$field_obj,
104
+				$original_value_maybe_array,
105
+				$request_version
106
+			);
107
+		}
108
+		return $new_value;
109
+	}
110
+
111
+
112
+	/**
113
+	 * Prepares incoming data from the json or $_REQUEST parameters for the models'
114
+	 * "$query_params".
115
+	 *
116
+	 * @param EE_Model_Field_Base $field_obj
117
+	 * @param mixed               $original_value
118
+	 * @param string              $requested_version
119
+	 * @param string              $timezone_string treat values as being in this timezone
120
+	 * @return mixed
121
+	 * @throws RestException
122
+	 * @throws DomainException
123
+	 * @throws EE_Error
124
+	 */
125
+	public static function prepareFieldValueFromJson(
126
+		$field_obj,
127
+		$original_value,
128
+		$requested_version,
129
+		$timezone_string = 'UTC' // UTC
130
+	) {
131
+		// check if they accidentally submitted an error value. If so throw an exception
132
+		if (is_array($original_value)
133
+			&& isset($original_value['error_code'], $original_value['error_message'])) {
134
+			throw new RestException(
135
+				'rest_submitted_error_value',
136
+				sprintf(
137
+					esc_html__(
138
+						'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.',
139
+						'event_espresso'
140
+					),
141
+					$field_obj->get_name()
142
+				),
143
+				array(
144
+					'status' => 400,
145
+				)
146
+			);
147
+		}
148
+		// double-check for serialized PHP. We never accept serialized PHP. No way Jose.
149
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
150
+		$timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', '');
151
+		$new_value = null;
152
+		// walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No
153
+		// way Jose.
154
+		ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value);
155
+		if ($field_obj instanceof EE_Infinite_Integer_Field
156
+			&& in_array($original_value, array(null, ''), true)
157
+		) {
158
+			$new_value = EE_INF;
159
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
160
+			$new_value = rest_parse_date(
161
+				self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string)
162
+			);
163
+			if ($new_value === false) {
164
+				throw new RestException(
165
+					'invalid_format_for_timestamp',
166
+					sprintf(
167
+						esc_html__(
168
+							'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format.  The timestamp provided (%3$s) is not that format.',
169
+							'event_espresso'
170
+						),
171
+						'RFC3339',
172
+						'ISO8601',
173
+						$original_value
174
+					),
175
+					array(
176
+						'status' => 400,
177
+					)
178
+				);
179
+			}
180
+		} else {
181
+			$new_value = $original_value;
182
+		}
183
+		return $new_value;
184
+	}
185
+
186
+
187
+	/**
188
+	 * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone
189
+	 * information via details obtained from the host site.
190
+	 *
191
+	 * @param string            $original_timestamp
192
+	 * @param EE_Datetime_Field $datetime_field
193
+	 * @param                   $timezone_string
194
+	 * @return string
195
+	 * @throws DomainException
196
+	 */
197
+	private static function getTimestampWithTimezoneOffset(
198
+		$original_timestamp,
199
+		EE_Datetime_Field $datetime_field,
200
+		$timezone_string
201
+	) {
202
+		// already have timezone information?
203
+		if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) {
204
+			// yes, we're ignoring the timezone.
205
+			return $original_timestamp;
206
+		}
207
+		// need to append timezone
208
+		list($offset_sign, $offset_secs) = self::parseTimezoneOffset(
209
+			$datetime_field->get_timezone_offset(
210
+				new \DateTimeZone($timezone_string),
211
+				$original_timestamp
212
+			)
213
+		);
214
+		$offset_string =
215
+			str_pad(
216
+				floor($offset_secs / HOUR_IN_SECONDS),
217
+				2,
218
+				'0',
219
+				STR_PAD_LEFT
220
+			)
221
+			. ':'
222
+			. str_pad(
223
+				($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS,
224
+				2,
225
+				'0',
226
+				STR_PAD_LEFT
227
+			);
228
+		return $original_timestamp . $offset_sign . $offset_string;
229
+	}
230
+
231
+
232
+	/**
233
+	 * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't
234
+	 * think that can happen). If $data is an array, recurses into its keys and values
235
+	 *
236
+	 * @param mixed $data
237
+	 * @throws RestException
238
+	 * @return void
239
+	 */
240
+	public static function throwExceptionIfContainsSerializedData($data)
241
+	{
242
+		if (is_array($data)) {
243
+			foreach ($data as $key => $value) {
244
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($key);
245
+				ModelDataTranslator::throwExceptionIfContainsSerializedData($value);
246
+			}
247
+		} else {
248
+			if (is_serialized($data) || is_object($data)) {
249
+				throw new RestException(
250
+					'serialized_data_submission_prohibited',
251
+					esc_html__(
252
+					// @codingStandardsIgnoreStart
253
+						'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.',
254
+						// @codingStandardsIgnoreEnd
255
+						'event_espresso'
256
+					)
257
+				);
258
+			}
259
+		}
260
+	}
261
+
262
+
263
+	/**
264
+	 * determines what's going on with them timezone strings
265
+	 *
266
+	 * @param int $timezone_offset
267
+	 * @return array
268
+	 */
269
+	private static function parseTimezoneOffset($timezone_offset)
270
+	{
271
+		$first_char = substr((string) $timezone_offset, 0, 1);
272
+		if ($first_char === '+' || $first_char === '-') {
273
+			$offset_sign = $first_char;
274
+			$offset_secs = substr((string) $timezone_offset, 1);
275
+		} else {
276
+			$offset_sign = '+';
277
+			$offset_secs = $timezone_offset;
278
+		}
279
+		return array($offset_sign, $offset_secs);
280
+	}
281
+
282
+
283
+	/**
284
+	 * Prepares a field's value for display in the API
285
+	 *
286
+	 * @param EE_Model_Field_Base $field_obj
287
+	 * @param mixed               $original_value
288
+	 * @param string              $requested_version
289
+	 * @return mixed
290
+	 */
291
+	public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version)
292
+	{
293
+		if ($original_value === EE_INF) {
294
+			$new_value = ModelDataTranslator::EE_INF_IN_REST;
295
+		} elseif ($field_obj instanceof EE_Datetime_Field) {
296
+			if (is_string($original_value)) {
297
+				// did they submit a string of a unix timestamp?
298
+				if (is_numeric($original_value)) {
299
+					$datetime_obj = new \DateTime();
300
+					$datetime_obj->setTimestamp((int) $original_value);
301
+				} else {
302
+					// first, check if its a MySQL timestamp in GMT
303
+					$datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value);
304
+				}
305
+				if (! $datetime_obj instanceof \DateTime) {
306
+					// so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format?
307
+					$datetime_obj = $field_obj->prepare_for_set($original_value);
308
+				}
309
+				$original_value = $datetime_obj;
310
+			}
311
+			if ($original_value instanceof \DateTime) {
312
+				$new_value = $original_value->format('Y-m-d H:i:s');
313
+			} elseif (is_int($original_value) || is_float($original_value)) {
314
+				$new_value = date('Y-m-d H:i:s', $original_value);
315
+			} elseif ($original_value === null || $original_value === '') {
316
+				$new_value = null;
317
+			} else {
318
+				// so it's not a datetime object, unix timestamp (as string or int),
319
+				// MySQL timestamp, or even a string in the field object's format. So no idea what it is
320
+				throw new \EE_Error(
321
+					sprintf(
322
+						esc_html__(
323
+						// @codingStandardsIgnoreStart
324
+							'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".',
325
+							// @codingStandardsIgnoreEnd
326
+							'event_espresso'
327
+						),
328
+						$original_value,
329
+						$field_obj->get_name(),
330
+						$field_obj->get_model_name(),
331
+						$field_obj->get_time_format() . ' ' . $field_obj->get_time_format()
332
+					)
333
+				);
334
+			}
335
+			if ($new_value !== null) {
336
+				$new_value = mysql_to_rfc3339($new_value);
337
+			}
338
+		} else {
339
+			$new_value = $original_value;
340
+		}
341
+		// are we about to send an object? just don't. We have no good way to represent it in JSON.
342
+		// can't just check using is_object() because that missed PHP incomplete objects
343
+		if (! ModelDataTranslator::isRepresentableInJson($new_value)) {
344
+			$new_value = array(
345
+				'error_code'    => 'php_object_not_return',
346
+				'error_message' => esc_html__(
347
+					'The value of this field in the database is a PHP object, which can\'t be represented in JSON.',
348
+					'event_espresso'
349
+				),
350
+			);
351
+		}
352
+		return apply_filters(
353
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api',
354
+			$new_value,
355
+			$field_obj,
356
+			$original_value,
357
+			$requested_version
358
+		);
359
+	}
360
+
361
+
362
+	/**
363
+	 * Prepares condition-query-parameters (like what's in where and having) from
364
+	 * the format expected in the API to use in the models
365
+	 *
366
+	 * @param array    $inputted_query_params_of_this_type
367
+	 * @param EEM_Base $model
368
+	 * @param string   $requested_version
369
+	 * @param boolean  $writing whether this data will be written to the DB, or if we're just building a query.
370
+	 *                          If we're writing to the DB, we don't expect any operators, or any logic query
371
+	 *                          parameters, and we also won't accept serialized data unless the current user has
372
+	 *                          unfiltered_html.
373
+	 * @return array
374
+	 * @throws DomainException
375
+	 * @throws RestException
376
+	 * @throws EE_Error
377
+	 */
378
+	public static function prepareConditionsQueryParamsForModels(
379
+		$inputted_query_params_of_this_type,
380
+		EEM_Base $model,
381
+		$requested_version,
382
+		$writing = false
383
+	) {
384
+		$query_param_for_models = array();
385
+		$valid_operators = $model->valid_operators();
386
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
387
+			$is_gmt_datetime_field = false;
388
+			$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
389
+				$query_param_key
390
+			);
391
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
392
+				$query_param_sans_stars,
393
+				$model
394
+			);
395
+			// double-check is it a *_gmt field?
396
+			if (! $field instanceof EE_Model_Field_Base
397
+				&& ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars)
398
+			) {
399
+				// yep, take off '_gmt', and find the field
400
+				$query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars);
401
+				$field = ModelDataTranslator::deduceFieldFromQueryParam(
402
+					$query_param_key,
403
+					$model
404
+				);
405
+				$timezone = 'UTC';
406
+				$is_gmt_datetime_field = true;
407
+			} elseif ($field instanceof EE_Datetime_Field) {
408
+				// so it's not a GMT field. Set the timezone on the model to the default
409
+				$timezone = \EEH_DTT_Helper::get_valid_timezone_string();
410
+			} else {
411
+				// just keep using what's already set for the timezone
412
+				$timezone = $model->get_timezone();
413
+			}
414
+			if ($field instanceof EE_Model_Field_Base) {
415
+				if (! $writing && is_array($query_param_value)) {
416
+					if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) {
417
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
418
+							throw new RestException(
419
+								'numerically_indexed_array_of_values_only',
420
+								sprintf(
421
+									esc_html__(
422
+										'The array provided for the parameter "%1$s" should be numerically indexed.',
423
+										'event_espresso'
424
+									),
425
+									$query_param_key
426
+								),
427
+								array(
428
+									'status' => 400,
429
+								)
430
+							);
431
+						}
432
+					}
433
+					// did they specify an operator?
434
+					if (isset($query_param_value[0])
435
+						&& isset($valid_operators[ $query_param_value[0] ])
436
+					) {
437
+						$op = $query_param_value[0];
438
+						$translated_value = array($op);
439
+						if (array_key_exists($op, $model->valid_in_style_operators())
440
+							&& isset($query_param_value[1])
441
+							&& ! isset($query_param_value[2])
442
+						) {
443
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
444
+								$field,
445
+								$query_param_value[1],
446
+								$requested_version,
447
+								$timezone
448
+							);
449
+						} elseif (array_key_exists($op, $model->valid_between_style_operators())
450
+								  && isset($query_param_value[1])
451
+								  && is_array($query_param_value[1])
452
+								  && isset($query_param_key[1][0], $query_param_value[1][1])
453
+								  && ! isset($query_param_value[1][2])
454
+								  && ! isset($query_param_value[2])
455
+						) {
456
+							$translated_value[] = array(
457
+								ModelDataTranslator::prepareFieldValuesFromJson(
458
+									$field,
459
+									$query_param_value[1][0],
460
+									$requested_version,
461
+									$timezone
462
+								),
463
+								ModelDataTranslator::prepareFieldValuesFromJson(
464
+									$field,
465
+									$query_param_value[1][1],
466
+									$requested_version,
467
+									$timezone
468
+								)
469
+							);
470
+						} elseif (array_key_exists($op, $model->valid_like_style_operators())
471
+								  && isset($query_param_value[1])
472
+								  && ! isset($query_param_value[2])
473
+						) {
474
+							// we want to leave this value mostly-as-is (eg don't force it to be a float
475
+							// or a boolean or an enum value. Leave it as-is with wildcards etc)
476
+							// but do verify it at least doesn't have any serialized data
477
+							ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]);
478
+							$translated_value[] = $query_param_value[1];
479
+						} elseif (array_key_exists($op, $model->valid_null_style_operators())
480
+								  && ! isset($query_param_value[1])) {
481
+							// no arguments should have been provided, so don't look for any
482
+						} elseif (isset($query_param_value[1])
483
+								  && ! isset($query_param_value[2])
484
+								  && ! array_key_exists(
485
+									  $op,
486
+									  array_merge(
487
+										  $model->valid_in_style_operators(),
488
+										  $model->valid_null_style_operators(),
489
+										  $model->valid_like_style_operators(),
490
+										  $model->valid_between_style_operators()
491
+									  )
492
+								  )
493
+						) {
494
+							// it's a valid operator, but none of the exceptions. Treat it normally.
495
+							$translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson(
496
+								$field,
497
+								$query_param_value[1],
498
+								$requested_version,
499
+								$timezone
500
+							);
501
+						} else {
502
+							// so they provided a valid operator, but wrong number of arguments
503
+							if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
504
+								throw new RestException(
505
+									'wrong_number_of_arguments',
506
+									sprintf(
507
+										esc_html__(
508
+											'The operator you provided, "%1$s" had the wrong number of arguments',
509
+											'event_espresso'
510
+										),
511
+										$op
512
+									),
513
+									array(
514
+										'status' => 400,
515
+									)
516
+								);
517
+							}
518
+							$translated_value = null;
519
+						}
520
+					} else {
521
+						// so they didn't provide a valid operator
522
+						if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
523
+							throw new RestException(
524
+								'invalid_operator',
525
+								sprintf(
526
+									esc_html__(
527
+										'You provided an invalid parameter, with key "%1$s" and value "%2$s"',
528
+										'event_espresso'
529
+									),
530
+									$query_param_key,
531
+									$query_param_value
532
+								),
533
+								array(
534
+									'status' => 400,
535
+								)
536
+							);
537
+						}
538
+						// if we aren't in debug mode, then just try our best to fulfill the user's request
539
+						$translated_value = null;
540
+					}
541
+				} else {
542
+					$translated_value = ModelDataTranslator::prepareFieldValueFromJson(
543
+						$field,
544
+						$query_param_value,
545
+						$requested_version,
546
+						$timezone
547
+					);
548
+				}
549
+				if ((isset($query_param_for_models[ $query_param_key ]) && $is_gmt_datetime_field)
550
+					|| $translated_value === null
551
+				) {
552
+					// they have already provided a non-gmt field, ignore the gmt one. That's what WP core
553
+					// currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954
554
+					// OR we couldn't create a translated value from their input
555
+					continue;
556
+				}
557
+				$query_param_for_models[ $query_param_key ] = $translated_value;
558
+			} else {
559
+				// so this param doesn't correspond to a field eh?
560
+				if ($writing) {
561
+					// always tell API clients about invalid parameters when they're creating data. Otherwise,
562
+					// they are probably going to create invalid data
563
+					throw new RestException(
564
+						'invalid_field',
565
+						sprintf(
566
+							esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'),
567
+							$query_param_key
568
+						)
569
+					);
570
+				} else {
571
+					// so it's not for a field, is it a logic query param key?
572
+					if (in_array(
573
+						$query_param_sans_stars,
574
+						$model->logic_query_param_keys()
575
+					)) {
576
+						$query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForModels(
577
+							$query_param_value,
578
+							$model,
579
+							$requested_version
580
+						);
581
+					} elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) {
582
+						// only tell API clients they got it wrong if we're in debug mode
583
+						// otherwise try our best ot fulfill their request by ignoring this invalid data
584
+						throw new RestException(
585
+							'invalid_parameter',
586
+							sprintf(
587
+								esc_html__(
588
+									'You provided an invalid parameter, with key "%1$s"',
589
+									'event_espresso'
590
+								),
591
+								$query_param_sans_stars
592
+							),
593
+							array(
594
+								'status' => 400,
595
+							)
596
+						);
597
+					}
598
+				}
599
+			}
600
+		}
601
+		return $query_param_for_models;
602
+	}
603
+
604
+
605
+	/**
606
+	 * Mostly checks if the last 4 characters are "_gmt", indicating its a
607
+	 * gmt date field name
608
+	 *
609
+	 * @param string $field_name
610
+	 * @return boolean
611
+	 */
612
+	public static function isGmtDateFieldName($field_name)
613
+	{
614
+		return substr(
615
+			ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name),
616
+			-4,
617
+			4
618
+		) === '_gmt';
619
+	}
620
+
621
+
622
+	/**
623
+	 * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone)
624
+	 *
625
+	 * @param string $field_name
626
+	 * @return string
627
+	 */
628
+	public static function removeGmtFromFieldName($field_name)
629
+	{
630
+		if (! ModelDataTranslator::isGmtDateFieldName($field_name)) {
631
+			return $field_name;
632
+		}
633
+		$query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey(
634
+			$field_name
635
+		);
636
+		$query_param_sans_gmt_and_sans_stars = substr(
637
+			$query_param_sans_stars,
638
+			0,
639
+			strrpos(
640
+				$field_name,
641
+				'_gmt'
642
+			)
643
+		);
644
+		return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name);
645
+	}
646
+
647
+
648
+	/**
649
+	 * Takes a field name from the REST API and prepares it for the model querying
650
+	 *
651
+	 * @param string $field_name
652
+	 * @return string
653
+	 */
654
+	public static function prepareFieldNameFromJson($field_name)
655
+	{
656
+		if (ModelDataTranslator::isGmtDateFieldName($field_name)) {
657
+			return ModelDataTranslator::removeGmtFromFieldName($field_name);
658
+		}
659
+		return $field_name;
660
+	}
661
+
662
+
663
+	/**
664
+	 * Takes array of field names from REST API and prepares for models
665
+	 *
666
+	 * @param array $field_names
667
+	 * @return array of field names (possibly include model prefixes)
668
+	 */
669
+	public static function prepareFieldNamesFromJson(array $field_names)
670
+	{
671
+		$new_array = array();
672
+		foreach ($field_names as $key => $field_name) {
673
+			$new_array[ $key ] = ModelDataTranslator::prepareFieldNameFromJson($field_name);
674
+		}
675
+		return $new_array;
676
+	}
677
+
678
+
679
+	/**
680
+	 * Takes array where array keys are field names (possibly with model path prefixes)
681
+	 * from the REST API and prepares them for model querying
682
+	 *
683
+	 * @param array $field_names_as_keys
684
+	 * @return array
685
+	 */
686
+	public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys)
687
+	{
688
+		$new_array = array();
689
+		foreach ($field_names_as_keys as $field_name => $value) {
690
+			$new_array[ ModelDataTranslator::prepareFieldNameFromJson($field_name) ] = $value;
691
+		}
692
+		return $new_array;
693
+	}
694
+
695
+
696
+	/**
697
+	 * Prepares an array of model query params for use in the REST API
698
+	 *
699
+	 * @param array    $model_query_params
700
+	 * @param EEM_Base $model
701
+	 * @param string   $requested_version  eg "4.8.36". If null is provided, defaults to the latest release of the EE4
702
+	 *                                     REST API
703
+	 * @return array which can be passed into the EE4 REST API when querying a model resource
704
+	 * @throws EE_Error
705
+	 */
706
+	public static function prepareQueryParamsForRestApi(
707
+		array $model_query_params,
708
+		EEM_Base $model,
709
+		$requested_version = null
710
+	) {
711
+		if ($requested_version === null) {
712
+			$requested_version = \EED_Core_Rest_Api::latest_rest_api_version();
713
+		}
714
+		$rest_query_params = $model_query_params;
715
+		if (isset($model_query_params[0])) {
716
+			$rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
717
+				$model_query_params[0],
718
+				$model,
719
+				$requested_version
720
+			);
721
+			unset($rest_query_params[0]);
722
+		}
723
+		if (isset($model_query_params['having'])) {
724
+			$rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
725
+				$model_query_params['having'],
726
+				$model,
727
+				$requested_version
728
+			);
729
+		}
730
+		return apply_filters(
731
+			'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api',
732
+			$rest_query_params,
733
+			$model_query_params,
734
+			$model,
735
+			$requested_version
736
+		);
737
+	}
738
+
739
+
740
+	/**
741
+	 * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api
742
+	 *
743
+	 * @param array    $inputted_query_params_of_this_type  eg like the "where" or "having" conditions query params
744
+	 *                                                      passed into EEM_Base::get_all()
745
+	 * @param EEM_Base $model
746
+	 * @param string   $requested_version                   eg "4.8.36"
747
+	 * @return array ready for use in the rest api query params
748
+	 * @throws EE_Error
749
+	 * @throws ObjectDetectedException if somehow a PHP object were in the query params' values,
750
+	 *                                                      (which would be really unusual)
751
+	 */
752
+	public static function prepareConditionsQueryParamsForRestApi(
753
+		$inputted_query_params_of_this_type,
754
+		EEM_Base $model,
755
+		$requested_version
756
+	) {
757
+		$query_param_for_models = array();
758
+		foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) {
759
+			$field = ModelDataTranslator::deduceFieldFromQueryParam(
760
+				ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key),
761
+				$model
762
+			);
763
+			if ($field instanceof EE_Model_Field_Base) {
764
+				// did they specify an operator?
765
+				if (is_array($query_param_value)) {
766
+					$op = $query_param_value[0];
767
+					$translated_value = array($op);
768
+					if (isset($query_param_value[1])) {
769
+						$value = $query_param_value[1];
770
+						$translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson(
771
+							$field,
772
+							$value,
773
+							$requested_version
774
+						);
775
+					}
776
+				} else {
777
+					$translated_value = ModelDataTranslator::prepareFieldValueForJson(
778
+						$field,
779
+						$query_param_value,
780
+						$requested_version
781
+					);
782
+				}
783
+				$query_param_for_models[ $query_param_key ] = $translated_value;
784
+			} else {
785
+				// so it's not for a field, assume it's a logic query param key
786
+				$query_param_for_models[ $query_param_key ] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi(
787
+					$query_param_value,
788
+					$model,
789
+					$requested_version
790
+				);
791
+			}
792
+		}
793
+		return $query_param_for_models;
794
+	}
795
+
796
+
797
+	/**
798
+	 * @param $condition_query_param_key
799
+	 * @return string
800
+	 */
801
+	public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key)
802
+	{
803
+		$pos_of_star = strpos($condition_query_param_key, '*');
804
+		if ($pos_of_star === false) {
805
+			return $condition_query_param_key;
806
+		} else {
807
+			$condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star);
808
+			return $condition_query_param_sans_star;
809
+		}
810
+	}
811
+
812
+
813
+	/**
814
+	 * Takes the input parameter and finds the model field that it indicates.
815
+	 *
816
+	 * @param string   $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID
817
+	 * @param EEM_Base $model
818
+	 * @return EE_Model_Field_Base
819
+	 * @throws EE_Error
820
+	 */
821
+	public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model)
822
+	{
823
+		// ok, now proceed with deducing which part is the model's name, and which is the field's name
824
+		// which will help us find the database table and column
825
+		$query_param_parts = explode('.', $query_param_name);
826
+		if (empty($query_param_parts)) {
827
+			throw new EE_Error(
828
+				sprintf(
829
+					__(
830
+						'_extract_column_name is empty when trying to extract column and table name from %s',
831
+						'event_espresso'
832
+					),
833
+					$query_param_name
834
+				)
835
+			);
836
+		}
837
+		$number_of_parts = count($query_param_parts);
838
+		$last_query_param_part = $query_param_parts[ count($query_param_parts) - 1 ];
839
+		if ($number_of_parts === 1) {
840
+			$field_name = $last_query_param_part;
841
+		} else {// $number_of_parts >= 2
842
+			// the last part is the column name, and there are only 2parts. therefore...
843
+			$field_name = $last_query_param_part;
844
+			$model = \EE_Registry::instance()->load_model($query_param_parts[ $number_of_parts - 2 ]);
845
+		}
846
+		try {
847
+			return $model->field_settings_for($field_name, false);
848
+		} catch (EE_Error $e) {
849
+			return null;
850
+		}
851
+	}
852
+
853
+
854
+	/**
855
+	 * Returns true if $data can be easily represented in JSON.
856
+	 * Basically, objects and resources can't be represented in JSON easily.
857
+	 *
858
+	 * @param mixed $data
859
+	 * @return bool
860
+	 */
861
+	protected static function isRepresentableInJson($data)
862
+	{
863
+		return is_scalar($data)
864
+			   || is_array($data)
865
+			   || is_null($data);
866
+	}
867 867
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelVersionInfo.php 2 patches
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -114,10 +114,10 @@  discard block
 block discarded – undo
114 114
         foreach ($this->resource_changes as $version => $model_classnames) {
115 115
             foreach ($model_classnames as $model_classname => $extra_fields) {
116 116
                 foreach ($extra_fields as $fieldname => $field_data) {
117
-                    $this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname;
117
+                    $this->resource_changes[$model_classname][$fieldname]['name'] = $fieldname;
118 118
                     foreach ($defaults as $attribute => $default_value) {
119
-                        if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) {
120
-                            $this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value;
119
+                        if ( ! isset($this->resource_changes[$model_classname][$fieldname][$attribute])) {
120
+                            $this->resource_changes[$model_classname][$fieldname][$attribute] = $default_value;
121 121
                         }
122 122
                     }
123 123
                 }
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
             $model_changes = array();
140 140
             foreach ($this->modelChanges() as $version => $models_changed_in_version) {
141 141
                 if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
142
-                    $model_changes[ $version ] = $models_changed_in_version;
142
+                    $model_changes[$version] = $models_changed_in_version;
143 143
                 }
144 144
             }
145 145
             $this->cached_model_changes_between_requested_version_and_current = $model_changes;
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
             $resource_changes = array();
162 162
             foreach ($this->resourceChanges() as $version => $model_classnames) {
163 163
                 if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
164
-                    $resource_changes[ $version ] = $model_classnames;
164
+                    $resource_changes[$version] = $model_classnames;
165 165
                 }
166 166
             }
167 167
             $this->cached_resource_changes_between_requested_version_and_current = $resource_changes;
@@ -212,7 +212,7 @@  discard block
 block discarded – undo
212 212
             foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) {
213 213
                 foreach ($models_changed as $model_name => $new_indicator_or_fields_added) {
214 214
                     if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) {
215
-                        unset($all_models_in_current_version[ $model_name ]);
215
+                        unset($all_models_in_current_version[$model_name]);
216 216
                     }
217 217
                 }
218 218
             }
@@ -237,7 +237,7 @@  discard block
 block discarded – undo
237 237
     public function isModelNameInThisVersion($model_name)
238 238
     {
239 239
         $model_names = $this->modelsForRequestedVersion();
240
-        if (isset($model_names[ $model_name ])) {
240
+        if (isset($model_names[$model_name])) {
241 241
             return true;
242 242
         } else {
243 243
             return false;
@@ -280,19 +280,19 @@  discard block
 block discarded – undo
280 280
      */
281 281
     public function fieldsOnModelInThisVersion($model)
282 282
     {
283
-        if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) {
283
+        if ( ! isset($this->cached_fields_on_models[$model->get_this_model_name()])) {
284 284
             // get all model changes between the requested version and current core version
285 285
             $changes = $this->modelChangesBetweenRequestedVersionAndCurrent();
286 286
             // fetch all fields currently on this model
287 287
             $current_fields = $model->field_settings();
288 288
             // remove all fields that have been added since
289 289
             foreach ($changes as $version => $changes_in_version) {
290
-                if (isset($changes_in_version[ $model->get_this_model_name() ])
291
-                    && $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED
290
+                if (isset($changes_in_version[$model->get_this_model_name()])
291
+                    && $changes_in_version[$model->get_this_model_name()] !== ModelVersionInfo::MODEL_ADDED
292 292
                 ) {
293 293
                     $current_fields = array_diff_key(
294 294
                         $current_fields,
295
-                        array_flip($changes_in_version[ $model->get_this_model_name() ])
295
+                        array_flip($changes_in_version[$model->get_this_model_name()])
296 296
                     );
297 297
                 }
298 298
             }
@@ -447,7 +447,7 @@  discard block
 block discarded – undo
447 447
         $relations = array();
448 448
         foreach ($model->relation_settings() as $relation_name => $relation_obj) {
449 449
             if ($this->isModelNameInThisVersion($relation_name)) {
450
-                $relations[ $relation_name ] = $relation_obj;
450
+                $relations[$relation_name] = $relation_obj;
451 451
             }
452 452
         }
453 453
         // filter the results, but use the old filter name
Please login to merge, or discard this patch.
Indentation   +436 added lines, -436 removed lines patch added patch discarded remove patch
@@ -21,440 +21,440 @@
 block discarded – undo
21 21
 class ModelVersionInfo
22 22
 {
23 23
 
24
-    /**
25
-     * Constant used in the $_model_changes array to indicate that a model
26
-     * was completely new in this version
27
-     */
28
-    const MODEL_ADDED = 'model_added_in_this_version';
29
-
30
-    /**
31
-     * Top-level keys are versions (major and minor version numbers, eg "4.6")
32
-     * next-level keys are model names (eg "Event") that underwent some change in that version
33
-     * and the value is either Model_Version_Info::model_added (indicating the model is completely NEW in this version),
34
-     * or it's an array where the values are model field names,
35
-     * or API resource properties (ie, non-model fields that appear in REST API results)
36
-     * If a version is missing then we don't know anything about what changes it introduced from the previous version
37
-     *
38
-     * @var array
39
-     */
40
-    protected $model_changes = array();
41
-
42
-    /**
43
-     * top-level keys are version numbers,
44
-     * next-level keys are model CLASSNAMES (even parent classnames),
45
-     * and next-level keys are extra resource properties to attach to those models' resources,
46
-     * and next-level key-value pairs, where the keys are:
47
-     * 'raw', 'type', 'nullable', 'table_alias', 'table_column',  'always_available'
48
-     *
49
-     * @var array
50
-     */
51
-    protected $resource_changes = array();
52
-
53
-    /**
54
-     * @var string indicating what version of the API was requested
55
-     * (eg although core might be at version 4.8.11, they may have sent a request
56
-     * for 4.6)
57
-     */
58
-    protected $requested_version = null;
59
-
60
-    /**
61
-     * Keys are model names, values are their classnames.
62
-     * We cache this so we only need to calculate this once per request
63
-     *
64
-     * @var array
65
-     */
66
-    protected $cached_models_for_requested_version = null;
67
-
68
-    /**
69
-     * @var array
70
-     */
71
-    protected $cached_model_changes_between_requested_version_and_current = null;
72
-
73
-    /**
74
-     * @var array
75
-     */
76
-    protected $cached_resource_changes_between_requested_version_and_current = null;
77
-
78
-    /**
79
-     * 2d array where top-level keys are model names, 2nd-level keys are field names
80
-     * and values are the actual field objects
81
-     *
82
-     * @var array
83
-     */
84
-    protected $cached_fields_on_models = array();
85
-
86
-
87
-    /**
88
-     * Model_Version_Info constructor.
89
-     *
90
-     * @param string $requested_version
91
-     */
92
-    public function __construct($requested_version)
93
-    {
94
-        $this->requested_version = (string) $requested_version;
95
-        $this->model_changes = array(
96
-            '4.8.29' => array(
97
-                // first version where the REST API is in EE core, so no need
98
-                // to specify how its different from the previous
99
-            ),
100
-        );
101
-        // setup data for "extra" fields added onto resources which don't actually exist on models
102
-        $this->resource_changes = apply_filters(
103
-            'FHEE__Model_Version_Info___construct__extra_resource_properties_for_models',
104
-            array()
105
-        );
106
-        $defaults = array(
107
-            'raw'              => false,
108
-            'type'             => 'N/A',
109
-            'nullable'         => true,
110
-            'table_alias'      => 'N/A',
111
-            'table_column'     => 'N/A',
112
-            'always_available' => true,
113
-        );
114
-        foreach ($this->resource_changes as $version => $model_classnames) {
115
-            foreach ($model_classnames as $model_classname => $extra_fields) {
116
-                foreach ($extra_fields as $fieldname => $field_data) {
117
-                    $this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname;
118
-                    foreach ($defaults as $attribute => $default_value) {
119
-                        if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) {
120
-                            $this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value;
121
-                        }
122
-                    }
123
-                }
124
-            }
125
-        }
126
-    }
127
-
128
-
129
-    /**
130
-     * Returns a slice of Model_Version_Info::model_changes()'s array
131
-     * indicating exactly what changes happened between the current core version,
132
-     * and the version requested
133
-     *
134
-     * @return array
135
-     */
136
-    public function modelChangesBetweenRequestedVersionAndCurrent()
137
-    {
138
-        if ($this->cached_model_changes_between_requested_version_and_current === null) {
139
-            $model_changes = array();
140
-            foreach ($this->modelChanges() as $version => $models_changed_in_version) {
141
-                if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
142
-                    $model_changes[ $version ] = $models_changed_in_version;
143
-                }
144
-            }
145
-            $this->cached_model_changes_between_requested_version_and_current = $model_changes;
146
-        }
147
-        return $this->cached_model_changes_between_requested_version_and_current;
148
-    }
149
-
150
-
151
-    /**
152
-     * Returns a slice of Model_Version_Info::model_changes()'s array
153
-     * indicating exactly what changes happened between the current core version,
154
-     * and the version requested
155
-     *
156
-     * @return array
157
-     */
158
-    public function resourceChangesBetweenRequestedVersionAndCurrent()
159
-    {
160
-        if ($this->cached_resource_changes_between_requested_version_and_current === null) {
161
-            $resource_changes = array();
162
-            foreach ($this->resourceChanges() as $version => $model_classnames) {
163
-                if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
164
-                    $resource_changes[ $version ] = $model_classnames;
165
-                }
166
-            }
167
-            $this->cached_resource_changes_between_requested_version_and_current = $resource_changes;
168
-        }
169
-        return $this->cached_resource_changes_between_requested_version_and_current;
170
-    }
171
-
172
-
173
-    /**
174
-     * If a request was sent to 'wp-json/ee/v4.7/events' this would be '4.7'
175
-     *
176
-     * @return string like '4.6'
177
-     */
178
-    public function requestedVersion()
179
-    {
180
-        return $this->requested_version;
181
-    }
182
-
183
-
184
-    /**
185
-     * Returns an array describing how the models have changed in each version of core
186
-     * that supports the API (starting at 4.6)
187
-     * Top-level keys are versions (major and minor version numbers, eg "4.6")
188
-     * next-level keys are model names (eg "Event") that underwent some change in that version
189
-     * and the value is either NULL (indicating the model is completely NEW in this version),
190
-     * or it's an array where fields are value names.
191
-     * If a version is missing then we don't know anything about what changes it introduced from the previous version
192
-     *
193
-     * @return array
194
-     */
195
-    public function modelChanges()
196
-    {
197
-        return $this->model_changes;
198
-    }
199
-
200
-
201
-    /**
202
-     * Takes into account the requested version, and the current version, and
203
-     * what changed between the two, and tries to return.
204
-     * Analogous to EE_Registry::instance()->non_abstract_db_models
205
-     *
206
-     * @return array keys are model names, values are their classname
207
-     */
208
-    public function modelsForRequestedVersion()
209
-    {
210
-        if ($this->cached_models_for_requested_version === null) {
211
-            $all_models_in_current_version = EE_Registry::instance()->non_abstract_db_models;
212
-            foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) {
213
-                foreach ($models_changed as $model_name => $new_indicator_or_fields_added) {
214
-                    if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) {
215
-                        unset($all_models_in_current_version[ $model_name ]);
216
-                    }
217
-                }
218
-            }
219
-            $this->cached_models_for_requested_version = apply_filters(
220
-                'FHEE__EventEspresso_core_libraries_rest_api__models_for_requested_version',
221
-                $all_models_in_current_version,
222
-                $this
223
-            );
224
-        }
225
-        return $this->cached_models_for_requested_version;
226
-    }
227
-
228
-
229
-    /**
230
-     * Determines if this is a valid model name in the requested version.
231
-     * Similar to EE_Registry::instance()->is_model_name(), but takes the requested
232
-     * version's models into account
233
-     *
234
-     * @param string $model_name eg 'Event'
235
-     * @return boolean
236
-     */
237
-    public function isModelNameInThisVersion($model_name)
238
-    {
239
-        $model_names = $this->modelsForRequestedVersion();
240
-        if (isset($model_names[ $model_name ])) {
241
-            return true;
242
-        } else {
243
-            return false;
244
-        }
245
-    }
246
-
247
-
248
-    /**
249
-     * Wrapper for EE_Registry::instance()->load_model(), but takes the requested
250
-     * version's models into account
251
-     *
252
-     * @param string $model_name
253
-     * @return \EEM_Base
254
-     * @throws \EE_Error
255
-     */
256
-    public function loadModel($model_name)
257
-    {
258
-        if ($this->isModelNameInThisVersion($model_name)) {
259
-            return EE_Registry::instance()->load_model($model_name);
260
-        } else {
261
-            throw new \EE_Error(
262
-                sprintf(
263
-                    __(
264
-                        'Cannot load model "%1$s" because it does not exist in version %2$s of Event Espresso',
265
-                        'event_espresso'
266
-                    ),
267
-                    $model_name,
268
-                    $this->requestedVersion()
269
-                )
270
-            );
271
-        }
272
-    }
273
-
274
-
275
-    /**
276
-     * Gets all the fields that should exist on this model right now
277
-     *
278
-     * @param \EEM_Base $model
279
-     * @return array|\EE_Model_Field_Base[]
280
-     */
281
-    public function fieldsOnModelInThisVersion($model)
282
-    {
283
-        if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) {
284
-            // get all model changes between the requested version and current core version
285
-            $changes = $this->modelChangesBetweenRequestedVersionAndCurrent();
286
-            // fetch all fields currently on this model
287
-            $current_fields = $model->field_settings();
288
-            // remove all fields that have been added since
289
-            foreach ($changes as $version => $changes_in_version) {
290
-                if (isset($changes_in_version[ $model->get_this_model_name() ])
291
-                    && $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED
292
-                ) {
293
-                    $current_fields = array_diff_key(
294
-                        $current_fields,
295
-                        array_flip($changes_in_version[ $model->get_this_model_name() ])
296
-                    );
297
-                }
298
-            }
299
-            $this->cached_fields_on_models = $current_fields;
300
-        }
301
-        return $this->cached_fields_on_models;
302
-    }
303
-
304
-
305
-    /**
306
-     * Determines if $object is of one of the classes of $classes. Similar to
307
-     * in_array(), except this checks if $object is a subclass of the classnames provided
308
-     * in $classnames
309
-     *
310
-     * @param object $object
311
-     * @param array  $classnames
312
-     * @return boolean
313
-     */
314
-    public function isSubclassOfOne($object, $classnames)
315
-    {
316
-        foreach ($classnames as $classname) {
317
-            if (is_a($object, $classname)) {
318
-                return true;
319
-            }
320
-        }
321
-        return false;
322
-    }
323
-
324
-
325
-    /**
326
-     * Returns the list of model field classes that that the API basically ignores
327
-     *
328
-     * @return array
329
-     */
330
-    public function fieldsIgnored()
331
-    {
332
-        return apply_filters(
333
-            'FHEE__Controller_Model_Read_fields_ignored',
334
-            array()
335
-        );
336
-    }
337
-
338
-
339
-    /**
340
-     * If this field one that should be ignored by the API?
341
-     *
342
-     * @param EE_Model_Field_Base
343
-     * @return boolean
344
-     */
345
-    public function fieldIsIgnored($field_obj)
346
-    {
347
-        return $this->isSubclassOfOne($field_obj, $this->fieldsIgnored());
348
-    }
349
-
350
-
351
-    /**
352
-     * Returns the list of model field classes that have a "raw" and non-raw formats.
353
-     * Normally the "raw" versions are only accessible to those who can edit them.
354
-     *
355
-     * @return array an array of EE_Model_Field_Base child classnames
356
-     */
357
-    public function fieldsThatHaveRenderedFormat()
358
-    {
359
-        return apply_filters(
360
-            'FHEE__Controller_Model_Read__fields_raw',
361
-            array('EE_Post_Content_Field', 'EE_Full_HTML_Field')
362
-        );
363
-    }
364
-
365
-
366
-    /**
367
-     * If this field one that has a raw format
368
-     *
369
-     * @param EE_Model_Field_Base
370
-     * @return boolean
371
-     */
372
-    public function fieldHasRenderedFormat($field_obj)
373
-    {
374
-        return $this->isSubclassOfOne($field_obj, $this->fieldsThatHaveRenderedFormat());
375
-    }
376
-
377
-
378
-    /**
379
-     * Returns the list of model field classes that have a "_pretty" and non-pretty versions.
380
-     * The pretty version of the field is NOT query-able or editable, but requires no extra permissions
381
-     * to view
382
-     *
383
-     * @return array an array of EE_Model_Field_Base child classnames
384
-     */
385
-    public function fieldsThatHavePrettyFormat()
386
-    {
387
-        return apply_filters(
388
-            'FHEE__Controller_Model_Read__fields_pretty',
389
-            array('EE_Enum_Integer_Field', 'EE_Enum_Text_Field', 'EE_Money_Field')
390
-        );
391
-    }
392
-
393
-
394
-    /**
395
-     * If this field one that has a pretty equivalent
396
-     *
397
-     * @param EE_Model_Field_Base
398
-     * @return boolean
399
-     */
400
-    public function fieldHasPrettyFormat($field_obj)
401
-    {
402
-        return $this->isSubclassOfOne($field_obj, $this->fieldsThatHavePrettyFormat());
403
-    }
404
-
405
-
406
-    /**
407
-     * Returns an array describing what extra API resource properties have been added through the versions
408
-     *
409
-     * @return array @see $this->_extra_resource_properties_for_models
410
-     */
411
-    public function resourceChanges()
412
-    {
413
-        return $this->resource_changes;
414
-    }
415
-
416
-
417
-    /**
418
-     * Returns an array where keys are extra resource properties in this version of the API,
419
-     * and values are key-value pairs describing the new properties. @see Model_Version::_resource_changes
420
-     *
421
-     * @param \EEM_Base $model
422
-     * @return array
423
-     */
424
-    public function extraResourcePropertiesForModel($model)
425
-    {
426
-        $extra_properties = array();
427
-        foreach ($this->resourceChangesBetweenRequestedVersionAndCurrent() as $version => $model_classnames) {
428
-            foreach ($model_classnames as $model_classname => $properties_added_in_this_version) {
429
-                if (is_subclass_of($model, $model_classname)) {
430
-                    $extra_properties = array_merge($extra_properties, $properties_added_in_this_version);
431
-                }
432
-            }
433
-        }
434
-        return $extra_properties;
435
-    }
436
-
437
-
438
-    /**
439
-     * Gets all the related models for the specified model. It's good to use this
440
-     * in case this model didn't exist for this version or something
441
-     *
442
-     * @param \EEM_Base $model
443
-     * @return \EE_Model_Relation_Base[]
444
-     */
445
-    public function relationSettings(\EEM_Base $model)
446
-    {
447
-        $relations = array();
448
-        foreach ($model->relation_settings() as $relation_name => $relation_obj) {
449
-            if ($this->isModelNameInThisVersion($relation_name)) {
450
-                $relations[ $relation_name ] = $relation_obj;
451
-            }
452
-        }
453
-        // filter the results, but use the old filter name
454
-        return apply_filters(
455
-            'FHEE__Read__create_entity_from_wpdb_result__related_models_to_include',
456
-            $relations,
457
-            $model
458
-        );
459
-    }
24
+	/**
25
+	 * Constant used in the $_model_changes array to indicate that a model
26
+	 * was completely new in this version
27
+	 */
28
+	const MODEL_ADDED = 'model_added_in_this_version';
29
+
30
+	/**
31
+	 * Top-level keys are versions (major and minor version numbers, eg "4.6")
32
+	 * next-level keys are model names (eg "Event") that underwent some change in that version
33
+	 * and the value is either Model_Version_Info::model_added (indicating the model is completely NEW in this version),
34
+	 * or it's an array where the values are model field names,
35
+	 * or API resource properties (ie, non-model fields that appear in REST API results)
36
+	 * If a version is missing then we don't know anything about what changes it introduced from the previous version
37
+	 *
38
+	 * @var array
39
+	 */
40
+	protected $model_changes = array();
41
+
42
+	/**
43
+	 * top-level keys are version numbers,
44
+	 * next-level keys are model CLASSNAMES (even parent classnames),
45
+	 * and next-level keys are extra resource properties to attach to those models' resources,
46
+	 * and next-level key-value pairs, where the keys are:
47
+	 * 'raw', 'type', 'nullable', 'table_alias', 'table_column',  'always_available'
48
+	 *
49
+	 * @var array
50
+	 */
51
+	protected $resource_changes = array();
52
+
53
+	/**
54
+	 * @var string indicating what version of the API was requested
55
+	 * (eg although core might be at version 4.8.11, they may have sent a request
56
+	 * for 4.6)
57
+	 */
58
+	protected $requested_version = null;
59
+
60
+	/**
61
+	 * Keys are model names, values are their classnames.
62
+	 * We cache this so we only need to calculate this once per request
63
+	 *
64
+	 * @var array
65
+	 */
66
+	protected $cached_models_for_requested_version = null;
67
+
68
+	/**
69
+	 * @var array
70
+	 */
71
+	protected $cached_model_changes_between_requested_version_and_current = null;
72
+
73
+	/**
74
+	 * @var array
75
+	 */
76
+	protected $cached_resource_changes_between_requested_version_and_current = null;
77
+
78
+	/**
79
+	 * 2d array where top-level keys are model names, 2nd-level keys are field names
80
+	 * and values are the actual field objects
81
+	 *
82
+	 * @var array
83
+	 */
84
+	protected $cached_fields_on_models = array();
85
+
86
+
87
+	/**
88
+	 * Model_Version_Info constructor.
89
+	 *
90
+	 * @param string $requested_version
91
+	 */
92
+	public function __construct($requested_version)
93
+	{
94
+		$this->requested_version = (string) $requested_version;
95
+		$this->model_changes = array(
96
+			'4.8.29' => array(
97
+				// first version where the REST API is in EE core, so no need
98
+				// to specify how its different from the previous
99
+			),
100
+		);
101
+		// setup data for "extra" fields added onto resources which don't actually exist on models
102
+		$this->resource_changes = apply_filters(
103
+			'FHEE__Model_Version_Info___construct__extra_resource_properties_for_models',
104
+			array()
105
+		);
106
+		$defaults = array(
107
+			'raw'              => false,
108
+			'type'             => 'N/A',
109
+			'nullable'         => true,
110
+			'table_alias'      => 'N/A',
111
+			'table_column'     => 'N/A',
112
+			'always_available' => true,
113
+		);
114
+		foreach ($this->resource_changes as $version => $model_classnames) {
115
+			foreach ($model_classnames as $model_classname => $extra_fields) {
116
+				foreach ($extra_fields as $fieldname => $field_data) {
117
+					$this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname;
118
+					foreach ($defaults as $attribute => $default_value) {
119
+						if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) {
120
+							$this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value;
121
+						}
122
+					}
123
+				}
124
+			}
125
+		}
126
+	}
127
+
128
+
129
+	/**
130
+	 * Returns a slice of Model_Version_Info::model_changes()'s array
131
+	 * indicating exactly what changes happened between the current core version,
132
+	 * and the version requested
133
+	 *
134
+	 * @return array
135
+	 */
136
+	public function modelChangesBetweenRequestedVersionAndCurrent()
137
+	{
138
+		if ($this->cached_model_changes_between_requested_version_and_current === null) {
139
+			$model_changes = array();
140
+			foreach ($this->modelChanges() as $version => $models_changed_in_version) {
141
+				if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
142
+					$model_changes[ $version ] = $models_changed_in_version;
143
+				}
144
+			}
145
+			$this->cached_model_changes_between_requested_version_and_current = $model_changes;
146
+		}
147
+		return $this->cached_model_changes_between_requested_version_and_current;
148
+	}
149
+
150
+
151
+	/**
152
+	 * Returns a slice of Model_Version_Info::model_changes()'s array
153
+	 * indicating exactly what changes happened between the current core version,
154
+	 * and the version requested
155
+	 *
156
+	 * @return array
157
+	 */
158
+	public function resourceChangesBetweenRequestedVersionAndCurrent()
159
+	{
160
+		if ($this->cached_resource_changes_between_requested_version_and_current === null) {
161
+			$resource_changes = array();
162
+			foreach ($this->resourceChanges() as $version => $model_classnames) {
163
+				if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) {
164
+					$resource_changes[ $version ] = $model_classnames;
165
+				}
166
+			}
167
+			$this->cached_resource_changes_between_requested_version_and_current = $resource_changes;
168
+		}
169
+		return $this->cached_resource_changes_between_requested_version_and_current;
170
+	}
171
+
172
+
173
+	/**
174
+	 * If a request was sent to 'wp-json/ee/v4.7/events' this would be '4.7'
175
+	 *
176
+	 * @return string like '4.6'
177
+	 */
178
+	public function requestedVersion()
179
+	{
180
+		return $this->requested_version;
181
+	}
182
+
183
+
184
+	/**
185
+	 * Returns an array describing how the models have changed in each version of core
186
+	 * that supports the API (starting at 4.6)
187
+	 * Top-level keys are versions (major and minor version numbers, eg "4.6")
188
+	 * next-level keys are model names (eg "Event") that underwent some change in that version
189
+	 * and the value is either NULL (indicating the model is completely NEW in this version),
190
+	 * or it's an array where fields are value names.
191
+	 * If a version is missing then we don't know anything about what changes it introduced from the previous version
192
+	 *
193
+	 * @return array
194
+	 */
195
+	public function modelChanges()
196
+	{
197
+		return $this->model_changes;
198
+	}
199
+
200
+
201
+	/**
202
+	 * Takes into account the requested version, and the current version, and
203
+	 * what changed between the two, and tries to return.
204
+	 * Analogous to EE_Registry::instance()->non_abstract_db_models
205
+	 *
206
+	 * @return array keys are model names, values are their classname
207
+	 */
208
+	public function modelsForRequestedVersion()
209
+	{
210
+		if ($this->cached_models_for_requested_version === null) {
211
+			$all_models_in_current_version = EE_Registry::instance()->non_abstract_db_models;
212
+			foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) {
213
+				foreach ($models_changed as $model_name => $new_indicator_or_fields_added) {
214
+					if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) {
215
+						unset($all_models_in_current_version[ $model_name ]);
216
+					}
217
+				}
218
+			}
219
+			$this->cached_models_for_requested_version = apply_filters(
220
+				'FHEE__EventEspresso_core_libraries_rest_api__models_for_requested_version',
221
+				$all_models_in_current_version,
222
+				$this
223
+			);
224
+		}
225
+		return $this->cached_models_for_requested_version;
226
+	}
227
+
228
+
229
+	/**
230
+	 * Determines if this is a valid model name in the requested version.
231
+	 * Similar to EE_Registry::instance()->is_model_name(), but takes the requested
232
+	 * version's models into account
233
+	 *
234
+	 * @param string $model_name eg 'Event'
235
+	 * @return boolean
236
+	 */
237
+	public function isModelNameInThisVersion($model_name)
238
+	{
239
+		$model_names = $this->modelsForRequestedVersion();
240
+		if (isset($model_names[ $model_name ])) {
241
+			return true;
242
+		} else {
243
+			return false;
244
+		}
245
+	}
246
+
247
+
248
+	/**
249
+	 * Wrapper for EE_Registry::instance()->load_model(), but takes the requested
250
+	 * version's models into account
251
+	 *
252
+	 * @param string $model_name
253
+	 * @return \EEM_Base
254
+	 * @throws \EE_Error
255
+	 */
256
+	public function loadModel($model_name)
257
+	{
258
+		if ($this->isModelNameInThisVersion($model_name)) {
259
+			return EE_Registry::instance()->load_model($model_name);
260
+		} else {
261
+			throw new \EE_Error(
262
+				sprintf(
263
+					__(
264
+						'Cannot load model "%1$s" because it does not exist in version %2$s of Event Espresso',
265
+						'event_espresso'
266
+					),
267
+					$model_name,
268
+					$this->requestedVersion()
269
+				)
270
+			);
271
+		}
272
+	}
273
+
274
+
275
+	/**
276
+	 * Gets all the fields that should exist on this model right now
277
+	 *
278
+	 * @param \EEM_Base $model
279
+	 * @return array|\EE_Model_Field_Base[]
280
+	 */
281
+	public function fieldsOnModelInThisVersion($model)
282
+	{
283
+		if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) {
284
+			// get all model changes between the requested version and current core version
285
+			$changes = $this->modelChangesBetweenRequestedVersionAndCurrent();
286
+			// fetch all fields currently on this model
287
+			$current_fields = $model->field_settings();
288
+			// remove all fields that have been added since
289
+			foreach ($changes as $version => $changes_in_version) {
290
+				if (isset($changes_in_version[ $model->get_this_model_name() ])
291
+					&& $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED
292
+				) {
293
+					$current_fields = array_diff_key(
294
+						$current_fields,
295
+						array_flip($changes_in_version[ $model->get_this_model_name() ])
296
+					);
297
+				}
298
+			}
299
+			$this->cached_fields_on_models = $current_fields;
300
+		}
301
+		return $this->cached_fields_on_models;
302
+	}
303
+
304
+
305
+	/**
306
+	 * Determines if $object is of one of the classes of $classes. Similar to
307
+	 * in_array(), except this checks if $object is a subclass of the classnames provided
308
+	 * in $classnames
309
+	 *
310
+	 * @param object $object
311
+	 * @param array  $classnames
312
+	 * @return boolean
313
+	 */
314
+	public function isSubclassOfOne($object, $classnames)
315
+	{
316
+		foreach ($classnames as $classname) {
317
+			if (is_a($object, $classname)) {
318
+				return true;
319
+			}
320
+		}
321
+		return false;
322
+	}
323
+
324
+
325
+	/**
326
+	 * Returns the list of model field classes that that the API basically ignores
327
+	 *
328
+	 * @return array
329
+	 */
330
+	public function fieldsIgnored()
331
+	{
332
+		return apply_filters(
333
+			'FHEE__Controller_Model_Read_fields_ignored',
334
+			array()
335
+		);
336
+	}
337
+
338
+
339
+	/**
340
+	 * If this field one that should be ignored by the API?
341
+	 *
342
+	 * @param EE_Model_Field_Base
343
+	 * @return boolean
344
+	 */
345
+	public function fieldIsIgnored($field_obj)
346
+	{
347
+		return $this->isSubclassOfOne($field_obj, $this->fieldsIgnored());
348
+	}
349
+
350
+
351
+	/**
352
+	 * Returns the list of model field classes that have a "raw" and non-raw formats.
353
+	 * Normally the "raw" versions are only accessible to those who can edit them.
354
+	 *
355
+	 * @return array an array of EE_Model_Field_Base child classnames
356
+	 */
357
+	public function fieldsThatHaveRenderedFormat()
358
+	{
359
+		return apply_filters(
360
+			'FHEE__Controller_Model_Read__fields_raw',
361
+			array('EE_Post_Content_Field', 'EE_Full_HTML_Field')
362
+		);
363
+	}
364
+
365
+
366
+	/**
367
+	 * If this field one that has a raw format
368
+	 *
369
+	 * @param EE_Model_Field_Base
370
+	 * @return boolean
371
+	 */
372
+	public function fieldHasRenderedFormat($field_obj)
373
+	{
374
+		return $this->isSubclassOfOne($field_obj, $this->fieldsThatHaveRenderedFormat());
375
+	}
376
+
377
+
378
+	/**
379
+	 * Returns the list of model field classes that have a "_pretty" and non-pretty versions.
380
+	 * The pretty version of the field is NOT query-able or editable, but requires no extra permissions
381
+	 * to view
382
+	 *
383
+	 * @return array an array of EE_Model_Field_Base child classnames
384
+	 */
385
+	public function fieldsThatHavePrettyFormat()
386
+	{
387
+		return apply_filters(
388
+			'FHEE__Controller_Model_Read__fields_pretty',
389
+			array('EE_Enum_Integer_Field', 'EE_Enum_Text_Field', 'EE_Money_Field')
390
+		);
391
+	}
392
+
393
+
394
+	/**
395
+	 * If this field one that has a pretty equivalent
396
+	 *
397
+	 * @param EE_Model_Field_Base
398
+	 * @return boolean
399
+	 */
400
+	public function fieldHasPrettyFormat($field_obj)
401
+	{
402
+		return $this->isSubclassOfOne($field_obj, $this->fieldsThatHavePrettyFormat());
403
+	}
404
+
405
+
406
+	/**
407
+	 * Returns an array describing what extra API resource properties have been added through the versions
408
+	 *
409
+	 * @return array @see $this->_extra_resource_properties_for_models
410
+	 */
411
+	public function resourceChanges()
412
+	{
413
+		return $this->resource_changes;
414
+	}
415
+
416
+
417
+	/**
418
+	 * Returns an array where keys are extra resource properties in this version of the API,
419
+	 * and values are key-value pairs describing the new properties. @see Model_Version::_resource_changes
420
+	 *
421
+	 * @param \EEM_Base $model
422
+	 * @return array
423
+	 */
424
+	public function extraResourcePropertiesForModel($model)
425
+	{
426
+		$extra_properties = array();
427
+		foreach ($this->resourceChangesBetweenRequestedVersionAndCurrent() as $version => $model_classnames) {
428
+			foreach ($model_classnames as $model_classname => $properties_added_in_this_version) {
429
+				if (is_subclass_of($model, $model_classname)) {
430
+					$extra_properties = array_merge($extra_properties, $properties_added_in_this_version);
431
+				}
432
+			}
433
+		}
434
+		return $extra_properties;
435
+	}
436
+
437
+
438
+	/**
439
+	 * Gets all the related models for the specified model. It's good to use this
440
+	 * in case this model didn't exist for this version or something
441
+	 *
442
+	 * @param \EEM_Base $model
443
+	 * @return \EE_Model_Relation_Base[]
444
+	 */
445
+	public function relationSettings(\EEM_Base $model)
446
+	{
447
+		$relations = array();
448
+		foreach ($model->relation_settings() as $relation_name => $relation_obj) {
449
+			if ($this->isModelNameInThisVersion($relation_name)) {
450
+				$relations[ $relation_name ] = $relation_obj;
451
+			}
452
+		}
453
+		// filter the results, but use the old filter name
454
+		return apply_filters(
455
+			'FHEE__Read__create_entity_from_wpdb_result__related_models_to_include',
456
+			$relations,
457
+			$model
458
+		);
459
+	}
460 460
 }
Please login to merge, or discard this patch.
core/libraries/rest_api/Capabilities.php 2 patches
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -15,152 +15,152 @@
 block discarded – undo
15 15
 class Capabilities
16 16
 {
17 17
 
18
-    /**
19
-     * The current user can see at least SOME of these entities.
20
-     *
21
-     * @param EEM_Base $model
22
-     * @param string   $model_context one of the return values from EEM_Base::valid_cap_contexts()
23
-     * @return boolean
24
-     */
25
-    public static function currentUserHasPartialAccessTo($model, $model_context = EEM_Base::caps_read)
26
-    {
27
-        if (apply_filters(
28
-            'FHEE__Capabilities__current_user_has_partial_access_to__override_begin',
29
-            false,
30
-            $model,
31
-            $model
32
-        )) {
33
-            return true;
34
-        }
35
-        foreach ($model->caps_missing($model_context) as $capability_name => $restriction_obj) {
36
-            if ($restriction_obj instanceof \EE_Return_None_Where_Conditions) {
37
-                return false;
38
-            }
39
-        }
40
-        if (apply_filters(
41
-            'FHEE__Capabilities__current_user_has_partial_access_to__override_end',
42
-            false,
43
-            $model,
44
-            $model
45
-        )) {
46
-            return false;
47
-        }
48
-        return true;
49
-    }
18
+	/**
19
+	 * The current user can see at least SOME of these entities.
20
+	 *
21
+	 * @param EEM_Base $model
22
+	 * @param string   $model_context one of the return values from EEM_Base::valid_cap_contexts()
23
+	 * @return boolean
24
+	 */
25
+	public static function currentUserHasPartialAccessTo($model, $model_context = EEM_Base::caps_read)
26
+	{
27
+		if (apply_filters(
28
+			'FHEE__Capabilities__current_user_has_partial_access_to__override_begin',
29
+			false,
30
+			$model,
31
+			$model
32
+		)) {
33
+			return true;
34
+		}
35
+		foreach ($model->caps_missing($model_context) as $capability_name => $restriction_obj) {
36
+			if ($restriction_obj instanceof \EE_Return_None_Where_Conditions) {
37
+				return false;
38
+			}
39
+		}
40
+		if (apply_filters(
41
+			'FHEE__Capabilities__current_user_has_partial_access_to__override_end',
42
+			false,
43
+			$model,
44
+			$model
45
+		)) {
46
+			return false;
47
+		}
48
+		return true;
49
+	}
50 50
 
51 51
 
52
-    /**
53
-     * Gets an array of all the capabilities the current user is missing that affected
54
-     * the query
55
-     *
56
-     * @param EEM_Base $model
57
-     * @param string   $request_type one of the constants on WP_JSON_Server
58
-     * @return array
59
-     */
60
-    public static function getMissingPermissions($model, $request_type = EEM_Base::caps_read)
61
-    {
62
-        return $model->caps_missing($request_type);
63
-    }
52
+	/**
53
+	 * Gets an array of all the capabilities the current user is missing that affected
54
+	 * the query
55
+	 *
56
+	 * @param EEM_Base $model
57
+	 * @param string   $request_type one of the constants on WP_JSON_Server
58
+	 * @return array
59
+	 */
60
+	public static function getMissingPermissions($model, $request_type = EEM_Base::caps_read)
61
+	{
62
+		return $model->caps_missing($request_type);
63
+	}
64 64
 
65 65
 
66
-    /**
67
-     * Gets a string of all the capabilities the current user is missing that affected
68
-     * the query
69
-     *
70
-     * @param EEM_Base $model
71
-     * @param string   $model_context one of the return values from EEM_Base::valid_cap_contexts()
72
-     * @return string
73
-     */
74
-    public static function getMissingPermissionsString($model, $model_context = EEM_Base::caps_read)
75
-    {
76
-        return implode(',', array_keys(self::getMissingPermissions($model, $model_context)));
77
-    }
66
+	/**
67
+	 * Gets a string of all the capabilities the current user is missing that affected
68
+	 * the query
69
+	 *
70
+	 * @param EEM_Base $model
71
+	 * @param string   $model_context one of the return values from EEM_Base::valid_cap_contexts()
72
+	 * @return string
73
+	 */
74
+	public static function getMissingPermissionsString($model, $model_context = EEM_Base::caps_read)
75
+	{
76
+		return implode(',', array_keys(self::getMissingPermissions($model, $model_context)));
77
+	}
78 78
 
79 79
 
80
-    /**
81
-     * Takes a entity that's ready to be returned and removes fields which the user shouldn't be able to access.
82
-     *
83
-     * @param array            $entity
84
-     * @param EEM_Base         $model
85
-     * @param string           $request_type         one of the return values from EEM_Base::valid_cap_contexts()
86
-     * @param ModelVersionInfo $model_version_info
87
-     * @param string           $primary_key_string   result of EEM_Base::get_index_primary_key_string(), so that we can
88
-     *                                               use this with models that have no primary key
89
-     * @return array ready for converting into json
90
-     */
91
-    public static function filterOutInaccessibleEntityFields(
92
-        $entity,
93
-        $model,
94
-        $request_type,
95
-        $model_version_info,
96
-        $primary_key_string = null
97
-    ) {
98
-        // if they didn't provide the primary key string, we'll just hope we can figure it out
99
-        // from the entity (although it's preferred client code does it, because the entity might be missing
100
-        // necessary fields for creating the primary key string, or they could be named differently)
101
-        if ($primary_key_string === null) {
102
-            $primary_key_string = $model->get_index_primary_key_string(
103
-                $model->deduce_fields_n_values_from_cols_n_values($entity)
104
-            );
105
-        }
106
-        // we only care to do this for frontend reads and when the user can't edit the item
107
-        if ($request_type !== EEM_Base::caps_read
108
-            || $model->exists(
109
-                $model->alter_query_params_to_restrict_by_ID(
110
-                    $primary_key_string,
111
-                    array(
112
-                        'default_where_conditions' => 'none',
113
-                        'caps'                     => EEM_Base::caps_edit,
114
-                    )
115
-                )
116
-            )
117
-        ) {
118
-            return $entity;
119
-        }
120
-        foreach ($model->field_settings() as $field_name => $field_obj) {
121
-            if ($model_version_info->fieldHasRenderedFormat($field_obj)
122
-                && isset($entity[ $field_name ])
123
-                && is_array($entity[ $field_name ])
124
-                && isset($entity[ $field_name ]['raw'])
125
-            ) {
126
-                unset($entity[ $field_name ]['raw']);
127
-            }
128
-        }
129
-        // theoretically we may want to filter out specific fields for specific models
130
-        return apply_filters(
131
-            'FHEE__Capabilities__filter_out_inaccessible_entity_fields',
132
-            $entity,
133
-            $model,
134
-            $request_type
135
-        );
136
-    }
80
+	/**
81
+	 * Takes a entity that's ready to be returned and removes fields which the user shouldn't be able to access.
82
+	 *
83
+	 * @param array            $entity
84
+	 * @param EEM_Base         $model
85
+	 * @param string           $request_type         one of the return values from EEM_Base::valid_cap_contexts()
86
+	 * @param ModelVersionInfo $model_version_info
87
+	 * @param string           $primary_key_string   result of EEM_Base::get_index_primary_key_string(), so that we can
88
+	 *                                               use this with models that have no primary key
89
+	 * @return array ready for converting into json
90
+	 */
91
+	public static function filterOutInaccessibleEntityFields(
92
+		$entity,
93
+		$model,
94
+		$request_type,
95
+		$model_version_info,
96
+		$primary_key_string = null
97
+	) {
98
+		// if they didn't provide the primary key string, we'll just hope we can figure it out
99
+		// from the entity (although it's preferred client code does it, because the entity might be missing
100
+		// necessary fields for creating the primary key string, or they could be named differently)
101
+		if ($primary_key_string === null) {
102
+			$primary_key_string = $model->get_index_primary_key_string(
103
+				$model->deduce_fields_n_values_from_cols_n_values($entity)
104
+			);
105
+		}
106
+		// we only care to do this for frontend reads and when the user can't edit the item
107
+		if ($request_type !== EEM_Base::caps_read
108
+			|| $model->exists(
109
+				$model->alter_query_params_to_restrict_by_ID(
110
+					$primary_key_string,
111
+					array(
112
+						'default_where_conditions' => 'none',
113
+						'caps'                     => EEM_Base::caps_edit,
114
+					)
115
+				)
116
+			)
117
+		) {
118
+			return $entity;
119
+		}
120
+		foreach ($model->field_settings() as $field_name => $field_obj) {
121
+			if ($model_version_info->fieldHasRenderedFormat($field_obj)
122
+				&& isset($entity[ $field_name ])
123
+				&& is_array($entity[ $field_name ])
124
+				&& isset($entity[ $field_name ]['raw'])
125
+			) {
126
+				unset($entity[ $field_name ]['raw']);
127
+			}
128
+		}
129
+		// theoretically we may want to filter out specific fields for specific models
130
+		return apply_filters(
131
+			'FHEE__Capabilities__filter_out_inaccessible_entity_fields',
132
+			$entity,
133
+			$model,
134
+			$request_type
135
+		);
136
+	}
137 137
 
138 138
 
139
-    /**
140
-     * Verifies the current user has at least partial access to do this action on this model.
141
-     * If not, throws an exception (so we can define the code that sets up this error object
142
-     * once)
143
-     *
144
-     * @param EEM_Base $model
145
-     * @param string   $model_action_context
146
-     * @param string   $action_name
147
-     * @return void
148
-     * @throws RestException
149
-     */
150
-    public static function verifyAtLeastPartialAccessTo($model, $model_action_context, $action_name = 'list')
151
-    {
152
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $model_action_context)) {
153
-            $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
154
-            throw new RestException(
155
-                sprintf('rest_cannot_%s_%s', strtolower($action_name), $model_name_plural),
156
-                sprintf(
157
-                    __('Sorry, you are not allowed to %1$s %2$s. Missing permissions: %3$s', 'event_espresso'),
158
-                    $action_name,
159
-                    $model_name_plural,
160
-                    Capabilities::getMissingPermissionsString($model, $model_action_context)
161
-                ),
162
-                array('status' => 403)
163
-            );
164
-        }
165
-    }
139
+	/**
140
+	 * Verifies the current user has at least partial access to do this action on this model.
141
+	 * If not, throws an exception (so we can define the code that sets up this error object
142
+	 * once)
143
+	 *
144
+	 * @param EEM_Base $model
145
+	 * @param string   $model_action_context
146
+	 * @param string   $action_name
147
+	 * @return void
148
+	 * @throws RestException
149
+	 */
150
+	public static function verifyAtLeastPartialAccessTo($model, $model_action_context, $action_name = 'list')
151
+	{
152
+		if (! Capabilities::currentUserHasPartialAccessTo($model, $model_action_context)) {
153
+			$model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
154
+			throw new RestException(
155
+				sprintf('rest_cannot_%s_%s', strtolower($action_name), $model_name_plural),
156
+				sprintf(
157
+					__('Sorry, you are not allowed to %1$s %2$s. Missing permissions: %3$s', 'event_espresso'),
158
+					$action_name,
159
+					$model_name_plural,
160
+					Capabilities::getMissingPermissionsString($model, $model_action_context)
161
+				),
162
+				array('status' => 403)
163
+			);
164
+		}
165
+	}
166 166
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -119,11 +119,11 @@  discard block
 block discarded – undo
119 119
         }
120 120
         foreach ($model->field_settings() as $field_name => $field_obj) {
121 121
             if ($model_version_info->fieldHasRenderedFormat($field_obj)
122
-                && isset($entity[ $field_name ])
123
-                && is_array($entity[ $field_name ])
124
-                && isset($entity[ $field_name ]['raw'])
122
+                && isset($entity[$field_name])
123
+                && is_array($entity[$field_name])
124
+                && isset($entity[$field_name]['raw'])
125 125
             ) {
126
-                unset($entity[ $field_name ]['raw']);
126
+                unset($entity[$field_name]['raw']);
127 127
             }
128 128
         }
129 129
         // theoretically we may want to filter out specific fields for specific models
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
      */
150 150
     public static function verifyAtLeastPartialAccessTo($model, $model_action_context, $action_name = 'list')
151 151
     {
152
-        if (! Capabilities::currentUserHasPartialAccessTo($model, $model_action_context)) {
152
+        if ( ! Capabilities::currentUserHasPartialAccessTo($model, $model_action_context)) {
153 153
             $model_name_plural = EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
154 154
             throw new RestException(
155 155
                 sprintf('rest_cannot_%s_%s', strtolower($action_name), $model_name_plural),
Please login to merge, or discard this patch.
core/libraries/batch/JobHandlers/AttendeesReport.php 2 patches
Indentation   +96 added lines, -96 removed lines patch added patch discarded remove patch
@@ -19,106 +19,106 @@
 block discarded – undo
19 19
 class AttendeesReport extends JobHandlerFile
20 20
 {
21 21
 
22
-    // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
23
-    public function create_job(JobParameters $job_parameters)
24
-    {
25
-        if (! \EE_Capabilities::instance()->current_user_can('ee_read_contacts', 'generating_report')) {
26
-            throw new BatchRequestException(
27
-                __('You do not have permission to view contacts', 'event_espresso')
28
-            );
29
-        }
30
-        $filepath = $this->create_file_from_job_with_name(
31
-            $job_parameters->job_id(),
32
-            __('contact-list-report.csv', 'event_espresso')
33
-        );
34
-        $job_parameters->add_extra_data('filepath', $filepath);
35
-        $job_parameters->set_job_size($this->count_units_to_process());
36
-        // we should also set the header columns
37
-        $csv_data_for_row = $this->get_csv_data(0, 1);
38
-        \EEH_Export::write_data_array_to_csv($filepath, $csv_data_for_row, true);
39
-        // if we actually processed a row there, record it
40
-        if ($job_parameters->job_size()) {
41
-            $job_parameters->mark_processed(1);
42
-        }
43
-        return new JobStepResponse(
44
-            $job_parameters,
45
-            __('Contacts report started successfully...', 'event_espresso')
46
-        );
47
-    }
22
+	// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
23
+	public function create_job(JobParameters $job_parameters)
24
+	{
25
+		if (! \EE_Capabilities::instance()->current_user_can('ee_read_contacts', 'generating_report')) {
26
+			throw new BatchRequestException(
27
+				__('You do not have permission to view contacts', 'event_espresso')
28
+			);
29
+		}
30
+		$filepath = $this->create_file_from_job_with_name(
31
+			$job_parameters->job_id(),
32
+			__('contact-list-report.csv', 'event_espresso')
33
+		);
34
+		$job_parameters->add_extra_data('filepath', $filepath);
35
+		$job_parameters->set_job_size($this->count_units_to_process());
36
+		// we should also set the header columns
37
+		$csv_data_for_row = $this->get_csv_data(0, 1);
38
+		\EEH_Export::write_data_array_to_csv($filepath, $csv_data_for_row, true);
39
+		// if we actually processed a row there, record it
40
+		if ($job_parameters->job_size()) {
41
+			$job_parameters->mark_processed(1);
42
+		}
43
+		return new JobStepResponse(
44
+			$job_parameters,
45
+			__('Contacts report started successfully...', 'event_espresso')
46
+		);
47
+	}
48 48
 
49 49
 
50
-    public function continue_job(JobParameters $job_parameters, $batch_size = 50)
51
-    {
52
-        $csv_data = $this->get_csv_data($job_parameters->units_processed(), $batch_size);
53
-        \EEH_Export::write_data_array_to_csv(
54
-            $job_parameters->extra_datum('filepath'),
55
-            $csv_data,
56
-            false
57
-        );
58
-        $units_processed = count($csv_data);
59
-        $job_parameters->mark_processed($units_processed);
60
-        $extra_response_data = array(
61
-            'file_url' => '',
62
-        );
63
-        if ($units_processed < $batch_size) {
64
-            $job_parameters->set_status(JobParameters::status_complete);
65
-            $extra_response_data['file_url'] = $this->get_url_to_file($job_parameters->extra_datum('filepath'));
66
-        }
67
-        return new JobStepResponse(
68
-            $job_parameters,
69
-            sprintf(
70
-                __('Wrote %1$s rows to report CSV file...', 'event_espresso'),
71
-                count($csv_data)
72
-            ),
73
-            $extra_response_data
74
-        );
75
-    }
50
+	public function continue_job(JobParameters $job_parameters, $batch_size = 50)
51
+	{
52
+		$csv_data = $this->get_csv_data($job_parameters->units_processed(), $batch_size);
53
+		\EEH_Export::write_data_array_to_csv(
54
+			$job_parameters->extra_datum('filepath'),
55
+			$csv_data,
56
+			false
57
+		);
58
+		$units_processed = count($csv_data);
59
+		$job_parameters->mark_processed($units_processed);
60
+		$extra_response_data = array(
61
+			'file_url' => '',
62
+		);
63
+		if ($units_processed < $batch_size) {
64
+			$job_parameters->set_status(JobParameters::status_complete);
65
+			$extra_response_data['file_url'] = $this->get_url_to_file($job_parameters->extra_datum('filepath'));
66
+		}
67
+		return new JobStepResponse(
68
+			$job_parameters,
69
+			sprintf(
70
+				__('Wrote %1$s rows to report CSV file...', 'event_espresso'),
71
+				count($csv_data)
72
+			),
73
+			$extra_response_data
74
+		);
75
+	}
76 76
 
77 77
 
78
-    public function cleanup_job(JobParameters $job_parameters)
79
-    {
80
-        $this->_file_helper->delete(
81
-            \EEH_File::remove_filename_from_filepath($job_parameters->extra_datum('filepath')),
82
-            true,
83
-            'd'
84
-        );
85
-        return new JobStepResponse($job_parameters, __('Cleaned up temporary file', 'event_espresso'));
86
-    }
78
+	public function cleanup_job(JobParameters $job_parameters)
79
+	{
80
+		$this->_file_helper->delete(
81
+			\EEH_File::remove_filename_from_filepath($job_parameters->extra_datum('filepath')),
82
+			true,
83
+			'd'
84
+		);
85
+		return new JobStepResponse($job_parameters, __('Cleaned up temporary file', 'event_espresso'));
86
+	}
87 87
 
88
-    public function count_units_to_process()
89
-    {
90
-        return \EEM_Attendee::instance()->count(array('caps' => \EEM_Base::caps_read_admin));
91
-    }
88
+	public function count_units_to_process()
89
+	{
90
+		return \EEM_Attendee::instance()->count(array('caps' => \EEM_Base::caps_read_admin));
91
+	}
92 92
 
93
-    public function get_csv_data($offset, $limit)
94
-    {
95
-        $attendee_rows = \EEM_Attendee::instance()->get_all_wpdb_results(
96
-            array(
97
-                'limit'      => array($offset, $limit),
98
-                'force_join' => array('State', 'Country'),
99
-                'caps'       => \EEM_Base::caps_read_admin,
100
-            )
101
-        );
102
-        $csv_data = array();
103
-        foreach ($attendee_rows as $attendee_row) {
104
-            $csv_row = array();
105
-            foreach (\EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
106
-                if ($field_name == 'STA_ID') {
107
-                    $state_name_field = \EEM_State::instance()->field_settings_for('STA_name');
108
-                    $csv_row[ __('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column() ];
109
-                } elseif ($field_name == 'CNT_ISO') {
110
-                    $country_name_field = \EEM_Country::instance()->field_settings_for('CNT_name');
111
-                    $csv_row[ __('Country', 'event_espresso') ] = $attendee_row[ $country_name_field->get_qualified_column() ];
112
-                } else {
113
-                    $csv_row[ wp_specialchars_decode($field_obj->get_nicename(), ENT_QUOTES) ] = $attendee_row[ $field_obj->get_qualified_column() ];
114
-                }
115
-            }
116
-            $csv_data[] = apply_filters(
117
-                'FHEE___EventEspresso_core_libraries_batch_JobHandlers_AttendeesReport__get_csv_data__row',
118
-                $csv_row,
119
-                $attendee_row
120
-            );
121
-        }
122
-        return $csv_data;
123
-    }
93
+	public function get_csv_data($offset, $limit)
94
+	{
95
+		$attendee_rows = \EEM_Attendee::instance()->get_all_wpdb_results(
96
+			array(
97
+				'limit'      => array($offset, $limit),
98
+				'force_join' => array('State', 'Country'),
99
+				'caps'       => \EEM_Base::caps_read_admin,
100
+			)
101
+		);
102
+		$csv_data = array();
103
+		foreach ($attendee_rows as $attendee_row) {
104
+			$csv_row = array();
105
+			foreach (\EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
106
+				if ($field_name == 'STA_ID') {
107
+					$state_name_field = \EEM_State::instance()->field_settings_for('STA_name');
108
+					$csv_row[ __('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column() ];
109
+				} elseif ($field_name == 'CNT_ISO') {
110
+					$country_name_field = \EEM_Country::instance()->field_settings_for('CNT_name');
111
+					$csv_row[ __('Country', 'event_espresso') ] = $attendee_row[ $country_name_field->get_qualified_column() ];
112
+				} else {
113
+					$csv_row[ wp_specialchars_decode($field_obj->get_nicename(), ENT_QUOTES) ] = $attendee_row[ $field_obj->get_qualified_column() ];
114
+				}
115
+			}
116
+			$csv_data[] = apply_filters(
117
+				'FHEE___EventEspresso_core_libraries_batch_JobHandlers_AttendeesReport__get_csv_data__row',
118
+				$csv_row,
119
+				$attendee_row
120
+			);
121
+		}
122
+		return $csv_data;
123
+	}
124 124
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -22,7 +22,7 @@  discard block
 block discarded – undo
22 22
     // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
23 23
     public function create_job(JobParameters $job_parameters)
24 24
     {
25
-        if (! \EE_Capabilities::instance()->current_user_can('ee_read_contacts', 'generating_report')) {
25
+        if ( ! \EE_Capabilities::instance()->current_user_can('ee_read_contacts', 'generating_report')) {
26 26
             throw new BatchRequestException(
27 27
                 __('You do not have permission to view contacts', 'event_espresso')
28 28
             );
@@ -105,12 +105,12 @@  discard block
 block discarded – undo
105 105
             foreach (\EEM_Attendee::instance()->field_settings() as $field_name => $field_obj) {
106 106
                 if ($field_name == 'STA_ID') {
107 107
                     $state_name_field = \EEM_State::instance()->field_settings_for('STA_name');
108
-                    $csv_row[ __('State', 'event_espresso') ] = $attendee_row[ $state_name_field->get_qualified_column() ];
108
+                    $csv_row[__('State', 'event_espresso')] = $attendee_row[$state_name_field->get_qualified_column()];
109 109
                 } elseif ($field_name == 'CNT_ISO') {
110 110
                     $country_name_field = \EEM_Country::instance()->field_settings_for('CNT_name');
111
-                    $csv_row[ __('Country', 'event_espresso') ] = $attendee_row[ $country_name_field->get_qualified_column() ];
111
+                    $csv_row[__('Country', 'event_espresso')] = $attendee_row[$country_name_field->get_qualified_column()];
112 112
                 } else {
113
-                    $csv_row[ wp_specialchars_decode($field_obj->get_nicename(), ENT_QUOTES) ] = $attendee_row[ $field_obj->get_qualified_column() ];
113
+                    $csv_row[wp_specialchars_decode($field_obj->get_nicename(), ENT_QUOTES)] = $attendee_row[$field_obj->get_qualified_column()];
114 114
                 }
115 115
             }
116 116
             $csv_data[] = apply_filters(
Please login to merge, or discard this patch.
core/libraries/batch/JobHandlers/DatetimeOffsetFix.php 2 patches
Indentation   +467 added lines, -467 removed lines patch added patch discarded remove patch
@@ -24,471 +24,471 @@
 block discarded – undo
24 24
 class DatetimeOffsetFix extends JobHandler
25 25
 {
26 26
 
27
-    /**
28
-     * Key for the option used to track which models have been processed when doing the batches.
29
-     */
30
-    const MODELS_TO_PROCESS_OPTION_KEY = 'ee_models_processed_for_datetime_offset_fix';
31
-
32
-
33
-    const COUNT_OF_MODELS_PROCESSED = 'ee_count_of_ee_models_processed_for_datetime_offset_fixed';
34
-
35
-    /**
36
-     * Key for the option used to track what the current offset is that will be applied when this tool is executed.
37
-     */
38
-    const OFFSET_TO_APPLY_OPTION_KEY = 'ee_datetime_offset_fix_offset_to_apply';
39
-
40
-
41
-    const OPTION_KEY_OFFSET_RANGE_START_DATE = 'ee_datetime_offset_start_date_range';
42
-
43
-
44
-    const OPTION_KEY_OFFSET_RANGE_END_DATE = 'ee_datetime_offset_end_date_range';
45
-
46
-
47
-    /**
48
-     * String labelling the datetime offset fix type for change-log entries.
49
-     */
50
-    const DATETIME_OFFSET_FIX_CHANGELOG_TYPE = 'datetime_offset_fix';
51
-
52
-
53
-    /**
54
-     * String labelling a datetime offset fix error for change-log entries.
55
-     */
56
-    const DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE = 'datetime_offset_fix_error';
57
-
58
-    /**
59
-     * @var EEM_Base[]
60
-     */
61
-    protected $models_with_datetime_fields = array();
62
-
63
-    // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
64
-
65
-    /**
66
-     * Performs any necessary setup for starting the job. This is also a good
67
-     * place to setup the $job_arguments which will be used for subsequent HTTP requests
68
-     * when continue_job will be called
69
-     *
70
-     * @param JobParameters $job_parameters
71
-     * @return JobStepResponse
72
-     * @throws EE_Error
73
-     * @throws InvalidArgumentException
74
-     * @throws InvalidDataTypeException
75
-     * @throws InvalidInterfaceException
76
-     */
77
-    public function create_job(JobParameters $job_parameters)
78
-    {
79
-        $models_with_datetime_fields = $this->getModelsWithDatetimeFields();
80
-        // we'll be doing each model as a batch.
81
-        $job_parameters->set_job_size(count($models_with_datetime_fields));
82
-        return new JobStepResponse(
83
-            $job_parameters,
84
-            esc_html__('Starting Datetime Offset Fix', 'event_espresso')
85
-        );
86
-    }
87
-
88
-    /**
89
-     * Performs another step of the job
90
-     *
91
-     * @param JobParameters $job_parameters
92
-     * @param int           $batch_size
93
-     * @return JobStepResponse
94
-     * @throws EE_Error
95
-     * @throws InvalidArgumentException
96
-     * @throws InvalidDataTypeException
97
-     * @throws InvalidInterfaceException
98
-     */
99
-    public function continue_job(JobParameters $job_parameters, $batch_size = 50)
100
-    {
101
-        $models_to_process = $this->getModelsWithDatetimeFields();
102
-        // let's pop off the a model and do the query to apply the offset.
103
-        $model_to_process = array_pop($models_to_process);
104
-        // update our record
105
-        $this->setModelsToProcess($models_to_process);
106
-        $this->processModel($model_to_process);
107
-        $this->updateCountOfModelsProcessed();
108
-        $job_parameters->set_units_processed($this->getCountOfModelsProcessed());
109
-        if (count($models_to_process) > 0) {
110
-            $job_parameters->set_status(JobParameters::status_continue);
111
-        } else {
112
-            $job_parameters->set_status(JobParameters::status_complete);
113
-        }
114
-        return new JobStepResponse(
115
-            $job_parameters,
116
-            sprintf(
117
-                esc_html__('Updated the offset for all datetime fields on the %s model.', 'event_espresso'),
118
-                $model_to_process
119
-            )
120
-        );
121
-    }
122
-
123
-    /**
124
-     * Performs any clean-up logic when we know the job is completed
125
-     *
126
-     * @param JobParameters $job_parameters
127
-     * @return JobStepResponse
128
-     * @throws BatchRequestException
129
-     */
130
-    public function cleanup_job(JobParameters $job_parameters)
131
-    {
132
-        // delete important saved options.
133
-        delete_option(self::MODELS_TO_PROCESS_OPTION_KEY);
134
-        delete_option(self::COUNT_OF_MODELS_PROCESSED);
135
-        delete_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE);
136
-        delete_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE);
137
-        return new JobStepResponse($job_parameters, esc_html__(
138
-            'Offset has been applied to all affected fields.',
139
-            'event_espresso'
140
-        ));
141
-    }
142
-
143
-
144
-    /**
145
-     * Contains the logic for processing a model and applying the datetime offset to affected fields on that model.
146
-     *
147
-     * @param string $model_class_name
148
-     * @throws EE_Error
149
-     */
150
-    protected function processModel($model_class_name)
151
-    {
152
-        global $wpdb;
153
-        /** @var EEM_Base $model */
154
-        $model = $model_class_name::instance();
155
-        $original_offset = self::getOffset();
156
-        $start_date_range = self::getStartDateRange();
157
-        $end_date_range = self::getEndDateRange();
158
-        $sql_date_function = $original_offset > 0 ? 'DATE_ADD' : 'DATE_SUB';
159
-        $offset = abs($original_offset) * 60;
160
-        $date_ranges = array();
161
-        // since some affected models might have two tables, we have to get our tables and set up a query for each table.
162
-        foreach ($model->get_tables() as $table) {
163
-            $query = 'UPDATE ' . $table->get_table_name();
164
-            $fields_affected = array();
165
-            $inner_query = array();
166
-            foreach ($model->_get_fields_for_table($table->get_table_alias()) as $model_field) {
167
-                if ($model_field instanceof EE_Datetime_Field) {
168
-                    $inner_query[ $model_field->get_table_column() ] = $model_field->get_table_column() . ' = '
169
-                                                                       . $sql_date_function . '('
170
-                                                                       . $model_field->get_table_column()
171
-                                                                       . ", INTERVAL {$offset} MINUTE)";
172
-                    $fields_affected[] = $model_field;
173
-                }
174
-            }
175
-            if (! $fields_affected) {
176
-                continue;
177
-            }
178
-            // do we do one query per column/field or one query for all fields on the model? It all depends on whether
179
-            // there is a date range applied or not.
180
-            if ($start_date_range instanceof DbSafeDateTime || $end_date_range instanceof DbSafeDateTime) {
181
-                $result = $this->doQueryForEachField($query, $inner_query, $start_date_range, $end_date_range);
182
-            } else {
183
-                $result = $this->doQueryForAllFields($query, $inner_query);
184
-            }
185
-
186
-            // record appropriate logs for the query
187
-            switch (true) {
188
-                case $result === false:
189
-                    // record error.
190
-                    $error_message = $wpdb->last_error;
191
-                    // handle the edgecases where last_error might be empty.
192
-                    if (! $error_message) {
193
-                        $error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
194
-                    }
195
-                    $this->recordChangeLog($model, $original_offset, $table, $fields_affected, $error_message);
196
-                    break;
197
-                case is_array($result) && ! empty($result):
198
-                    foreach ($result as $field_name => $error_message) {
199
-                        $this->recordChangeLog($model, $original_offset, $table, array($field_name), $error_message);
200
-                    }
201
-                    break;
202
-                default:
203
-                    $this->recordChangeLog($model, $original_offset, $table, $fields_affected);
204
-            }
205
-        }
206
-    }
207
-
208
-
209
-    /**
210
-     * Does the query on each $inner_query individually.
211
-     *
212
-     * @param string              $query
213
-     * @param array               $inner_query
214
-     * @param DbSafeDateTime|null $start_date_range
215
-     * @param DbSafeDateTime|null $end_date_range
216
-     * @return array  An array of any errors encountered and the fields they were for.
217
-     */
218
-    private function doQueryForEachField($query, array $inner_query, $start_date_range, $end_date_range)
219
-    {
220
-        global $wpdb;
221
-        $errors = array();
222
-        foreach ($inner_query as $field_name => $field_query) {
223
-            $query_to_run = $query;
224
-            $where_conditions = array();
225
-            $query_to_run .= ' SET ' . $field_query;
226
-            if ($start_date_range instanceof DbSafeDateTime) {
227
-                $start_date = $start_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
228
-                $where_conditions[] = "{$field_name} > '{$start_date}'";
229
-            }
230
-            if ($end_date_range instanceof DbSafeDateTime) {
231
-                $end_date = $end_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
232
-                $where_conditions[] = "{$field_name} < '{$end_date}'";
233
-            }
234
-            if ($where_conditions) {
235
-                $query_to_run .= ' WHERE ' . implode(' AND ', $where_conditions);
236
-            }
237
-            $result = $wpdb->query($query_to_run);
238
-            if ($result === false) {
239
-                // record error.
240
-                $error_message = $wpdb->last_error;
241
-                // handle the edgecases where last_error might be empty.
242
-                if (! $error_message) {
243
-                    $error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
244
-                }
245
-                $errors[ $field_name ] = $error_message;
246
-            }
247
-        }
248
-        return $errors;
249
-    }
250
-
251
-
252
-    /**
253
-     * Performs the query for all fields within the inner_query
254
-     *
255
-     * @param string $query
256
-     * @param array  $inner_query
257
-     * @return false|int
258
-     */
259
-    private function doQueryForAllFields($query, array $inner_query)
260
-    {
261
-        global $wpdb;
262
-        $query .= ' SET ' . implode(',', $inner_query);
263
-        return $wpdb->query($query);
264
-    }
265
-
266
-
267
-    /**
268
-     * Records a changelog entry using the given information.
269
-     *
270
-     * @param EEM_Base              $model
271
-     * @param float                 $offset
272
-     * @param EE_Table_Base         $table
273
-     * @param EE_Model_Field_Base[] $model_fields_affected
274
-     * @param string                $error_message If present then there was an error so let's record that instead.
275
-     * @throws EE_Error
276
-     */
277
-    private function recordChangeLog(
278
-        EEM_Base $model,
279
-        $offset,
280
-        EE_Table_Base $table,
281
-        $model_fields_affected,
282
-        $error_message = ''
283
-    ) {
284
-        // setup $fields list.
285
-        $fields = array();
286
-        /** @var EE_Datetime_Field $model_field */
287
-        foreach ($model_fields_affected as $model_field) {
288
-            if (! $model_field instanceof EE_Datetime_Field) {
289
-                continue;
290
-            }
291
-            $fields[] = $model_field->get_name();
292
-        }
293
-        // setup the message for the changelog entry.
294
-        $message = $error_message
295
-            ? sprintf(
296
-                esc_html__(
297
-                    'The %1$s table for the %2$s model did not have the offset of %3$f applied to its fields (%4$s), because of the following error:%5$s',
298
-                    'event_espresso'
299
-                ),
300
-                $table->get_table_name(),
301
-                $model->get_this_model_name(),
302
-                $offset,
303
-                implode(',', $fields),
304
-                $error_message
305
-            )
306
-            : sprintf(
307
-                esc_html__(
308
-                    'The %1$s table for the %2$s model has had the offset of %3$f applied to its following fields: %4$s',
309
-                    'event_espresso'
310
-                ),
311
-                $table->get_table_name(),
312
-                $model->get_this_model_name(),
313
-                $offset,
314
-                implode(',', $fields)
315
-            );
316
-        // write to the log
317
-        $changelog = EE_Change_Log::new_instance(array(
318
-            'LOG_type'    => $error_message
319
-                ? self::DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE
320
-                : self::DATETIME_OFFSET_FIX_CHANGELOG_TYPE,
321
-            'LOG_message' => $message,
322
-        ));
323
-        $changelog->save();
324
-    }
325
-
326
-
327
-    /**
328
-     * Returns an array of models that have datetime fields.
329
-     * This array is added to a short lived transient cache to keep having to build this list to a minimum.
330
-     *
331
-     * @return array an array of model class names.
332
-     * @throws EE_Error
333
-     * @throws InvalidDataTypeException
334
-     * @throws InvalidInterfaceException
335
-     * @throws InvalidArgumentException
336
-     */
337
-    private function getModelsWithDatetimeFields()
338
-    {
339
-        $this->getModelsToProcess();
340
-        if (! empty($this->models_with_datetime_fields)) {
341
-            return $this->models_with_datetime_fields;
342
-        }
343
-
344
-        $all_non_abstract_models = EE_Registry::instance()->non_abstract_db_models;
345
-        foreach ($all_non_abstract_models as $non_abstract_model) {
346
-            // get model instance
347
-            /** @var EEM_Base $non_abstract_model */
348
-            $non_abstract_model = $non_abstract_model::instance();
349
-            if ($non_abstract_model->get_a_field_of_type('EE_Datetime_Field') instanceof EE_Datetime_Field) {
350
-                $this->models_with_datetime_fields[] = get_class($non_abstract_model);
351
-            }
352
-        }
353
-        $this->setModelsToProcess($this->models_with_datetime_fields);
354
-        return $this->models_with_datetime_fields;
355
-    }
356
-
357
-
358
-    /**
359
-     * This simply records the models that have been processed with our tracking option.
360
-     *
361
-     * @param array $models_to_set array of model class names.
362
-     */
363
-    private function setModelsToProcess($models_to_set)
364
-    {
365
-        update_option(self::MODELS_TO_PROCESS_OPTION_KEY, $models_to_set);
366
-    }
367
-
368
-
369
-    /**
370
-     * Used to keep track of how many models have been processed for the batch
371
-     *
372
-     * @param $count
373
-     */
374
-    private function updateCountOfModelsProcessed($count = 1)
375
-    {
376
-        $count = $this->getCountOfModelsProcessed() + (int) $count;
377
-        update_option(self::COUNT_OF_MODELS_PROCESSED, $count);
378
-    }
379
-
380
-
381
-    /**
382
-     * Retrieve the tracked number of models processed between requests.
383
-     *
384
-     * @return int
385
-     */
386
-    private function getCountOfModelsProcessed()
387
-    {
388
-        return (int) get_option(self::COUNT_OF_MODELS_PROCESSED, 0);
389
-    }
390
-
391
-
392
-    /**
393
-     * Returns the models that are left to process.
394
-     *
395
-     * @return array  an array of model class names.
396
-     */
397
-    private function getModelsToProcess()
398
-    {
399
-        if (empty($this->models_with_datetime_fields)) {
400
-            $this->models_with_datetime_fields = get_option(self::MODELS_TO_PROCESS_OPTION_KEY, array());
401
-        }
402
-        return $this->models_with_datetime_fields;
403
-    }
404
-
405
-
406
-    /**
407
-     * Used to record the offset that will be applied to dates and times for EE_Datetime_Field columns.
408
-     *
409
-     * @param float $offset
410
-     */
411
-    public static function updateOffset($offset)
412
-    {
413
-        update_option(self::OFFSET_TO_APPLY_OPTION_KEY, $offset);
414
-    }
415
-
416
-
417
-    /**
418
-     * Used to retrieve the saved offset that will be applied to dates and times for EE_Datetime_Field columns.
419
-     *
420
-     * @return float
421
-     */
422
-    public static function getOffset()
423
-    {
424
-        return (float) get_option(self::OFFSET_TO_APPLY_OPTION_KEY, 0);
425
-    }
426
-
427
-
428
-    /**
429
-     * Used to set the saved offset range start date.
430
-     *
431
-     * @param DbSafeDateTime|null $start_date
432
-     */
433
-    public static function updateStartDateRange(DbSafeDateTime $start_date = null)
434
-    {
435
-        $date_to_save = $start_date instanceof DbSafeDateTime
436
-            ? $start_date->format('U')
437
-            : '';
438
-        update_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, $date_to_save);
439
-    }
440
-
441
-
442
-    /**
443
-     * Used to get the saved offset range start date.
444
-     *
445
-     * @return DbSafeDateTime|null
446
-     */
447
-    public static function getStartDateRange()
448
-    {
449
-        $start_date = get_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, null);
450
-        try {
451
-            $datetime = DateTime::createFromFormat('U', $start_date, new DateTimeZone('UTC'));
452
-            $start_date = $datetime instanceof DateTime
453
-                ? DbSafeDateTime::createFromDateTime($datetime)
454
-                : null;
455
-        } catch (Exception $e) {
456
-            $start_date = null;
457
-        }
458
-        return $start_date;
459
-    }
460
-
461
-
462
-    /**
463
-     * Used to set the saved offset range end date.
464
-     *
465
-     * @param DbSafeDateTime|null $end_date
466
-     */
467
-    public static function updateEndDateRange(DbSafeDateTime $end_date = null)
468
-    {
469
-        $date_to_save = $end_date instanceof DbSafeDateTime
470
-            ? $end_date->format('U')
471
-            : '';
472
-        update_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, $date_to_save);
473
-    }
474
-
475
-
476
-    /**
477
-     * Used to get the saved offset range end date.
478
-     *
479
-     * @return DbSafeDateTime|null
480
-     */
481
-    public static function getEndDateRange()
482
-    {
483
-        $end_date = get_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, null);
484
-        try {
485
-            $datetime = DateTime::createFromFormat('U', $end_date, new DateTimeZone('UTC'));
486
-            $end_date = $datetime instanceof Datetime
487
-                ? DbSafeDateTime::createFromDateTime($datetime)
488
-                : null;
489
-        } catch (Exception $e) {
490
-            $end_date = null;
491
-        }
492
-        return $end_date;
493
-    }
27
+	/**
28
+	 * Key for the option used to track which models have been processed when doing the batches.
29
+	 */
30
+	const MODELS_TO_PROCESS_OPTION_KEY = 'ee_models_processed_for_datetime_offset_fix';
31
+
32
+
33
+	const COUNT_OF_MODELS_PROCESSED = 'ee_count_of_ee_models_processed_for_datetime_offset_fixed';
34
+
35
+	/**
36
+	 * Key for the option used to track what the current offset is that will be applied when this tool is executed.
37
+	 */
38
+	const OFFSET_TO_APPLY_OPTION_KEY = 'ee_datetime_offset_fix_offset_to_apply';
39
+
40
+
41
+	const OPTION_KEY_OFFSET_RANGE_START_DATE = 'ee_datetime_offset_start_date_range';
42
+
43
+
44
+	const OPTION_KEY_OFFSET_RANGE_END_DATE = 'ee_datetime_offset_end_date_range';
45
+
46
+
47
+	/**
48
+	 * String labelling the datetime offset fix type for change-log entries.
49
+	 */
50
+	const DATETIME_OFFSET_FIX_CHANGELOG_TYPE = 'datetime_offset_fix';
51
+
52
+
53
+	/**
54
+	 * String labelling a datetime offset fix error for change-log entries.
55
+	 */
56
+	const DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE = 'datetime_offset_fix_error';
57
+
58
+	/**
59
+	 * @var EEM_Base[]
60
+	 */
61
+	protected $models_with_datetime_fields = array();
62
+
63
+	// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
64
+
65
+	/**
66
+	 * Performs any necessary setup for starting the job. This is also a good
67
+	 * place to setup the $job_arguments which will be used for subsequent HTTP requests
68
+	 * when continue_job will be called
69
+	 *
70
+	 * @param JobParameters $job_parameters
71
+	 * @return JobStepResponse
72
+	 * @throws EE_Error
73
+	 * @throws InvalidArgumentException
74
+	 * @throws InvalidDataTypeException
75
+	 * @throws InvalidInterfaceException
76
+	 */
77
+	public function create_job(JobParameters $job_parameters)
78
+	{
79
+		$models_with_datetime_fields = $this->getModelsWithDatetimeFields();
80
+		// we'll be doing each model as a batch.
81
+		$job_parameters->set_job_size(count($models_with_datetime_fields));
82
+		return new JobStepResponse(
83
+			$job_parameters,
84
+			esc_html__('Starting Datetime Offset Fix', 'event_espresso')
85
+		);
86
+	}
87
+
88
+	/**
89
+	 * Performs another step of the job
90
+	 *
91
+	 * @param JobParameters $job_parameters
92
+	 * @param int           $batch_size
93
+	 * @return JobStepResponse
94
+	 * @throws EE_Error
95
+	 * @throws InvalidArgumentException
96
+	 * @throws InvalidDataTypeException
97
+	 * @throws InvalidInterfaceException
98
+	 */
99
+	public function continue_job(JobParameters $job_parameters, $batch_size = 50)
100
+	{
101
+		$models_to_process = $this->getModelsWithDatetimeFields();
102
+		// let's pop off the a model and do the query to apply the offset.
103
+		$model_to_process = array_pop($models_to_process);
104
+		// update our record
105
+		$this->setModelsToProcess($models_to_process);
106
+		$this->processModel($model_to_process);
107
+		$this->updateCountOfModelsProcessed();
108
+		$job_parameters->set_units_processed($this->getCountOfModelsProcessed());
109
+		if (count($models_to_process) > 0) {
110
+			$job_parameters->set_status(JobParameters::status_continue);
111
+		} else {
112
+			$job_parameters->set_status(JobParameters::status_complete);
113
+		}
114
+		return new JobStepResponse(
115
+			$job_parameters,
116
+			sprintf(
117
+				esc_html__('Updated the offset for all datetime fields on the %s model.', 'event_espresso'),
118
+				$model_to_process
119
+			)
120
+		);
121
+	}
122
+
123
+	/**
124
+	 * Performs any clean-up logic when we know the job is completed
125
+	 *
126
+	 * @param JobParameters $job_parameters
127
+	 * @return JobStepResponse
128
+	 * @throws BatchRequestException
129
+	 */
130
+	public function cleanup_job(JobParameters $job_parameters)
131
+	{
132
+		// delete important saved options.
133
+		delete_option(self::MODELS_TO_PROCESS_OPTION_KEY);
134
+		delete_option(self::COUNT_OF_MODELS_PROCESSED);
135
+		delete_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE);
136
+		delete_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE);
137
+		return new JobStepResponse($job_parameters, esc_html__(
138
+			'Offset has been applied to all affected fields.',
139
+			'event_espresso'
140
+		));
141
+	}
142
+
143
+
144
+	/**
145
+	 * Contains the logic for processing a model and applying the datetime offset to affected fields on that model.
146
+	 *
147
+	 * @param string $model_class_name
148
+	 * @throws EE_Error
149
+	 */
150
+	protected function processModel($model_class_name)
151
+	{
152
+		global $wpdb;
153
+		/** @var EEM_Base $model */
154
+		$model = $model_class_name::instance();
155
+		$original_offset = self::getOffset();
156
+		$start_date_range = self::getStartDateRange();
157
+		$end_date_range = self::getEndDateRange();
158
+		$sql_date_function = $original_offset > 0 ? 'DATE_ADD' : 'DATE_SUB';
159
+		$offset = abs($original_offset) * 60;
160
+		$date_ranges = array();
161
+		// since some affected models might have two tables, we have to get our tables and set up a query for each table.
162
+		foreach ($model->get_tables() as $table) {
163
+			$query = 'UPDATE ' . $table->get_table_name();
164
+			$fields_affected = array();
165
+			$inner_query = array();
166
+			foreach ($model->_get_fields_for_table($table->get_table_alias()) as $model_field) {
167
+				if ($model_field instanceof EE_Datetime_Field) {
168
+					$inner_query[ $model_field->get_table_column() ] = $model_field->get_table_column() . ' = '
169
+																	   . $sql_date_function . '('
170
+																	   . $model_field->get_table_column()
171
+																	   . ", INTERVAL {$offset} MINUTE)";
172
+					$fields_affected[] = $model_field;
173
+				}
174
+			}
175
+			if (! $fields_affected) {
176
+				continue;
177
+			}
178
+			// do we do one query per column/field or one query for all fields on the model? It all depends on whether
179
+			// there is a date range applied or not.
180
+			if ($start_date_range instanceof DbSafeDateTime || $end_date_range instanceof DbSafeDateTime) {
181
+				$result = $this->doQueryForEachField($query, $inner_query, $start_date_range, $end_date_range);
182
+			} else {
183
+				$result = $this->doQueryForAllFields($query, $inner_query);
184
+			}
185
+
186
+			// record appropriate logs for the query
187
+			switch (true) {
188
+				case $result === false:
189
+					// record error.
190
+					$error_message = $wpdb->last_error;
191
+					// handle the edgecases where last_error might be empty.
192
+					if (! $error_message) {
193
+						$error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
194
+					}
195
+					$this->recordChangeLog($model, $original_offset, $table, $fields_affected, $error_message);
196
+					break;
197
+				case is_array($result) && ! empty($result):
198
+					foreach ($result as $field_name => $error_message) {
199
+						$this->recordChangeLog($model, $original_offset, $table, array($field_name), $error_message);
200
+					}
201
+					break;
202
+				default:
203
+					$this->recordChangeLog($model, $original_offset, $table, $fields_affected);
204
+			}
205
+		}
206
+	}
207
+
208
+
209
+	/**
210
+	 * Does the query on each $inner_query individually.
211
+	 *
212
+	 * @param string              $query
213
+	 * @param array               $inner_query
214
+	 * @param DbSafeDateTime|null $start_date_range
215
+	 * @param DbSafeDateTime|null $end_date_range
216
+	 * @return array  An array of any errors encountered and the fields they were for.
217
+	 */
218
+	private function doQueryForEachField($query, array $inner_query, $start_date_range, $end_date_range)
219
+	{
220
+		global $wpdb;
221
+		$errors = array();
222
+		foreach ($inner_query as $field_name => $field_query) {
223
+			$query_to_run = $query;
224
+			$where_conditions = array();
225
+			$query_to_run .= ' SET ' . $field_query;
226
+			if ($start_date_range instanceof DbSafeDateTime) {
227
+				$start_date = $start_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
228
+				$where_conditions[] = "{$field_name} > '{$start_date}'";
229
+			}
230
+			if ($end_date_range instanceof DbSafeDateTime) {
231
+				$end_date = $end_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
232
+				$where_conditions[] = "{$field_name} < '{$end_date}'";
233
+			}
234
+			if ($where_conditions) {
235
+				$query_to_run .= ' WHERE ' . implode(' AND ', $where_conditions);
236
+			}
237
+			$result = $wpdb->query($query_to_run);
238
+			if ($result === false) {
239
+				// record error.
240
+				$error_message = $wpdb->last_error;
241
+				// handle the edgecases where last_error might be empty.
242
+				if (! $error_message) {
243
+					$error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
244
+				}
245
+				$errors[ $field_name ] = $error_message;
246
+			}
247
+		}
248
+		return $errors;
249
+	}
250
+
251
+
252
+	/**
253
+	 * Performs the query for all fields within the inner_query
254
+	 *
255
+	 * @param string $query
256
+	 * @param array  $inner_query
257
+	 * @return false|int
258
+	 */
259
+	private function doQueryForAllFields($query, array $inner_query)
260
+	{
261
+		global $wpdb;
262
+		$query .= ' SET ' . implode(',', $inner_query);
263
+		return $wpdb->query($query);
264
+	}
265
+
266
+
267
+	/**
268
+	 * Records a changelog entry using the given information.
269
+	 *
270
+	 * @param EEM_Base              $model
271
+	 * @param float                 $offset
272
+	 * @param EE_Table_Base         $table
273
+	 * @param EE_Model_Field_Base[] $model_fields_affected
274
+	 * @param string                $error_message If present then there was an error so let's record that instead.
275
+	 * @throws EE_Error
276
+	 */
277
+	private function recordChangeLog(
278
+		EEM_Base $model,
279
+		$offset,
280
+		EE_Table_Base $table,
281
+		$model_fields_affected,
282
+		$error_message = ''
283
+	) {
284
+		// setup $fields list.
285
+		$fields = array();
286
+		/** @var EE_Datetime_Field $model_field */
287
+		foreach ($model_fields_affected as $model_field) {
288
+			if (! $model_field instanceof EE_Datetime_Field) {
289
+				continue;
290
+			}
291
+			$fields[] = $model_field->get_name();
292
+		}
293
+		// setup the message for the changelog entry.
294
+		$message = $error_message
295
+			? sprintf(
296
+				esc_html__(
297
+					'The %1$s table for the %2$s model did not have the offset of %3$f applied to its fields (%4$s), because of the following error:%5$s',
298
+					'event_espresso'
299
+				),
300
+				$table->get_table_name(),
301
+				$model->get_this_model_name(),
302
+				$offset,
303
+				implode(',', $fields),
304
+				$error_message
305
+			)
306
+			: sprintf(
307
+				esc_html__(
308
+					'The %1$s table for the %2$s model has had the offset of %3$f applied to its following fields: %4$s',
309
+					'event_espresso'
310
+				),
311
+				$table->get_table_name(),
312
+				$model->get_this_model_name(),
313
+				$offset,
314
+				implode(',', $fields)
315
+			);
316
+		// write to the log
317
+		$changelog = EE_Change_Log::new_instance(array(
318
+			'LOG_type'    => $error_message
319
+				? self::DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE
320
+				: self::DATETIME_OFFSET_FIX_CHANGELOG_TYPE,
321
+			'LOG_message' => $message,
322
+		));
323
+		$changelog->save();
324
+	}
325
+
326
+
327
+	/**
328
+	 * Returns an array of models that have datetime fields.
329
+	 * This array is added to a short lived transient cache to keep having to build this list to a minimum.
330
+	 *
331
+	 * @return array an array of model class names.
332
+	 * @throws EE_Error
333
+	 * @throws InvalidDataTypeException
334
+	 * @throws InvalidInterfaceException
335
+	 * @throws InvalidArgumentException
336
+	 */
337
+	private function getModelsWithDatetimeFields()
338
+	{
339
+		$this->getModelsToProcess();
340
+		if (! empty($this->models_with_datetime_fields)) {
341
+			return $this->models_with_datetime_fields;
342
+		}
343
+
344
+		$all_non_abstract_models = EE_Registry::instance()->non_abstract_db_models;
345
+		foreach ($all_non_abstract_models as $non_abstract_model) {
346
+			// get model instance
347
+			/** @var EEM_Base $non_abstract_model */
348
+			$non_abstract_model = $non_abstract_model::instance();
349
+			if ($non_abstract_model->get_a_field_of_type('EE_Datetime_Field') instanceof EE_Datetime_Field) {
350
+				$this->models_with_datetime_fields[] = get_class($non_abstract_model);
351
+			}
352
+		}
353
+		$this->setModelsToProcess($this->models_with_datetime_fields);
354
+		return $this->models_with_datetime_fields;
355
+	}
356
+
357
+
358
+	/**
359
+	 * This simply records the models that have been processed with our tracking option.
360
+	 *
361
+	 * @param array $models_to_set array of model class names.
362
+	 */
363
+	private function setModelsToProcess($models_to_set)
364
+	{
365
+		update_option(self::MODELS_TO_PROCESS_OPTION_KEY, $models_to_set);
366
+	}
367
+
368
+
369
+	/**
370
+	 * Used to keep track of how many models have been processed for the batch
371
+	 *
372
+	 * @param $count
373
+	 */
374
+	private function updateCountOfModelsProcessed($count = 1)
375
+	{
376
+		$count = $this->getCountOfModelsProcessed() + (int) $count;
377
+		update_option(self::COUNT_OF_MODELS_PROCESSED, $count);
378
+	}
379
+
380
+
381
+	/**
382
+	 * Retrieve the tracked number of models processed between requests.
383
+	 *
384
+	 * @return int
385
+	 */
386
+	private function getCountOfModelsProcessed()
387
+	{
388
+		return (int) get_option(self::COUNT_OF_MODELS_PROCESSED, 0);
389
+	}
390
+
391
+
392
+	/**
393
+	 * Returns the models that are left to process.
394
+	 *
395
+	 * @return array  an array of model class names.
396
+	 */
397
+	private function getModelsToProcess()
398
+	{
399
+		if (empty($this->models_with_datetime_fields)) {
400
+			$this->models_with_datetime_fields = get_option(self::MODELS_TO_PROCESS_OPTION_KEY, array());
401
+		}
402
+		return $this->models_with_datetime_fields;
403
+	}
404
+
405
+
406
+	/**
407
+	 * Used to record the offset that will be applied to dates and times for EE_Datetime_Field columns.
408
+	 *
409
+	 * @param float $offset
410
+	 */
411
+	public static function updateOffset($offset)
412
+	{
413
+		update_option(self::OFFSET_TO_APPLY_OPTION_KEY, $offset);
414
+	}
415
+
416
+
417
+	/**
418
+	 * Used to retrieve the saved offset that will be applied to dates and times for EE_Datetime_Field columns.
419
+	 *
420
+	 * @return float
421
+	 */
422
+	public static function getOffset()
423
+	{
424
+		return (float) get_option(self::OFFSET_TO_APPLY_OPTION_KEY, 0);
425
+	}
426
+
427
+
428
+	/**
429
+	 * Used to set the saved offset range start date.
430
+	 *
431
+	 * @param DbSafeDateTime|null $start_date
432
+	 */
433
+	public static function updateStartDateRange(DbSafeDateTime $start_date = null)
434
+	{
435
+		$date_to_save = $start_date instanceof DbSafeDateTime
436
+			? $start_date->format('U')
437
+			: '';
438
+		update_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, $date_to_save);
439
+	}
440
+
441
+
442
+	/**
443
+	 * Used to get the saved offset range start date.
444
+	 *
445
+	 * @return DbSafeDateTime|null
446
+	 */
447
+	public static function getStartDateRange()
448
+	{
449
+		$start_date = get_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, null);
450
+		try {
451
+			$datetime = DateTime::createFromFormat('U', $start_date, new DateTimeZone('UTC'));
452
+			$start_date = $datetime instanceof DateTime
453
+				? DbSafeDateTime::createFromDateTime($datetime)
454
+				: null;
455
+		} catch (Exception $e) {
456
+			$start_date = null;
457
+		}
458
+		return $start_date;
459
+	}
460
+
461
+
462
+	/**
463
+	 * Used to set the saved offset range end date.
464
+	 *
465
+	 * @param DbSafeDateTime|null $end_date
466
+	 */
467
+	public static function updateEndDateRange(DbSafeDateTime $end_date = null)
468
+	{
469
+		$date_to_save = $end_date instanceof DbSafeDateTime
470
+			? $end_date->format('U')
471
+			: '';
472
+		update_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, $date_to_save);
473
+	}
474
+
475
+
476
+	/**
477
+	 * Used to get the saved offset range end date.
478
+	 *
479
+	 * @return DbSafeDateTime|null
480
+	 */
481
+	public static function getEndDateRange()
482
+	{
483
+		$end_date = get_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, null);
484
+		try {
485
+			$datetime = DateTime::createFromFormat('U', $end_date, new DateTimeZone('UTC'));
486
+			$end_date = $datetime instanceof Datetime
487
+				? DbSafeDateTime::createFromDateTime($datetime)
488
+				: null;
489
+		} catch (Exception $e) {
490
+			$end_date = null;
491
+		}
492
+		return $end_date;
493
+	}
494 494
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -160,19 +160,19 @@  discard block
 block discarded – undo
160 160
         $date_ranges = array();
161 161
         // since some affected models might have two tables, we have to get our tables and set up a query for each table.
162 162
         foreach ($model->get_tables() as $table) {
163
-            $query = 'UPDATE ' . $table->get_table_name();
163
+            $query = 'UPDATE '.$table->get_table_name();
164 164
             $fields_affected = array();
165 165
             $inner_query = array();
166 166
             foreach ($model->_get_fields_for_table($table->get_table_alias()) as $model_field) {
167 167
                 if ($model_field instanceof EE_Datetime_Field) {
168
-                    $inner_query[ $model_field->get_table_column() ] = $model_field->get_table_column() . ' = '
169
-                                                                       . $sql_date_function . '('
168
+                    $inner_query[$model_field->get_table_column()] = $model_field->get_table_column().' = '
169
+                                                                       . $sql_date_function.'('
170 170
                                                                        . $model_field->get_table_column()
171 171
                                                                        . ", INTERVAL {$offset} MINUTE)";
172 172
                     $fields_affected[] = $model_field;
173 173
                 }
174 174
             }
175
-            if (! $fields_affected) {
175
+            if ( ! $fields_affected) {
176 176
                 continue;
177 177
             }
178 178
             // do we do one query per column/field or one query for all fields on the model? It all depends on whether
@@ -189,7 +189,7 @@  discard block
 block discarded – undo
189 189
                     // record error.
190 190
                     $error_message = $wpdb->last_error;
191 191
                     // handle the edgecases where last_error might be empty.
192
-                    if (! $error_message) {
192
+                    if ( ! $error_message) {
193 193
                         $error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
194 194
                     }
195 195
                     $this->recordChangeLog($model, $original_offset, $table, $fields_affected, $error_message);
@@ -222,7 +222,7 @@  discard block
 block discarded – undo
222 222
         foreach ($inner_query as $field_name => $field_query) {
223 223
             $query_to_run = $query;
224 224
             $where_conditions = array();
225
-            $query_to_run .= ' SET ' . $field_query;
225
+            $query_to_run .= ' SET '.$field_query;
226 226
             if ($start_date_range instanceof DbSafeDateTime) {
227 227
                 $start_date = $start_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
228 228
                 $where_conditions[] = "{$field_name} > '{$start_date}'";
@@ -232,17 +232,17 @@  discard block
 block discarded – undo
232 232
                 $where_conditions[] = "{$field_name} < '{$end_date}'";
233 233
             }
234 234
             if ($where_conditions) {
235
-                $query_to_run .= ' WHERE ' . implode(' AND ', $where_conditions);
235
+                $query_to_run .= ' WHERE '.implode(' AND ', $where_conditions);
236 236
             }
237 237
             $result = $wpdb->query($query_to_run);
238 238
             if ($result === false) {
239 239
                 // record error.
240 240
                 $error_message = $wpdb->last_error;
241 241
                 // handle the edgecases where last_error might be empty.
242
-                if (! $error_message) {
242
+                if ( ! $error_message) {
243 243
                     $error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
244 244
                 }
245
-                $errors[ $field_name ] = $error_message;
245
+                $errors[$field_name] = $error_message;
246 246
             }
247 247
         }
248 248
         return $errors;
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
     private function doQueryForAllFields($query, array $inner_query)
260 260
     {
261 261
         global $wpdb;
262
-        $query .= ' SET ' . implode(',', $inner_query);
262
+        $query .= ' SET '.implode(',', $inner_query);
263 263
         return $wpdb->query($query);
264 264
     }
265 265
 
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
         $fields = array();
286 286
         /** @var EE_Datetime_Field $model_field */
287 287
         foreach ($model_fields_affected as $model_field) {
288
-            if (! $model_field instanceof EE_Datetime_Field) {
288
+            if ( ! $model_field instanceof EE_Datetime_Field) {
289 289
                 continue;
290 290
             }
291 291
             $fields[] = $model_field->get_name();
@@ -337,7 +337,7 @@  discard block
 block discarded – undo
337 337
     private function getModelsWithDatetimeFields()
338 338
     {
339 339
         $this->getModelsToProcess();
340
-        if (! empty($this->models_with_datetime_fields)) {
340
+        if ( ! empty($this->models_with_datetime_fields)) {
341 341
             return $this->models_with_datetime_fields;
342 342
         }
343 343
 
Please login to merge, or discard this patch.