Completed
Push — develop ( f11ef2...d41b65 )
by David
06:01 queued 11s
created

Wordlift_Entity_Uri_Service::get_entity()   B

Complexity

Conditions 6
Paths 11

Size

Total Lines 65

Duplication

Lines 9
Ratio 13.85 %

Importance

Changes 0
Metric Value
cc 6
nc 11
nop 1
dl 9
loc 65
rs 8.1414
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Services: Entity Uri Service
4
 *
5
 * Provides access to entities' URIs, i.e. URIs stored as `entity_url` (the main
6
 * entity item ID) or as `same_as`.
7
 *
8
 * @since      3.16.3
9
 * @package    Wordlift
10
 * @subpackage Wordlift/includes
11
 */
12
13
/**
14
 * Define the {@link Wordlift_Entity_Uri_Service} class.
15
 *
16
 * @since 3.16.3
17
 */
18
class Wordlift_Entity_Uri_Service {
19
20
	/**
21
	 * Holds the {@link Wordlift_Entity_Uri_Service} instance.
22
	 *
23
	 * @since 3.21.5
24
	 * @access private
25
	 * @var Wordlift_Entity_Uri_Service $instance The {@link Wordlift_Entity_Uri_Service} singleton.
26
	 */
27
	private static $instance;
28
29
	/**
30
	 * A {@link Wordlift_Log_Service} instance.
31
	 *
32
	 * @since  3.16.3
33
	 * @access private
34
	 * @var \Wordlift_Log_Service $log A {@link Wordlift_Log_Service} instance.
35
	 */
36
	private $log;
37
38
	/**
39
	 * The {@link Wordlift_Configuration_Service} instance.
40
	 *
41
	 * @since  3.16.3
42
	 * @access private
43
	 * @var \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
44
	 */
45
	private $configuration_service;
46
47
	/**
48
	 * An array of URIs to post ID valid for the current request.
49
	 *
50
	 * @since  3.16.3
51
	 * @access private
52
	 * @var array $uri_to_post An array of URIs to post ID valid for the current request.
53
	 */
54
	protected $uri_to_post;
55
56
	/**
57
	 * Create a {@link Wordlift_Entity_Uri_Service} instance.
58
	 *
59
	 * @param \Wordlift_Configuration_Service $configuration_service The {@link Wordlift_Configuration_Service} instance.
60
	 *
61
	 * @since 3.16.3
62
	 *
63
	 */
64
	public function __construct( $configuration_service ) {
65
66
		$this->log = Wordlift_Log_Service::get_logger( get_class() );
67
68
		$this->configuration_service = $configuration_service;
69
70
		// Add a filter to the `rest_post_dispatch` filter to add the wl_entity_url meta as `wl:entity_url`.
71
		add_filter( 'rest_post_dispatch', array( $this, 'rest_post_dispatch' ) );
72
73
		self::$instance = $this;
74
75
	}
76
77
	/**
78
	 * Get the singleton.
79
	 *
80
	 * @return Wordlift_Entity_Uri_Service The singleton instance.
81
	 * @since 3.21.5
82
	 */
83
	public static function get_instance() {
84
85
		return self::$instance;
86
	}
87
88
	/**
89
	 * Preload the provided URIs in the local cache.
90
	 *
91
	 * This function will populate the local `$uri_to_post` array by running a
92
	 * single query with all the URIs and returning the mappings in the array.
93
	 *
94
	 * @param array $uris An array of URIs.
95
	 *
96
	 * @since 3.16.3
97
	 *
98
	 */
99
	public function preload_uris( $uris ) {
100
101
		// Bail out if there are no URIs.
102
		if ( 0 === count( $uris ) ) {
103
			return;
104
		}
105
106
		$this->log->trace( 'Preloading ' . count( $uris ) . ' URI(s)...' );
107
108
		$that          = $this;
109
		$external_uris = array_filter( $uris, function ( $item ) use ( $that ) {
110
			return ! $that->is_internal( $item );
111
		} );
112
113
		$query_args = array(
114
			// See https://github.com/insideout10/wordlift-plugin/issues/654.
115
			'ignore_sticky_posts' => 1,
116
			'cache_results'       => false,
117
			'numberposts'         => - 1,
118
			'post_status'         => 'any',
119
			'post_type'           => Wordlift_Entity_Service::valid_entity_post_types(),
120
			'meta_query'          => array(
121
				array(
122
					'key'     => WL_ENTITY_URL_META_NAME,
123
					'value'   => $uris,
124
					'compare' => 'IN',
125
				),
126
			),
127
		);
128
129
		// Only if the current uri is not an internal uri, entity search is
130
		// performed also looking at sameAs values.
131
		//
132
		// This solve issues like https://github.com/insideout10/wordlift-plugin/issues/237
133 View Code Duplication
		if ( 0 < count( $external_uris ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
134
135
			$query_args['meta_query']['relation'] = 'OR';
136
			$query_args['meta_query'][]           = array(
137
				'key'     => Wordlift_Schema_Service::FIELD_SAME_AS,
138
				'value'   => $external_uris,
139
				'compare' => 'IN',
140
			);
141
142
		}
143
144
		// Get the posts.
145
		$posts = get_posts( $query_args );
146
147
		// Populate the array. We reinitialize the array on purpose because
148
		// we don't want these data to long live.
149
		$this->uri_to_post = array_reduce( $posts, function ( $carry, $item ) use ( $that ) {
0 ignored issues
show
Documentation Bug introduced by
It seems like array_reduce($posts, fun...is, $item); }, array()) of type * is incompatible with the declared type array of property $uri_to_post.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
150
			$uris = array_merge(
151
				get_post_meta( $item->ID, WL_ENTITY_URL_META_NAME ),
152
				get_post_meta( $item->ID, Wordlift_Schema_Service::FIELD_SAME_AS )
153
			);
154
155
			return $carry
156
			       // Get the URI related to the post and fill them with the item id.
157
			       + array_fill_keys( $uris, $item );
158
		}, array() );
159
160
		// Add the not found URIs.
161
		$this->uri_to_post += array_fill_keys( $uris, null );
162
163
		$this->log->debug( count( $this->uri_to_post ) . " URI(s) preloaded." );
164
165
	}
166
167
	/**
168
	 * Reset the URI to post local cache.
169
	 *
170
	 * @since 3.16.3
171
	 */
172
	public function reset_uris() {
173
174
		$this->uri_to_post = array();
175
176
	}
177
178
	/**
179
	 * Find entity posts by the entity URI. Entity as searched by their entity URI or same as.
180
	 *
181
	 * @param string $uri The entity URI.
182
	 *
183
	 * @return WP_Post|null A WP_Post instance or null if not found.
184
	 * @since 3.2.0
185
	 *
186
	 */
187
	public function get_entity( $uri ) {
188
189
		$this->log->trace( "Getting an entity post for URI $uri..." );
190
191
		// Check if we've been provided with a value otherwise return null.
192
		if ( empty( $uri ) ) {
193
			return null;
194
		}
195
196
		$this->log->debug( "Querying post for $uri..." );
197
198
		$query_args = array(
199
			// See https://github.com/insideout10/wordlift-plugin/issues/654.
200
			'ignore_sticky_posts' => 1,
201
			'posts_per_page'      => 1,
202
			'post_status'         => 'any',
203
			'post_type'           => Wordlift_Entity_Service::valid_entity_post_types(),
204
			'meta_query'          => array(
205
				array(
206
					'key'     => WL_ENTITY_URL_META_NAME,
207
					'value'   => $uri,
208
					'compare' => '=',
209
				),
210
			),
211
		);
212
213
		// Only if the current uri is not an internal uri, entity search is
214
		// performed also looking at sameAs values.
215
		//
216
		// This solve issues like https://github.com/insideout10/wordlift-plugin/issues/237
217 View Code Duplication
		if ( ! $this->is_internal( $uri ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
218
219
			$query_args['meta_query']['relation'] = 'OR';
220
			$query_args['meta_query'][]           = array(
221
				'key'     => Wordlift_Schema_Service::FIELD_SAME_AS,
222
				'value'   => $uri,
223
				'compare' => '=',
224
			);
225
		}
226
227
		$posts = get_posts( $query_args );
228
229
		// Attempt to find post by URI (only for local entity URLs)
230
		if ( empty( $posts ) ) {
231
232
			$this->log->debug( "Finding post by $uri..." );
233
			$postid = url_to_postid( $uri );
234
			if ( $postid !== 0 ) {
235
				$this->log->trace( "Found post $postid by URL" );
236
237
				return get_post( $postid );
238
			}
239
240
		}
241
242
		// Return null if no post is found.
243
		if ( empty( $posts ) ) {
244
			$this->log->warn( "No post for URI $uri." );
245
246
			return null;
247
		}
248
249
		// Return the found post.
250
		return current( $posts );
251
	}
252
253
	/**
254
	 * Determines whether a given uri is an internal uri or not.
255
	 *
256
	 * @param string $uri An uri.
257
	 *
258
	 * @return true if the uri internal to the current dataset otherwise false.
259
	 * @since 3.16.3
260
	 *
261
	 */
262
	public function is_internal( $uri ) {
263
264
		return ( 0 === strrpos( $uri, (string) $this->configuration_service->get_dataset_uri() ) );
265
	}
266
267
	/**
268
	 * Hook to `rest_post_dispatch` to alter the response and add the `wl_entity_url` post meta as `wl:entity_url`.
269
	 *
270
	 * We're using this filter instead of the well known `register_meta` / `register_rest_field` because we still need
271
	 * to provide full compatibility with WordPress 4.4+.
272
	 *
273
	 * @param WP_HTTP_Response $result Result to send to the client. Usually a WP_REST_Response.
274
	 *
275
	 * @return WP_HTTP_Response The result to send to the client.
276
	 *
277
	 * @since 3.23.0
278
	 */
279
	public function rest_post_dispatch( $result ) {
280
281
		// Get a reference to the actual data.
282
		$data = &$result->data;
283
284
		// Bail out if we don't have the required parameters, or if the type is not a valid entity.
285
		if ( ! is_array( $data ) || ! isset( $data['id'] ) || ! isset( $data['type'] )
286
		     || ! Wordlift_Entity_Type_Service::is_valid_entity_post_type( $data['type'] ) ) {
287
			return $result;
288
		}
289
290
		// Add the `wl:entity_url`.
291
		$data['wl:entity_url'] = Wordlift_Entity_Service::get_instance()->get_uri( $data['id'] );
292
293
		return $result;
294
	}
295
296
}
297