From f944ef3f47d4e187f080e8d5a553ea2da8ec21b4 Mon Sep 17 00:00:00 2001 From: Lee Rowlands <lee.rowlands@previousnext.com.au> Date: Thu, 15 Aug 2019 10:32:38 +1000 Subject: [PATCH] Issue #3052931 by gabesullice, Wim Leers, larowlan: Permit arrays as target attribute values in Drupal\jsonapi\JsonApiResource\Link --- .../jsonapi/src/JsonApiResource/Link.php | 16 +-- .../src/Unit/JsonApiResource/LinkTest.php | 99 +++++++++++++++++++ 2 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 core/modules/jsonapi/tests/src/Unit/JsonApiResource/LinkTest.php diff --git a/core/modules/jsonapi/src/JsonApiResource/Link.php b/core/modules/jsonapi/src/JsonApiResource/Link.php index 1da2d0afe8a1..5634f983df56 100644 --- a/core/modules/jsonapi/src/JsonApiResource/Link.php +++ b/core/modules/jsonapi/src/JsonApiResource/Link.php @@ -76,9 +76,7 @@ public function __construct(CacheableMetadata $cacheability, Url $url, array $li assert(/* !empty($link_relation_types) && */Inspector::assertAllStrings($link_relation_types)); assert(Inspector::assertAllStrings(array_keys($target_attributes))); assert(Inspector::assertAll(function ($target_attribute_value) { - return is_string($target_attribute_value) - || is_array($target_attribute_value) - && Inspector::assertAllStrings($target_attribute_value); + return is_string($target_attribute_value) || is_array($target_attribute_value); }, array_values($target_attributes))); $generated_url = $url->setAbsolute()->toString(TRUE); $this->href = $generated_url->getGeneratedUrl(); @@ -160,17 +158,7 @@ public static function compare(Link $a, Link $b) { public static function merge(Link $a, Link $b) { assert(static::compare($a, $b) === 0); $merged_rels = array_unique(array_merge($a->getLinkRelationTypes(), $b->getLinkRelationTypes())); - $merged_attributes = $a->getTargetAttributes(); - foreach ($b->getTargetAttributes() as $key => $value) { - if (isset($merged_attributes[$key])) { - // The attribute values can be either a string or an array of strings. - $value = array_unique(array_merge( - is_string($merged_attributes[$key]) ? [$merged_attributes[$key]] : $merged_attributes[$key], - is_string($value) ? [$value] : $value - )); - } - $merged_attributes[$key] = count($value) === 1 ? reset($value) : $value; - } + $merged_attributes = array_merge_recursive($a->getTargetAttributes(), $b->getTargetAttributes()); $merged_cacheability = (new CacheableMetadata())->addCacheableDependency($a)->addCacheableDependency($b); return new static($merged_cacheability, $a->getUri(), $merged_rels, $merged_attributes); } diff --git a/core/modules/jsonapi/tests/src/Unit/JsonApiResource/LinkTest.php b/core/modules/jsonapi/tests/src/Unit/JsonApiResource/LinkTest.php new file mode 100644 index 000000000000..91441a8ea5ec --- /dev/null +++ b/core/modules/jsonapi/tests/src/Unit/JsonApiResource/LinkTest.php @@ -0,0 +1,99 @@ +<?php + +namespace Drupal\Tests\jsonapi\Unit\JsonApiResource; + +use Drupal\Core\Cache\CacheableMetadata; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\GeneratedUrl; +use Drupal\Core\Url; +use Drupal\Core\Utility\UnroutedUrlAssemblerInterface; +use Drupal\jsonapi\JsonApiResource\Link; +use Drupal\Tests\UnitTestCase; + +/** + * @coversDefaultClass \Drupal\jsonapi\JsonApiResource\Link + * @group jsonapi + * + * @internal + */ +class LinkTest extends UnitTestCase { + + /** + * @covers ::merge + * @dataProvider mergeTargetAttributesProvider + */ + public function testMergeTargetAttributes($a, $b, $expected) { + $this->assertSame($expected->getTargetAttributes(), Link::merge($a, $b)->getTargetAttributes()); + } + + /** + * Provides test data for link merging. + */ + public function mergeTargetAttributesProvider() { + $cases = [ + 'strings' => [ + ['key' => 'foo'], + ['key' => 'bar'], + ['key' => ['foo', 'bar']], + ], + 'string and array' => [ + ['key' => 'foo'], + ['key' => ['bar', 'baz']], + ['key' => ['foo', 'bar', 'baz']], + ], + 'one-dimensional indexed arrays' => [ + ['key' => ['foo']], + ['key' => ['bar']], + ['key' => ['foo', 'bar']], + ], + 'one-dimensional keyed arrays' => [ + ['key' => ['foo' => 'tball']], + ['key' => ['bar' => 'ista']], + [ + 'key' => [ + 'foo' => 'tball', + 'bar' => 'ista', + ], + ], + ], + 'two-dimensional indexed arrays' => [ + ['one' => ['two' => ['foo']]], + ['one' => ['two' => ['bar']]], + ['one' => ['two' => ['foo', 'bar']]], + ], + 'two-dimensional keyed arrays' => [ + ['one' => ['two' => ['foo' => 'tball']]], + ['one' => ['two' => ['bar' => 'ista']]], + [ + 'one' => [ + 'two' => [ + 'foo' => 'tball', + 'bar' => 'ista', + ], + ], + ], + ], + ]; + $this->mockUrlAssembler(); + return array_map(function ($arguments) { + return array_map(function ($attributes) { + return new Link(new CacheableMetadata(), Url::fromUri('https://jsonapi.org/'), ['item'], $attributes); + }, $arguments); + }, $cases); + } + + /** + * Mocks the unrouted URL assembler. + */ + protected function mockUrlAssembler() { + $url_assembler = $this->getMockBuilder(UnroutedUrlAssemblerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $url_assembler->method('assemble')->willReturn((new GeneratedUrl())->setGeneratedUrl('https://jsonapi.org/')); + + $container = new ContainerBuilder(); + $container->set('unrouted_url_assembler', $url_assembler); + \Drupal::setContainer($container); + } + +} -- GitLab