Skip to content

Commit 1fe568b

Browse files
committed
[Map] Complete and simplify the normalization/denormalization process of Map's value objects, add MapOptionsNormalizer
1 parent 66b1bcf commit 1fe568b

14 files changed

+425
-47
lines changed

src/Map/src/Bridge/Google/tests/GoogleRendererTest.php

Lines changed: 9 additions & 9 deletions
Large diffs are not rendered by default.

src/Map/src/Bridge/Leaflet/tests/LeafletRendererTest.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\UX\Map\Map;
1717
use Symfony\UX\Map\Marker;
1818
use Symfony\UX\Map\Point;
19+
use Symfony\UX\Map\Polygon;
1920
use Symfony\UX\Map\Test\RendererTestCase;
2021
use Symfony\UX\StimulusBundle\Helper\StimulusHelper;
2122

@@ -28,24 +29,32 @@ public function provideTestRenderMap(): iterable
2829
->zoom(12);
2930

3031
yield 'simple map' => [
31-
'expected_render' => '<div data-controller="symfony--ux-leaflet-map--map" data-symfony--ux-leaflet-map--map-provider-options-value="&#x7B;&#x7D;" data-symfony--ux-leaflet-map--map-center-value="&#x7B;&quot;lat&quot;&#x3A;48.8566,&quot;lng&quot;&#x3A;2.3522&#x7D;" data-symfony--ux-leaflet-map--map-zoom-value="12" data-symfony--ux-leaflet-map--map-fit-bounds-to-markers-value="false" data-symfony--ux-leaflet-map--map-options-value="&#x7B;&quot;tileLayer&quot;&#x3A;&#x7B;&quot;url&quot;&#x3A;&quot;https&#x3A;&#x5C;&#x2F;&#x5C;&#x2F;tile.openstreetmap.org&#x5C;&#x2F;&#x7B;z&#x7D;&#x5C;&#x2F;&#x7B;x&#x7D;&#x5C;&#x2F;&#x7B;y&#x7D;.png&quot;,&quot;attribution&quot;&#x3A;&quot;&#x5C;u00a9&#x20;&lt;a&#x20;href&#x3D;&#x5C;&quot;https&#x3A;&#x5C;&#x2F;&#x5C;&#x2F;www.openstreetmap.org&#x5C;&#x2F;copyright&#x5C;&quot;&gt;OpenStreetMap&lt;&#x5C;&#x2F;a&gt;&quot;,&quot;options&quot;&#x3A;&#x7B;&#x7D;&#x7D;&#x7D;" data-symfony--ux-leaflet-map--map-markers-value="&#x5B;&#x5D;" data-symfony--ux-leaflet-map--map-polygons-value="&#x5B;&#x5D;"></div>',
32+
'expected_render' => '<div data-controller="symfony--ux-leaflet-map--map" data-symfony--ux-leaflet-map--map-provider-options-value="{}" data-symfony--ux-leaflet-map--map-center-value="{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522}" data-symfony--ux-leaflet-map--map-zoom-value="12" data-symfony--ux-leaflet-map--map-fit-bounds-to-markers-value="false" data-symfony--ux-leaflet-map--map-options-value="{&quot;tileLayer&quot;:{&quot;url&quot;:&quot;https:\/\/tile.openstreetmap.org\/{z}\/{x}\/{y}.png&quot;,&quot;attribution&quot;:&quot;\u00a9 &lt;a href=\&quot;https:\/\/www.openstreetmap.org\/copyright\&quot;&gt;OpenStreetMap&lt;\/a&gt;&quot;,&quot;options&quot;:[]},&quot;@provider&quot;:&quot;leaflet&quot;}" data-symfony--ux-leaflet-map--map-markers-value="[]" data-symfony--ux-leaflet-map--map-polygons-value="[]"></div>',
3233
'renderer' => new LeafletRenderer(new StimulusHelper(null)),
3334
'map' => $map,
3435
];
3536

3637
yield 'with custom attributes' => [
37-
'expected_render' => '<div data-controller="my-custom-controller symfony--ux-leaflet-map--map" data-symfony--ux-leaflet-map--map-provider-options-value="&#x7B;&#x7D;" data-symfony--ux-leaflet-map--map-center-value="&#x7B;&quot;lat&quot;&#x3A;48.8566,&quot;lng&quot;&#x3A;2.3522&#x7D;" data-symfony--ux-leaflet-map--map-zoom-value="12" data-symfony--ux-leaflet-map--map-fit-bounds-to-markers-value="false" data-symfony--ux-leaflet-map--map-options-value="&#x7B;&quot;tileLayer&quot;&#x3A;&#x7B;&quot;url&quot;&#x3A;&quot;https&#x3A;&#x5C;&#x2F;&#x5C;&#x2F;tile.openstreetmap.org&#x5C;&#x2F;&#x7B;z&#x7D;&#x5C;&#x2F;&#x7B;x&#x7D;&#x5C;&#x2F;&#x7B;y&#x7D;.png&quot;,&quot;attribution&quot;&#x3A;&quot;&#x5C;u00a9&#x20;&lt;a&#x20;href&#x3D;&#x5C;&quot;https&#x3A;&#x5C;&#x2F;&#x5C;&#x2F;www.openstreetmap.org&#x5C;&#x2F;copyright&#x5C;&quot;&gt;OpenStreetMap&lt;&#x5C;&#x2F;a&gt;&quot;,&quot;options&quot;&#x3A;&#x7B;&#x7D;&#x7D;&#x7D;" data-symfony--ux-leaflet-map--map-markers-value="&#x5B;&#x5D;" data-symfony--ux-leaflet-map--map-polygons-value="&#x5B;&#x5D;" class="map"></div>',
38+
'expected_render' => '<div data-controller="my-custom-controller symfony--ux-leaflet-map--map" data-symfony--ux-leaflet-map--map-provider-options-value="{}" data-symfony--ux-leaflet-map--map-center-value="{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522}" data-symfony--ux-leaflet-map--map-zoom-value="12" data-symfony--ux-leaflet-map--map-fit-bounds-to-markers-value="false" data-symfony--ux-leaflet-map--map-options-value="{&quot;tileLayer&quot;:{&quot;url&quot;:&quot;https:\/\/tile.openstreetmap.org\/{z}\/{x}\/{y}.png&quot;,&quot;attribution&quot;:&quot;\u00a9 &lt;a href=\&quot;https:\/\/www.openstreetmap.org\/copyright\&quot;&gt;OpenStreetMap&lt;\/a&gt;&quot;,&quot;options&quot;:[]},&quot;@provider&quot;:&quot;leaflet&quot;}" data-symfony--ux-leaflet-map--map-markers-value="[]" data-symfony--ux-leaflet-map--map-polygons-value="[]" class="map"></div>',
3839
'renderer' => new LeafletRenderer(new StimulusHelper(null)),
3940
'map' => $map,
4041
'attributes' => ['data-controller' => 'my-custom-controller', 'class' => 'map'],
4142
];
4243

4344
yield 'with markers and infoWindows' => [
44-
'expected_render' => '<div data-controller="symfony--ux-leaflet-map--map" data-symfony--ux-leaflet-map--map-provider-options-value="&#x7B;&#x7D;" data-symfony--ux-leaflet-map--map-center-value="&#x7B;&quot;lat&quot;&#x3A;48.8566,&quot;lng&quot;&#x3A;2.3522&#x7D;" data-symfony--ux-leaflet-map--map-zoom-value="12" data-symfony--ux-leaflet-map--map-fit-bounds-to-markers-value="false" data-symfony--ux-leaflet-map--map-options-value="&#x7B;&quot;tileLayer&quot;&#x3A;&#x7B;&quot;url&quot;&#x3A;&quot;https&#x3A;&#x5C;&#x2F;&#x5C;&#x2F;tile.openstreetmap.org&#x5C;&#x2F;&#x7B;z&#x7D;&#x5C;&#x2F;&#x7B;x&#x7D;&#x5C;&#x2F;&#x7B;y&#x7D;.png&quot;,&quot;attribution&quot;&#x3A;&quot;&#x5C;u00a9&#x20;&lt;a&#x20;href&#x3D;&#x5C;&quot;https&#x3A;&#x5C;&#x2F;&#x5C;&#x2F;www.openstreetmap.org&#x5C;&#x2F;copyright&#x5C;&quot;&gt;OpenStreetMap&lt;&#x5C;&#x2F;a&gt;&quot;,&quot;options&quot;&#x3A;&#x7B;&#x7D;&#x7D;&#x7D;" data-symfony--ux-leaflet-map--map-markers-value="&#x5B;&#x7B;&quot;position&quot;&#x3A;&#x7B;&quot;lat&quot;&#x3A;48.8566,&quot;lng&quot;&#x3A;2.3522&#x7D;,&quot;title&quot;&#x3A;&quot;Paris&quot;,&quot;infoWindow&quot;&#x3A;null,&quot;extra&quot;&#x3A;&#x7B;&#x7D;&#x7D;,&#x7B;&quot;position&quot;&#x3A;&#x7B;&quot;lat&quot;&#x3A;48.8566,&quot;lng&quot;&#x3A;2.3522&#x7D;,&quot;title&quot;&#x3A;&quot;Lyon&quot;,&quot;infoWindow&quot;&#x3A;&#x7B;&quot;headerContent&quot;&#x3A;null,&quot;content&quot;&#x3A;&quot;Lyon&quot;,&quot;position&quot;&#x3A;null,&quot;opened&quot;&#x3A;false,&quot;autoClose&quot;&#x3A;true,&quot;extra&quot;&#x3A;&#x7B;&#x7D;&#x7D;,&quot;extra&quot;&#x3A;&#x7B;&#x7D;&#x7D;&#x5D;" data-symfony--ux-leaflet-map--map-polygons-value="&#x5B;&#x5D;"></div>',
45+
'expected_render' => '<div data-controller="symfony--ux-leaflet-map--map" data-symfony--ux-leaflet-map--map-provider-options-value="{}" data-symfony--ux-leaflet-map--map-center-value="{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522}" data-symfony--ux-leaflet-map--map-zoom-value="12" data-symfony--ux-leaflet-map--map-fit-bounds-to-markers-value="false" data-symfony--ux-leaflet-map--map-options-value="{&quot;tileLayer&quot;:{&quot;url&quot;:&quot;https:\/\/tile.openstreetmap.org\/{z}\/{x}\/{y}.png&quot;,&quot;attribution&quot;:&quot;\u00a9 &lt;a href=\&quot;https:\/\/www.openstreetmap.org\/copyright\&quot;&gt;OpenStreetMap&lt;\/a&gt;&quot;,&quot;options&quot;:[]},&quot;@provider&quot;:&quot;leaflet&quot;}" data-symfony--ux-leaflet-map--map-markers-value="[{&quot;position&quot;:{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522},&quot;title&quot;:&quot;Paris&quot;,&quot;infoWindow&quot;:null,&quot;extra&quot;:[],&quot;@id&quot;:&quot;abd45a2c703af97a&quot;},{&quot;position&quot;:{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522},&quot;title&quot;:&quot;Lyon&quot;,&quot;infoWindow&quot;:{&quot;headerContent&quot;:null,&quot;content&quot;:&quot;Lyon&quot;,&quot;position&quot;:null,&quot;opened&quot;:false,&quot;autoClose&quot;:true,&quot;extra&quot;:[]},&quot;extra&quot;:[],&quot;@id&quot;:&quot;219637cbd8e62ea6&quot;}]" data-symfony--ux-leaflet-map--map-polygons-value="[]"></div>',
4546
'renderer' => new LeafletRenderer(new StimulusHelper(null)),
4647
'map' => (clone $map)
4748
->addMarker(new Marker(new Point(48.8566, 2.3522), 'Paris'))
4849
->addMarker(new Marker(new Point(48.8566, 2.3522), 'Lyon', infoWindow: new InfoWindow(content: 'Lyon'))),
4950
];
51+
52+
yield 'with polygons and infoWindows' => [
53+
'expected_render' => '<div data-controller="symfony--ux-leaflet-map--map" data-symfony--ux-leaflet-map--map-provider-options-value="{}" data-symfony--ux-leaflet-map--map-center-value="{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522}" data-symfony--ux-leaflet-map--map-zoom-value="12" data-symfony--ux-leaflet-map--map-fit-bounds-to-markers-value="false" data-symfony--ux-leaflet-map--map-options-value="{&quot;tileLayer&quot;:{&quot;url&quot;:&quot;https:\/\/tile.openstreetmap.org\/{z}\/{x}\/{y}.png&quot;,&quot;attribution&quot;:&quot;\u00a9 &lt;a href=\&quot;https:\/\/www.openstreetmap.org\/copyright\&quot;&gt;OpenStreetMap&lt;\/a&gt;&quot;,&quot;options&quot;:[]},&quot;@provider&quot;:&quot;leaflet&quot;}" data-symfony--ux-leaflet-map--map-markers-value="[]" data-symfony--ux-leaflet-map--map-polygons-value="[{&quot;points&quot;:[{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522},{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522},{&quot;lat&quot;:48.8566,&quot;lng&quot;:2.3522}],&quot;title&quot;:null,&quot;infoWindow&quot;:null,&quot;extra&quot;:[],&quot;@id&quot;:&quot;2dc7aa290e8fc88a&quot;},{&quot;points&quot;:[{&quot;lat&quot;:1.1,&quot;lng&quot;:2.2},{&quot;lat&quot;:3.3,&quot;lng&quot;:4.4},{&quot;lat&quot;:5.5,&quot;lng&quot;:6.6}],&quot;title&quot;:null,&quot;infoWindow&quot;:{&quot;headerContent&quot;:null,&quot;content&quot;:&quot;Polygon&quot;,&quot;position&quot;:null,&quot;opened&quot;:false,&quot;autoClose&quot;:true,&quot;extra&quot;:[]},&quot;extra&quot;:[],&quot;@id&quot;:&quot;d6cab193e60e5faf&quot;}]"></div>',
54+
'renderer' => new LeafletRenderer(new StimulusHelper(null)),
55+
'map' => (clone $map)
56+
->addPolygon(new Polygon(points: [new Point(48.8566, 2.3522), new Point(48.8566, 2.3522), new Point(48.8566, 2.3522)]))
57+
->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'))),
58+
];
5059
}
5160
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Symfony\UX\Map\Exception;
15+
16+
use Symfony\UX\Map\MapOptionsInterface;
17+
18+
final class UnableToDenormalizeOptionsException extends LogicException
19+
{
20+
public function __construct(string $message)
21+
{
22+
parent::__construct(\sprintf('Unable to denormalize the map options: %s', $message));
23+
}
24+
25+
public static function missingProviderKey(string $key): self
26+
{
27+
return new self(\sprintf('the provider key ("%s") is missing in the normalized options.', $key));
28+
}
29+
30+
public static function unsupportedProvider(string $provider, array $supportedProviders): self
31+
{
32+
return new self(\sprintf('the provider "%s" is not supported. Supported providers are "%s".', $provider, implode('", "', $supportedProviders)));
33+
}
34+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Symfony\UX\Map\Exception;
15+
16+
use Symfony\UX\Map\MapOptionsInterface;
17+
18+
final class UnableToNormalizeOptionsException extends LogicException
19+
{
20+
public function __construct(string $message)
21+
{
22+
parent::__construct(\sprintf('Unable to normalize the map options: %s', $message));
23+
}
24+
25+
/**
26+
* @param class-string<MapOptionsInterface> $classOptions
27+
*/
28+
public static function unsupportedProviderClass(string $classOptions): self
29+
{
30+
return new self(\sprintf('the class "%s" is not supported.', $classOptions));
31+
}
32+
}

src/Map/src/InfoWindow.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public function toArray(): array
5050
'position' => $this->position?->toArray(),
5151
'opened' => $this->opened,
5252
'autoClose' => $this->autoClose,
53-
'extra' => (object) $this->extra,
53+
'extra' => $this->extra,
5454
];
5555
}
5656

@@ -61,7 +61,7 @@ public function toArray(): array
6161
* position: array{lat: float, lng: float}|null,
6262
* opened: bool,
6363
* autoClose: bool,
64-
* extra: object,
64+
* extra: array,
6565
* } $data
6666
*
6767
* @internal
@@ -71,10 +71,6 @@ public static function fromArray(array $data): self
7171
if (isset($data['position'])) {
7272
$data['position'] = Point::fromArray($data['position']);
7373
}
74-
75-
if (isset($data['extra'])) {
76-
$data['extra'] = (array) $data['extra'];
77-
}
7874

7975
return new self(...$data);
8076
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Symfony\UX\Map\Live;
15+
16+
use Symfony\UX\LiveComponent\Attribute\LiveProp;
17+
use Symfony\UX\Map\Map;
18+
use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate;
19+
use Symfony\UX\TwigComponent\Attribute\PostMount;
20+
21+
/**
22+
*
23+
* @author Hugo Alliaume <[email protected]>
24+
*/
25+
trait ComponentWithMapTrait
26+
{
27+
/**
28+
* @internal
29+
*/
30+
#[LiveProp(hydrateWith: 'hydrateMap', dehydrateWith: 'dehydrateMap')]
31+
#[ExposeInTemplate(getter: 'getMap')]
32+
public ?Map $map = null;
33+
34+
abstract protected function instantiateMap(): Map;
35+
36+
public function getMap(): Map
37+
{
38+
if (null === $this->map) {
39+
$this->map = $this->instantiateMap();
40+
}
41+
42+
return $this->map;
43+
}
44+
45+
/**
46+
* @internal
47+
*/
48+
#[PostMount]
49+
public function initializeMap(array $data): array
50+
{
51+
// allow the Map object to be passed into the component() as "map"
52+
if (\array_key_exists('map', $data)) {
53+
$this->map = $data['map'];
54+
unset($data['map']);
55+
}
56+
57+
return $data;
58+
}
59+
60+
/**
61+
* @internal
62+
*/
63+
public function hydrateMap(array $data): Map
64+
{
65+
return Map::fromArray($data);
66+
}
67+
68+
/**
69+
* @internal
70+
*/
71+
public function dehydrateMap(Map $map): array
72+
{
73+
return $map->toArray();
74+
}
75+
}

src/Map/src/Map.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function toArray(): array
111111
'center' => $this->center?->toArray(),
112112
'zoom' => $this->zoom,
113113
'fitBoundsToMarkers' => $this->fitBoundsToMarkers,
114-
'options' => (object) ($this->options?->toArray() ?? []),
114+
'options' => $this->options ? MapOptionsNormalizer::normalize($this->options) : [],
115115
'markers' => array_map(static fn (Marker $marker) => $marker->toArray(), $this->markers),
116116
'polygons' => array_map(static fn (Polygon $polygon) => $polygon->toArray(), $this->polygons),
117117
];
@@ -124,7 +124,7 @@ public function toArray(): array
124124
* markers?: list<array>,
125125
* polygons?: list<array>,
126126
* fitBoundsToMarkers?: bool,
127-
* options?: object,
127+
* options?: array<string, mixed>,
128128
* } $map
129129
*
130130
* @internal
@@ -133,6 +133,10 @@ public static function fromArray(array $map): self
133133
{
134134
$map['fitBoundsToMarkers'] = true;
135135

136+
if (isset($map['options'])) {
137+
$map['options'] = [] === $map['options'] ? null : MapOptionsNormalizer::denormalize($map['options']);
138+
}
139+
136140
if (isset($map['center'])) {
137141
$map['center'] = Point::fromArray($map['center']);
138142
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Symfony\UX\Map;
15+
16+
use Symfony\UX\Map\Bridge as MapBridge;
17+
use Symfony\UX\Map\Exception\UnableToDenormalizeOptionsException;
18+
use Symfony\UX\Map\Exception\UnableToNormalizeOptionsException;
19+
20+
/**
21+
* Normalizes and denormalizes map options.
22+
*
23+
* @internal
24+
* @author Hugo Alliaume <[email protected]>
25+
*/
26+
final class MapOptionsNormalizer
27+
{
28+
private const string KEY_PROVIDER = '@provider';
29+
30+
/**
31+
* @var array<string, class-string<MapOptionsInterface>>
32+
*/
33+
public static array $providers = [
34+
'google' => MapBridge\Google\GoogleOptions::class,
35+
'leaflet' => MapBridge\Leaflet\LeafletOptions::class,
36+
];
37+
38+
public static function denormalize(array $array): MapOptionsInterface
39+
{
40+
if (null === ($provider = $array[self::KEY_PROVIDER] ?? null)) {
41+
throw UnableToDenormalizeOptionsException::missingProviderKey(self::KEY_PROVIDER);
42+
}
43+
44+
if (!isset(self::$providers[$provider])) {
45+
throw UnableToDenormalizeOptionsException::unsupportedProvider($provider, array_keys(self::$providers));
46+
}
47+
48+
unset($array[self::KEY_PROVIDER]);
49+
50+
$class = self::$providers[$provider];
51+
52+
return $class::fromArray($array);
53+
}
54+
55+
public static function normalize(MapOptionsInterface $options): array
56+
{
57+
$provider = array_search($options::class, self::$providers, true);
58+
if (!\is_string($provider)) {
59+
throw UnableToNormalizeOptionsException::unsupportedProviderClass($options::class);
60+
}
61+
62+
$array = $options->toArray();
63+
$array[self::KEY_PROVIDER] = $provider;
64+
65+
return $array;
66+
}
67+
}

src/Map/src/Marker.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function toArray(): array
4646
'position' => $this->position->toArray(),
4747
'title' => $this->title,
4848
'infoWindow' => $this->infoWindow?->toArray(),
49-
'extra' => (object) $this->extra,
49+
'extra' => $this->extra,
5050
];
5151
}
5252

src/Map/src/Polygon.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function toArray(): array
4040
'points' => array_map(fn (Point $point) => $point->toArray(), $this->points),
4141
'title' => $this->title,
4242
'infoWindow' => $this->infoWindow?->toArray(),
43-
'extra' => (object) $this->extra,
43+
'extra' => $this->extra,
4444
];
4545
}
4646

0 commit comments

Comments
 (0)