Chris@18
|
1 <?php
|
Chris@18
|
2
|
Chris@18
|
3 namespace Drupal\jsonapi\JsonApiResource;
|
Chris@18
|
4
|
Chris@18
|
5 use Drupal\Component\Assertion\Inspector;
|
Chris@18
|
6 use Drupal\jsonapi\Exception\EntityAccessDeniedHttpException;
|
Chris@18
|
7
|
Chris@18
|
8 /**
|
Chris@18
|
9 * Represents the `data` and `included` objects of a top-level object.
|
Chris@18
|
10 *
|
Chris@18
|
11 * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class
|
Chris@18
|
12 * may change at any time and could break any dependencies on it.
|
Chris@18
|
13 *
|
Chris@18
|
14 * @see https://www.drupal.org/project/jsonapi/issues/3032787
|
Chris@18
|
15 * @see jsonapi.api.php
|
Chris@18
|
16 */
|
Chris@18
|
17 abstract class Data implements \IteratorAggregate, \Countable {
|
Chris@18
|
18
|
Chris@18
|
19 /**
|
Chris@18
|
20 * Various representations of JSON:API objects.
|
Chris@18
|
21 *
|
Chris@18
|
22 * @var \Drupal\jsonapi\JsonApiResource\ResourceIdentifierInterface[]
|
Chris@18
|
23 */
|
Chris@18
|
24 protected $data;
|
Chris@18
|
25
|
Chris@18
|
26 /**
|
Chris@18
|
27 * The number of resources permitted in this collection.
|
Chris@18
|
28 *
|
Chris@18
|
29 * @var int
|
Chris@18
|
30 */
|
Chris@18
|
31 protected $cardinality;
|
Chris@18
|
32
|
Chris@18
|
33 /**
|
Chris@18
|
34 * Holds a boolean indicating if there is a next page.
|
Chris@18
|
35 *
|
Chris@18
|
36 * @var bool
|
Chris@18
|
37 */
|
Chris@18
|
38 protected $hasNextPage;
|
Chris@18
|
39
|
Chris@18
|
40 /**
|
Chris@18
|
41 * Holds the total count of entities.
|
Chris@18
|
42 *
|
Chris@18
|
43 * @var int
|
Chris@18
|
44 */
|
Chris@18
|
45 protected $count;
|
Chris@18
|
46
|
Chris@18
|
47 /**
|
Chris@18
|
48 * Instantiates a Data object.
|
Chris@18
|
49 *
|
Chris@18
|
50 * @param \Drupal\jsonapi\JsonApiResource\ResourceIdentifierInterface[] $data
|
Chris@18
|
51 * The resources or resource identifiers for the collection.
|
Chris@18
|
52 * @param int $cardinality
|
Chris@18
|
53 * The number of resources that this collection may contain. Related
|
Chris@18
|
54 * resource collections may handle both to-one or to-many relationships. A
|
Chris@18
|
55 * to-one relationship should have a cardinality of 1. Use -1 for unlimited
|
Chris@18
|
56 * cardinality.
|
Chris@18
|
57 */
|
Chris@18
|
58 public function __construct(array $data, $cardinality = -1) {
|
Chris@18
|
59 assert(Inspector::assertAllObjects($data, ResourceIdentifierInterface::class));
|
Chris@18
|
60 assert($cardinality >= -1 && $cardinality !== 0, 'Cardinality must be -1 for unlimited cardinality or a positive integer.');
|
Chris@18
|
61 assert($cardinality === -1 || count($data) <= $cardinality, 'If cardinality is not unlimited, the number of given resources must not exceed the cardinality of the collection.');
|
Chris@18
|
62 $this->data = array_values($data);
|
Chris@18
|
63 $this->cardinality = $cardinality;
|
Chris@18
|
64 }
|
Chris@18
|
65
|
Chris@18
|
66 /**
|
Chris@18
|
67 * Returns an iterator for entities.
|
Chris@18
|
68 *
|
Chris@18
|
69 * @return \ArrayIterator
|
Chris@18
|
70 * An \ArrayIterator instance
|
Chris@18
|
71 */
|
Chris@18
|
72 public function getIterator() {
|
Chris@18
|
73 return new \ArrayIterator($this->data);
|
Chris@18
|
74 }
|
Chris@18
|
75
|
Chris@18
|
76 /**
|
Chris@18
|
77 * Returns the number of entities.
|
Chris@18
|
78 *
|
Chris@18
|
79 * @return int
|
Chris@18
|
80 * The number of parameters
|
Chris@18
|
81 */
|
Chris@18
|
82 public function count() {
|
Chris@18
|
83 return count($this->data);
|
Chris@18
|
84 }
|
Chris@18
|
85
|
Chris@18
|
86 /**
|
Chris@18
|
87 * {@inheritdoc}
|
Chris@18
|
88 */
|
Chris@18
|
89 public function getTotalCount() {
|
Chris@18
|
90 return $this->count;
|
Chris@18
|
91 }
|
Chris@18
|
92
|
Chris@18
|
93 /**
|
Chris@18
|
94 * {@inheritdoc}
|
Chris@18
|
95 */
|
Chris@18
|
96 public function setTotalCount($count) {
|
Chris@18
|
97 $this->count = $count;
|
Chris@18
|
98 }
|
Chris@18
|
99
|
Chris@18
|
100 /**
|
Chris@18
|
101 * Returns the collection as an array.
|
Chris@18
|
102 *
|
Chris@18
|
103 * @return \Drupal\Core\Entity\EntityInterface[]
|
Chris@18
|
104 * The array of entities.
|
Chris@18
|
105 */
|
Chris@18
|
106 public function toArray() {
|
Chris@18
|
107 return $this->data;
|
Chris@18
|
108 }
|
Chris@18
|
109
|
Chris@18
|
110 /**
|
Chris@18
|
111 * Checks if there is a next page in the collection.
|
Chris@18
|
112 *
|
Chris@18
|
113 * @return bool
|
Chris@18
|
114 * TRUE if the collection has a next page.
|
Chris@18
|
115 */
|
Chris@18
|
116 public function hasNextPage() {
|
Chris@18
|
117 return (bool) $this->hasNextPage;
|
Chris@18
|
118 }
|
Chris@18
|
119
|
Chris@18
|
120 /**
|
Chris@18
|
121 * Sets the has next page flag.
|
Chris@18
|
122 *
|
Chris@18
|
123 * Once the collection query has been executed and we build the entity
|
Chris@18
|
124 * collection, we now if there will be a next page with extra entities.
|
Chris@18
|
125 *
|
Chris@18
|
126 * @param bool $has_next_page
|
Chris@18
|
127 * TRUE if the collection has a next page.
|
Chris@18
|
128 */
|
Chris@18
|
129 public function setHasNextPage($has_next_page) {
|
Chris@18
|
130 $this->hasNextPage = (bool) $has_next_page;
|
Chris@18
|
131 }
|
Chris@18
|
132
|
Chris@18
|
133 /**
|
Chris@18
|
134 * Gets the cardinality of this collection.
|
Chris@18
|
135 *
|
Chris@18
|
136 * @return int
|
Chris@18
|
137 * The cardinality of the resource collection. -1 for unlimited cardinality.
|
Chris@18
|
138 */
|
Chris@18
|
139 public function getCardinality() {
|
Chris@18
|
140 return $this->cardinality;
|
Chris@18
|
141 }
|
Chris@18
|
142
|
Chris@18
|
143 /**
|
Chris@18
|
144 * Returns a new Data object containing the entities of $this and $other.
|
Chris@18
|
145 *
|
Chris@18
|
146 * @param \Drupal\jsonapi\JsonApiResource\Data $a
|
Chris@18
|
147 * A Data object object to be merged.
|
Chris@18
|
148 * @param \Drupal\jsonapi\JsonApiResource\Data $b
|
Chris@18
|
149 * A Data object to be merged.
|
Chris@18
|
150 *
|
Chris@18
|
151 * @return \Drupal\jsonapi\JsonApiResource\Data
|
Chris@18
|
152 * A new merged Data object.
|
Chris@18
|
153 */
|
Chris@18
|
154 public static function merge(Data $a, Data $b) {
|
Chris@18
|
155 return new static(array_merge($a->toArray(), $b->toArray()));
|
Chris@18
|
156 }
|
Chris@18
|
157
|
Chris@18
|
158 /**
|
Chris@18
|
159 * Returns a new, deduplicated Data object.
|
Chris@18
|
160 *
|
Chris@18
|
161 * @param \Drupal\jsonapi\JsonApiResource\Data $collection
|
Chris@18
|
162 * The Data object to deduplicate.
|
Chris@18
|
163 *
|
Chris@18
|
164 * @return static
|
Chris@18
|
165 * A new merged Data object.
|
Chris@18
|
166 */
|
Chris@18
|
167 public static function deduplicate(Data $collection) {
|
Chris@18
|
168 $deduplicated = [];
|
Chris@18
|
169 foreach ($collection as $resource) {
|
Chris@18
|
170 $dedupe_key = $resource->getTypeName() . ':' . $resource->getId();
|
Chris@18
|
171 if ($resource instanceof EntityAccessDeniedHttpException && ($error = $resource->getError()) && !is_null($error['relationship_field'])) {
|
Chris@18
|
172 $dedupe_key .= ':' . $error['relationship_field'];
|
Chris@18
|
173 }
|
Chris@18
|
174 $deduplicated[$dedupe_key] = $resource;
|
Chris@18
|
175 }
|
Chris@18
|
176 return new static(array_values($deduplicated));
|
Chris@18
|
177 }
|
Chris@18
|
178
|
Chris@18
|
179 }
|