Completed
Push — develop ( d47cfb...7b174f )
by David
06:38
created

Wordlift_Entity_Service::get_uri()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 11
nc 4
nop 1
dl 0
loc 23
rs 8.5906
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Provide entity-related services.
5
 *
6
 * @since 3.1.0
7
 */
8
class Wordlift_Entity_Service {
9
10
	/**
11
	 * The Log service.
12
	 *
13
	 * @since  3.2.0
14
	 * @access private
15
	 * @var \Wordlift_Log_Service $log The Log service.
16
	 */
17
	private $log;
18
19
	/**
20
	 * The UI service.
21
	 *
22
	 * @since  3.2.0
23
	 * @access private
24
	 * @var \Wordlift_UI_Service $ui_service The UI service.
25
	 */
26
	private $ui_service;
27
28
	/**
29
	 * The entity post type name.
30
	 *
31
	 * @since 3.1.0
32
	 */
33
	const TYPE_NAME = 'entity';
34
35
	/**
36
	 * The alternative label meta key.
37
	 *
38
	 * @since 3.2.0
39
	 */
40
	const ALTERNATIVE_LABEL_META_KEY = '_wl_alt_label';
41
42
	/**
43
	 * The alternative label input template.
44
	 *
45
	 * @since 3.2.0
46
	 */
47
	// TODO: this should be moved to a class that deals with HTML code.
48
	const ALTERNATIVE_LABEL_INPUT_TEMPLATE = '<div class="wl-alternative-label">
49
                <label class="screen-reader-text" id="wl-alternative-label-prompt-text" for="wl-alternative-label">Enter alternative label here</label>
50
                <input name="wl_alternative_label[]" size="30" value="%s" id="wl-alternative-label" type="text">
51
                <button class="button wl-delete-button">%s</button>
52
                </div>';
53
54
	/**
55
	 * A singleton instance of the Entity service.
56
	 *
57
	 * @since  3.2.0
58
	 * @access private
59
	 * @var \Wordlift_Entity_Service $instance A singleton instance of the Entity service.
60
	 */
61
	private static $instance;
62
63
	/**
64
	 * Create a Wordlift_Entity_Service instance.
65
	 *
66
	 * @since 3.2.0
67
	 *
68
	 * @param \Wordlift_UI_Service $ui_service The UI service.
69
	 */
70
	public function __construct( $ui_service ) {
71
72
		$this->log = Wordlift_Log_Service::get_logger( 'Wordlift_Entity_Service' );
73
74
		// Set the UI service.
75
		$this->ui_service = $ui_service;
76
77
		// Set the singleton instance.
78
		self::$instance = $this;
79
80
	}
81
82
	/**
83
	 * Get the singleton instance of the Entity service.
84
	 *
85
	 * @since 3.2.0
86
	 * @return \Wordlift_Entity_Service The singleton instance of the Entity service.
87
	 */
88
	public static function get_instance() {
89
90
		return self::$instance;
91
	}
92
93
	/**
94
	 * Determines whether a post is an entity or not.
95
	 *
96
	 * @since 3.1.0
97
	 *
98
	 * @param int $post_id A post id.
99
	 *
100
	 * @return bool Return true if the post is an entity otherwise false.
101
	 */
102
	public function is_entity( $post_id ) {
103
104
		return ( self::TYPE_NAME === get_post_type( $post_id ) );
105
	}
106
107
	/**
108
	 * Get the proper classification scope for a given entity post
109
	 *
110
	 * @since 3.5.0
111
	 *
112
	 * @param integer $post_id An entity post id.
113
	 *
114
	 * @return string Returns an uri.
115
	 */
116
	public function get_classification_scope_for( $post_id ) {
117
118
		if ( false === $this->is_entity( $post_id ) ) {
119
			return null;
120
		}
121
		// Retrieve the entity type
122
		$entity_type_arr = wl_entity_type_taxonomy_get_type( $post_id );
0 ignored issues
show
Deprecated Code introduced by
The function wl_entity_type_taxonomy_get_type() has been deprecated with message: use Wordlift_Entity_Type_Service::get_instance()->get( $post_id )

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
123
		$entity_type     = str_replace( 'wl-', '', $entity_type_arr['css_class'] );
124
		// Retrieve classification boxes configuration
125
		$classification_boxes = unserialize( WL_CORE_POST_CLASSIFICATION_BOXES );
126
		foreach ( $classification_boxes as $cb ) {
127
			if ( in_array( $entity_type, $cb['registeredTypes'] ) ) {
128
				return $cb['id'];
129
			}
130
		}
131
132
		// or null
133
		return null;
134
135
	}
136
137
138
	public function is_used( $post_id ) {
139
140
		if ( false === $this->is_entity( $post_id ) ) {
141
			return null;
142
		}
143
		// Retrieve the post
144
		$entity = get_post( $post_id );
145
146
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
147
		// Retrieve Wordlift relation instances table name
148
		$table_name = wl_core_get_relation_instances_table_name();
149
150
		// Check is it's referenced / related to another post / entity
151
		$stmt = $wpdb->prepare(
152
			"SELECT COUNT(*) FROM $table_name WHERE  object_id = %d",
153
			$entity->ID
154
		);
155
156
		// Perform the query
157
		$relation_instances = (int) $wpdb->get_var( $stmt );
158
		// If there is at least one relation instance for the current entity, then it's used
159
		if ( 0 < $relation_instances ) {
160
			return true;
161
		}
162
163
		// Check if the entity uri is used as meta_value
164
		$stmt = $wpdb->prepare(
165
			"SELECT COUNT(*) FROM $wpdb->postmeta WHERE post_id != %d AND meta_value = %s",
166
			$entity->ID,
167
			wl_get_entity_uri( $entity->ID )
0 ignored issues
show
Deprecated Code introduced by
The function wl_get_entity_uri() has been deprecated with message: use Wordlift_Entity_Service::get_instance()->get_uri( $post_id )

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
168
		);
169
		// Perform the query
170
		$meta_instances = (int) $wpdb->get_var( $stmt );
171
172
		// If there is at least one meta that refers the current entity uri, then current entity is used
173
		if ( 0 < $meta_instances ) {
174
			return true;
175
		}
176
177
		// If we are here, it means the current entity is not used at the moment
178
		return false;
179
	}
180
181
	/**
182
	 * Determines whether a given uri is an internal uri or not.
183
	 *
184
	 * @since 3.3.2
185
	 *
186
	 * @param int $uri An uri.
187
	 *
188
	 * @return true if the uri internal to the current dataset otherwise false.
189
	 */
190
	public function is_internal_uri( $uri ) {
191
192
		return ( 0 === strrpos( $uri, wl_configuration_get_redlink_dataset_uri() ) );
0 ignored issues
show
Deprecated Code introduced by
The function wl_configuration_get_redlink_dataset_uri() has been deprecated with message: use Wordlift_Configuration_Service::get_instance()->get_dataset_uri();

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
193
	}
194
195
	/**
196
	 * Find entity posts by the entity URI. Entity as searched by their entity URI or same as.
197
	 *
198
	 * @since 3.2.0
199
	 *
200
	 * @param string $uri The entity URI.
201
	 *
202
	 * @return WP_Post|null A WP_Post instance or null if not found.
203
	 */
204
	public function get_entity_post_by_uri( $uri ) {
205
206
		// Check if we've been provided with a value otherwise return null.
207
		if ( empty( $uri ) ) {
208
			return null;
209
		}
210
211
		$query_args = array(
212
			'posts_per_page' => 1,
213
			'post_status'    => 'any',
214
			'post_type'      => self::TYPE_NAME,
215
			'meta_query'     => array(
216
				array(
217
					'key'     => WL_ENTITY_URL_META_NAME,
218
					'value'   => $uri,
219
					'compare' => '=',
220
				),
221
			),
222
		);
223
224
		// Only if the current uri is not an internal uri, entity search is
225
		// performed also looking at sameAs values.
226
		//
227
		// This solve issues like https://github.com/insideout10/wordlift-plugin/issues/237
228
		if ( ! $this->is_internal_uri( $uri ) ) {
229
230
			$query_args['meta_query']['relation'] = 'OR';
231
			$query_args['meta_query'][]           = array(
232
				'key'     => Wordlift_Schema_Service::FIELD_SAME_AS,
233
				'value'   => $uri,
234
				'compare' => '=',
235
			);
236
		}
237
238
		$query = new WP_Query( $query_args );
239
240
		// Get the matching entity posts.
241
		$posts = $query->get_posts();
242
243
		// Return null if no post is found.
244
		if ( 0 === count( $posts ) ) {
245
			return null;
246
		}
247
248
		// Return the found post.
249
		return $posts[0];
250
	}
251
252
	/**
253
	 * Fires once a post has been saved. This function uses the $_REQUEST, therefore
254
	 * we check that the post we're saving is the current post.
255
	 *
256
	 * @see   https://github.com/insideout10/wordlift-plugin/issues/363
257
	 *
258
	 * @since 3.2.0
259
	 *
260
	 * @param int     $post_id Post ID.
261
	 * @param WP_Post $post    Post object.
262
	 * @param bool    $update  Whether this is an existing post being updated or not.
263
	 */
264
	public function save_post( $post_id, $post, $update ) {
0 ignored issues
show
Unused Code introduced by
The parameter $update is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
save_post uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
265
266
		// Avoid doing anything if post is autosave or a revision.
267
268
		if ( wp_is_post_autosave( $post ) || wp_is_post_revision( $post ) ) {
269
			return;
270
		}
271
272
		// We're setting the alternative label that have been provided via the UI
273
		// (in fact we're using $_REQUEST), while save_post may be also called
274
		// programmatically by some other function: we need to check therefore if
275
		// the $post_id in the save_post call matches the post id set in the request.
276
		//
277
		// If this is not the current post being saved or if it's not an entity, return.
278
		if ( ! isset( $_REQUEST['post_ID'] ) || $_REQUEST['post_ID'] != $post_id || ! $this->is_entity( $post_id ) ) {
279
			return;
280
		}
281
282
		// Get the alt labels from the request (or empty array).
283
		$alt_labels = isset( $_REQUEST['wl_alternative_label'] ) ? $_REQUEST['wl_alternative_label'] : array();
284
285
		// Set the alternative labels.
286
		$this->set_alternative_labels( $post_id, $alt_labels );
287
288
	}
289
290
	/**
291
	 * Set the alternative labels.
292
	 *
293
	 * @since 3.2.0
294
	 *
295
	 * @param int   $post_id    The post id.
296
	 * @param array $alt_labels An array of labels.
297
	 */
298
	public function set_alternative_labels( $post_id, $alt_labels ) {
299
300
		// Force $alt_labels to be an array
301
		if ( ! is_array( $alt_labels ) ) {
302
			$alt_labels = array( $alt_labels );
303
		}
304
305
		$this->log->debug( "Setting alternative labels [ post id :: $post_id ][ alt labels :: " . implode( ',', $alt_labels ) . " ]" );
306
307
		// Delete all the existing alternate labels.
308
		delete_post_meta( $post_id, self::ALTERNATIVE_LABEL_META_KEY );
309
310
		// Set the alternative labels.
311
		foreach ( $alt_labels as $alt_label ) {
312
			if ( ! empty( $alt_label ) ) {
313
				add_post_meta( $post_id, self::ALTERNATIVE_LABEL_META_KEY, $alt_label );
314
			}
315
		}
316
317
	}
318
319
	/**
320
	 * Retrieve the alternate labels.
321
	 *
322
	 * @since 3.2.0
323
	 *
324
	 * @param int $post_id Post id.
325
	 *
326
	 * @return mixed An array  of alternative labels.
327
	 */
328
	public function get_alternative_labels( $post_id ) {
329
330
		return get_post_meta( $post_id, self::ALTERNATIVE_LABEL_META_KEY );
331
	}
332
333
	/**
334
	 * Retrieve the labels for an entity, i.e. the title + the synonyms.
335
	 *
336
	 * @since 3.12.0
337
	 *
338
	 * @param int $post_id The entity {@link WP_Post} id.
339
	 *
340
	 * @return array An array with the entity title and labels.
341
	 */
342
	public function get_labels( $post_id ) {
343
344
		return array_merge( (array) get_the_title( $post_id ), $this->get_alternative_labels( $post_id ) );
345
	}
346
347
	/**
348
	 * Fires before the permalink field in the edit form (this event is available in WP from 4.1.0).
349
	 *
350
	 * @since 3.2.0
351
	 *
352
	 * @param WP_Post $post Post object.
353
	 */
354
	public function edit_form_before_permalink( $post ) {
355
356
		// If it's not an entity, return.
357
		if ( ! $this->is_entity( $post->ID ) ) {
358
			return;
359
		}
360
361
		// Print the input template.
362
		$this->ui_service->print_template( 'wl-tmpl-alternative-label-input', $this->get_alternative_label_input() );
363
364
		// Print all the currently set alternative labels.
365
		foreach ( $this->get_alternative_labels( $post->ID ) as $alt_label ) {
366
367
			echo $this->get_alternative_label_input( $alt_label );
368
369
		};
370
371
		// Print the button.
372
		$this->ui_service->print_button( 'wl-add-alternative-labels-button', __( 'Add more titles', 'wordlift' ) );
373
374
	}
375
376
	/**
377
	 * Get the URI for the entity with the specified post id.
378
	 *
379
	 * @since 3.6.0
380
	 *
381
	 * @param int $post_id The entity post id.
382
	 *
383
	 * @return null|string The entity URI or NULL if not found or the dataset URI is not configured.
384
	 */
385
	public function get_uri( $post_id ) {
386
387
		// If a null is given, nothing to do
388
		if ( null == $post_id ) {
389
			return null;
390
		}
391
392
		$uri = get_post_meta( $post_id, WL_ENTITY_URL_META_NAME, true );
393
394
		// If the dataset uri is not properly configured, null is returned
395
		if ( '' === wl_configuration_get_redlink_dataset_uri() ) {
0 ignored issues
show
Deprecated Code introduced by
The function wl_configuration_get_redlink_dataset_uri() has been deprecated with message: use Wordlift_Configuration_Service::get_instance()->get_dataset_uri();

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
396
			return null;
397
		}
398
399
		// Set the URI if it isn't set yet.
400
		$post_status = get_post_status( $post_id );
401
		if ( empty( $uri ) && 'auto-draft' !== $post_status && 'revision' !== $post_status ) {
402
			$uri = wl_build_entity_uri( $post_id );
403
			wl_set_entity_uri( $post_id, $uri );
404
		}
405
406
		return $uri;
407
	}
408
409
410
	/**
411
	 * Get the alternative label input HTML code.
412
	 *
413
	 * @since 3.2.0
414
	 *
415
	 * @param string $value The input value.
416
	 *
417
	 * @return string The input HTML code.
418
	 */
419
	private function get_alternative_label_input( $value = '' ) {
420
421
		return sprintf( self::ALTERNATIVE_LABEL_INPUT_TEMPLATE, esc_attr( $value ), __( 'Delete', 'wordlift' ) );
422
	}
423
424
	/**
425
	 * Get the number of entity posts published in this blog.
426
	 *
427
	 * @since 3.6.0
428
	 *
429
	 * @return int The number of published entity posts.
430
	 */
431
	public function count() {
432
433
		$count = wp_count_posts( self::TYPE_NAME );
434
435
		return $count->publish;
436
	}
437
438
	/**
439
	 * Create a new entity.
440
	 *
441
	 * @since 3.9.0
442
	 *
443
	 * @param string $name     The entity name.
444
	 * @param string $type_uri The entity's type URI.
445
	 * @param null   $logo     The entity logo id (or NULL if none).
446
	 * @param string $status   The post status, by default 'publish'.
447
	 *
448
	 * @return int|WP_Error The entity post id or a {@link WP_Error} in case the `wp_insert_post` call fails.
449
	 */
450
	public function create( $name, $type_uri, $logo = null, $status = 'publish' ) {
451
452
		// Create an entity for the publisher.
453
		$post_id = wp_insert_post( array(
454
			'post_type'    => self::TYPE_NAME,
455
			'post_title'   => $name,
456
			'post_status'  => $status,
457
			'post_content' => '',
458
		) );
459
460
		// Return the error if any.
461
		if ( is_wp_error( $post_id ) ) {
462
			return $post_id;
463
		}
464
465
		// Set the entity logo.
466
		if ( $logo && is_numeric( $logo ) ) {
467
			set_post_thumbnail( $post_id, $logo );
468
		}
469
470
		// Set the entity type.
471
		Wordlift_Entity_Type_Service::get_instance()->set( $post_id, $type_uri );
472
473
		return $post_id;
474
	}
475
476
	/**
477
	 * Get the entities related to the one with the specified id. By default only
478
	 * published entities will be returned.
479
	 *
480
	 * @since 3.10.0
481
	 *
482
	 * @param int    $id          The post id.
483
	 * @param string $post_status The target post status (default = publish).
484
	 *
485
	 * @return array An array of post ids.
486
	 */
487
	public function get_related_entities( $id, $post_status = 'publish' ) {
488
489
		return wl_core_inner_get_related_entities( 'post_ids', $id, null, $post_status );
490
	}
491
492
}
493