Passed
Push — main ( f8d78a...6afd83 )
by Lode
01:12 queued 12s
created

ResourceDocument::setLocalId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace alsvanzelf\jsonapi;
4
5
use alsvanzelf\jsonapi\CollectionDocument;
6
use alsvanzelf\jsonapi\DataDocument;
7
use alsvanzelf\jsonapi\Document;
8
use alsvanzelf\jsonapi\exceptions\Exception;
9
use alsvanzelf\jsonapi\exceptions\InputException;
10
use alsvanzelf\jsonapi\helpers\Converter;
11
use alsvanzelf\jsonapi\interfaces\RecursiveResourceContainerInterface;
12
use alsvanzelf\jsonapi\interfaces\ResourceInterface;
13
use alsvanzelf\jsonapi\objects\AttributesObject;
14
use alsvanzelf\jsonapi\objects\RelationshipObject;
15
use alsvanzelf\jsonapi\objects\RelationshipsObject;
16
use alsvanzelf\jsonapi\objects\ResourceIdentifierObject;
17
use alsvanzelf\jsonapi\objects\ResourceObject;
18
19
/**
20
 * this document represents an entity or other resource of the api
21
 * it can contain other Resources as relationships
22
 * a CollectionDocument should be used if the primary Resource is (or can be) a set
23
 */
24
class ResourceDocument extends DataDocument implements ResourceInterface {
25
	/** @var ResourceIdentifierObject|ResourceObject */
26
	protected $resource;
27
	/** @var array */
28
	protected static $defaults = [
29
		/**
30
		 * add resources inside relationships to /included when adding resources to the collection
31
		 */
32
		'includeContainedResources' => true,
33
	];
34
	
35
	/**
36
	 * @note $type and $id are optional to pass during construction
37
	 *       however they are required for a valid ResourceDocument
38
	 *       so use ->setPrimaryResource() if not passing them during construction
39
	 * 
40
	 * @param string     $type optional
41
	 * @param string|int $id   optional
42
	 */
43 32
	public function __construct($type=null, $id=null) {
44 32
		parent::__construct();
45
		
46 32
		$this->setPrimaryResource(new ResourceObject($type, $id));
47 32
	}
48
	
49
	/**
50
	 * human api
51
	 */
52
	
53
	/**
54
	 * @param  array      $attributes
55
	 * @param  string     $type       optional
56
	 * @param  string|int $id         optional
57
	 * @param  array      $options    optional {@see ResourceDocument::$defaults} {@see ResourceObject::$defaults}
58
	 * @return ResourceDocument
59
	 */
60 4
	public static function fromArray(array $attributes, $type=null, $id=null, array $options=[]) {
61 4
		$resourceDocument = new self();
62 4
		$resourceDocument->setPrimaryResource(ResourceObject::fromArray($attributes, $type, $id, $options), $options);
63
		
64 4
		return $resourceDocument;
65
	}
66
	
67
	/**
68
	 * @param  object     $attributes
69
	 * @param  string     $type       optional
70
	 * @param  string|int $id         optional
71
	 * @param  array      $options    optional {@see ResourceDocument::$defaults}
72
	 * @return ResourceDocument
73
	 */
74 4
	public static function fromObject($attributes, $type=null, $id=null, array $options=[]) {
75 4
		$array = Converter::objectToArray($attributes);
76
		
77 4
		return self::fromArray($array, $type, $id, $options);
78
	}
79
	
80
	/**
81
	 * add key-value pairs to the resource's attributes
82
	 * 
83
	 * @param string $key
84
	 * @param mixed  $value   objects will be converted using `get_object_vars()`
85
	 * @param array  $options optional {@see ResourceDocument::$defaults}
86
	 */
87 5
	public function add($key, $value, array $options=[]) {
88 5
		$this->ensureResourceObject();
89
		
90 4
		$this->resource->add($key, $value, $options);
0 ignored issues
show
introduced by
The method add() does not exist on alsvanzelf\jsonapi\objec...esourceIdentifierObject. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

90
		$this->resource->/** @scrutinizer ignore-call */ 
91
                   add($key, $value, $options);
Loading history...
91 4
	}
92
	
93
	/**
94
	 * add a relation to the resource
95
	 * 
96
	 * adds included resources if found inside the relation, unless $options['includeContainedResources'] is set to false
97
	 * 
98
	 * @param string  $key
99
	 * @param mixed   $relation ResourceInterface | ResourceInterface[] | CollectionDocument
100
	 * @param array   $links    optional
101
	 * @param array   $meta     optional
102
	 * @param array   $options  optional {@see ResourceDocument::$defaults}
103
	 */
104 6
	public function addRelationship($key, $relation, array $links=[], array $meta=[], array $options=[]) {
105 6
		$this->ensureResourceObject();
106
		
107 6
		$options = array_merge(self::$defaults, $options);
108
		
109 6
		$relationshipObject = $this->resource->addRelationship($key, $relation, $links, $meta);
0 ignored issues
show
introduced by
The method addRelationship() does not exist on alsvanzelf\jsonapi\objec...esourceIdentifierObject. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

109
		/** @scrutinizer ignore-call */ 
110
  $relationshipObject = $this->resource->addRelationship($key, $relation, $links, $meta);
Loading history...
110
		
111 6
		if ($options['includeContainedResources']) {
112 5
			$this->addIncludedResourceObject(...$relationshipObject->getNestedContainedResourceObjects());
113
		}
114 6
	}
115
	
116
	/**
117
	 * @param string $key
118
	 * @param string $href
119
	 * @param array  $meta optional, if given a LinkObject is added, otherwise a link string is added
120
	 * @param string $level one of the Document::LEVEL_* constants, optional, defaults to Document::LEVEL_ROOT
121
	 */
122 4
	public function addLink($key, $href, array $meta=[], $level=Document::LEVEL_ROOT) {
123 4
		$this->ensureResourceObject();
124
		
125 4
		if ($level === Document::LEVEL_RESOURCE) {
126 1
			$this->resource->addLink($key, $href, $meta);
0 ignored issues
show
introduced by
The method addLink() does not exist on alsvanzelf\jsonapi\objec...esourceIdentifierObject. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

126
			$this->resource->/** @scrutinizer ignore-call */ 
127
                    addLink($key, $href, $meta);
Loading history...
127
		}
128
		else {
129 4
			parent::addLink($key, $href, $meta, $level);
130
		}
131 4
	}
132
	
133
	/**
134
	 * set the self link on the resource
135
	 * 
136
	 * @param string $href
137
	 * @param array  $meta optional
138
	 */
139 2
	public function setSelfLink($href, array $meta=[], $level=Document::LEVEL_RESOURCE) {
140 2
		$this->ensureResourceObject();
141
		
142 2
		if ($level === Document::LEVEL_RESOURCE) {
143 1
			$this->resource->setSelfLink($href, $meta);
0 ignored issues
show
introduced by
The method setSelfLink() does not exist on alsvanzelf\jsonapi\objec...esourceIdentifierObject. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

143
			$this->resource->/** @scrutinizer ignore-call */ 
144
                    setSelfLink($href, $meta);
Loading history...
144
		}
145
		else {
146 1
			parent::setSelfLink($href, $meta, $level);
147
		}
148 2
	}
149
	
150
	/**
151
	 * @param string $key
152
	 * @param mixed  $value
153
	 * @param string $level one of the Document::LEVEL_* constants, optional, defaults to Document::LEVEL_ROOT
154
	 */
155 5
	public function addMeta($key, $value, $level=Document::LEVEL_ROOT) {
156 5
		if ($level === Document::LEVEL_RESOURCE) {
157 2
			$this->resource->addMeta($key, $value);
158
		}
159
		else {
160 4
			parent::addMeta($key, $value, $level);
161
		}
162 5
	}
163
	
164
	/**
165
	 * wrapping ResourceObject spec api
166
	 */
167
	
168
	/**
169
	 * @param string $type
170
	 */
171 2
	public function setType($type) {
172 2
		$this->resource->setType($type);
173 2
	}
174
	
175
	/**
176
	 * @param string|int $id will be casted to a string
177
	 */
178 1
	public function setId($id) {
179 1
		$this->resource->setId($id);
180 1
	}
181
	
182
	/**
183
	 * @param string|int $localId will be casted to a string
184
	 */
185 1
	public function setLocalId($localId) {
186 1
		$this->resource->setLocalId($localId);
187 1
	}
188
	
189
	/**
190
	 * @param AttributesObject $attributesObject
191
	 * @param array            $options          optional {@see ResourceObject::$defaults}
192
	 */
193 1
	public function setAttributesObject(AttributesObject $attributesObject, array $options=[]) {
194 1
		$this->ensureResourceObject();
195
		
196 1
		$this->resource->setAttributesObject($attributesObject, $options);
0 ignored issues
show
introduced by
The method setAttributesObject() does not exist on alsvanzelf\jsonapi\objec...esourceIdentifierObject. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

196
		$this->resource->/** @scrutinizer ignore-call */ 
197
                   setAttributesObject($attributesObject, $options);
Loading history...
197 1
	}
198
	
199
	/**
200
	 * add a RelationshipObject to the resource
201
	 * 
202
	 * adds included resources if found inside the RelationshipObject, unless $options['includeContainedResources'] is set to false
203
	 * 
204
	 * @param string             $key
205
	 * @param RelationshipObject $relationshipObject
206
	 * @param array              $options            optional {@see ResourceDocument::$defaults}
207
	 */
208 5
	public function addRelationshipObject($key, RelationshipObject $relationshipObject, array $options=[]) {
209 5
		$this->ensureResourceObject();
210
		
211 5
		$options = array_merge(self::$defaults, $options);
212
		
213 5
		$this->resource->addRelationshipObject($key, $relationshipObject);
0 ignored issues
show
introduced by
The method addRelationshipObject() does not exist on alsvanzelf\jsonapi\objec...esourceIdentifierObject. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

213
		$this->resource->/** @scrutinizer ignore-call */ 
214
                   addRelationshipObject($key, $relationshipObject);
Loading history...
214
		
215 5
		if ($options['includeContainedResources']) {
216 4
			$this->addIncludedResourceObject(...$relationshipObject->getNestedContainedResourceObjects());
217
		}
218 5
	}
219
	
220
	/**
221
	 * set the RelationshipsObject to the resource
222
	 * 
223
	 * adds included resources if found inside the RelationshipObjects inside the RelationshipsObject, unless $options['includeContainedResources'] is set to false
224
	 * 
225
	 * @param RelationshipsObject $relationshipsObject
226
	 * @param array               $options             optional {@see ResourceDocument::$defaults}
227
	 */
228 3
	public function setRelationshipsObject(RelationshipsObject $relationshipsObject, array $options=[]) {
229 3
		$this->ensureResourceObject();
230
		
231 3
		$options = array_merge(self::$defaults, $options);
232
		
233 3
		$this->resource->setRelationshipsObject($relationshipsObject);
0 ignored issues
show
introduced by
The method setRelationshipsObject() does not exist on alsvanzelf\jsonapi\objec...esourceIdentifierObject. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

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

233
		$this->resource->/** @scrutinizer ignore-call */ 
234
                   setRelationshipsObject($relationshipsObject);
Loading history...
234
		
235 3
		if ($options['includeContainedResources']) {
236 2
			$this->addIncludedResourceObject(...$relationshipsObject->getNestedContainedResourceObjects());
237
		}
238 3
	}
239
	
240
	/**
241
	 * spec api
242
	 */
243
	
244
	/**
245
	 * overwrites the primary resource
246
	 * 
247
	 * adds included resources if found inside the resource's relationships, unless $options['includeContainedResources'] is set to false
248
	 * 
249
	 * @param ResourceInterface $resource
250
	 * @param array             $options  optional {@see ResourceDocument::$defaults}
251
	 * 
252
	 * @throws InputException if the $resource is a ResourceDocument itself
253
	 */
254 32
	public function setPrimaryResource(ResourceInterface $resource, array $options=[]) {
255 32
		if ($resource instanceof ResourceDocument) {
256 1
			throw new InputException('does not make sense to set a document inside a document, use ResourceObject or ResourceIdentifierObject instead');
257
		}
258
		
259 32
		$options = array_merge(self::$defaults, $options);
260
		
261 32
		$this->resource = $resource;
0 ignored issues
show
Documentation Bug introduced by
$resource is of type alsvanzelf\jsonapi\interfaces\ResourceInterface, but the property $resource was declared to be of type alsvanzelf\jsonapi\objec...\objects\ResourceObject. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
262
		
263 32
		if ($options['includeContainedResources'] && $this->resource instanceof RecursiveResourceContainerInterface) {
264 32
			$this->addIncludedResourceObject(...$this->resource->getNestedContainedResourceObjects());
0 ignored issues
show
Bug introduced by
The method getNestedContainedResourceObjects() does not exist on alsvanzelf\jsonapi\interfaces\ResourceInterface. It seems like you code against a sub-type of alsvanzelf\jsonapi\interfaces\ResourceInterface such as alsvanzelf\jsonapi\objects\ResourceObject. ( Ignorable by Annotation )

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

264
			$this->addIncludedResourceObject(...$this->resource->/** @scrutinizer ignore-call */ getNestedContainedResourceObjects());
Loading history...
265
		}
266 32
	}
267
	
268
	/**
269
	 * internal api
270
	 */
271
	
272
	/**
273
	 * @internal
274
	 * 
275
	 * @throws Exception
276
	 */
277 17
	private function ensureResourceObject() {
278 17
		if ($this->resource instanceof ResourceObject === false) {
279 1
			throw new Exception('the resource is an identifier-only object');
280
		}
281 16
	}
282
	
283
	/**
284
	 * DocumentInterface
285
	 */
286
	
287
	/**
288
	 * @inheritDoc
289
	 */
290 29
	public function toArray() {
291 29
		$array = parent::toArray();
292
		
293 29
		$array['data'] = null;
294 29
		if ($this->resource !== null && $this->resource->isEmpty() === false) {
295 27
			$array['data'] = $this->resource->toArray();
296
		}
297
		
298 29
		return $array;
299
	}
300
	
301
	/**
302
	 * ResourceInterface
303
	 */
304
	
305
	/**
306
	 * @inheritDoc
307
	 */
308 3
	public function getResource($identifierOnly=false) {
309 3
		return $this->resource->getResource($identifierOnly);
310
	}
311
}
312