annotate core/modules/jsonapi/src/JsonApiResource/Link.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents
children
rev   line source
Chris@5 1 <?php
Chris@5 2
Chris@5 3 namespace Drupal\jsonapi\JsonApiResource;
Chris@5 4
Chris@5 5 use Drupal\Component\Assertion\Inspector;
Chris@5 6 use Drupal\Core\Cache\CacheableDependencyInterface;
Chris@5 7 use Drupal\Core\Cache\CacheableDependencyTrait;
Chris@5 8 use Drupal\Core\Cache\CacheableMetadata;
Chris@5 9 use Drupal\Core\Url;
Chris@5 10
Chris@5 11 /**
Chris@5 12 * Represents an RFC8288 based link.
Chris@5 13 *
Chris@5 14 * @internal JSON:API maintains no PHP API. The API is the HTTP API. This class
Chris@5 15 * may change at any time and could break any dependencies on it.
Chris@5 16 *
Chris@5 17 * @see https://www.drupal.org/project/jsonapi/issues/3032787
Chris@5 18 * @see jsonapi.api.php
Chris@5 19 *
Chris@5 20 * @see https://tools.ietf.org/html/rfc8288
Chris@5 21 */
Chris@5 22 final class Link implements CacheableDependencyInterface {
Chris@5 23
Chris@5 24 use CacheableDependencyTrait;
Chris@5 25
Chris@5 26 /**
Chris@5 27 * The link URI.
Chris@5 28 *
Chris@5 29 * @var \Drupal\Core\Url
Chris@5 30 */
Chris@5 31 protected $uri;
Chris@5 32
Chris@5 33 /**
Chris@5 34 * The URI, as a string.
Chris@5 35 *
Chris@5 36 * @var string
Chris@5 37 */
Chris@5 38 protected $href;
Chris@5 39
Chris@5 40 /**
Chris@5 41 * The link relation types.
Chris@5 42 *
Chris@5 43 * @var string[]
Chris@5 44 */
Chris@5 45 protected $rel;
Chris@5 46
Chris@5 47 /**
Chris@5 48 * The link target attributes.
Chris@5 49 *
Chris@5 50 * @var string[]
Chris@5 51 * An associative array where the keys are the attribute keys and values are
Chris@5 52 * either string or an array of strings.
Chris@5 53 */
Chris@5 54 protected $attributes;
Chris@5 55
Chris@5 56 /**
Chris@5 57 * JSON:API Link constructor.
Chris@5 58 *
Chris@5 59 * @param \Drupal\Core\Cache\CacheableMetadata $cacheability
Chris@5 60 * Any cacheability metadata associated with the link. For example, a
Chris@5 61 * 'call-to-action' link might reference a registration resource if an event
Chris@5 62 * has vacancies or a wait-list resource otherwise. Therefore, the link's
Chris@5 63 * cacheability might be depend on a certain entity's values other than the
Chris@5 64 * entity on which the link will appear.
Chris@5 65 * @param \Drupal\Core\Url $url
Chris@5 66 * The Url object for the link.
Chris@5 67 * @param string[] $link_relation_types
Chris@5 68 * An array of registered or extension RFC8288 link relation types.
Chris@5 69 * @param array $target_attributes
Chris@5 70 * An associative array of target attributes for the link.
Chris@5 71 *
Chris@5 72 * @see https://tools.ietf.org/html/rfc8288#section-2.1
Chris@5 73 */
Chris@5 74 public function __construct(CacheableMetadata $cacheability, Url $url, array $link_relation_types, array $target_attributes = []) {
Chris@5 75 // @todo: uncomment the extra assertion below when JSON:API begins to use its own extension relation types.
Chris@5 76 assert(/* !empty($link_relation_types) && */Inspector::assertAllStrings($link_relation_types));
Chris@5 77 assert(Inspector::assertAllStrings(array_keys($target_attributes)));
Chris@5 78 assert(Inspector::assertAll(function ($target_attribute_value) {
Chris@5 79 return is_string($target_attribute_value)
Chris@5 80 || is_array($target_attribute_value)
Chris@5 81 && Inspector::assertAllStrings($target_attribute_value);
Chris@5 82 }, array_values($target_attributes)));
Chris@5 83 $generated_url = $url->setAbsolute()->toString(TRUE);
Chris@5 84 $this->href = $generated_url->getGeneratedUrl();
Chris@5 85 $this->uri = $url;
Chris@5 86 $this->rel = $link_relation_types;
Chris@5 87 $this->attributes = $target_attributes;
Chris@5 88 $this->setCacheability($cacheability->addCacheableDependency($generated_url));
Chris@5 89 }
Chris@5 90
Chris@5 91 /**
Chris@5 92 * Gets the link's URI.
Chris@5 93 *
Chris@5 94 * @return \Drupal\Core\Url
Chris@5 95 * The link's URI as a Url object.
Chris@5 96 */
Chris@5 97 public function getUri() {
Chris@5 98 return $this->uri;
Chris@5 99 }
Chris@5 100
Chris@5 101 /**
Chris@5 102 * Gets the link's URI as a string.
Chris@5 103 *
Chris@5 104 * @return string
Chris@5 105 * The link's URI as a string.
Chris@5 106 */
Chris@5 107 public function getHref() {
Chris@5 108 return $this->href;
Chris@5 109 }
Chris@5 110
Chris@5 111 /**
Chris@5 112 * Gets the link's relation types.
Chris@5 113 *
Chris@5 114 * @return string[]
Chris@5 115 * The link's relation types.
Chris@5 116 */
Chris@5 117 public function getLinkRelationTypes() {
Chris@5 118 return $this->rel;
Chris@5 119 }
Chris@5 120
Chris@5 121 /**
Chris@5 122 * Gets the link's target attributes.
Chris@5 123 *
Chris@5 124 * @return string[]
Chris@5 125 * The link's target attributes.
Chris@5 126 */
Chris@5 127 public function getTargetAttributes() {
Chris@5 128 return $this->attributes;
Chris@5 129 }
Chris@5 130
Chris@5 131 /**
Chris@5 132 * Compares two links by their href.
Chris@5 133 *
Chris@5 134 * @param \Drupal\jsonapi\JsonApiResource\Link $a
Chris@5 135 * The first link.
Chris@5 136 * @param \Drupal\jsonapi\JsonApiResource\Link $b
Chris@5 137 * The second link.
Chris@5 138 *
Chris@5 139 * @return int
Chris@5 140 * The result of strcmp() on the links' hrefs.
Chris@5 141 */
Chris@5 142 public static function compare(Link $a, Link $b) {
Chris@5 143 return strcmp($a->getHref(), $b->getHref());
Chris@5 144 }
Chris@5 145
Chris@5 146 /**
Chris@5 147 * Merges two link objects' relation types and target attributes.
Chris@5 148 *
Chris@5 149 * The links must share the same URI.
Chris@5 150 *
Chris@5 151 * @param \Drupal\jsonapi\JsonApiResource\Link $a
Chris@5 152 * The first link.
Chris@5 153 * @param \Drupal\jsonapi\JsonApiResource\Link $b
Chris@5 154 * The second link.
Chris@5 155 *
Chris@5 156 * @return static
Chris@5 157 * A new JSON:API Link object with the link relation type and target
Chris@5 158 * attributes merged.
Chris@5 159 */
Chris@5 160 public static function merge(Link $a, Link $b) {
Chris@5 161 assert(static::compare($a, $b) === 0);
Chris@5 162 $merged_rels = array_unique(array_merge($a->getLinkRelationTypes(), $b->getLinkRelationTypes()));
Chris@5 163 $merged_attributes = $a->getTargetAttributes();
Chris@5 164 foreach ($b->getTargetAttributes() as $key => $value) {
Chris@5 165 if (isset($merged_attributes[$key])) {
Chris@5 166 // The attribute values can be either a string or an array of strings.
Chris@5 167 $value = array_unique(array_merge(
Chris@5 168 is_string($merged_attributes[$key]) ? [$merged_attributes[$key]] : $merged_attributes[$key],
Chris@5 169 is_string($value) ? [$value] : $value
Chris@5 170 ));
Chris@5 171 }
Chris@5 172 $merged_attributes[$key] = count($value) === 1 ? reset($value) : $value;
Chris@5 173 }
Chris@5 174 $merged_cacheability = (new CacheableMetadata())->addCacheableDependency($a)->addCacheableDependency($b);
Chris@5 175 return new static($merged_cacheability, $a->getUri(), $merged_rels, $merged_attributes);
Chris@5 176 }
Chris@5 177
Chris@5 178 }