Passed
Push — master ( 1762a2...1d376a )
by Denis
02:57
created

ParseCityAddressRu::parse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 49
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 22
nc 3
nop 0
dl 0
loc 49
rs 9.2258
c 0
b 0
f 0
1
<?php
2
3
namespace Ngtfkx\Laradeck\AddressGenerator\Commands;
4
5
use Illuminate\Console\Command;
1 ignored issue
show
Bug introduced by
The type Illuminate\Console\Command was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\Storage;
8
use Symfony\Component\DomCrawler\Crawler;
1 ignored issue
show
Bug introduced by
The type Symfony\Component\DomCrawler\Crawler was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
10
/**
11
 * Парсер улиц и домов с сайта www.city-address.ru
12
 *
13
 * Class ParseCityAddressRu
14
 * @package Ngtfkx\Laradeck\AddressGenerator\Commands
15
 */
16
class ParseCityAddressRu extends Command
17
{
18
    /**
19
     * The name and signature of the console command.
20
     *
21
     * @var string
22
     */
23
    protected $signature = 'address:city-address-ru {city} {url} {--limit=0}';
24
25
    /**
26
     * The console command description.
27
     *
28
     * @var string
29
     */
30
    protected $description = 'Parse streets and building numbers from www.city-address.ru';
31
32
    /**
33
     * @var Collection
34
     */
35
    protected $streets;
36
37
    /**
38
     * @var int
39
     */
40
    protected $cityId;
41
42
    /**
43
     * @var int
44
     */
45
    protected $limit;
46
47
    /**
48
     * @var string
49
     */
50
    protected $url;
51
52
    /**
53
     * @var string
54
     */
55
    protected $name;
56
57
    public function __construct()
58
    {
59
        $this->streets = new Collection();
60
61
        parent::__construct();
62
    }
63
64
    public function handle(): void
65
    {
66
        $this->cityId = $this->argument('city');
67
68
        $this->url = $this->argument('url');
69
70
        $this->limit = (int)$this->option('limit');
71
72
        $this->parse();
73
74
        $this->generateFile();
75
76
        $this->info('Data was saved');
77
    }
78
79
    /**
80
     * Парсинг данных
81
     */
82
    protected function parse(): void
83
    {
84
        /**
85
         * Получаем список всех страниц с улицами
86
         */
87
        $firstPage = $this->download($this->url);
88
89
        $allPages = (int)(new Crawler($firstPage))->filter('.uk-pagination > li')->last()->text();
90
91
        $name = (new Crawler($firstPage))->filterXpath('//meta[@name="geo.placename"]')->attr('content');
92
93
        $this->name = explode(', ', $name)[0];
94
95
        $k = 0;
96
97
        for ($i = 1; $i <= $allPages; $i++) {
98
            /**
99
             * Получам список улиц на текущей странице
100
             */
101
            $page = $this->download($this->url . '/page-' . $i . '/');
102
103
            $this->line('Downloading streets and building numbers from page #' . $i . ' from ' . $allPages);
104
105
            $streets = (new Crawler($page))->filter('.c4 > a');
106
107
            $streets->each(function ($node) {
108
                /**
109
                 * Получаем список домов
110
                 */
111
                $url = 'http://www.city-address.ru' . $node->attr('href');
112
113
                $page = $this->download($url);
114
115
                /**
116
                 * Обрабатываем список домов
117
                 */
118
                $numbers = collect((new Crawler($page))->filter('.c6 > div > a')->extract('_text'))
119
                    ->reject(function ($item) {
120
                        return strpos($item, 'дом ') !== 0;
121
                    })->map(function ($item) {
122
                        return str_replace('дом № ', '', $item);
123
                    })->toArray();
124
125
                $this->streets->put($node->text(), $numbers);
126
            });
127
128
            if (++$k == $this->limit) {
129
                $this->warn('Interrupted by the limit');
130
                break;
131
            }
132
        }
133
    }
134
135
    /**
136
     * Скачивание страница
137
     *
138
     * @param string $url
139
     * @return string
140
     */
141
    protected function download(string $url): string
142
    {
143
        $content = file_get_contents($url);
144
145
        return $content;
146
    }
147
148
    /**
149
     * Запись данных в файл
150
     */
151
    protected function generateFile(): void
152
    {
153
        $output = '<?php' . PHP_EOL . PHP_EOL;
154
        $output .= '/**' . PHP_EOL;
155
        $output .= ' * ' . $this->name . ', Россия' . PHP_EOL;
156
        $output .= ' */' . PHP_EOL . PHP_EOL;
157
        $output .= 'return [' . PHP_EOL;
158
        foreach ($this->streets as $street => $numbers) {
159
            $glueNumbers = implode('", "', $numbers);
160
            if (!empty($glueNumbers)) {
161
                $output .= '    "' . trim($street, ";") . '" => ["' . $glueNumbers . '"],' . PHP_EOL;
162
            }
163
        }
164
        $output .= '];' . PHP_EOL;
165
166
        Storage::put($this->cityId . '.php', $output);
167
    }
168
}
169