annotate core/modules/jsonapi/src/JsonApiResource/Link.php @ 19:fa3358dc1485 tip

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