Passed
Push — master ( 227e6c...6addba )
by Paul
03:57
created

BaseType::addProperties()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 6
ccs 0
cts 6
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules\Schema;
4
5
use ArrayAccess;
6
use DateTime;
7
use JsonSerializable;
8
use ReflectionClass;
9
use DateTimeInterface;
10
use GeminiLabs\SiteReviews\Helper;
11
use GeminiLabs\SiteReviews\Modules\Schema\Type;
12
use GeminiLabs\SiteReviews\Modules\Schema\Exceptions\InvalidProperty;
13
14
abstract class BaseType implements ArrayAccess, JsonSerializable, Type
15
{
16
	/**
17
	 * @var array
18
	 */
19
	public $allowed = [];
20
21
	/**
22
	 * @var array
23
	 */
24
	public $parents = [];
25
26
	/**
27
	 * @var array
28
	 */
29
	protected $properties = [];
30
31
	/**
32
	 * @var string
33
	 */
34
	protected $type;
35
36
	/**
37
	 * @param string $method
38
	 * @return static
39
	 */
40
	public function __call( $method, array $arguments )
41
	{
42
		return $this->setProperty( $method, $arguments[0] ?? '' );
43
	}
44
45
	/**
46
	 * @param string $type
47
	 */
48
	public function __construct( $type = null )
49
	{
50
		$this->type = !is_string( $type )
51
			? (new ReflectionClass( $this ))->getShortName()
52
			: $type;
53
		$this->setAllowedProperties();
54
	}
55
56
	/**
57
	 * @return string
58
	 */
59
	public function __toString()
60
	{
61
		return $this->toScript();
62
	}
63
64
	/**
65
	 * @return static
66
	 */
67
	public function addProperties( array $properties )
68
	{
69
		foreach( $properties as $property => $value ) {
70
			$this->setProperty( $property, $value );
71
		}
72
		return $this;
73
	}
74
75
	/**
76
	 * @return string
77
	 */
78
	public function getContext()
79
	{
80
		return 'https://schema.org';
81
	}
82
83
	/**
84
	 * @return array
85
	 */
86
	public function getProperties()
87
	{
88
		return $this->properties;
89
	}
90
91
	/**
92
	 * @param string $property
93
	 * @param mixed $default
94
	 * @return mixed
95
	 */
96
	public function getProperty( $property, $default = null)
97
	{
98
		return $this->properties[$property] ?? $default;
99
	}
100
101
	/**
102
	 * @return string
103
	 */
104
	public function getType()
105
	{
106
		return $this->type;
107
	}
108
109
	/**
110
	 * @param bool $condition
111
	 * @param mixed $callback
112
	 * @return static
113
	 */
114
	public function doIf( $condition, $callback )
115
	{
116
		if( $condition ) {
117
			$callback( $this );
118
		}
119
		return $this;
120
	}
121
122
	/**
123
	 * @return array
124
	 */
125
	public function jsonSerialize()
126
	{
127
		return $this->toArray();
128
	}
129
130
	/**
131
	 * @param mixed $offset
132
	 * @return bool
133
	 */
134
	public function offsetExists( $offset )
135
	{
136
		return array_key_exists( $offset, $this->properties );
137
	}
138
139
	/**
140
	 * @param string $offset
141
	 * @return mixed
142
	 */
143
	public function offsetGet( $offset )
144
	{
145
		return $this->getProperty( $offset );
146
	}
147
148
	/**
149
	 * @param string $offset
150
	 * @param mixed $value
151
	 * @return void
152
	 */
153
	public function offsetSet( $offset, $value )
154
	{
155
		$this->setProperty( $offset, $value );
156
	}
157
158
	/**
159
	 * @param string $offset
160
	 * @return void
161
	 */
162
	public function offsetUnset( $offset )
163
	{
164
		unset( $this->properties[$offset] );
165
	}
166
167
	/**
168
	 * @param string $property
169
	 * @param mixed $value
170
	 * @return static
171
	 */
172
	public function setProperty( $property, $value )
173
	{
174
		if( !in_array( $property, $this->allowed )
175
			&& (new ReflectionClass( $this ))->getShortName() != 'UnknownType' ) {
176
			glsr_log()->warning( $this->getType().' does not allow the "'.$property.'" property' );
177
			return $this;
178
		}
179
		$this->properties[$property] = $value;
180
		return $this;
181
	}
182
183
	/**
184
	 * @return array
185
	 */
186
	public function toArray()
187
	{
188
		return [
189
			'@context' => $this->getContext(),
190
			'@type' => $this->getType(),
191
		] + $this->serializeProperty( $this->getProperties() );
192
	}
193
194
	/**
195
	 * @return string
196
	 */
197
	public function toScript()
198
	{
199
		return sprintf( '<script type="application/ld+json">%s</script>',
200
			json_encode( $this->toArray(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES )
201
		);
202
	}
203
204
	/**
205
	 * @param null|array $parents
206
	 * @return array
207
	 */
208
	protected function getParents( $parents = null )
209
	{
210
		if( !isset( $parents )) {
211
			$parents = $this->parents;
212
		}
213
		$newParents = $parents;
214
		foreach( $parents as $parent ) {
215
			$parentClass = glsr( Helper::class )->buildClassName( $parent, __NAMESPACE__ );
216
			if( !class_exists( $parentClass ))continue;
217
			$newParents = array_merge( $newParents, $this->getParents( (new $parentClass)->parents ));
218
		}
219
		return array_values( array_unique( $newParents ));
220
	}
221
222
	/**
223
	 * @return void
224
	 */
225
	protected function setAllowedProperties()
226
	{
227
		$parents = $this->getParents();
228
		foreach( $parents as $parent ) {
229
			$parentClass = glsr( Helper::class )->buildClassName( $parent, __NAMESPACE__ );
230
			if( !class_exists( $parentClass ))continue;
231
			$this->allowed = array_values( array_unique( array_merge( (new $parentClass)->allowed, $this->allowed )));
232
		}
233
	}
234
235
	/**
236
	 * @param mixed $property
237
	 * @return array|string
238
	 */
239
	protected function serializeProperty( $property )
240
	{
241
		if( is_array( $property )) {
242
			return array_map( [$this, 'serializeProperty'], $property );
243
		}
244
		if( $property instanceof Type ) {
245
			$property = $property->toArray();
246
			unset( $property['@context'] );
247
		}
248
		if( $property instanceof DateTimeInterface ) {
249
			$property = $property->format( DateTime::ATOM );
250
		}
251
		if( is_object( $property )) {
252
			throw new InvalidProperty();
253
		}
254
		return $property;
255
	}
256
}
257