Loading core/modules/jsonapi/src/Normalizer/LinkCollectionNormalizer.php +25 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ * * When normalizing more than one link in a LinkCollection with the same key, a * unique and random string is appended to the link's key after a double dash * (--) to differentiate the links. * (--) to differentiate the links. See this class's hashByHref() method for * details. * * This may change with a later version of the JSON:API specification. * Loading Loading @@ -82,7 +83,15 @@ public function normalize($object, $format = NULL, array $context = []) { } /** * Hashes a link by its href. * Hashes a link using its href and its target attributes, if any. * * This method generates an unpredictable, but deterministic, 7 character * alphanumeric hash for a given link. * * The hash is unpredictable because a random hash salt will be used for every * request. The hash is deterministic because, within a single request, links * with the same href and target attributes (i.o.w. duplicates) will generate * equivalent hash values. * * @param \Drupal\jsonapi\JsonApiResource\Link $link * A link to be hashed. Loading @@ -91,10 +100,23 @@ public function normalize($object, $format = NULL, array $context = []) { * A 7 character alphanumeric hash. */ protected function hashByHref(Link $link) { // Generate a salt unique to each instance of this class. if (!$this->hashSalt) { $this->hashSalt = Crypt::randomBytesBase64(); } return substr(str_replace(['-', '_'], '', Crypt::hashBase64($this->hashSalt . $link->getHref())), 0, 7); // Create a dictionary of link parameters. $link_parameters = [ 'href' => $link->getHref(), ] + $link->getTargetAttributes(); // Serialize the dictionary into a string. foreach ($link_parameters as $name => $value) { $serialized_parameters[] = sprintf('%s="%s"', $name, implode(' ', (array) $value)); } // Hash the string. $b64_hash = Crypt::hashBase64($this->hashSalt . implode('; ', $serialized_parameters)); // Remove any dashes and underscores from the base64 hash and then return // the first 7 characters. return substr(str_replace(['-', '_'], '', $b64_hash), 0, 7); } } core/modules/jsonapi/tests/src/Kernel/Normalizer/LinkCollectionNormalizerTest.php 0 → 100644 +76 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\jsonapi\Kernel\Normalizer; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Url; use Drupal\jsonapi\JsonApiResource\Link; use Drupal\jsonapi\JsonApiResource\LinkCollection; use Drupal\jsonapi\JsonApiResource\ResourceObject; use Drupal\jsonapi\Normalizer\LinkCollectionNormalizer; use Drupal\jsonapi\ResourceType\ResourceType; use Drupal\KernelTests\KernelTestBase; /** * @coversDefaultClass \Drupal\jsonapi\Normalizer\LinkCollectionNormalizer * @group jsonapi * * @internal */ class LinkCollectionNormalizerTest extends KernelTestBase { /** * The subject under test. * * @var \Symfony\Component\Serializer\Normalizer\NormalizerInterface */ protected $normalizer; /** * {@inheritDoc} */ protected static $modules = [ 'jsonapi', 'serialization', ]; /** * {@inheritDoc} */ protected function setUp(): void { parent::setUp(); $this->normalizer = new LinkCollectionNormalizer(); $this->normalizer->setSerializer($this->container->get('jsonapi.serializer')); } /** * Tests the link collection normalizer. */ public function testNormalize() { $link_context = new ResourceObject(new CacheableMetadata(), new ResourceType('n/a', 'n/a', 'n/a'), 'n/a', NULL, [], new LinkCollection([])); $link_collection = (new LinkCollection([])) ->withLink('related', new Link(new CacheableMetadata(), Url::fromUri('http://example.com/post/42'), 'related', ['title' => 'Most viewed'])) ->withLink('related', new Link(new CacheableMetadata(), Url::fromUri('http://example.com/post/42'), 'related', ['title' => 'Top rated'])) ->withContext($link_context); $normalized = $this->normalizer->normalize($link_collection)->getNormalization(); $this->assertIsArray($normalized); foreach (array_keys($normalized) as $key) { $this->assertStringStartsWith('related', $key); } $this->assertSame([ [ 'href' => 'http://example.com/post/42', 'meta' => [ 'title' => 'Most viewed', ], ], [ 'href' => 'http://example.com/post/42', 'meta' => [ 'title' => 'Top rated', ], ], ], array_values($normalized)); } } Loading
core/modules/jsonapi/src/Normalizer/LinkCollectionNormalizer.php +25 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ * * When normalizing more than one link in a LinkCollection with the same key, a * unique and random string is appended to the link's key after a double dash * (--) to differentiate the links. * (--) to differentiate the links. See this class's hashByHref() method for * details. * * This may change with a later version of the JSON:API specification. * Loading Loading @@ -82,7 +83,15 @@ public function normalize($object, $format = NULL, array $context = []) { } /** * Hashes a link by its href. * Hashes a link using its href and its target attributes, if any. * * This method generates an unpredictable, but deterministic, 7 character * alphanumeric hash for a given link. * * The hash is unpredictable because a random hash salt will be used for every * request. The hash is deterministic because, within a single request, links * with the same href and target attributes (i.o.w. duplicates) will generate * equivalent hash values. * * @param \Drupal\jsonapi\JsonApiResource\Link $link * A link to be hashed. Loading @@ -91,10 +100,23 @@ public function normalize($object, $format = NULL, array $context = []) { * A 7 character alphanumeric hash. */ protected function hashByHref(Link $link) { // Generate a salt unique to each instance of this class. if (!$this->hashSalt) { $this->hashSalt = Crypt::randomBytesBase64(); } return substr(str_replace(['-', '_'], '', Crypt::hashBase64($this->hashSalt . $link->getHref())), 0, 7); // Create a dictionary of link parameters. $link_parameters = [ 'href' => $link->getHref(), ] + $link->getTargetAttributes(); // Serialize the dictionary into a string. foreach ($link_parameters as $name => $value) { $serialized_parameters[] = sprintf('%s="%s"', $name, implode(' ', (array) $value)); } // Hash the string. $b64_hash = Crypt::hashBase64($this->hashSalt . implode('; ', $serialized_parameters)); // Remove any dashes and underscores from the base64 hash and then return // the first 7 characters. return substr(str_replace(['-', '_'], '', $b64_hash), 0, 7); } }
core/modules/jsonapi/tests/src/Kernel/Normalizer/LinkCollectionNormalizerTest.php 0 → 100644 +76 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\jsonapi\Kernel\Normalizer; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Url; use Drupal\jsonapi\JsonApiResource\Link; use Drupal\jsonapi\JsonApiResource\LinkCollection; use Drupal\jsonapi\JsonApiResource\ResourceObject; use Drupal\jsonapi\Normalizer\LinkCollectionNormalizer; use Drupal\jsonapi\ResourceType\ResourceType; use Drupal\KernelTests\KernelTestBase; /** * @coversDefaultClass \Drupal\jsonapi\Normalizer\LinkCollectionNormalizer * @group jsonapi * * @internal */ class LinkCollectionNormalizerTest extends KernelTestBase { /** * The subject under test. * * @var \Symfony\Component\Serializer\Normalizer\NormalizerInterface */ protected $normalizer; /** * {@inheritDoc} */ protected static $modules = [ 'jsonapi', 'serialization', ]; /** * {@inheritDoc} */ protected function setUp(): void { parent::setUp(); $this->normalizer = new LinkCollectionNormalizer(); $this->normalizer->setSerializer($this->container->get('jsonapi.serializer')); } /** * Tests the link collection normalizer. */ public function testNormalize() { $link_context = new ResourceObject(new CacheableMetadata(), new ResourceType('n/a', 'n/a', 'n/a'), 'n/a', NULL, [], new LinkCollection([])); $link_collection = (new LinkCollection([])) ->withLink('related', new Link(new CacheableMetadata(), Url::fromUri('http://example.com/post/42'), 'related', ['title' => 'Most viewed'])) ->withLink('related', new Link(new CacheableMetadata(), Url::fromUri('http://example.com/post/42'), 'related', ['title' => 'Top rated'])) ->withContext($link_context); $normalized = $this->normalizer->normalize($link_collection)->getNormalization(); $this->assertIsArray($normalized); foreach (array_keys($normalized) as $key) { $this->assertStringStartsWith('related', $key); } $this->assertSame([ [ 'href' => 'http://example.com/post/42', 'meta' => [ 'title' => 'Most viewed', ], ], [ 'href' => 'http://example.com/post/42', 'meta' => [ 'title' => 'Top rated', ], ], ], array_values($normalized)); } }