Chris@18: links = array_map(function ($link) { Chris@18: return is_array($link) ? $link : [$link]; Chris@18: }, $links); Chris@18: $this->context = $context; Chris@18: } Chris@18: Chris@18: /** Chris@18: * {@inheritdoc} Chris@18: */ Chris@18: public function getIterator() { Chris@18: assert(!is_null($this->context), 'A LinkCollection is invalid unless a context has been established.'); Chris@18: return new \ArrayIterator($this->links); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Gets a new LinkCollection with the given link inserted. Chris@18: * Chris@18: * @param string $key Chris@18: * A key for the link. If the key already exists and the link shares an href Chris@18: * with an existing link with that key, those links will be merged together. Chris@18: * @param \Drupal\jsonapi\JsonApiResource\Link $new_link Chris@18: * The link to insert. Chris@18: * Chris@18: * @return static Chris@18: * A new LinkCollection with the given link inserted or merged with the Chris@18: * current set of links. Chris@18: */ Chris@18: public function withLink($key, Link $new_link) { Chris@18: assert(static::validKey($key)); Chris@18: $merged = $this->links; Chris@18: if (isset($merged[$key])) { Chris@18: foreach ($merged[$key] as $index => $existing_link) { Chris@18: if (Link::compare($existing_link, $new_link) === 0) { Chris@18: $merged[$key][$index] = Link::merge($existing_link, $new_link); Chris@18: return new static($merged, $this->context); Chris@18: } Chris@18: } Chris@18: } Chris@18: $merged[$key][] = $new_link; Chris@18: return new static($merged, $this->context); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Whether a link with the given key exists. Chris@18: * Chris@18: * @param string $key Chris@18: * The key. Chris@18: * Chris@18: * @return bool Chris@18: * TRUE if a link with the given key exist, FALSE otherwise. Chris@18: */ Chris@18: public function hasLinkWithKey($key) { Chris@18: return array_key_exists($key, $this->links); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Establishes a new context for a LinkCollection. Chris@18: * Chris@18: * @param \Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel|\Drupal\jsonapi\JsonApiResource\ResourceObject $context Chris@18: * The new context object. Chris@18: * Chris@18: * @return static Chris@18: * A new LinkCollection with the given context. Chris@18: */ Chris@18: public function withContext($context) { Chris@18: return new static($this->links, $context); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Gets the LinkCollection's context object. Chris@18: * Chris@18: * @return \Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel|\Drupal\jsonapi\JsonApiResource\ResourceObject Chris@18: * The LinkCollection's context. Chris@18: */ Chris@18: public function getContext() { Chris@18: assert(!is_null($this->context), 'A LinkCollection is invalid unless a context has been established.'); Chris@18: return $this->context; Chris@18: } Chris@18: Chris@18: /** Chris@18: * Filters a LinkCollection using the provided callback. Chris@18: * Chris@18: * @param callable $f Chris@18: * The filter callback. The callback has the signature below. Chris@18: * Chris@18: * @code Chris@18: * boolean callback(string $key, \Drupal\jsonapi\JsonApiResource\Link $link, mixed $context)) Chris@18: * @endcode Chris@18: * Chris@18: * @return \Drupal\jsonapi\JsonApiResource\LinkCollection Chris@18: * A new, filtered LinkCollection. Chris@18: */ Chris@18: public function filter(callable $f) { Chris@18: $links = iterator_to_array($this); Chris@18: $filtered = array_reduce(array_keys($links), function ($filtered, $key) use ($links, $f) { Chris@18: if ($f($key, $links[$key], $this->context)) { Chris@18: $filtered[$key] = $links[$key]; Chris@18: } Chris@18: return $filtered; Chris@18: }, []); Chris@18: return new LinkCollection($filtered, $this->context); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Merges two LinkCollections. Chris@18: * Chris@18: * @param \Drupal\jsonapi\JsonApiResource\LinkCollection $a Chris@18: * The first link collection. Chris@18: * @param \Drupal\jsonapi\JsonApiResource\LinkCollection $b Chris@18: * The second link collection. Chris@18: * Chris@18: * @return \Drupal\jsonapi\JsonApiResource\LinkCollection Chris@18: * A new LinkCollection with the links of both inputs. Chris@18: */ Chris@18: public static function merge(LinkCollection $a, LinkCollection $b) { Chris@18: assert($a->getContext() === $b->getContext()); Chris@18: $merged = new LinkCollection([], $a->getContext()); Chris@18: foreach ($a as $key => $links) { Chris@18: $merged = array_reduce($links, function (self $merged, Link $link) use ($key) { Chris@18: return $merged->withLink($key, $link); Chris@18: }, $merged); Chris@18: } Chris@18: foreach ($b as $key => $links) { Chris@18: $merged = array_reduce($links, function (self $merged, Link $link) use ($key) { Chris@18: return $merged->withLink($key, $link); Chris@18: }, $merged); Chris@18: } Chris@18: return $merged; Chris@18: } Chris@18: Chris@18: /** Chris@18: * Ensures that a link key is valid. Chris@18: * Chris@18: * @param string $key Chris@18: * A key name. Chris@18: * Chris@18: * @return bool Chris@18: * TRUE if the key is valid, FALSE otherwise. Chris@18: */ Chris@18: protected static function validKey($key) { Chris@18: return is_string($key) && !is_numeric($key) && strpos($key, ':') === FALSE; Chris@18: } Chris@18: Chris@18: }