Passed
Push — master ( 4c5faf...429320 )
by Chris
04:23
created

FormAddressGeocoder::formatAddress()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 14
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 21
ccs 14
cts 14
cp 1
crap 1
rs 9.7998
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