1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace WebTheory\Saveyour\Processors; |
4
|
|
|
|
5
|
|
|
use CommerceGuys\Addressing\Address; |
6
|
|
|
use CommerceGuys\Addressing\AddressFormat\AddressFormatRepository; |
7
|
|
|
use CommerceGuys\Addressing\Country\CountryRepository; |
8
|
|
|
use CommerceGuys\Addressing\Formatter\DefaultFormatter; |
9
|
|
|
use CommerceGuys\Addressing\Subdivision\SubdivisionRepository; |
10
|
|
|
use Geocoder\Provider\Provider; |
11
|
|
|
use Geocoder\Query\GeocodeQuery; |
12
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
13
|
|
|
use Respect\Validation\Validator; |
14
|
|
|
use WebTheory\Saveyour\Contracts\DataFormatterInterface; |
15
|
|
|
use WebTheory\Saveyour\Contracts\FieldDataManagerInterface; |
16
|
|
|
use WebTheory\Saveyour\Contracts\FormDataProcessingCacheInterface; |
17
|
|
|
use WebTheory\Saveyour\Contracts\FormDataProcessorInterface; |
18
|
|
|
use WebTheory\Saveyour\Controllers\FormDataProcessingCache; |
19
|
|
|
use WebTheory\Saveyour\Formatters\LazyFormatter; |
20
|
|
|
use WebTheory\Saveyour\InputPurifier; |
21
|
|
|
|
22
|
|
|
class FormAddressGeocoder extends AbstractRestrictedFormDataProcessor implements FormDataProcessorInterface |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* @var array |
26
|
|
|
*/ |
27
|
|
|
protected $fields = []; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var string |
31
|
|
|
*/ |
32
|
|
|
protected $countryCode = 'US'; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var Provider |
36
|
|
|
*/ |
37
|
|
|
protected $provider; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var FieldDataManagerInterface |
41
|
|
|
*/ |
42
|
|
|
protected $addressDataManager; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var DataFormatterInterface |
46
|
|
|
*/ |
47
|
|
|
protected $geoDataFormatter; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var FieldDataManagerInterface |
51
|
|
|
*/ |
52
|
|
|
protected $geoDataManager; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @var DataFormatterInterface |
56
|
|
|
*/ |
57
|
|
|
protected $addressDataFormatter; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* {@inheritDoc} |
61
|
|
|
*/ |
62
|
|
|
public const ACCEPTED_FIELDS = ['street', 'city', 'state', 'zip', 'country']; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* |
66
|
|
|
*/ |
67
|
3 |
|
public function __construct( |
68
|
|
|
Provider $provider, |
69
|
|
|
FieldDataManagerInterface $geoDataManager, |
70
|
|
|
?DataFormatterInterface $geoDataFormatter = null, |
71
|
|
|
?FieldDataManagerInterface $addressDataManager = null, |
72
|
|
|
?DataFormatterInterface $addressDataFormatter = null |
73
|
|
|
) { |
74
|
3 |
|
$this->provider = $provider; |
75
|
3 |
|
$this->geoDataManager = $geoDataManager; |
76
|
3 |
|
$this->geoDataFormatter = $geoDataFormatter ?? new LazyFormatter(); |
77
|
|
|
|
78
|
3 |
|
if ($addressDataManager) { |
79
|
|
|
$this->addressDataManager = $addressDataManager; |
80
|
|
|
$this->addressDataFormatter = $addressDataFormatter ?? new LazyFormatter(); |
81
|
|
|
} |
82
|
3 |
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Get the value of countryCode |
86
|
|
|
* |
87
|
|
|
* @return string |
88
|
|
|
*/ |
89
|
|
|
public function getCountryCode(): string |
90
|
|
|
{ |
91
|
|
|
return $this->countryCode; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Set the value of countryCode |
96
|
|
|
* |
97
|
|
|
* @param string $countryCode |
98
|
|
|
* |
99
|
|
|
* @return self |
100
|
|
|
*/ |
101
|
|
|
public function setCountryCode(string $countryCode) |
102
|
|
|
{ |
103
|
|
|
$this->countryCode = $countryCode; |
104
|
|
|
|
105
|
|
|
return $this; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* |
110
|
|
|
*/ |
111
|
3 |
|
protected function formatAddress($fields) |
112
|
|
|
{ |
113
|
3 |
|
$address = (new Address()) |
114
|
3 |
|
->withAddressLine1($fields['street']) |
115
|
3 |
|
->withLocality($fields['city']) |
116
|
3 |
|
->withAdministrativeArea($fields['state']) |
117
|
3 |
|
->withPostalCode($fields['zip']) |
118
|
3 |
|
->withCountryCode($fields['country'] ?? $this->countryCode); |
119
|
|
|
|
120
|
|
|
$options = [ |
121
|
3 |
|
'html' => false, |
122
|
|
|
]; |
123
|
|
|
|
124
|
3 |
|
$formatter = new DefaultFormatter( |
125
|
3 |
|
new AddressFormatRepository(), |
126
|
3 |
|
new CountryRepository(), |
127
|
3 |
|
new SubdivisionRepository(), |
128
|
1 |
|
$options |
129
|
|
|
); |
130
|
|
|
|
131
|
3 |
|
return str_replace("\n", ", ", $formatter->format($address)); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* |
136
|
|
|
*/ |
137
|
3 |
|
protected function formatGeoDataInput($value) |
138
|
|
|
{ |
139
|
3 |
|
return $this->geoDataFormatter->formatInput($value); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* |
144
|
|
|
*/ |
145
|
|
|
protected function formatAddressInput($value) |
146
|
|
|
{ |
147
|
|
|
return $this->addressDataFormatter->formatInput($value); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* |
152
|
|
|
*/ |
153
|
3 |
|
protected function createInputPurifier(): InputPurifier |
154
|
|
|
{ |
155
|
3 |
|
return (new InputPurifier()) |
156
|
3 |
|
->addRule('float', Validator::floatType()) |
157
|
|
|
->addFilter(function ($input) { |
158
|
3 |
|
return filter_var( |
159
|
3 |
|
$input, |
160
|
3 |
|
FILTER_SANITIZE_NUMBER_FLOAT, |
161
|
3 |
|
FILTER_FLAG_ALLOW_FRACTION |
162
|
|
|
); |
163
|
3 |
|
}); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* |
168
|
|
|
*/ |
169
|
3 |
|
public function process(ServerRequestInterface $request, array $results): ?FormDataProcessingCacheInterface |
170
|
|
|
{ |
171
|
3 |
|
if ($this->valueUpdated($results)) { |
172
|
3 |
|
return $this->processResults($request, $results); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
return null; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* |
180
|
|
|
*/ |
181
|
3 |
|
protected function processResults(ServerRequestInterface $request, $results): FormDataProcessingCacheInterface |
182
|
|
|
{ |
183
|
3 |
|
$address = $this->formatAddress($this->extractValues($results)); |
184
|
3 |
|
$data = $this->provider |
185
|
3 |
|
->geocodeQuery(GeocodeQuery::create($address)) |
186
|
3 |
|
->get(0) |
187
|
3 |
|
->getCoordinates(); |
188
|
|
|
|
189
|
3 |
|
$coordinates = $this->createInputPurifier()->filterInput([ |
190
|
3 |
|
'lat' => $data->getLatitude(), |
191
|
3 |
|
'lng' => $data->getLongitude() |
192
|
|
|
]); |
193
|
|
|
|
194
|
3 |
|
$geoUpdated = $this->geoDataManager->handleSubmittedData( |
195
|
3 |
|
$request, |
196
|
3 |
|
$this->formatGeoDataInput($coordinates) |
197
|
|
|
); |
198
|
|
|
|
199
|
3 |
|
if (isset($this->addressDataManager)) { |
200
|
|
|
$addressUpdated = $this->addressDataManager->handleSubmittedData( |
201
|
|
|
$request, |
202
|
|
|
$this->formatAddressInput($address) |
203
|
|
|
); |
204
|
|
|
} |
205
|
|
|
|
206
|
3 |
|
return (new FormDataProcessingCache()) |
207
|
3 |
|
->withResult('coordinates', $coordinates) |
208
|
3 |
|
->withResult('coordinates_updated', $geoUpdated) |
209
|
3 |
|
->withResult('address_updated', $addressUpdated ?? false); |
210
|
|
|
} |
211
|
|
|
} |
212
|
|
|
|