1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | /* |
||
6 | * This file is part of the Geocoder package. |
||
7 | * For the full copyright and license information, please view the LICENSE |
||
8 | * file that was distributed with this source code. |
||
9 | * |
||
10 | * @license MIT License |
||
11 | */ |
||
12 | |||
13 | namespace Geocoder; |
||
14 | |||
15 | use Geocoder\Exception\ProviderNotRegistered; |
||
16 | use Geocoder\Model\Coordinates; |
||
17 | use Geocoder\Provider\Provider; |
||
18 | use Geocoder\Query\GeocodeQuery; |
||
19 | use Geocoder\Query\ReverseQuery; |
||
20 | |||
21 | /** |
||
22 | * @author William Durand <[email protected]> |
||
23 | */ |
||
24 | class ProviderAggregator implements Geocoder |
||
25 | { |
||
26 | /** |
||
27 | * @var Provider[] |
||
28 | */ |
||
29 | private $providers = []; |
||
30 | |||
31 | /** |
||
32 | * @var Provider |
||
33 | */ |
||
34 | private $provider; |
||
35 | |||
36 | /** |
||
37 | * @var int |
||
38 | */ |
||
39 | private $limit; |
||
40 | |||
41 | /** |
||
42 | * A callable that decided what provider to use. |
||
43 | * |
||
44 | * @var callable |
||
45 | */ |
||
46 | private $decider; |
||
47 | |||
48 | 9 | public function __construct(callable $decider = null, int $limit = Geocoder::DEFAULT_RESULT_LIMIT) |
|
49 | { |
||
50 | 9 | $this->limit = $limit; |
|
51 | 9 | $this->decider = $decider ?? __CLASS__.'::getProvider'; |
|
52 | } |
||
53 | |||
54 | 1 | public function geocodeQuery(GeocodeQuery $query): Collection |
|
55 | { |
||
56 | 1 | return call_user_func($this->decider, $query, $this->providers, $this->provider)->geocodeQuery($query); |
|
57 | } |
||
58 | |||
59 | 1 | public function reverseQuery(ReverseQuery $query): Collection |
|
60 | { |
||
61 | 1 | return call_user_func($this->decider, $query, $this->providers, $this->provider)->reverseQuery($query); |
|
62 | } |
||
63 | |||
64 | public function getName(): string |
||
65 | { |
||
66 | return 'provider_aggregator'; |
||
67 | } |
||
68 | |||
69 | 1 | public function geocode(string $value): Collection |
|
70 | { |
||
71 | 1 | return $this->geocodeQuery(GeocodeQuery::create($value) |
|
72 | 1 | ->withLimit($this->limit)); |
|
73 | } |
||
74 | |||
75 | 1 | public function reverse(float $latitude, float $longitude): Collection |
|
76 | { |
||
77 | 1 | return $this->reverseQuery(ReverseQuery::create(new Coordinates($latitude, $longitude)) |
|
78 | 1 | ->withLimit($this->limit)); |
|
79 | } |
||
80 | |||
81 | /** |
||
82 | * Registers a new provider to the aggregator. |
||
83 | */ |
||
84 | 6 | public function registerProvider(Provider $provider): self |
|
85 | { |
||
86 | 6 | $this->providers[$provider->getName()] = $provider; |
|
87 | |||
88 | 6 | return $this; |
|
89 | } |
||
90 | |||
91 | /** |
||
92 | * Registers a set of providers. |
||
93 | * |
||
94 | * @param Provider[] $providers |
||
95 | */ |
||
96 | 2 | public function registerProviders(array $providers = []): self |
|
97 | { |
||
98 | 2 | foreach ($providers as $provider) { |
|
99 | 2 | $this->registerProvider($provider); |
|
100 | } |
||
101 | |||
102 | 2 | return $this; |
|
103 | } |
||
104 | |||
105 | /** |
||
106 | * Sets the default provider to use. |
||
107 | */ |
||
108 | 3 | public function using(string $name): self |
|
109 | { |
||
110 | 3 | if (!isset($this->providers[$name])) { |
|
111 | 2 | throw ProviderNotRegistered::create($name, array_keys($this->providers)); |
|
112 | } |
||
113 | |||
114 | 1 | $this->provider = $this->providers[$name]; |
|
115 | |||
116 | 1 | return $this; |
|
117 | } |
||
118 | |||
119 | /** |
||
120 | * Returns all registered providers indexed by their name. |
||
121 | * |
||
122 | * @return Provider[] |
||
123 | */ |
||
124 | 1 | public function getProviders(): array |
|
125 | { |
||
126 | 1 | return $this->providers; |
|
127 | } |
||
128 | |||
129 | /** |
||
130 | * Get a provider to use for this query. |
||
131 | * |
||
132 | * @param GeocodeQuery|ReverseQuery $query |
||
133 | * @param Provider[] $providers |
||
134 | * @param Provider $currentProvider |
||
135 | * |
||
136 | * @throws ProviderNotRegistered |
||
137 | */ |
||
138 | 4 | private static function getProvider($query, array $providers, Provider $currentProvider = null): Provider |
|
139 | { |
||
140 | 4 | if (null !== $currentProvider) { |
|
141 | 2 | return $currentProvider; |
|
142 | } |
||
143 | |||
144 | 3 | if ([] === $providers) { |
|
145 | 1 | throw ProviderNotRegistered::noProviderRegistered(); |
|
146 | } |
||
147 | |||
148 | // Take first |
||
149 | 2 | $key = key($providers); |
|
150 | |||
151 | 2 | return $providers[$key]; |
|
152 | } |
||
153 | } |
||
154 |