ResourceObject::addRelationshipObject()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 2
b 0
f 0
nc 3
nop 3
dl 0
loc 12
ccs 7
cts 7
cp 1
crap 3
rs 10
1
<?php
2
3
namespace alsvanzelf\jsonapi\objects;
4
5
use alsvanzelf\jsonapi\CollectionDocument;
6
use alsvanzelf\jsonapi\exceptions\DuplicateException;
7
use alsvanzelf\jsonapi\helpers\Converter;
8
use alsvanzelf\jsonapi\helpers\LinksManager;
9
use alsvanzelf\jsonapi\helpers\Validator;
10
use alsvanzelf\jsonapi\interfaces\RecursiveResourceContainerInterface;
11
use alsvanzelf\jsonapi\interfaces\ResourceInterface;
12
use alsvanzelf\jsonapi\objects\AttributesObject;
13
use alsvanzelf\jsonapi\objects\RelationshipObject;
14
use alsvanzelf\jsonapi\objects\RelationshipsObject;
15
use alsvanzelf\jsonapi\objects\ResourceIdentifierObject;
16
17
class ResourceObject extends ResourceIdentifierObject implements RecursiveResourceContainerInterface {
18
	use LinksManager;
19
	
20
	/** @var AttributesObject */
21
	protected $attributes;
22
	/** @var RelationshipsObject */
23
	protected $relationships;
24
	/** @var array */
25
	protected static $defaults = [
26
		/**
27
		 * blocks 'type' as a keyword inside attributes or relationships
28
		 * the specification doesn't allow this as 'type' is already set at the root of a resource
29
		 * set to true if migrating to jsonapi and currently using 'type' as attribute or relationship
30
		 */
31
		'enforceTypeFieldNamespace' => true,
32
	];
33
	
34
	/**
35
	 * human api
36
	 */
37
	
38
	/**
39
	 * @note if an `id` is set inside $attributes, it is removed from there
40
	 *       and if $id is null, it is filled with that value
41
	 *       it is common to find it inside, and not doing so will cause an exception
42
	 * 
43
	 * @param  array      $attributes
44
	 * @param  string     $type       optional
45
	 * @param  string|int $id         optional
46
	 * @param  array      $options    optional {@see ResourceObject::$defaults}
47
	 * @return ResourceObject
48
	 */
49 10
	public static function fromArray(array $attributes, $type=null, $id=null, array $options=[]) {
50 10
		if (isset($attributes['id'])) {
51 5
			if ($id === null) {
52 1
				$id = $attributes['id'];
53
			}
54
			
55 5
			unset($attributes['id']);
56
		}
57
		
58 10
		$resourceObject = new self($type, $id);
59 10
		$resourceObject->setAttributesObject(AttributesObject::fromArray($attributes), $options);
60
		
61 10
		return $resourceObject;
62
	}
63
	
64
	/**
65
	 * @param  object     $attributes
66
	 * @param  string     $type       optional
67
	 * @param  string|int $id         optional
68
	 * @param  array      $options    optional {@see ResourceObject::$defaults}
69
	 * @return ResourceObject
70
	 */
71 1
	public static function fromObject($attributes, $type=null, $id=null, array $options=[]) {
72 1
		$array = Converter::objectToArray($attributes);
73
		
74 1
		return self::fromArray($array, $type, $id, $options);
75
	}
76
	
77
	/**
78
	 * add key-value pairs to attributes
79
	 * 
80
	 * @param string $key
81
	 * @param mixed  $value
82
	 * @param array  $options optional {@see ResourceObject::$defaults}
83
	 */
84 23
	public function add($key, $value, array $options=[]) {
85 23
		$options = array_merge(self::$defaults, $options);
86
		
87 23
		if ($this->attributes === null) {
88 22
			$this->attributes = new AttributesObject();
89
		}
90
		
91 23
		$this->validator->claimUsedFields([$key], Validator::OBJECT_CONTAINER_ATTRIBUTES, $options);
92
		
93 23
		$this->attributes->add($key, $value);
94
	}
95
	
96
	/**
97
	 * @param  string $key
98
	 * @param  mixed  $relation ResourceInterface | ResourceInterface[] | CollectionDocument
99
	 * @param  array  $links    optional
100
	 * @param  array  $meta     optional
101
	 * @param  array  $options  optional {@see ResourceObject::$defaults}
102
	 * @return RelationshipObject
103
	 */
104 15
	public function addRelationship($key, $relation, array $links=[], array $meta=[], array $options=[]) {
105 15
		$relationshipObject = RelationshipObject::fromAnything($relation, $links, $meta);
106
		
107 15
		$this->addRelationshipObject($key, $relationshipObject, $options);
108
		
109 15
		return $relationshipObject;
110
	}
111
	
112
	/**
113
	 * @param string $href
114
	 * @param array  $meta optional, if given a LinkObject is added, otherwise a link string is added
115
	 */
116 2
	public function setSelfLink($href, array $meta=[]) {
117 2
		$this->addLink('self', $href, $meta);
118
	}
119
	
120
	/**
121
	 * spec api
122
	 */
123
	
124
	/**
125
	 * @param AttributesObject $attributesObject
126
	 * @param array            $options          optional {@see ResourceObject::$defaults}
127
	 */
128 14
	public function setAttributesObject(AttributesObject $attributesObject, array $options=[]) {
129 14
		$newKeys = $attributesObject->getKeys();
130 14
		$this->validator->clearUsedFields(Validator::OBJECT_CONTAINER_ATTRIBUTES);
131 14
		$this->validator->claimUsedFields($newKeys, Validator::OBJECT_CONTAINER_ATTRIBUTES, $options);
132
		
133 14
		$this->attributes = $attributesObject;
134
	}
135
	
136
	/**
137
	 * @param string             $key
138
	 * @param RelationshipObject $relationshipObject
139
	 * @param array              $options            optional {@see ResourceObject::$defaults}
140
	 * 
141
	 * @throws DuplicateException if the resource is contained as a resource in the relationship
142
	 */
143 20
	public function addRelationshipObject($key, RelationshipObject $relationshipObject, array $options=[]) {
144 20
		if ($relationshipObject->hasResource($this)) {
145 1
			throw new DuplicateException('can not add relation to self');
146
		}
147
		
148 19
		if ($this->relationships === null) {
149 19
			$this->setRelationshipsObject(new RelationshipsObject());
150
		}
151
		
152 19
		$this->validator->claimUsedFields([$key], Validator::OBJECT_CONTAINER_RELATIONSHIPS, $options);
153
		
154 19
		$this->relationships->addRelationshipObject($key, $relationshipObject);
155
	}
156
	
157
	/**
158
	 * @param RelationshipsObject $relationshipsObject
159
	 */
160 25
	public function setRelationshipsObject(RelationshipsObject $relationshipsObject) {
161 25
		$newKeys = $relationshipsObject->getKeys();
162 25
		$this->validator->clearUsedFields(Validator::OBJECT_CONTAINER_RELATIONSHIPS);
163 25
		$this->validator->claimUsedFields($newKeys, Validator::OBJECT_CONTAINER_RELATIONSHIPS);
164
		
165 25
		$this->relationships = $relationshipsObject;
166
	}
167
	
168
	/**
169
	 * internal api
170
	 */
171
	
172
	/**
173
	 * whether the ResourceObject is empty except for the ResourceIdentifierObject
174
	 * 
175
	 * this can be used to determine if a Relationship's resource could be added as included resource
176
	 * 
177
	 * @internal
178
	 * 
179
	 * @return boolean
180
	 */
181 18
	public function hasIdentifierPropertiesOnly() {
182 18
		if ($this->attributes !== null && $this->attributes->isEmpty() === false) {
183 15
			return false;
184
		}
185 6
		if ($this->relationships !== null && $this->relationships->isEmpty() === false) {
186 1
			return false;
187
		}
188 6
		if ($this->links !== null && $this->links->isEmpty() === false) {
189 1
			return false;
190
		}
191
		
192 5
		return true;
193
	}
194
	
195
	/**
196
	 * ResourceInterface
197
	 */
198
	
199
	/**
200
	 * @inheritDoc
201
	 */
202 51
	public function getResource($identifierOnly=false) {
203 51
		if ($identifierOnly) {
204 36
			return ResourceIdentifierObject::fromResourceObject($this);
205
		}
206
		
207 37
		return $this;
208
	}
209
	
210
	/**
211
	 * ObjectInterface
212
	 */
213
	
214
	/**
215
	 * @inheritDoc
216
	 */
217 43
	public function isEmpty() {
218 43
		if (parent::isEmpty() === false) {
219 37
			return false;
220
		}
221 7
		if ($this->attributes !== null && $this->attributes->isEmpty() === false) {
222 2
			return false;
223
		}
224 6
		if ($this->relationships !== null && $this->relationships->isEmpty() === false) {
225 2
			return false;
226
		}
227 4
		if ($this->links !== null && $this->links->isEmpty() === false) {
228 1
			return false;
229
		}
230
		
231 4
		return true;
232
	}
233
	
234
	/**
235
	 * @inheritDoc
236
	 */
237 40
	public function toArray() {
238 40
		$array = parent::toArray();
239
		
240 40
		if ($this->attributes !== null && $this->attributes->isEmpty() === false) {
241 24
			$array['attributes'] = $this->attributes->toArray();
242
		}
243 40
		if ($this->relationships !== null && $this->relationships->isEmpty() === false) {
244 21
			$array['relationships'] = $this->relationships->toArray();
245
		}
246 40
		if ($this->links !== null && $this->links->isEmpty() === false) {
247 4
			$array['links'] = $this->links->toArray();
248
		}
249
		
250 40
		return $array;
251
	}
252
	
253
	/**
254
	 * RecursiveResourceContainerInterface
255
	 */
256
	
257
	/**
258
	 * @inheritDoc
259
	 */
260 43
	public function getNestedContainedResourceObjects() {
261 43
		if ($this->relationships === null) {
262 42
			return [];
263
		}
264
		
265 8
		return $this->relationships->getNestedContainedResourceObjects();
266
	}
267
}
268