Passed
Push — master ( 6b8ca8...3384db )
by Paul
04:57
created

Schema   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 32
dl 0
loc 224
ccs 0
cts 146
cp 0
rs 9.6
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
B getSchemaOptionValue() 0 16 8
A build() 0 16 3
A getReviews() 0 7 3
B buildReview() 0 24 2
A render() 0 6 2
A getRatingValue() 0 3 1
A getThingUrl() 0 3 1
A getThingName() 0 3 1
A getReviewCount() 0 3 1
A getSchemaType() 0 4 1
A getThingDescription() 0 3 1
A store() 0 5 1
A getSchemaOption() 0 9 3
B buildSummary() 0 25 3
A getThingImage() 0 3 1
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use DateTime;
6
use GeminiLabs\SchemaOrg\Review as ReviewSchema;
7
use GeminiLabs\SchemaOrg\Schema as SchemaOrg;
8
use GeminiLabs\SiteReviews\Database;
9
use GeminiLabs\SiteReviews\Database\OptionManager;
10
use GeminiLabs\SiteReviews\Modules\Rating;
11
12
class Schema
13
{
14
	/**
15
	 * @var array
16
	 */
17
	protected $args;
18
19
	/**
20
	 * @var array
21
	 */
22
	protected $reviews;
23
24
	/**
25
	 * @return array
26
	 */
27
	public function build( array $args = [] )
28
	{
29
		$this->args = $args;
30
		$schema = $this->buildSummary( $args );
31
		$reviews = [];
32
		foreach( glsr( Database::class )->getReviews( $this->args )->reviews as $review ) {
33
			$reviews[] = $this->buildReview( $review );
34
		}
35
		if( !empty( $reviews )) {
36
			array_walk( $reviews, function( &$review ) {
37
				unset( $review['@context'] );
38
				unset( $review['itemReviewed'] );
39
			});
40
			$schema['review'] = $reviews;
41
		}
42
		return $schema;
43
	}
44
45
	/**
46
	 * @param object $review
47
	 * @return array
48
	 */
49
	public function buildReview( $review )
50
	{
51
		$schema = SchemaOrg::Review()
52
			->doIf( !in_array( 'title', $this->args['hide'] ), function( ReviewSchema $schema ) use( $review ) {
53
				$schema->name( $review->title );
54
			})
55
			->doIf( !in_array( 'excerpt', $this->args['hide'] ), function( ReviewSchema $schema ) use( $review ) {
56
				$schema->reviewBody( $review->content );
57
			})
58
			->datePublished(( new DateTime( $review->date ))->format( DateTime::ISO8601 ))
0 ignored issues
show
Bug introduced by
new DateTime($review->da...rmat(DateTime::ISO8601) of type string is incompatible with the type DateTimeInterface expected by parameter $datePublished of GeminiLabs\SchemaOrg\CreativeWork::datePublished(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

58
			->datePublished(/** @scrutinizer ignore-type */ ( new DateTime( $review->date ))->format( DateTime::ISO8601 ))
Loading history...
59
			->author( SchemaOrg::Person()
60
				->name( $review->author )
61
			)
62
			->itemReviewed( $this->getSchemaType()
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getSchemaType()->...($this->getThingName()) targeting GeminiLabs\SchemaOrg\Type::__call() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
63
				->name( $this->getThingName() )
64
			);
65
		if( !empty( $review->rating )) {
66
			$schema->reviewRating( SchemaOrg::Rating()
67
				->ratingValue( $review->rating )
68
				->bestRating( Rating::MAX_RATING )
69
				->worstRating( Rating::MIN_RATING )
70
			);
71
		}
72
		return apply_filters( 'site-reviews/schema/Review', $schema->toArray(), $review, $this->args );
73
	}
74
75
	/**
76
	 * @param null|array $args
77
	 * @return array
78
	 */
79
	public function buildSummary( $args = null )
80
	{
81
		if( is_array( $args )) {
82
			$this->args = $args;
83
		}
84
		$schema = $this->getSchemaType()
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getSchemaType()->...ion(...) { /* ... */ }) targeting GeminiLabs\SchemaOrg\Type::__call() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
85
			->doIf( $this->getSchemaOption( 'type' ) == 'Product', function( $schema ) {
0 ignored issues
show
Bug introduced by
The call to GeminiLabs\SiteReviews\M...hema::getSchemaOption() has too few arguments starting with fallback. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

85
			->doIf( $this->/** @scrutinizer ignore-call */ getSchemaOption( 'type' ) == 'Product', function( $schema ) {

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
86
				$schema->setProperty( '@id', $this->getThingUrl() );
87
			})
88
			->name( $this->getThingName() )
89
			->description( $this->getThingDescription() )
90
			->image( $this->getThingImage() )
91
			->url( $this->getThingUrl() );
92
		$count = $this->getReviewCount();
93
		if( !empty( $count )) {
94
			$schema->aggregateRating( SchemaOrg::AggregateRating()
95
				->ratingValue( $this->getRatingValue() )
96
				->reviewCount( $count )
97
				->bestRating( Rating::MAX_RATING )
98
				->worstRating( Rating::MIN_RATING )
99
			);
100
		}
101
		$schema = $schema->toArray();
102
		$args = wp_parse_args( ['count' => -1], $this->args );
103
		return apply_filters( sprintf( 'site-reviews/schema/%s', $schema['@type'] ), $schema, $args );
104
	}
105
106
	/**
107
	 * @return void
108
	 */
109
	public function render()
110
	{
111
		if( is_null( glsr()->schemas ))return;
112
		printf( '<script type="application/ld+json">%s</script>', json_encode(
113
			apply_filters( 'site-reviews/schema/all', glsr()->schemas ),
114
			JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
115
		));
116
	}
117
118
	/**
119
	 * @return void
120
	 */
121
	public function store( array $schema )
122
	{
123
		$schemas = (array) glsr()->schemas;
124
		$schemas[] = $schema;
125
		glsr()->schemas = array_map( 'unserialize', array_unique( array_map( 'serialize', $schemas )));
126
	}
127
128
	/**
129
	 * @return int|float
130
	 */
131
	protected function getRatingValue()
132
	{
133
		return glsr( Rating::class )->getAverage( $this->getReviews() );
134
	}
135
136
	/**
137
	 * @return int
138
	 */
139
	protected function getReviewCount()
140
	{
141
		return count( $this->getReviews() );
142
	}
143
144
	/**
145
	 * Get all reviews possible for given args
146
	 * @return array
147
	 */
148
	protected function getReviews( $force = false )
149
	{
150
		if( !is_array( $this->reviews ) || $force ) {
0 ignored issues
show
introduced by
The condition is_array($this->reviews) is always true.
Loading history...
151
			$args = wp_parse_args( ['count' => -1], $this->args );
152
			$this->reviews = glsr( Database::class )->getReviews( $args )->reviews;
153
		}
154
		return $this->reviews;
155
	}
156
157
	/**
158
	 * @param string $option
159
	 * @param string $fallback
160
	 * @return string
161
	 */
162
	protected function getSchemaOption( $option, $fallback )
163
	{
164
		if( $schemaOption = trim( get_post_meta( get_the_ID(), 'schema_'.$option, true ))) {
0 ignored issues
show
Bug introduced by
It seems like get_post_meta(get_the_ID...hema_' . $option, true) can also be of type false; however, parameter $str of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

164
		if( $schemaOption = trim( /** @scrutinizer ignore-type */ get_post_meta( get_the_ID(), 'schema_'.$option, true ))) {
Loading history...
Bug introduced by
It seems like get_the_ID() can also be of type false; however, parameter $post_id of get_post_meta() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

164
		if( $schemaOption = trim( get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), 'schema_'.$option, true ))) {
Loading history...
165
			return $schemaOption;
166
		}
167
		$default = glsr( OptionManager::class )->get( 'settings.reviews.schema.'.$option.'.default', $fallback );
168
		return $default == 'custom'
169
			? glsr( OptionManager::class )->get( 'settings.reviews.schema.'.$option.'.custom', $fallback )
170
			: $default;
171
	}
172
173
	/**
174
	 * @param string $option
175
	 * @param string $fallback
176
	 * @return null|string
177
	 */
178
	protected function getSchemaOptionValue( $option, $fallback = 'post' )
179
	{
180
		$value = $this->getSchemaOption( $option, $fallback );
181
		if( $value != $fallback ) {
182
			return $value;
183
		}
184
		if( !is_single() && !is_page() )return;
185
		switch( $option ) {
186
			case 'description':
187
				return get_the_excerpt();
188
			case 'image':
189
				return (string)get_the_post_thumbnail_url( null, 'large' );
190
			case 'name':
191
				return get_the_title();
192
			case 'url':
193
				return (string)get_the_permalink();
194
		}
195
	}
196
197
	/**
198
	 * @return \GeminiLabs\SchemaOrg\Type
199
	 */
200
	protected function getSchemaType()
201
	{
202
		$type = $this->getSchemaOption( 'type', 'LocalBusiness' );
203
		return SchemaOrg::$type( $type );
204
	}
205
206
	/**
207
	 * @return null|string
208
	 */
209
	protected function getThingDescription()
210
	{
211
		return $this->getSchemaOptionValue( 'description' );
212
	}
213
214
	/**
215
	 * @return null|string
216
	 */
217
	protected function getThingImage()
218
	{
219
		return $this->getSchemaOptionValue( 'image' );
220
	}
221
222
	/**
223
	 * @return null|string
224
	 */
225
	protected function getThingName()
226
	{
227
		return $this->getSchemaOptionValue( 'name' );
228
	}
229
230
	/**
231
	 * @return null|string
232
	 */
233
	protected function getThingUrl()
234
	{
235
		return $this->getSchemaOptionValue( 'url' );
236
	}
237
}
238