Passed
Push — master ( 9c6765...7e8500 )
by Denis
03:30
created

Generator::prepare()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Ngtfkx\Laradeck\AddressGenerator;
4
5
6
use Illuminate\Support\Collection;
7
use Ngtfkx\Laradeck\AddressGenerator\Exceptions\CityDataFileNotFound;
8
use Ngtfkx\Laradeck\AddressGenerator\Exceptions\CityListFileNotFound;
9
use Ngtfkx\Laradeck\AddressGenerator\Exceptions\CityNotFound;
10
11
class Generator
12
{
13
    /**
14
     * @var Collection Список городов для которых будем генерировать адреса
15
     */
16
    protected $cities;
17
18
    /**
19
     * @var Collection Список доступных для поиска имен городов городов
20
     */
21
    protected $searchableCityNames;
22
23
    /**
24
     * @var Collection Список достпупных гордов
25
     */
26
    protected $availableCities;
27
28
    /**
29
     * @var Collection Список достпупных адресов
30
     */
31
    protected $availableAddresses;
32
33
    /**
34
     * @var Collection Список городов, для которых сгенерированы адреса
35
     */
36
    protected $usedCities;
37
38
    /**
39
     * Generator constructor.
40
     */
41
    public function __construct()
42
    {
43
        $this->cities = new Collection();
44
45
        $this->usedCities = new Collection();
46
47
        $this->availableAddresses = new Collection();
48
49
        $this->makeCities();
50
    }
51
52
    /**
53
     * Получить случайный адрес
54
     *
55
     * @param string|null $forCity Имя города, для которого генерировать адрес. По умолчанию null - из любого установленного
56
     * @return Address
57
     * @throws CityNotFound Город не найден в списке доступных
58
     */
59
    public function getRandomAddress($forCity = null): Address
60
    {
61
        $forCity = $forCity ?: $this->getCities()->random();
62
63
        $forCity = $this->prepare($forCity);
64
65
        $cityId = $this->getCityIdByName($forCity);
66
67
        if ($this->usedCities->contains($cityId) === false) {
68
            $this->makeAddresses($cityId);
69
        }
70
71
        $address = $this->availableAddresses->get($cityId)->random();
72
73
        return $address;
74
    }
75
76
    /**
77
     * Получить все сгенированные адреса
78
     *
79
     * @return Collection
80
     */
81
    public function getAllAddresses(): Collection
82
    {
83
        return $this->availableAddresses;
84
    }
85
86
    /**
87
     * Получить несколько случайных адресов
88
     *
89
     * @param int $count Кол-во требуемых адресов
90
     * @param null $forCity Имя города, для которого генерировать адрес. По умолчанию null - из любого установленного
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $forCity is correct as it would always require null to be passed?
Loading history...
91
     * @return Collection
92
     */
93
    public function getRandomAddresses(int $count, $forCity = null): Collection
94
    {
95
        $addresses = new Collection();
96
97
        for ($i = 1; $i <= $count; $i++) {
98
            $addresses->push($this->getRandomAddress($forCity));
99
        }
100
101
        return $addresses;
102
    }
103
104
    /**
105
     * Добавить город в список, для которого будем генерировать адреса
106
     *
107
     * @param string $city
108
     * @return Generator
109
     * @throws CityNotFound Город не найден в списке доступных
110
     */
111
    public function addCity(string $city): Generator
112
    {
113
        $key = $this->getCityIdByName($city);
114
115
        if (!$this->cities->contains($city)) {
116
            $this->cities->put($key, $city);
117
            $this->makeAddresses($key);
118
        }
119
120
        return $this;
121
    }
122
123
    /**
124
     * Добавить несколько городо в список, для которого будем генерировать адреса
125
     *
126
     * @param array ...$cities
127
     * @return Generator
128
     */
129
    public function addCities(): Generator
130
    {
131
        $cities = func_get_args();
132
133
        foreach ($cities as $city) {
134
            if (!is_array($city)) {
135
                $city = [$city];
136
            }
137
            foreach ($city as $item) {
138
                $this->addCity($item);
139
            }
140
        }
141
142
        return $this;
143
    }
144
145
    /**
146
     * Установить список городов, для которого будем генерировать адреса
147
     *
148
     * @param array ...$cities
149
     * @return Generator
150
     */
151
    public function setCities(): Generator
152
    {
153
        $cities = func_get_args();
154
155
        $this->clearCities();
156
157
        if (sizeof($cities) === 1 && is_array($cities[0])) {
158
            $cities = $cities[0];
159
        }
160
161
        $this->addCities($cities);
162
163
        return $this;
164
    }
165
166
    /**
167
     * Очистить список гордов, для которых можно генерировать адреса
168
     *
169
     * @return Generator
170
     */
171
    public function clearCities(): Generator
172
    {
173
        $this->cities = new Collection();
174
175
        $this->clearAddresses();
176
177
        return $this;
178
    }
179
180
    /**
181
     * Очистить список сгенерированных адресов
182
     *
183
     * @return Generator
184
     */
185
    public function clearAddresses(): Generator
186
    {
187
        $this->availableAddresses = new Collection();
188
189
        $this->usedCities = new Collection();
190
191
        return $this;
192
    }
193
194
    /**
195
     * Получить коллекцию городов, для которых можно получать адреса.
196
     *
197
     * Если города заданы, то их. Если нет, то все доступные города.
198
     *
199
     * @return Collection
200
     */
201
    public function getCities(): Collection
202
    {
203
        return $this->cities->isEmpty() ? $this->availableCities : $this->cities;
204
    }
205
206
    /**
207
     * Получить имена городов, установленные для которых можно получать адреса
208
     *
209
     * @return Collection
210
     */
211
    public function getCityNames(): Collection
212
    {
213
        return $this->cities->values();
214
    }
215
216
    /**
217
     * Получить ID города по его имени
218
     *
219
     * @param string $name
220
     * @return int
221
     * @throws CityNotFound
222
     */
223
    protected function getCityIdByName(string $name): int
224
    {
225
        $key = $this->searchableCityNames->get($this->prepare($name));
226
227
        if (empty($key)) {
228
            throw new CityNotFound();
229
        }
230
231
        return $key;
232
    }
233
234
    /**
235
     * Генерируем коллекцию всех доступных адресов для указанного города
236
     *
237
     * @param int $cityId
238
     */
239
    protected function makeAddresses(int $cityId)
240
    {
241
        $city = $this->availableCities->get($cityId);
242
243
        $addresses = new Collection();
244
245
        foreach ($this->loadData($cityId) as $street => $buildings) {
246
            foreach ($buildings as $building) {
247
                $address = new Address($city, $street, $building);
248
                $addresses->push($address);
249
            }
250
        }
251
252
        $this->usedCities->push($cityId);
253
254
        $this->availableAddresses->put($cityId, $addresses);
255
    }
256
257
    /**
258
     * Загрузка сырых данных по городу
259
     *
260
     * @param int $cityId
261
     * @return array
262
     * @throws CityDataFileNotFound
263
     */
264
    protected function loadData(int $cityId): array
265
    {
266
        $file = __DIR__ . '/data/ru/' . $cityId . '.php';
267
268
        if (!file_exists($file)) {
269
            throw new CityDataFileNotFound();
270
        }
271
272
        $rawData = require($file);
273
274
        return $rawData;
275
    }
276
277
    /**
278
     * Загрузка списка городов с алиасами
279
     *
280
     * @return array
281
     * @throws CityListFileNotFound
282
     */
283
    protected function loadCities(): array
284
    {
285
        $file = __DIR__ . '/data/cities.php';
286
287
        if (!file_exists($file)) {
288
            throw new CityListFileNotFound();
289
        }
290
291
        $rawData = require($file);
292
293
        return $rawData;
294
    }
295
296
    /**
297
     * Генерирум коллекцию всех доступных городов
298
     */
299
    protected function makeCities()
300
    {
301
        $this->availableCities = new Collection();
302
303
        $this->searchableCityNames = new Collection();
304
305
        foreach ($this->loadCities() as $key => $items) {
306
307
            $this->availableCities->put($key, $items[0]);
308
309
            foreach ($items as $item) {
310
                $item = $this->prepare($item);
311
312
                if (!$this->searchableCityNames->contains($item)) {
313
                    $this->searchableCityNames->put($item, $key);
314
                }
315
            }
316
        }
317
    }
318
319
    /**
320
     * Приведение разных вариантов написания наименования города к общему виду
321
     *
322
     * @param $string
323
     * @return string
324
     */
325
    protected function prepare($string): string
326
    {
327
        $string = str_replace([' ', '-', '_'], '', mb_strtolower($string));
328
329
        return $string;
330
    }
331
}