Issues (4)

src/Entity/Address.php (3 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Communibase\Entity;
6
7
use Communibase\CommunibaseId;
8
use Communibase\DataBag;
9
use Communibase\Exception\InvalidGeoLocationException;
10
11
/**
12
 * Communibase Address
13
 *
14
 * @author Kingsquare ([email protected])
15
 * @copyright Copyright (c) Kingsquare BV (http://www.kingsquare.nl)
16
 */
17
class Address
18
{
19
    /**
20
     * @var DataBag;
21
     */
22
    protected $dataBag;
23
24
    /**
25
     * @param array{'_id'?: string, 'type'?: string, 'property'?: string, 'street'?: string, 'streetNumber'?: string, 'streetNumberAddition'?: string, 'zipcode'?: string, 'city'?: string, 'countryCode'?: string, point?: array{coordinates: array{float, float}}, latitude?: float, longitude?: float} $addressData
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{'_id'?: string, 't...oat, longitude?: float} at position 46 could not be parsed: Expected ':' at position 46, but found 'float'.
Loading history...
26
     */
27
    final private function __construct(array $addressData = [])
28
    {
29
        $this->dataBag = DataBag::create();
30
        if ($addressData === []) {
31
            return;
32
        }
33
        $this->dataBag->addEntityData('address', $addressData);
34
    }
35
36
    public static function create(): Address
37
    {
38
        return new static();
39
    }
40
41
    /**
42
     * @param ?array{'_id'?: string, 'type'?: string, 'property'?: string, 'street'?: string, 'streetNumber'?: string, 'streetNumberAddition'?: string, 'zipcode'?: string, 'city'?: string, 'countryCode'?: string, point?: array{coordinates: array{float, float}}, latitude?: float, longitude?: float} $addressData
0 ignored issues
show
Documentation Bug introduced by
The doc comment ?array{'_id'?: string, '...oat, longitude?: float} at position 46 could not be parsed: Expected ':' at position 46, but found 'float'.
Loading history...
43
     */
44
    public static function fromAddressData(array $addressData = null): Address
45
    {
46
        if ($addressData === null) {
47
            $addressData = [];
48
        }
49
        return new static($addressData);
50
    }
51
52
    public function getProperty(): string
53
    {
54
        return (string)$this->dataBag->get('address.property');
55
    }
56
57
    public function setProperty(?string $property): void
58
    {
59
        $this->dataBag->set('address.property', $property);
60
    }
61
62
    public function getStreet(): string
63
    {
64
        return trim((string)$this->dataBag->get('address.street'));
65
    }
66
67
    public function setStreet(?string $street): void
68
    {
69
        $this->dataBag->set('address.street', $street);
70
    }
71
72
    public function getStreetNumber(): string
73
    {
74
        return (string)$this->dataBag->get('address.streetNumber');
75
    }
76
77
    public function setStreetNumber(?string $streetNumber): void
78
    {
79
        $this->dataBag->set('address.streetNumber', $streetNumber);
80
    }
81
82
    public function getStreetNumberAddition(): string
83
    {
84
        return (string)$this->dataBag->get('address.streetNumberAddition');
85
    }
86
87
    public function setStreetNumberAddition(?string $streetNumberAddition): void
88
    {
89
        $this->dataBag->set('address.streetNumberAddition', $streetNumberAddition);
90
    }
91
92
    public function getZipcode(): string
93
    {
94
        return trim((string)$this->dataBag->get('address.zipcode'));
95
    }
96
97
    public function setZipcode(?string $zipcode): void
98
    {
99
        $this->dataBag->set('address.zipcode', $zipcode);
100
    }
101
102
    public function getCity(): string
103
    {
104
        return trim((string)$this->dataBag->get('address.city'));
105
    }
106
107
    public function setCity(?string $city): void
108
    {
109
        $this->dataBag->set('address.city', $city);
110
    }
111
112
    public function getCountryCode(string $default = 'NL'): string
113
    {
114
        return trim((string)$this->dataBag->get('address.countryCode', $default));
115
    }
116
117
    public function setCountryCode(string $countryCode): void
118
    {
119
        $this->dataBag->set('address.countryCode', $countryCode);
120
    }
121
122
    public function getType(): string
123
    {
124
        return trim((string)$this->dataBag->get('address.type'));
125
    }
126
127
    public function setType(?string $type): void
128
    {
129
        $this->dataBag->set('address.type', $type);
130
    }
131
132
    public function getId(): CommunibaseId
133
    {
134
        return CommunibaseId::fromString($this->dataBag->get('address._id'));
135
    }
136
137
    public function __toString(): string
138
    {
139
        return $this->toString();
140
    }
141
142
    public function toString(bool $singleLine = true): string
143
    {
144
        if ($this->getState() === null) {
145
            return '';
146
        }
147
        $lines = [
148
            array_filter([$this->getStreet(), $this->getStreetNumber(), $this->getStreetNumberAddition()]),
149
            array_filter([$this->getZipcode(), $this->getCity()]),
150
        ];
151
152
        if ($singleLine) {
153
            return implode(
154
                ', ',
155
                array_filter(
156
                    [
157
                        implode(' ', $lines[0]),
158
                        implode(', ', $lines[1]),
159
                    ]
160
                )
161
            );
162
        }
163
        return implode(
164
            PHP_EOL,
165
            array_filter(
166
                [
167
                    implode(' ', $lines[0]),
168
                    implode(' ', $lines[1]),
169
                ]
170
            )
171
        );
172
    }
173
174
    /**
175
     * @return ?array<float>
176
     */
177
    public function getGeoLocation(): ?array
178
    {
179
        // native geo handling
180
        if ($this->isGeoStorageUsingNativePoint()) {
181
            $point = $this->dataBag->get('address.point');
182
            if (empty($point) || empty($point['coordinates']) || empty($point['coordinates'][0]) || empty($point['coordinates'][1])) {
183
                return null;
184
            }
185
            return [
186
                'lat' => (float)$point['coordinates'][1],
187
                'lng' => (float)$point['coordinates'][0],
188
            ];
189
        }
190
191
        // `old`-style
192
        $lat = $this->dataBag->get('address.latitude');
193
        $lng = $this->dataBag->get('address.longitude');
194
        if (!isset($lat, $lng)) {
195
            return null;
196
        }
197
        return [
198
            'lat' => (float)$lat,
199
            'lng' => (float)$lng,
200
        ];
201
    }
202
203
    /**
204
     * @throws InvalidGeoLocationException
205
     */
206
    public function setGeoLocation(float $latitude, float $longitude): void
207
    {
208
        $this->guardAgainstInvalidLatLong($latitude, $longitude);
209
210
        // native geo handling
211
        if ($this->isGeoStorageUsingNativePoint()) {
212
            $this->dataBag->set(
213
                'address.point',
214
                [
215
                    'coordinates' => [
216
                        0 => $longitude,
217
                        1 => $latitude,
218
                    ],
219
                ]
220
            );
221
            return;
222
        }
223
        $this->dataBag->set('address.latitude', $latitude);
224
        $this->dataBag->set('address.longitude', $longitude);
225
    }
226
227
    private function isGeoStorageUsingNativePoint(): bool
228
    {
229
        return !empty($this->dataBag->get('address.point'));
230
    }
231
232
    public function isEmpty(): bool
233
    {
234
        return empty(
235
        array_filter(
236
            [
237
                $this->getStreet(),
238
                $this->getStreetNumber(),
239
                $this->getZipcode(),
240
                $this->getCity()
241
            ]
242
        )
243
        );
244
    }
245
246
    public function __clone()
247
    {
248
        $state = $this->getState();
249
        if ($state !== null) {
250
            unset($state['_id']);
251
            $this->dataBag->addEntityData('address', $state);
252
        }
253
    }
254
255
    /**
256
     * @return ?array{'_id'?: string, 'type'?: string, 'property'?: string, 'street'?: string, 'streetNumber'?: string, 'streetNumberAddition'?: string, 'zipcode'?: string, 'city'?: string, 'countryCode'?: string, point?: array{coordinates: array{float, float}}, latitude?: float, longitude?: float}
0 ignored issues
show
Documentation Bug introduced by
The doc comment ?array{'_id'?: string, '...oat, longitude?: float} at position 46 could not be parsed: Expected ':' at position 46, but found 'float'.
Loading history...
257
     */
258
    public function getState(): ?array
259
    {
260
        if ($this->isEmpty()) {
261
            return null;
262
        }
263
        return $this->dataBag->getState('address');
264
    }
265
266
    /**
267
     * @throws InvalidGeoLocationException
268
     */
269
    private function guardAgainstInvalidLatLong(float $latitude, float $longitude): void
270
    {
271
        if ($latitude < -90 || $latitude > 90 || $longitude < -180 || $longitude > 180) {
272
            throw new InvalidGeoLocationException(
273
                sprintf('Invalid latitude/longitude: %s, %s', $latitude, $longitude)
274
            );
275
        }
276
    }
277
}
278