From 1fe568bdbf6b22e7cecf6e9c84e7c81d775cf05c Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sat, 16 Nov 2024 16:50:59 +0100 Subject: [PATCH] [Map] Complete and simplify the normalization/denormalization process of Map's value objects, add MapOptionsNormalizer --- .../Google/tests/GoogleRendererTest.php | 18 ++--- .../Leaflet/tests/LeafletRendererTest.php | 15 +++- .../UnableToDenormalizeOptionsException.php | 34 +++++++++ .../UnableToNormalizeOptionsException.php | 32 ++++++++ src/Map/src/InfoWindow.php | 8 +- src/Map/src/Live/ComponentWithMapTrait.php | 75 +++++++++++++++++++ src/Map/src/Map.php | 8 +- src/Map/src/MapOptionsNormalizer.php | 67 +++++++++++++++++ src/Map/src/Marker.php | 2 +- src/Map/src/Polygon.php | 2 +- src/Map/tests/DummyOptions.php | 52 +++++++++++++ src/Map/tests/MapFactoryTest.php | 47 ++++++++++++ src/Map/tests/MapOptionsNormalizerTest.php | 59 +++++++++++++++ src/Map/tests/MapTest.php | 53 ++++++------- 14 files changed, 425 insertions(+), 47 deletions(-) create mode 100644 src/Map/src/Exception/UnableToDenormalizeOptionsException.php create mode 100644 src/Map/src/Exception/UnableToNormalizeOptionsException.php create mode 100644 src/Map/src/Live/ComponentWithMapTrait.php create mode 100644 src/Map/src/MapOptionsNormalizer.php create mode 100644 src/Map/tests/DummyOptions.php create mode 100644 src/Map/tests/MapOptionsNormalizerTest.php diff --git a/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php b/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php index ee183792997..df73d90c463 100644 --- a/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php +++ b/src/Map/src/Bridge/Google/tests/GoogleRendererTest.php @@ -29,26 +29,26 @@ public function provideTestRenderMap(): iterable ->zoom(12); yield 'simple map, with minimum options' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), apiKey: 'api_key'), 'map' => $map, ]; yield 'with every options' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), apiKey: 'api_key', id: 'gmap', language: 'fr', region: 'FR', nonce: 'abcd', retries: 10, url: 'https://maps.googleapis.com/maps/api/js', version: 'quarterly'), 'map' => $map, ]; yield 'with custom attributes' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), apiKey: 'api_key'), 'map' => $map, 'attributes' => ['data-controller' => 'my-custom-controller', 'class' => 'map'], ]; yield 'with markers and infoWindows' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), apiKey: 'api_key'), 'map' => (clone $map) ->addMarker(new Marker(new Point(48.8566, 2.3522), 'Paris')) @@ -56,7 +56,7 @@ public function provideTestRenderMap(): iterable ]; yield 'with controls enabled' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), apiKey: 'api_key'), 'map' => (clone $map) ->options(new GoogleOptions( @@ -68,7 +68,7 @@ public function provideTestRenderMap(): iterable ]; yield 'without controls enabled' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), apiKey: 'api_key'), 'map' => (clone $map) ->options(new GoogleOptions( @@ -80,18 +80,18 @@ public function provideTestRenderMap(): iterable ]; yield 'with default map id' => [ - 'expected_renderer' => '
', + 'expected_renderer' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), 'my_api_key', defaultMapId: 'DefaultMapId'), 'map' => (clone $map), ]; yield 'with default map id, when passing options (except the "mapId")' => [ - 'expected_renderer' => '
', + 'expected_renderer' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), 'my_api_key', defaultMapId: 'DefaultMapId'), 'map' => (clone $map) ->options(new GoogleOptions()), ]; yield 'with default map id overridden by option "mapId"' => [ - 'expected_renderer' => '
', + 'expected_renderer' => '
', 'renderer' => new GoogleRenderer(new StimulusHelper(null), 'my_api_key', defaultMapId: 'DefaultMapId'), 'map' => (clone $map) ->options(new GoogleOptions(mapId: 'CustomMapId')), diff --git a/src/Map/src/Bridge/Leaflet/tests/LeafletRendererTest.php b/src/Map/src/Bridge/Leaflet/tests/LeafletRendererTest.php index 6138407bf6a..b7e1394e3d0 100644 --- a/src/Map/src/Bridge/Leaflet/tests/LeafletRendererTest.php +++ b/src/Map/src/Bridge/Leaflet/tests/LeafletRendererTest.php @@ -16,6 +16,7 @@ use Symfony\UX\Map\Map; use Symfony\UX\Map\Marker; use Symfony\UX\Map\Point; +use Symfony\UX\Map\Polygon; use Symfony\UX\Map\Test\RendererTestCase; use Symfony\UX\StimulusBundle\Helper\StimulusHelper; @@ -28,24 +29,32 @@ public function provideTestRenderMap(): iterable ->zoom(12); yield 'simple map' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new LeafletRenderer(new StimulusHelper(null)), 'map' => $map, ]; yield 'with custom attributes' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new LeafletRenderer(new StimulusHelper(null)), 'map' => $map, 'attributes' => ['data-controller' => 'my-custom-controller', 'class' => 'map'], ]; yield 'with markers and infoWindows' => [ - 'expected_render' => '
', + 'expected_render' => '
', 'renderer' => new LeafletRenderer(new StimulusHelper(null)), 'map' => (clone $map) ->addMarker(new Marker(new Point(48.8566, 2.3522), 'Paris')) ->addMarker(new Marker(new Point(48.8566, 2.3522), 'Lyon', infoWindow: new InfoWindow(content: 'Lyon'))), ]; + + yield 'with polygons and infoWindows' => [ + 'expected_render' => '
', + 'renderer' => new LeafletRenderer(new StimulusHelper(null)), + 'map' => (clone $map) + ->addPolygon(new Polygon(points: [new Point(48.8566, 2.3522), new Point(48.8566, 2.3522), new Point(48.8566, 2.3522)])) + ->addPolygon(new Polygon(points: [new Point(1.1, 2.2), new Point(3.3, 4.4), new Point(5.5, 6.6)], infoWindow: new InfoWindow(content: 'Polygon'))), + ]; } } diff --git a/src/Map/src/Exception/UnableToDenormalizeOptionsException.php b/src/Map/src/Exception/UnableToDenormalizeOptionsException.php new file mode 100644 index 00000000000..6fa13a43e33 --- /dev/null +++ b/src/Map/src/Exception/UnableToDenormalizeOptionsException.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\Map\Exception; + +use Symfony\UX\Map\MapOptionsInterface; + +final class UnableToDenormalizeOptionsException extends LogicException +{ + public function __construct(string $message) + { + parent::__construct(\sprintf('Unable to denormalize the map options: %s', $message)); + } + + public static function missingProviderKey(string $key): self + { + return new self(\sprintf('the provider key ("%s") is missing in the normalized options.', $key)); + } + + public static function unsupportedProvider(string $provider, array $supportedProviders): self + { + return new self(\sprintf('the provider "%s" is not supported. Supported providers are "%s".', $provider, implode('", "', $supportedProviders))); + } +} diff --git a/src/Map/src/Exception/UnableToNormalizeOptionsException.php b/src/Map/src/Exception/UnableToNormalizeOptionsException.php new file mode 100644 index 00000000000..081888b896a --- /dev/null +++ b/src/Map/src/Exception/UnableToNormalizeOptionsException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\Map\Exception; + +use Symfony\UX\Map\MapOptionsInterface; + +final class UnableToNormalizeOptionsException extends LogicException +{ + public function __construct(string $message) + { + parent::__construct(\sprintf('Unable to normalize the map options: %s', $message)); + } + + /** + * @param class-string $classOptions + */ + public static function unsupportedProviderClass(string $classOptions): self + { + return new self(\sprintf('the class "%s" is not supported.', $classOptions)); + } +} diff --git a/src/Map/src/InfoWindow.php b/src/Map/src/InfoWindow.php index 6416d6cb8ff..f3f1cb9dd5e 100644 --- a/src/Map/src/InfoWindow.php +++ b/src/Map/src/InfoWindow.php @@ -50,7 +50,7 @@ public function toArray(): array 'position' => $this->position?->toArray(), 'opened' => $this->opened, 'autoClose' => $this->autoClose, - 'extra' => (object) $this->extra, + 'extra' => $this->extra, ]; } @@ -61,7 +61,7 @@ public function toArray(): array * position: array{lat: float, lng: float}|null, * opened: bool, * autoClose: bool, - * extra: object, + * extra: array, * } $data * * @internal @@ -71,10 +71,6 @@ public static function fromArray(array $data): self if (isset($data['position'])) { $data['position'] = Point::fromArray($data['position']); } - - if (isset($data['extra'])) { - $data['extra'] = (array) $data['extra']; - } return new self(...$data); } diff --git a/src/Map/src/Live/ComponentWithMapTrait.php b/src/Map/src/Live/ComponentWithMapTrait.php new file mode 100644 index 00000000000..cb0a50ae4c5 --- /dev/null +++ b/src/Map/src/Live/ComponentWithMapTrait.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\Map\Live; + +use Symfony\UX\LiveComponent\Attribute\LiveProp; +use Symfony\UX\Map\Map; +use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate; +use Symfony\UX\TwigComponent\Attribute\PostMount; + +/** + * + * @author Hugo Alliaume + */ +trait ComponentWithMapTrait +{ + /** + * @internal + */ + #[LiveProp(hydrateWith: 'hydrateMap', dehydrateWith: 'dehydrateMap')] + #[ExposeInTemplate(getter: 'getMap')] + public ?Map $map = null; + + abstract protected function instantiateMap(): Map; + + public function getMap(): Map + { + if (null === $this->map) { + $this->map = $this->instantiateMap(); + } + + return $this->map; + } + + /** + * @internal + */ + #[PostMount] + public function initializeMap(array $data): array + { + // allow the Map object to be passed into the component() as "map" + if (\array_key_exists('map', $data)) { + $this->map = $data['map']; + unset($data['map']); + } + + return $data; + } + + /** + * @internal + */ + public function hydrateMap(array $data): Map + { + return Map::fromArray($data); + } + + /** + * @internal + */ + public function dehydrateMap(Map $map): array + { + return $map->toArray(); + } +} diff --git a/src/Map/src/Map.php b/src/Map/src/Map.php index 3ab240ae1e2..374b7e1a8ad 100644 --- a/src/Map/src/Map.php +++ b/src/Map/src/Map.php @@ -111,7 +111,7 @@ public function toArray(): array 'center' => $this->center?->toArray(), 'zoom' => $this->zoom, 'fitBoundsToMarkers' => $this->fitBoundsToMarkers, - 'options' => (object) ($this->options?->toArray() ?? []), + 'options' => $this->options ? MapOptionsNormalizer::normalize($this->options) : [], 'markers' => array_map(static fn (Marker $marker) => $marker->toArray(), $this->markers), 'polygons' => array_map(static fn (Polygon $polygon) => $polygon->toArray(), $this->polygons), ]; @@ -124,7 +124,7 @@ public function toArray(): array * markers?: list, * polygons?: list, * fitBoundsToMarkers?: bool, - * options?: object, + * options?: array, * } $map * * @internal @@ -133,6 +133,10 @@ public static function fromArray(array $map): self { $map['fitBoundsToMarkers'] = true; + if (isset($map['options'])) { + $map['options'] = [] === $map['options'] ? null : MapOptionsNormalizer::denormalize($map['options']); + } + if (isset($map['center'])) { $map['center'] = Point::fromArray($map['center']); } diff --git a/src/Map/src/MapOptionsNormalizer.php b/src/Map/src/MapOptionsNormalizer.php new file mode 100644 index 00000000000..f0e5abcfac8 --- /dev/null +++ b/src/Map/src/MapOptionsNormalizer.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\Map; + +use Symfony\UX\Map\Bridge as MapBridge; +use Symfony\UX\Map\Exception\UnableToDenormalizeOptionsException; +use Symfony\UX\Map\Exception\UnableToNormalizeOptionsException; + +/** + * Normalizes and denormalizes map options. + * + * @internal + * @author Hugo Alliaume + */ +final class MapOptionsNormalizer +{ + private const string KEY_PROVIDER = '@provider'; + + /** + * @var array> + */ + public static array $providers = [ + 'google' => MapBridge\Google\GoogleOptions::class, + 'leaflet' => MapBridge\Leaflet\LeafletOptions::class, + ]; + + public static function denormalize(array $array): MapOptionsInterface + { + if (null === ($provider = $array[self::KEY_PROVIDER] ?? null)) { + throw UnableToDenormalizeOptionsException::missingProviderKey(self::KEY_PROVIDER); + } + + if (!isset(self::$providers[$provider])) { + throw UnableToDenormalizeOptionsException::unsupportedProvider($provider, array_keys(self::$providers)); + } + + unset($array[self::KEY_PROVIDER]); + + $class = self::$providers[$provider]; + + return $class::fromArray($array); + } + + public static function normalize(MapOptionsInterface $options): array + { + $provider = array_search($options::class, self::$providers, true); + if (!\is_string($provider)) { + throw UnableToNormalizeOptionsException::unsupportedProviderClass($options::class); + } + + $array = $options->toArray(); + $array[self::KEY_PROVIDER] = $provider; + + return $array; + } +} diff --git a/src/Map/src/Marker.php b/src/Map/src/Marker.php index ac0dc0e0af6..f14082f9977 100644 --- a/src/Map/src/Marker.php +++ b/src/Map/src/Marker.php @@ -46,7 +46,7 @@ public function toArray(): array 'position' => $this->position->toArray(), 'title' => $this->title, 'infoWindow' => $this->infoWindow?->toArray(), - 'extra' => (object) $this->extra, + 'extra' => $this->extra, ]; } diff --git a/src/Map/src/Polygon.php b/src/Map/src/Polygon.php index 5d474346e7d..7dd4cc60ce6 100644 --- a/src/Map/src/Polygon.php +++ b/src/Map/src/Polygon.php @@ -40,7 +40,7 @@ public function toArray(): array 'points' => array_map(fn (Point $point) => $point->toArray(), $this->points), 'title' => $this->title, 'infoWindow' => $this->infoWindow?->toArray(), - 'extra' => (object) $this->extra, + 'extra' => $this->extra, ]; } diff --git a/src/Map/tests/DummyOptions.php b/src/Map/tests/DummyOptions.php new file mode 100644 index 00000000000..f04acc97a12 --- /dev/null +++ b/src/Map/tests/DummyOptions.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\Map\Tests; + +use Symfony\UX\Map\MapOptionsInterface; +use Symfony\UX\Map\MapOptionsNormalizer; + +final readonly class DummyOptions implements MapOptionsInterface +{ + public function __construct( + private string $mapId, + private string $mapType, + ) { + } + + public static function registerToNormalizer(): void + { + MapOptionsNormalizer::$providers['dummy'] = self::class; + } + + public static function unregisterFromNormalizer(): void + { + unset(MapOptionsNormalizer::$providers['dummy']); + } + + public static function fromArray(array $array): MapOptionsInterface + { + return new self( + $array['mapId'], + $array['mapType'], + ); + } + + public function toArray(): array + { + return [ + 'mapId' => $this->mapId, + 'mapType' => $this->mapType, + ]; + } +} diff --git a/src/Map/tests/MapFactoryTest.php b/src/Map/tests/MapFactoryTest.php index fcff3b0539c..bdf737cb320 100644 --- a/src/Map/tests/MapFactoryTest.php +++ b/src/Map/tests/MapFactoryTest.php @@ -12,10 +12,24 @@ namespace Symfony\UX\Map\Tests; use PHPUnit\Framework\TestCase; +use Symfony\UX\Map\InfoWindow; use Symfony\UX\Map\Map; +use Symfony\UX\Map\Marker; +use Symfony\UX\Map\Point; +use Symfony\UX\Map\Polygon; class MapFactoryTest extends TestCase { + protected function setUp(): void + { + DummyOptions::registerToNormalizer(); + } + + protected function tearDown(): void + { + DummyOptions::unregisterFromNormalizer(); + } + public function testFromArray(): void { $array = self::createMapArray(); @@ -41,6 +55,39 @@ public function testFromArray(): void $this->assertSame($array['polygons'][0]['infoWindow']['content'], $polygons[0]['infoWindow']['content']); } + public function testToArrayFromArray(): void + { + $map = (new Map()) + ->center(new Point(48.8566, 2.3522)) + ->zoom(12) + ->addMarker(new Marker( + position: new Point(48.8566, 2.3522), + title: 'Paris', + infoWindow: new InfoWindow('Welcome to Paris, the city of lights', extra: ['color' => 'red']), + extra: ['color' => 'blue'], + )) + ->addMarker(new Marker( + position: new Point(44.837789, -0.57918), + title: 'Bordeaux', + infoWindow: new InfoWindow('Welcome to Bordeaux, the city of wine', extra: ['color' => 'red']), + extra: ['color' => 'blue'], + )) + ->addPolygon(new Polygon( + points: [ + new Point(48.858844, 2.294351), + new Point(48.853, 2.3499), + new Point(48.8566, 2.3522), + ], + title: 'Polygon 1', + infoWindow: new InfoWindow('Polygon 1', 'Polygon 1', extra: ['color' => 'red']), + extra: ['color' => 'blue'], + )); + + $newMap = Map::fromArray($map->toArray()); + + $this->assertEquals($map->toArray(), $newMap->toArray()); + } + public function testFromArrayWithInvalidCenter(): void { $array = self::createMapArray(); diff --git a/src/Map/tests/MapOptionsNormalizerTest.php b/src/Map/tests/MapOptionsNormalizerTest.php new file mode 100644 index 00000000000..de859f45d7e --- /dev/null +++ b/src/Map/tests/MapOptionsNormalizerTest.php @@ -0,0 +1,59 @@ +expectException(UnableToDenormalizeOptionsException::class); + $this->expectExceptionMessage(' the provider key ("@provider") is missing in the normalized options.'); + + MapOptionsNormalizer::denormalize([]); + } + + public function testDenormalizingWhenProviderIsNotSupported(): void + { + $this->expectException(UnableToDenormalizeOptionsException::class); + $this->expectExceptionMessage(' the provider "foo" is not supported. Supported providers are "google", "leaflet".'); + + MapOptionsNormalizer::denormalize(['@provider' => 'foo']); + } + + public function testDenormalizingAndNormalizing(): void + { + DummyOptions::registerToNormalizer(); + + $options = MapOptionsNormalizer::denormalize([ + '@provider' => 'dummy', + 'mapId' => 'abcdef', + 'mapType' => 'satellite', + ]); + + self::assertInstanceOf(DummyOptions::class, $options); + self::assertEquals([ + 'mapId' => 'abcdef', + 'mapType' => 'satellite', + ], $options->toArray()); + + self::assertEquals([ + '@provider' => 'dummy', + 'mapId' => 'abcdef', + 'mapType' => 'satellite', + ], MapOptionsNormalizer::normalize($options)); + + self::assertEquals($options, MapOptionsNormalizer::denormalize(MapOptionsNormalizer::normalize($options))); + } +} diff --git a/src/Map/tests/MapTest.php b/src/Map/tests/MapTest.php index 95703724466..7445dbc8b52 100644 --- a/src/Map/tests/MapTest.php +++ b/src/Map/tests/MapTest.php @@ -15,13 +15,22 @@ use Symfony\UX\Map\Exception\InvalidArgumentException; use Symfony\UX\Map\InfoWindow; use Symfony\UX\Map\Map; -use Symfony\UX\Map\MapOptionsInterface; use Symfony\UX\Map\Marker; use Symfony\UX\Map\Point; use Symfony\UX\Map\Polygon; class MapTest extends TestCase { + protected function setUp(): void + { + DummyOptions::registerToNormalizer(); + } + + protected function tearDown(): void + { + DummyOptions::unregisterFromNormalizer(); + } + public function testCenterValidation(): void { self::expectException(InvalidArgumentException::class); @@ -86,18 +95,12 @@ public function testWithMaximumConfiguration(): void ->center(new Point(48.8566, 2.3522)) ->zoom(6) ->fitBoundsToMarkers() - ->options(new class implements MapOptionsInterface { - public function toArray(): array - { - return [ - 'mapTypeId' => 'roadmap', - ]; - } - }) + ->options(new DummyOptions(mapId: '1a2b3c4d5e', mapType: 'roadmap')) ->addMarker(new Marker( position: new Point(48.8566, 2.3522), title: 'Paris', - infoWindow: new InfoWindow(headerContent: 'Paris', content: 'Paris', position: new Point(48.8566, 2.3522)) + infoWindow: new InfoWindow(headerContent: 'Paris', content: 'Paris', position: new Point(48.8566, 2.3522), extra: ['baz' => 'qux']), + extra: ['foo' => 'bar'], )) ->addMarker(new Marker( position: new Point(45.764, 4.8357), @@ -135,13 +138,15 @@ public function toArray(): array )) ; - $array = $map->toArray(); - self::assertEquals([ 'center' => ['lat' => 48.8566, 'lng' => 2.3522], 'zoom' => 6.0, 'fitBoundsToMarkers' => true, - 'options' => $array['options'], + 'options' => [ + '@provider' => 'dummy', + 'mapId' => '1a2b3c4d5e', + 'mapType' => 'roadmap', + ], 'markers' => [ [ 'position' => ['lat' => 48.8566, 'lng' => 2.3522], @@ -152,9 +157,9 @@ public function toArray(): array 'position' => ['lat' => 48.8566, 'lng' => 2.3522], 'opened' => false, 'autoClose' => true, - 'extra' => $array['markers'][0]['infoWindow']['extra'], + 'extra' => ['baz' => 'qux'], ], - 'extra' => $array['markers'][0]['extra'], + 'extra' => ['foo' => 'bar'], ], [ 'position' => ['lat' => 45.764, 'lng' => 4.8357], @@ -165,9 +170,9 @@ public function toArray(): array 'position' => ['lat' => 45.764, 'lng' => 4.8357], 'opened' => true, 'autoClose' => true, - 'extra' => $array['markers'][1]['infoWindow']['extra'], + 'extra' => [], ], - 'extra' => $array['markers'][1]['extra'], + 'extra' => [], ], [ 'position' => ['lat' => 43.2965, 'lng' => 5.3698], @@ -178,9 +183,9 @@ public function toArray(): array 'position' => ['lat' => 43.2965, 'lng' => 5.3698], 'opened' => true, 'autoClose' => true, - 'extra' => $array['markers'][2]['infoWindow']['extra'], + 'extra' => [], ], - 'extra' => $array['markers'][2]['extra'], + 'extra' => [], ], ], 'polygons' => [ @@ -192,7 +197,7 @@ public function toArray(): array ], 'title' => 'Polygon 1', 'infoWindow' => null, - 'extra' => $array['polygons'][0]['extra'], + 'extra' => [], ], [ 'points' => [ @@ -207,13 +212,11 @@ public function toArray(): array 'position' => ['lat' => 45.764, 'lng' => 4.8357], 'opened' => true, 'autoClose' => true, - 'extra' => $array['polygons'][1]['infoWindow']['extra'], + 'extra' => [], ], - 'extra' => $array['polygons'][1]['extra'], + 'extra' => [], ], ], - ], $array); - - self::assertSame('roadmap', $array['options']->mapTypeId); + ], $map->toArray()); } }