Skip to content

Commit 8fa51dc

Browse files
committed
Source
1 parent 5b05951 commit 8fa51dc

File tree

11 files changed

+196
-125
lines changed

11 files changed

+196
-125
lines changed

resources/converter.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
include __DIR__.'/../vendor/autoload.php';
44

5+
use Recca0120\Twzipcode\Sources\CSV;
56
use Recca0120\Twzipcode\Storages\File;
67

78
set_error_handler(static function ($severity, $message, $file, $line) {
@@ -14,6 +15,8 @@
1415
// https://data.gov.tw/dataset/5948
1516
$url = 'https://quality.data.gov.tw/dq_download_csv.php?nid=5948&md5_url=e1f6004ad33eb3ff3a824fb992a4b01a';
1617

18+
$contents = file_get_contents($url);
19+
1720
if (file_exists($file) === false) {
1821
touch($file);
1922
$contents = file_get_contents($url);
@@ -35,5 +38,5 @@
3538
$zip->close();
3639
}
3740

38-
(new File)->loadFile($file);
41+
(new File)->load(new CSV($file));
3942
echo 'benchmark: '.(microtime(true) - $start)."\n";

src/Contracts/Source.php

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Recca0120\Twzipcode\Contracts;
4+
5+
interface Source
6+
{
7+
public function each(callable $callback);
8+
}

src/Contracts/Storage.php

+5-11
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,15 @@ public function zip3(Address $address);
2323
public function rules($zip3);
2424

2525
/**
26-
* load.
27-
*
28-
* @param string $source
29-
* @return $this
30-
*/
31-
public function load($source);
32-
33-
/**
34-
* @param string|null $file
3526
* @return $this
3627
*/
37-
public function loadFile($file = null);
28+
public function flush();
3829

3930
/**
31+
* load.
32+
*
33+
* @param Source $source
4034
* @return $this
4135
*/
42-
public function flush();
36+
public function load($source);
4337
}

src/Sources/CSV.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Recca0120\Twzipcode\Sources;
4+
5+
class CSV extends Source
6+
{
7+
/** @var string */
8+
protected $file;
9+
10+
/** @var string */
11+
private $extension;
12+
13+
public function __construct($file)
14+
{
15+
$this->file = $file;
16+
$this->extension = pathinfo($this->file, PATHINFO_EXTENSION);
17+
}
18+
19+
protected function getContents()
20+
{
21+
return $this->extension === 'zip' ? static::unzip($this->file) : file_get_contents($this->file);
22+
}
23+
}

src/Sources/Source.php

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace Recca0120\Twzipcode\Sources;
4+
5+
use Recca0120\Twzipcode\Contracts\Source as SourceContract;
6+
use ZipArchive;
7+
8+
abstract class Source implements SourceContract
9+
{
10+
private static $tricks = [
11+
'宜蘭縣壯圍鄉' => '263',
12+
'新竹縣寶山鄉' => '308',
13+
'臺南市新市區' => '744',
14+
];
15+
16+
public function each(callable $callback)
17+
{
18+
static::eachGroup(static::prepare($this->rows()), $callback);
19+
}
20+
21+
/**
22+
* @return string
23+
*/
24+
abstract protected function getContents();
25+
26+
/**
27+
* @return array{array{zipcode: string, county: string, district: string, text: string}} $rows
28+
*/
29+
protected function rows()
30+
{
31+
$lines = preg_split('/\n|\r\n$/', $this->getContents());
32+
$lines = array_filter($lines, static function ($line) {
33+
return ! empty(trim($line));
34+
});
35+
36+
return array_map(static function ($line) {
37+
$data = explode(',', $line);
38+
39+
return ['zipcode' => $data[0], 'county' => $data[1], 'district' => $data[2], 'text' => $line];
40+
}, $lines);
41+
}
42+
43+
/**
44+
* @param array{array{zipcode: string, county: string, district: string, text: string}} $rows
45+
* @return array
46+
*/
47+
protected static function prepare($rows)
48+
{
49+
return array_reduce($rows, static function ($results, $row) {
50+
$zip3 = ! empty(self::$tricks[$row['county'].$row['district']])
51+
? self::$tricks[$row['county'].$row['district']]
52+
: substr($row['zipcode'], 0, 3);
53+
54+
$results[$row['county']][$row['district']][$zip3][] = $row['text'];
55+
56+
return $results;
57+
}, []);
58+
}
59+
60+
protected static function eachGroup($ruleGroup, $callback)
61+
{
62+
foreach ($ruleGroup as $county => $districts) {
63+
foreach ($districts as $district => $addresses) {
64+
foreach ($addresses as $zipcode => $rule) {
65+
$callback($zipcode, $county, $district, $rule);
66+
}
67+
}
68+
}
69+
}
70+
71+
/**
72+
* @param string $file
73+
* @return string
74+
*/
75+
protected static function unzip($file)
76+
{
77+
$zip = new ZipArchive;
78+
$zip->open($file);
79+
$contents = $zip->getFromIndex(0);
80+
$zip->close();
81+
82+
return $contents;
83+
}
84+
}

src/Sources/Text.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Recca0120\Twzipcode\Sources;
4+
5+
class Text extends Source
6+
{
7+
/**
8+
* @var string
9+
*/
10+
private $text;
11+
12+
/**
13+
* @param string $text
14+
*/
15+
public function __construct($text)
16+
{
17+
$this->text = $text;
18+
}
19+
20+
protected function getContents()
21+
{
22+
return $this->text;
23+
}
24+
}

src/Storages/File.php

+34-104
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
namespace Recca0120\Twzipcode\Storages;
44

5-
use Closure;
65
use Recca0120\Lodash\JArray;
76
use Recca0120\Lodash\JString;
87
use Recca0120\Twzipcode\Address;
8+
use Recca0120\Twzipcode\Contracts\Source;
99
use Recca0120\Twzipcode\Contracts\Storage;
1010
use Recca0120\Twzipcode\Rule;
11-
use ZipArchive;
1211

1312
class File implements Storage
1413
{
@@ -50,36 +49,6 @@ public function zip3(Address $address)
5049
return null;
5150
}
5251

53-
/**
54-
* @param string $source
55-
* @return $this
56-
*/
57-
public function load($source)
58-
{
59-
$zip5 = [];
60-
$zip3 = [];
61-
$this->each(
62-
$this->prepareSource($source),
63-
function ($zipcode, $county, $district, $rules) use (&$zip5, &$zip3) {
64-
$zip5[$zipcode] = $this->compress(array_map(static function ($rule) {
65-
return new Rule($rule);
66-
}, $rules));
67-
68-
if (empty($zip3[$county])) {
69-
$zip3[$county] = substr($zipcode, 0, 1);
70-
}
71-
72-
if (empty($zip3[$county.$district])) {
73-
$zip3[$county.$district] = substr($zipcode, 0, 3);
74-
}
75-
});
76-
77-
$this->store('zip3', $zip3);
78-
$this->store('zip5', $zip5);
79-
80-
return $this;
81-
}
82-
8352
/**
8453
* @param string $zip3
8554
* @return JArray
@@ -94,27 +63,53 @@ public function rules($zip3)
9463
}
9564

9665
/**
97-
* @param string $file
9866
* @return $this
9967
*/
100-
public function loadFile($file = null)
68+
public function flush()
10169
{
102-
$file = $file ?: $this->path.'../Zip32_utf8_10501_1.csv';
103-
$this->load($this->getSource($file));
70+
static::$cached = ['zip3' => null, 'zip5' => null];
10471

10572
return $this;
10673
}
10774

10875
/**
76+
* @param Source $source
10977
* @return $this
11078
*/
111-
public function flush()
79+
public function load($source)
11280
{
113-
static::$cached = ['zip3' => null, 'zip5' => null];
81+
$zip5 = [];
82+
$zip3 = [];
83+
$source->each(function ($zipcode, $county, $district, $rules) use (&$zip5, &$zip3) {
84+
$zip5[$zipcode] = $this->compress(array_map(static function ($rule) {
85+
return new Rule($rule);
86+
}, $rules));
87+
88+
if (empty($zip3[$county])) {
89+
$zip3[$county] = substr($zipcode, 0, 1);
90+
}
91+
92+
if (empty($zip3[$county.$district])) {
93+
$zip3[$county.$district] = substr($zipcode, 0, 3);
94+
}
95+
});
96+
97+
$this->store('zip3', $zip3);
98+
$this->store('zip5', $zip5);
11499

115100
return $this;
116101
}
117102

103+
/**
104+
* @param string $filename
105+
* @param array $data
106+
* @return void
107+
*/
108+
private function store($filename, $data)
109+
{
110+
file_put_contents($this->path.$filename.$this->suffix, $this->compress($data));
111+
}
112+
118113
/**
119114
* @param string $filename
120115
* @return void
@@ -134,63 +129,6 @@ private function restore($filename)
134129
));
135130
}
136131

137-
/**
138-
* @param string $file
139-
* @return string
140-
*/
141-
private function getSource($file)
142-
{
143-
$extension = pathinfo($file, PATHINFO_EXTENSION);
144-
145-
if ($extension === 'zip') {
146-
$zip = new ZipArchive;
147-
$zip->open($file);
148-
$contents = $zip->getFromIndex(0);
149-
$zip->close();
150-
} else {
151-
$contents = file_get_contents($file);
152-
}
153-
154-
return $contents;
155-
}
156-
157-
/**
158-
* @param string $source
159-
* @return array
160-
*/
161-
private function prepareSource($source)
162-
{
163-
$tricks = ['宜蘭縣壯圍鄉' => '263', '新竹縣寶山鄉' => '308', '臺南市新市區' => '744'];
164-
$results = [];
165-
$rules = preg_split('/\n|\r\n$/', $source);
166-
foreach ($rules as $rule) {
167-
if (! empty(trim($rule))) {
168-
list($zipcode, $county, $district) = explode(',', $rule);
169-
$zip3 = ! empty($tricks[$county.$district])
170-
? $tricks[$county.$district]
171-
: substr($zipcode, 0, 3);
172-
$results[$county][$district][$zip3][] = $rule;
173-
}
174-
}
175-
176-
return $results;
177-
}
178-
179-
/**
180-
* @param array $ruleGroup
181-
* @param Closure $callback
182-
*/
183-
private function each($ruleGroup, $callback)
184-
{
185-
foreach ($ruleGroup as $county => $districts) {
186-
foreach ($districts as $district => $addresses) {
187-
foreach ($addresses as $zipcode => $rule) {
188-
$callback($zipcode, $county, $district, $rule);
189-
}
190-
}
191-
}
192-
}
193-
194132
/**
195133
* @param array $array
196134
* @return string
@@ -209,13 +147,5 @@ private function decompress($compressed)
209147
return unserialize(gzuncompress($compressed));
210148
}
211149

212-
/**
213-
* @param string $filename
214-
* @param array $data
215-
* @return void
216-
*/
217-
private function store($filename, $data)
218-
{
219-
file_put_contents($this->path.$filename.$this->suffix, $this->compress($data));
220-
}
150+
221151
}

0 commit comments

Comments
 (0)