Completed
Branch BUG-9625-better-us-phone-valid... (e0ce21)
by
unknown
631:18 queued 616:37
created

Read::validate_context()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 1
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace EventEspresso\core\libraries\rest_api\controllers\model;
3
4
use EventEspresso\core\libraries\rest_api\Capabilities;
5
use EventEspresso\core\libraries\rest_api\Calculated_Model_Fields;
6
use EventEspresso\core\libraries\rest_api\Rest_Exception;
7
use EventEspresso\core\libraries\rest_api\Model_Data_Translator;
8
9
if ( !defined( 'EVENT_ESPRESSO_VERSION' ) ) {
10
	exit( 'No direct script access allowed' );
11
}
12
13
/**
14
 *
15
 * Read controller for models
16
 *
17
 * Handles requests relating to GET-ting model information
18
 *
19
 * @package			Event Espresso
20
 * @subpackage
21
 * @author				Mike Nelson
22
 *
23
 */
24
class Read extends Base {
25
26
27
28
	/**
29
	 *
30
	 * @var Calculated_Model_Fields
31
	 */
32
	protected $_fields_calculator;
33
34
35
36
	/**
37
	 * Read constructor.
38
	 */
39
	public function __construct() {
40
		parent::__construct();
41
		\EE_Registry::instance()->load_helper( 'Inflector' );
42
		$this->_fields_calculator = new Calculated_Model_Fields();
43
	}
44
45
	/**
46
	 * Handles requests to get all (or a filtered subset) of entities for a particular model
47
	 * @param \WP_REST_Request $request
48
	 * @return \WP_REST_Response|\WP_Error
49
	 */
50 View Code Duplication
	public static function handle_request_get_all( \WP_REST_Request $request) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
51
		$controller = new Read();
52
		try{
53
			$matches = $controller->parse_route(
54
				$request->get_route(),
55
				'~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)~',
56
				array( 'version', 'model' )
57
			);
58
			$controller->set_requested_version( $matches[ 'version' ] );
59
			$model_name_singular = \EEH_Inflector::singularize_and_upper( $matches[ 'model' ] );
60
			if ( ! $controller->get_model_version_info()->is_model_name_in_this_version( $model_name_singular ) ) {
61
				return $controller->send_response(
62
					new \WP_Error(
63
						'endpoint_parsing_error',
64
						sprintf(
65
							__( 'There is no model for endpoint %s. Please contact event espresso support', 'event_espresso' ),
66
							$model_name_singular
67
						)
68
					)
69
				);
70
			}
71
			return $controller->send_response(
72
					$controller->get_entities_from_model(
73
							$controller->get_model_version_info()->load_model( $model_name_singular ),
0 ignored issues
show
Documentation introduced by
$controller->get_model_v...l($model_name_singular) is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
74
							$request
75
					)
76
			);
77
		} catch( \Exception $e ) {
78
			return $controller->send_response( $e );
79
		}
80
	}
81
82
	/**
83
	 * Gets a single entity related to the model indicated in the path and its id
84
	 *
85
	 * @param \WP_REST_Request $request
86
	 * @return \WP_REST_Response|\WP_Error
87
	 */
88 View Code Duplication
	public static function handle_request_get_one( \WP_REST_Request $request ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
89
		$controller = new Read();
90
		try{
91
			$matches = $controller->parse_route(
92
				$request->get_route(),
93
				'~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)~',
94
				array( 'version', 'model', 'id' ) );
95
			$controller->set_requested_version( $matches[ 'version' ] );
96
			$model_name_singular = \EEH_Inflector::singularize_and_upper( $matches[ 'model' ] );
97
			if ( ! $controller->get_model_version_info()->is_model_name_in_this_version( $model_name_singular ) ) {
98
				return $controller->send_response(
99
					new \WP_Error(
100
						'endpoint_parsing_error',
101
						sprintf(
102
							__( 'There is no model for endpoint %s. Please contact event espresso support', 'event_espresso' ),
103
							$model_name_singular
104
						)
105
					)
106
				);
107
			}
108
			return $controller->send_response(
109
					$controller->get_entity_from_model(
110
							$controller->get_model_version_info()->load_model( $model_name_singular ),
0 ignored issues
show
Documentation introduced by
$controller->get_model_v...l($model_name_singular) is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
111
							$request
112
						)
113
				);
114
		} catch( \Exception $e ) {
115
			return $controller->send_response( $e );
116
		}
117
	}
118
119
	/**
120
	 *
121
	 * Gets all the related entities (or if its a belongs-to relation just the one)
122
	 * to the item with the given id
123
	 *
124
	 * @param \WP_REST_Request $request
125
	 * @return \WP_REST_Response|\WP_Error
126
	 */
127
	public static function handle_request_get_related( \WP_REST_Request $request ) {
128
		$controller = new Read();
129
		try{
130
			$matches = $controller->parse_route(
131
				$request->get_route(),
132
				'~' . \EED_Core_Rest_Api::ee_api_namespace_for_regex . '(.*)/(.*)/(.*)~',
133
				array( 'version', 'model', 'id', 'related_model' )
134
			);
135
			$controller->set_requested_version( $matches[ 'version' ] );
136
			$main_model_name_singular = \EEH_Inflector::singularize_and_upper( $matches[ 'model' ] );
137
			if ( ! $controller->get_model_version_info()->is_model_name_in_this_version( $main_model_name_singular ) ) {
138
				return $controller->send_response(
139
					new \WP_Error(
140
						'endpoint_parsing_error',
141
						sprintf(
142
							__( 'There is no model for endpoint %s. Please contact event espresso support', 'event_espresso' ),
143
							$main_model_name_singular
144
						)
145
					)
146
				);
147
			}
148
			$main_model = $controller->get_model_version_info()->load_model( $main_model_name_singular );
149
			//assume the related model name is plural and try to find the model's name
150
			$related_model_name_singular = \EEH_Inflector::singularize_and_upper( $matches[ 'related_model' ] );
151
			if ( ! $controller->get_model_version_info()->is_model_name_in_this_version( $related_model_name_singular ) ) {
152
				//so the word didn't singularize well. Maybe that's just because it's a singular word?
153
				$related_model_name_singular = \EEH_Inflector::humanize( $matches[ 'related_model' ] );
154
			}
155
			if ( ! $controller->get_model_version_info()->is_model_name_in_this_version( $related_model_name_singular ) ) {
156
				return $controller->send_response(
157
					new \WP_Error(
158
						'endpoint_parsing_error',
159
						sprintf(
160
							__( 'There is no model for endpoint %s. Please contact event espresso support', 'event_espresso' ),
161
							$related_model_name_singular
162
						)
163
					)
164
				);
165
			}
166
167
			return $controller->send_response(
168
					$controller->get_entities_from_relation(
169
						$request->get_param( 'id' ),
170
						$main_model->related_settings_for( $related_model_name_singular ) ,
0 ignored issues
show
Bug introduced by
The method related_settings_for cannot be called on $main_model (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
171
						$request
172
					)
173
				);
174
		} catch( \Exception $e ) {
175
			return $controller->send_response( $e );
176
		}
177
	}
178
179
180
181
	/**
182
	 * Gets a collection for the given model and filters
183
	 *
184
	 * @param \EEM_Base $model
185
	 * @param \WP_REST_Request $request
186
	 * @return array
187
	 */
188
	public function get_entities_from_model( $model, $request) {
189
		$query_params = $this->create_model_query_params( $model, $request->get_params() );
190
		if( ! Capabilities::current_user_has_partial_access_to( $model, $query_params[ 'caps' ] ) ) {
191
			$model_name_plural = \EEH_Inflector::pluralize_and_lower( $model->get_this_model_name() );
192
			return new \WP_Error(
193
				sprintf( 'rest_%s_cannot_list', $model_name_plural ),
194
				sprintf(
195
					__( 'Sorry, you are not allowed to list %1$s. Missing permissions: %2$s', 'event_espresso' ),
196
					$model_name_plural,
197
					Capabilities::get_missing_permissions_string( $model, $query_params[ 'caps' ] )
198
				),
199
				array( 'status' => 403 )
200
			);
201
		}
202
		if( ! $request->get_header( 'no_rest_headers' ) ) {
203
			$this->_set_headers_from_query_params( $model, $query_params );
204
		}
205
		/** @type array $results */
206
		$results = $model->get_all_wpdb_results( $query_params );
207
		$nice_results = array( );
208
		foreach ( $results as $result ) {
209
			$nice_results[ ] = $this->create_entity_from_wpdb_result(
210
					$model,
211
					$result,
212
					$request
213
				);
214
		}
215
		return $nice_results;
216
	}
217
218
	/**
219
	 * Gets the collection for given relation object
220
	 *
221
	 * The same as Read::get_entities_from_model(), except if the relation
222
	 * is a HABTM relation, in which case it merges any non-foreign-key fields from
223
	 * the join-model-object into the results
224
	 *
225
	 * @param string $id the ID of the thing we are fetching related stuff from
226
	 * @param \EE_Model_Relation_Base $relation
227
	 * @param \WP_REST_Request $request
228
	 * @return array
229
	 */
230
	public function get_entities_from_relation( $id,  $relation, $request ) {
231
		$context = $this->validate_context( $request->get_param( 'caps' ));
232
		$model = $relation->get_this_model();
233
		$related_model = $relation->get_other_model();
234
		//check if they can access the 1st model object
235
		$query_params = array( array( $model->primary_key_name() => $id ),'limit' => 1 );
0 ignored issues
show
Bug introduced by
The method primary_key_name cannot be called on $model (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
236
		if( $model instanceof \EEM_Soft_Delete_Base ){
237
			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
238
		}
239
		$restricted_query_params = $query_params;
240
		$restricted_query_params[ 'caps' ] = $context;
241
		$this->_set_debug_info( 'main model query params', $restricted_query_params );
242
		$this->_set_debug_info( 'missing caps', Capabilities::get_missing_permissions_string( $related_model, $context ) );
0 ignored issues
show
Documentation introduced by
$related_model is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
243
244
		if(
245
			! (
246
				Capabilities::current_user_has_partial_access_to( $related_model, $context )
0 ignored issues
show
Documentation introduced by
$related_model is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
247
				&& $model->exists( $restricted_query_params )
0 ignored issues
show
Bug introduced by
The method exists cannot be called on $model (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
248
			)
249
		){
250
			if( $relation instanceof \EE_Belongs_To_Relation ) {
251
				$related_model_name_maybe_plural = strtolower( $related_model->get_this_model_name() );
0 ignored issues
show
Bug introduced by
The method get_this_model_name cannot be called on $related_model (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
252
			}else{
253
				$related_model_name_maybe_plural = \EEH_Inflector::pluralize_and_lower( $related_model->get_this_model_name() );
0 ignored issues
show
Bug introduced by
The method get_this_model_name cannot be called on $related_model (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
254
			}
255
			return new \WP_Error(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \WP_Error(spr...rray('status' => 403)); (WP_Error) is incompatible with the return type documented by EventEspresso\core\libra..._entities_from_relation of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
256
				sprintf( 'rest_%s_cannot_list', $related_model_name_maybe_plural ),
257
				sprintf(
258
					__(	'Sorry, you are not allowed to list %1$s related to %2$s. Missing permissions: %3$s', 'event_espresso' ),
259
					$related_model_name_maybe_plural,
260
					$relation->get_this_model()->get_this_model_name(),
0 ignored issues
show
Bug introduced by
The method get_this_model_name cannot be called on $relation->get_this_model() (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
261
					implode(
262
						',',
263
						array_keys(
264
							Capabilities::get_missing_permissions( $related_model, $context )
0 ignored issues
show
Documentation introduced by
$related_model is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
265
						)
266
					)
267
				),
268
				array( 'status' => 403 )
269
			);
270
		}
271
		$query_params = $this->create_model_query_params( $relation->get_other_model(), $request->get_params() );
0 ignored issues
show
Documentation introduced by
$relation->get_other_model() is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
272
		$query_params[0][ $relation->get_this_model()->get_this_model_name() . '.' . $relation->get_this_model()->primary_key_name() ] = $id;
0 ignored issues
show
Bug introduced by
The method get_this_model_name cannot be called on $relation->get_this_model() (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug introduced by
The method primary_key_name cannot be called on $relation->get_this_model() (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
273
		$query_params[ 'default_where_conditions' ] = 'none';
274
		$query_params[ 'caps' ] = $context;
275
		if( ! $request->get_header( 'no_rest_headers' ) ) {
276
			$this->_set_headers_from_query_params( $relation->get_other_model(), $query_params );
0 ignored issues
show
Documentation introduced by
$relation->get_other_model() is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
277
		}
278
		/** @type array $results */
279
		$results = $relation->get_other_model()->get_all_wpdb_results( $query_params );
0 ignored issues
show
Bug introduced by
The method get_all_wpdb_results cannot be called on $relation->get_other_model() (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
280
		$nice_results = array();
281
		foreach( $results as $result ) {
282
			$nice_result = $this->create_entity_from_wpdb_result(
283
				$relation->get_other_model(),
0 ignored issues
show
Documentation introduced by
$relation->get_other_model() is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
284
				$result,
285
				$request
286
			);
287
			if( $relation instanceof \EE_HABTM_Relation ) {
288
				//put the unusual stuff (properties from the HABTM relation) first, and make sure
289
				//if there are conflicts we prefer the properties from the main model
290
				$join_model_result = $this->create_entity_from_wpdb_result(
291
					$relation->get_join_model(),
0 ignored issues
show
Documentation introduced by
$relation->get_join_model() is of type boolean, but the function expects a object<EEM_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
292
					$result,
293
					$request
294
				);
295
				$joined_result = array_merge( $nice_result, $join_model_result );
296
				//but keep the meta stuff from the main model
297
				if( isset( $nice_result['meta'] ) ){
298
					$joined_result['meta'] = $nice_result['meta'];
299
				}
300
				$nice_result = $joined_result;
301
			}
302
			$nice_results[] = $nice_result;
303
		}
304
		if( $relation instanceof \EE_Belongs_To_Relation ){
305
			return array_shift( $nice_results );
306
		}else{
307
			return $nice_results;
308
		}
309
	}
310
311
	/**
312
	 * Sets the headers that are based on the model and query params,
313
	 * like the total records. This should only be called on the original request
314
	 * from the client, not on subsequent internal
315
	 * @param \EEM_Base $model
316
	 * @param array $query_params
317
	 * @return void
318
	 */
319
	protected function _set_headers_from_query_params( $model, $query_params ) {
320
		$this->_set_debug_info( 'model query params', $query_params );
321
		$this->_set_debug_info( 'missing caps', Capabilities::get_missing_permissions_string( $model, $query_params[ 'caps' ] ) );
322
		//normally the limit to a 2-part array, where the 2nd item is the limit
323
		if( ! isset( $query_params[ 'limit' ] ) ) {
324
			$query_params[ 'limit' ] = \EED_Core_Rest_Api::get_default_query_limit();
325
		}
326
		if( is_array( $query_params[ 'limit' ] )  ) {
327
			$limit_parts = $query_params[ 'limit' ];
328
		} else {
329
			$limit_parts = explode(',', $query_params[ 'limit' ] );
330
			if( count( $limit_parts ) == 1 ){
331
				$limit_parts = array(0, $limit_parts[ 0 ] );
332
			}
333
		}
334
		//remove the group by and having parts of the query, as those will
335
		//make the sql query return an array of values, instead of just a single value
336
		unset( $query_params[ 'group_by' ], $query_params[ 'having' ], $query_params[ 'limit' ] );
337
		$count = $model->count( $query_params, null, true );
338
339
		$pages = $count / $limit_parts[ 1 ];
340
		$this->_set_response_header( 'Total', $count, false );
341
		$this->_set_response_header( 'PageSize', $limit_parts[ 1 ], false );
342
		$this->_set_response_header( 'TotalPages', ceil( $pages ), false );
343
	}
344
345
346
347
	/**
348
	 * Changes database results into REST API entities
349
	 * @param \EEM_Base $model
350
	 * @param array $db_row like results from $wpdb->get_results()
351
	 * @param \WP_REST_Request $rest_request
352
	 * @param string $deprecated no longer used
353
	 * @return array ready for being converted into json for sending to client
354
	 */
355
	public function create_entity_from_wpdb_result( $model, $db_row, $rest_request, $deprecated = null ) {
356
		if( ! $rest_request instanceof \WP_REST_Request ) {
0 ignored issues
show
Bug introduced by
The class WP_REST_Request does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
357
			//ok so this was called in the old style, where the 3rd arg was
358
			//$include, and the 4th arg was $context
359
			//now setup the request just to avoid fatal errors, although we won't be able
360
			//to truly make use of it because it's kinda devoid of info
361
			$rest_request = new \WP_REST_Request();
362
			$rest_request->set_param( 'include', $rest_request );
363
			$rest_request->set_param( 'caps', $deprecated );
364
		}
365
		if( $rest_request->get_param( 'caps' ) == null ) {
366
			$rest_request->set_param( 'caps', \EEM_Base::caps_read );
367
		}
368
		$entity_array = $this->_create_bare_entity_from_wpdb_results( $model, $db_row );
369
		$entity_array = $this->_add_extra_fields( $model, $db_row, $entity_array );
370
		$entity_array[ '_links' ] = $this->_get_entity_links( $model, $db_row, $entity_array );
371
		$entity_array[ '_calculated_fields'] = $this->_get_entity_calculations( $model, $db_row, $rest_request );
372
		$entity_array = $this->_include_requested_models( $model, $rest_request, $entity_array );
373
		$entity_array = apply_filters(
374
			'FHEE__Read__create_entity_from_wpdb_results__entity_before_inaccessible_field_removal',
375
			$entity_array,
376
			$model,
377
			$rest_request->get_param( 'caps' ),
378
			$rest_request,
379
			$this
380
		);
381
		$result_without_inaccessible_fields = Capabilities::filter_out_inaccessible_entity_fields(
382
			$entity_array,
383
			$model,
384
			$rest_request->get_param( 'caps' ),
385
			$this->get_model_version_info()
386
		);
387
		$this->_set_debug_info(
388
			'inaccessible fields',
389
			array_keys( array_diff_key( $entity_array, $result_without_inaccessible_fields ) )
390
		);
391
		return apply_filters(
392
			'FHEE__Read__create_entity_from_wpdb_results__entity_return',
393
			$result_without_inaccessible_fields,
394
			$model,
395
			$rest_request->get_param( 'caps' )
396
		);
397
	}
398
399
	/**
400
	 * Creates a REST entity array (JSON object we're going to return in the response, but
401
	 * for now still a PHP array, but soon enough we'll call json_encode on it, don't worry),
402
	 * from $wpdb->get_row( $sql, ARRAY_A)
403
	 * @param \EEM_Base $model
404
	 * @param array $db_row
405
	 * @return array entity mostly ready for converting to JSON and sending in the response
406
	 */
407
	protected function _create_bare_entity_from_wpdb_results( \EEM_Base $model, $db_row ) {
408
		$result = $model->deduce_fields_n_values_from_cols_n_values( $db_row );
409
		$result = array_intersect_key( $result, $this->get_model_version_info()->fields_on_model_in_this_version( $model ) );
410
		foreach( $result as $field_name => $raw_field_value ) {
411
			$field_obj = $model->field_settings_for($field_name);
412
			$field_value = $field_obj->prepare_for_set_from_db( $raw_field_value );
413
			if( $this->is_subclass_of_one(  $field_obj, $this->get_model_version_info()->fields_ignored() ) ){
414
				unset( $result[ $field_name ] );
415
			}elseif(
416
				$this->is_subclass_of_one( $field_obj, $this->get_model_version_info()->fields_that_have_rendered_format() )
417
			){
418
				$result[ $field_name ] = array(
419
					'raw' => $field_obj->prepare_for_get( $field_value ),
420
					'rendered' => $field_obj->prepare_for_pretty_echoing( $field_value )
421
				);
422
			}elseif(
423
				$this->is_subclass_of_one( $field_obj, $this->get_model_version_info()->fields_that_have_pretty_format() )
424
			){
425
				$result[ $field_name ] = array(
426
					'raw' => $field_obj->prepare_for_get( $field_value ),
427
					'pretty' => $field_obj->prepare_for_pretty_echoing( $field_value )
428
				);
429
			} elseif ( $field_obj instanceof \EE_Datetime_Field ) {
430
				$result[ $field_name ] = Model_Data_Translator::prepare_field_value_for_json(
431
					$field_obj,
432
					$field_value,
433
					$this->get_model_version_info()->requested_version()
434
				);
435
			} else {
436
				$result[ $field_name ] = Model_Data_Translator::prepare_field_value_for_json(
437
					$field_obj,
438
					$field_obj->prepare_for_get( $field_value ),
439
					$this->get_model_version_info()->requested_version()
440
				);
441
			}
442
		}
443
		return $result;
444
	}
445
446
	/**
447
	 * Adds a few extra fields to the entity response
448
	 * @param \EEM_Base $model
449
	 * @param array $db_row
450
	 * @param array $entity_array
451
	 * @return array modified entity
452
	 */
453
	protected function _add_extra_fields( \EEM_Base $model, $db_row, $entity_array ) {
454
		if( $model instanceof \EEM_CPT_Base ) {
455
			$entity_array[ 'link' ] = get_permalink( $db_row[ $model->get_primary_key_field()->get_qualified_column() ] );
456
		}
457
		return $entity_array;
458
	}
459
460
	/**
461
	 * Gets links we want to add to the response
462
	 *
463
*@global \WP_REST_Server $wp_rest_server
464
	 * @param \EEM_Base $model
465
	 * @param array $db_row
466
	 * @param array $entity_array
467
	 * @return array the _links item in the entity
468
	 */
469
	protected function _get_entity_links( $model, $db_row, $entity_array ) {
470
		//add basic links
471
		$links = array(
472
			'self' => array(
473
				array(
474
					'href' => $this->get_versioned_link_to(
475
						\EEH_Inflector::pluralize_and_lower( $model->get_this_model_name() ) . '/' . $entity_array[ $model->primary_key_name() ]
476
					)
477
				)
478
			),
479
			'collection' => array(
480
				array(
481
					'href' => $this->get_versioned_link_to(
482
						\EEH_Inflector::pluralize_and_lower( $model->get_this_model_name() )
483
					)
484
				)
485
			),
486
		);
487
488
		//add link to the wp core endpoint, if wp api is active
489
		global $wp_rest_server;
490
		if( $model instanceof \EEM_CPT_Base &&
491
			$wp_rest_server instanceof \WP_REST_Server &&
0 ignored issues
show
Bug introduced by
The class WP_REST_Server does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
492
			$wp_rest_server->get_route_options( '/wp/v2/posts' ) ) {
493
			$links[ \EED_Core_Rest_Api::ee_api_link_namespace . 'self_wp_post' ] = array(
494
				array(
495
					'href' => rest_url( '/wp/v2/posts/' . $db_row[ $model->get_primary_key_field()->get_qualified_column() ] ),
496
					'single' => true
497
				)
498
			);
499
		}
500
501
		//add links to related models
502
		foreach( $this->get_model_version_info()->relation_settings( $model ) as $relation_name => $relation_obj ) {
503
			$related_model_part = Read::get_related_entity_name( $relation_name, $relation_obj );
504
			$links[ \EED_Core_Rest_Api::ee_api_link_namespace . $related_model_part ] = array(
505
				array(
506
					'href' => $this->get_versioned_link_to(
507
						\EEH_Inflector::pluralize_and_lower( $model->get_this_model_name() ) . '/' . $entity_array[ $model->primary_key_name() ] . '/' . $related_model_part
508
					),
509
					'single' => $relation_obj instanceof \EE_Belongs_To_Relation ? true : false
510
				)
511
			);
512
		}
513
		return $links;
514
	}
515
516
	/**
517
	 * Adds the included models indicated in the request to the entity provided
518
	 * @param \EEM_Base $model
519
	 * @param \WP_REST_Request $rest_request
520
	 * @param array $entity_array
521
	 * @return array the modified entity
522
	 */
523
	protected function _include_requested_models( \EEM_Base $model, \WP_REST_Request $rest_request, $entity_array ) {
524
		$includes_for_this_model = $this->explode_and_get_items_prefixed_with( $rest_request->get_param( 'include' ), '' );
525
		$includes_for_this_model = $this->_remove_model_names_from_array( $includes_for_this_model );
526
		//if they passed in * or didn't specify any includes, return everything
527
		if( ! in_array( '*', $includes_for_this_model )
528
			&& ! empty( $includes_for_this_model ) ) {
529
			if( $model->has_primary_key_field() ) {
530
				//always include the primary key. ya just gotta know that at least
531
				$includes_for_this_model[] = $model->primary_key_name();
532
			}
533
			if( $this->explode_and_get_items_prefixed_with( $rest_request->get_param( 'calculate' ), '' ) ) {
534
				$includes_for_this_model[] = '_calculated_fields';
535
			}
536
			$entity_array = array_intersect_key( $entity_array, array_flip( $includes_for_this_model ) );
537
		}
538
		$relation_settings = $this->get_model_version_info()->relation_settings( $model );
539
		foreach( $relation_settings as $relation_name => $relation_obj ) {
540
			$related_fields_to_include = $this->explode_and_get_items_prefixed_with(
541
				$rest_request->get_param( 'include' ),
542
				$relation_name
543
			);
544
			$related_fields_to_calculate = $this->explode_and_get_items_prefixed_with(
545
				$rest_request->get_param( 'calculate' ),
546
				$relation_name
547
			);
548
			//did they specify they wanted to include a related model, or
549
			//specific fields from a related model?
550
			//or did they specify to calculate a field from a related model?
551
			if( $related_fields_to_include || $related_fields_to_calculate ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $related_fields_to_include of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Bug Best Practice introduced by
The expression $related_fields_to_calculate of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
552
				//if so, we should include at least some part of the related model
553
				$pretend_related_request = new \WP_REST_Request();
554
				$pretend_related_request->set_query_params(
555
					array(
556
						'caps' => $rest_request->get_param( 'caps' ),
557
						'include' => $related_fields_to_include,
558
						'calculate' => $related_fields_to_calculate,
559
					)
560
				);
561
				$pretend_related_request->add_header( 'no_rest_headers', true );
562
				$related_results = $this->get_entities_from_relation(
563
					$entity_array[ $model->primary_key_name() ],
564
					$relation_obj,
565
					$pretend_related_request
566
				);
567
				$entity_array[ Read::get_related_entity_name( $relation_name, $relation_obj ) ] = $related_results instanceof \WP_Error
0 ignored issues
show
Bug introduced by
The class WP_Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
568
					? null
569
					: $related_results;
570
			}
571
		}
572
		return $entity_array;
573
	}
574
575
	/**
576
	 * Returns a new array with all the names of models removed. Eg
577
	 * array( 'Event', 'Datetime.*', 'foobar' ) would become array( 'Datetime.*', 'foobar' )
578
	 * @param array $arr
579
	 * @return array
580
	 */
581
	private function _remove_model_names_from_array( $arr ) {
582
		return array_diff( $arr, array_keys( \EE_Registry::instance()->non_abstract_db_models ) );
583
	}
584
	/**
585
	 * Gets the calculated fields for the response
586
	 *
587
	 * @param \EEM_Base        $model
588
	 * @param array            $wpdb_row
589
	 * @param \WP_REST_Request $rest_request
590
	 * @return array the _calculations item in the entity
591
	 */
592
	protected function _get_entity_calculations( $model, $wpdb_row, $rest_request ) {
593
		$calculated_fields = $this->explode_and_get_items_prefixed_with(
594
			$rest_request->get_param( 'calculate' ),
595
			''
596
		);
597
		//note: setting calculate=* doesn't do anything
598
		$calculated_fields_to_return = new \stdClass();
599
		foreach( $calculated_fields as $field_to_calculate ) {
600
			try{
601
				$calculated_fields_to_return->$field_to_calculate = Model_Data_Translator::prepare_field_value_for_json(
602
					null,
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<EE_Model_Field_Base>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
603
					$this->_fields_calculator->retrieve_calculated_field_value(
604
						$model,
605
						$field_to_calculate,
606
						$wpdb_row,
607
						$rest_request,
608
						$this
609
					),
610
					$this->get_model_version_info()->requested_version()
611
				);
612
			} catch( Rest_Exception $e ) {
613
				//if we don't have permission to read it, just leave it out. but let devs know about the problem
614
				$this->_set_response_header(
615
					'Notices-Field-Calculation-Errors[' . $e->get_string_code() . '][' . $model->get_this_model_name() . '][' . $field_to_calculate . ']',
616
					$e->getMessage(),
617
					true
618
				);
619
			}
620
		}
621
		return $calculated_fields_to_return;
622
	}
623
624
	/**
625
	 * Gets the full URL to the resource, taking the requested version into account
626
	 * @param string $link_part_after_version_and_slash eg "events/10/datetimes"
627
	 * @return string url eg "http://mysite.com/wp-json/ee/v4.6/events/10/datetimes"
628
	 */
629
	public function get_versioned_link_to( $link_part_after_version_and_slash ) {
630
		return rest_url(
631
			\EED_Core_Rest_Api::ee_api_namespace
632
			. $this->get_model_version_info()->requested_version()
633
			. '/'
634
			. $link_part_after_version_and_slash
635
		);
636
	}
637
638
	/**
639
	 * Gets the correct lowercase name for the relation in the API according
640
	 * to the relation's type
641
	 * @param string $relation_name
642
	 * @param \EE_Model_Relation_Base $relation_obj
643
	 * @return string
644
	 */
645
	public static function get_related_entity_name( $relation_name, $relation_obj ){
646
		if( $relation_obj instanceof \EE_Belongs_To_Relation ) {
647
			return strtolower( $relation_name );
648
		}else{
649
			return \EEH_Inflector::pluralize_and_lower( $relation_name );
650
		}
651
	}
652
653
//	public function
654
655
656
	/**
657
	 * Gets the one model object with the specified id for the specified model
658
	 * @param \EEM_Base $model
659
	 * @param \WP_REST_Request $request
660
	 * @return array
661
	 */
662
	public function get_entity_from_model( $model, $request ) {
663
		$query_params = array( array( $model->primary_key_name() => $request->get_param( 'id' ) ),'limit' => 1);
664
		if( $model instanceof \EEM_Soft_Delete_Base ){
665
			$query_params = $model->alter_query_params_so_deleted_and_undeleted_items_included($query_params);
666
		}
667
		$restricted_query_params = $query_params;
668
		$restricted_query_params[ 'caps' ] =  $this->validate_context(  $request->get_param( 'caps' ) );
669
		$this->_set_debug_info( 'model query params', $restricted_query_params );
670
		$model_rows = $model->get_all_wpdb_results( $restricted_query_params );
671
		if ( ! empty ( $model_rows ) ) {
672
			return $this->create_entity_from_wpdb_result(
673
				$model,
674
				array_shift( $model_rows ),
675
				$request );
676
		} else {
677
			//ok let's test to see if we WOULD have found it, had we not had restrictions from missing capabilities
678
			$lowercase_model_name = strtolower( $model->get_this_model_name() );
679
			$model_rows_found_sans_restrictions = $model->get_all_wpdb_results( $query_params );
680
			if( ! empty( $model_rows_found_sans_restrictions ) ) {
681
				//you got shafted- it existed but we didn't want to tell you!
682
				return new \WP_Error(
683
					'rest_user_cannot_read',
684
					sprintf(
685
						__( 'Sorry, you cannot read this %1$s. Missing permissions are: %2$s', 'event_espresso' ),
686
						strtolower( $model->get_this_model_name() ),
687
						Capabilities::get_missing_permissions_string(
688
							$model,
689
							$this->validate_context( $request->get_param( 'caps' ) ) )
690
					),
691
					array( 'status' => 403 )
692
				);
693
			} else {
694
				//it's not you. It just doesn't exist
695
				return new \WP_Error(
696
					sprintf( 'rest_%s_invalid_id', $lowercase_model_name ),
697
					sprintf( __( 'Invalid %s ID.', 'event_espresso' ), $lowercase_model_name ),
698
					array( 'status' => 404 )
699
				);
700
			}
701
		}
702
	}
703
704
	/**
705
	 * If a context is provided which isn't valid, maybe it was added in a future
706
	 * version so just treat it as a default read
707
	 *
708
	 * @param string $context
709
	 * @return string array key of EEM_Base::cap_contexts_to_cap_action_map()
710
	 */
711
	public function validate_context( $context ) {
712
		if( ! $context ) {
713
			$context = \EEM_Base::caps_read;
714
		}
715
		$valid_contexts = \EEM_Base::valid_cap_contexts();
716
		if( in_array( $context, $valid_contexts )  ){
717
			return $context;
718
		}else{
719
			return \EEM_Base::caps_read;
720
		}
721
	}
722
723
724
725
	/**
726
	 * Translates API filter get parameter into $query_params array used by EEM_Base::get_all().
727
	 * Note: right now the query parameter keys for fields (and related fields)
728
	 * can be left as-is, but it's quite possible this will change someday.
729
	 * Also, this method's contents might be candidate for moving to Model_Data_Translator
730
	 *
731
	 * @param \EEM_Base $model
732
	 * @param array     $query_parameters from $_GET parameter @see Read:handle_request_get_all
733
	 * @return array like what EEM_Base::get_all() expects or FALSE to indicate
734
	 *                          that absolutely no results should be returned
735
	 * @throws \EE_Error
736
	 */
737
	public function create_model_query_params( $model, $query_parameters ) {
738
		$model_query_params = array( );
739 View Code Duplication
		if ( isset( $query_parameters[ 'where' ] ) ) {
740
			$model_query_params[ 0 ] = Model_Data_Translator::prepare_conditions_query_params_for_models(
741
				$query_parameters[ 'where' ],
742
				$model,
743
				$this->get_model_version_info()->requested_version()
744
			);
745
		}
746
		if ( isset( $query_parameters[ 'order_by' ] ) ) {
747
			$order_by = $query_parameters[ 'order_by' ];
748
		} elseif ( isset( $query_parameters[ 'orderby' ] ) ) {
749
			$order_by = $query_parameters[ 'orderby' ];
750
		}else{
751
			$order_by = null;
752
		}
753
		if( $order_by !== null ){
754
			$model_query_params[ 'order_by' ] =  $order_by;
755
		}
756
		if ( isset( $query_parameters[ 'group_by' ] ) ) {
757
			$group_by = $query_parameters[ 'group_by' ];
758
		} elseif ( isset( $query_parameters[ 'groupby' ] ) ) {
759
			$group_by = $query_parameters[ 'groupby' ];
760
		}else{
761
			$group_by = array_keys( $model->get_combined_primary_key_fields() );
762
		}
763
		if( $group_by !== null ){
764
			$model_query_params[ 'group_by' ] = $group_by;
765
		}
766 View Code Duplication
		if ( isset( $query_parameters[ 'having' ] ) ) {
767
			$model_query_params[ 'having' ] = Model_Data_Translator::prepare_conditions_query_params_for_models(
768
				$query_parameters[ 'having' ],
769
				$model,
770
				$this->get_model_version_info()->requested_version()
771
			);
772
		}
773
		if ( isset( $query_parameters[ 'order' ] ) ) {
774
			$model_query_params[ 'order' ] = $query_parameters[ 'order' ];
775
		}
776
		if ( isset( $query_parameters[ 'mine' ] ) ){
777
			$model_query_params = $model->alter_query_params_to_only_include_mine( $model_query_params );
778
		}
779
		if( isset( $query_parameters[ 'limit' ] ) ) {
780
			//limit should be either a string like '23' or '23,43', or an array with two items in it
781
			if( ! is_array( $query_parameters[ 'limit' ] ) ) {
782
				$limit_array = explode(',', (string)$query_parameters['limit']);
783
			}else {
784
				$limit_array = $query_parameters[ 'limit' ];
785
			}
786
			$sanitized_limit = array();
787
			foreach( $limit_array as $key => $limit_part ) {
788
				if( $this->_debug_mode && ( ! is_numeric( $limit_part ) || count( $sanitized_limit ) > 2 ) ) {
789
					throw new \EE_Error(
790
						sprintf(
791
							__( 'An invalid limit filter was provided. It was: %s. If the EE4 JSON REST API weren\'t in debug mode, this message would not appear.', 'event_espresso' ),
792
							json_encode( $query_parameters[ 'limit' ] )
793
						)
794
					);
795
				}
796
				$sanitized_limit[] = (int)$limit_part;
797
			}
798
			$model_query_params[ 'limit' ] = implode( ',', $sanitized_limit );
799
		}else{
800
			$model_query_params[ 'limit' ] = \EED_Core_Rest_Api::get_default_query_limit();
801
		}
802
		if( isset( $query_parameters[ 'caps' ] ) ) {
803
			$model_query_params[ 'caps' ] = $this->validate_context( $query_parameters[ 'caps' ] );
804
		}else{
805
			$model_query_params[ 'caps' ] = \EEM_Base::caps_read;
806
		}
807
		return apply_filters( 'FHEE__Read__create_model_query_params', $model_query_params, $query_parameters, $model );
808
	}
809
810
811
812
	/**
813
	 * Changes the REST-style query params for use in the models
814
	 * @deprecated
815
	 * @param \EEM_Base $model
816
	 * @param array     $query_params sub-array from @see EEM_Base::get_all()
817
	 * @return array
818
	 */
819 View Code Duplication
	public function prepare_rest_query_params_key_for_models( $model,  $query_params ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
820
		$model_ready_query_params = array();
821
		foreach( $query_params as $key => $value ) {
822
			if( is_array( $value ) ) {
823
				$model_ready_query_params[ $key ] = $this->prepare_rest_query_params_key_for_models( $model, $value );
0 ignored issues
show
Deprecated Code introduced by
The method EventEspresso\core\libra...params_key_for_models() has been deprecated.

This method has been deprecated.

Loading history...
824
			}else{
825
				$model_ready_query_params[ $key ] = $value;
826
			}
827
		}
828
		return $model_ready_query_params;
829
	}
830
831
832
833
	/**
834
	 * @deprecated
835
	 * @param $model
836
	 * @param $query_params
837
	 * @return array
838
	 */
839 View Code Duplication
	public function prepare_rest_query_params_values_for_models( $model, $query_params ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
840
		$model_ready_query_params = array();
841
		foreach( $query_params as $key => $value ) {
842
			if( is_array( $value ) ) {
843
				$model_ready_query_params[ $key ] = $this->prepare_rest_query_params_values_for_models( $model, $value );
0 ignored issues
show
Deprecated Code introduced by
The method EventEspresso\core\libra...ams_values_for_models() has been deprecated.

This method has been deprecated.

Loading history...
844
			} else {
845
				$model_ready_query_params[ $key ] = $value;
846
			}
847
		}
848
		return $model_ready_query_params;
849
	}
850
851
	/**
852
	 * Explodes the string on commas, and only returns items with $prefix followed by a period.
853
	 * If no prefix is specified, returns items with no period.
854
	 * @param string|array $string_to_explode eg "jibba,jabba, blah, blaabla" or array('jibba', 'jabba' )
855
	 * @param string $prefix "Event" or "foobar"
856
	 * @return array $string_to_exploded exploded on COMMAS, and if a prefix was specified
857
	 * we only return strings starting with that and a period; if no prefix was specified
858
	 * we return all items containing NO periods
859
	 */
860
	public function explode_and_get_items_prefixed_with( $string_to_explode, $prefix ) {
861
		if( is_string( $string_to_explode ) ) {
862
			$exploded_contents = explode( ',', $string_to_explode );
863
		} else if( is_array( $string_to_explode ) ) {
864
			$exploded_contents = $string_to_explode;
865
		} else {
866
			$exploded_contents = array();
867
		}
868
		//if the string was empty, we want an empty array
869
		$exploded_contents = array_filter( $exploded_contents );
870
		$contents_with_prefix = array();
871
		foreach( $exploded_contents as $item ) {
872
			$item = trim( $item );
873
			//if no prefix was provided, so we look for items with no "." in them
874
			if( ! $prefix ) {
875
				//does this item have a period?
876
				if( strpos( $item, '.' ) === false ) {
877
					//if not, then its what we're looking for
878
					$contents_with_prefix[] = $item;
879
				}
880
			} else if( strpos( $item, $prefix . '.' ) === 0 ) {
881
				//this item has the prefix and a period, grab it
882
				$contents_with_prefix[] = substr(
883
					$item,
884
					strpos( $item, $prefix . '.' ) + strlen( $prefix . '.' )
885
					);
886
			} else if( $item === $prefix ) {
887
				//this item is JUST the prefix
888
				//so let's grab everything after, which is a blank string
889
				$contents_with_prefix[] = '';
890
			}
891
		}
892
		return $contents_with_prefix;
893
	}
894
895
	/**
896
	 * @deprecated since 4.8.36.rc.001 You should instead use Read::explode_and_get_items_prefixed_with.
897
	 * Deprecated because its return values were really quite confusing- sometimes it returned
898
	 * an empty array (when the include string was blank or '*') or sometimes it returned
899
	 * array('*') (when you provided a model and a model of that kind was found).
900
	 * Parses the $include_string so we fetch all the field names relating to THIS model
901
	 * (ie have NO period in them), or for the provided model (ie start with the model
902
	 * name and then a period).
903
	 * @param string $include_string @see Read:handle_request_get_all
904
	 * @param string $model_name
905
	 * @return array of fields for this model. If $model_name is provided, then
906
	 * the fields for that model, with the model's name removed from each.
907
	 * If $include_string was blank or '*' returns an empty array
908
	 */
909
	public function extract_includes_for_this_model( $include_string, $model_name = null ) {
910
		if( is_array( $include_string ) ) {
911
			$include_string = implode( ',', $include_string );
912
		}
913
		if( $include_string === '*' || $include_string === '' ) {
914
			return array();
915
		}
916
		$includes = explode( ',', $include_string );
917
		$extracted_fields_to_include = array();
918
		if( $model_name ){
0 ignored issues
show
Bug Best Practice introduced by
The expression $model_name of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
919
			foreach( $includes as $field_to_include ) {
920
				$field_to_include = trim( $field_to_include );
921
				if( strpos( $field_to_include, $model_name . '.' ) === 0 ) {
922
					//found the model name at the exact start
923
					$field_sans_model_name = str_replace( $model_name . '.', '', $field_to_include );
924
					$extracted_fields_to_include[] = $field_sans_model_name;
925
				}elseif( $field_to_include == $model_name ){
926
					$extracted_fields_to_include[] = '*';
927
				}
928
			}
929
		}else{
930
			//look for ones with no period
931
			foreach( $includes as $field_to_include ) {
932
				$field_to_include = trim( $field_to_include );
933
				if (
934
					strpos( $field_to_include, '.' ) === false
935
					&& ! $this->get_model_version_info()->is_model_name_in_this_version( $field_to_include )
936
				) {
937
					$extracted_fields_to_include[] = $field_to_include;
938
				}
939
			}
940
		}
941
		return $extracted_fields_to_include;
942
943
	}
944
}
945
946
947
// End of file Read.php