Total Complexity | 45 |
Total Lines | 241 |
Duplicated Lines | 0 % |
Changes | 5 | ||
Bugs | 1 | Features | 1 |
Complex classes like Table often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Table, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
13 | class Table { |
||
14 | private $headers = null; |
||
15 | private $columns = null; |
||
16 | public $error = false; |
||
17 | public $error_info = null; |
||
18 | |||
19 | private $db, $fp; |
||
20 | |||
21 | private $versions = [ |
||
22 | 2 => ["FoxBase"], |
||
23 | 3 => ["dBASE III", "dBASE IV", "dBASE 5", "FoxPro", "FoxBASE+"], |
||
24 | 4 => ["dBASE 7"], |
||
25 | 48 => ["Visual FoxPro"], |
||
26 | 49 => ["Visual FoxPro"], |
||
27 | 50 => ["Visual FoxPro"], |
||
28 | 67 => ["dBASE IV", "dBASE 5"], |
||
29 | 99 => ["dBASE IV", "dBASE 5"], |
||
30 | 131 => ["dBASE III", "FoxBASE+", "FoxPro"], |
||
31 | 139 => ["dBASE IV", "dBASE 5"], |
||
32 | 140 => ["dBASE 7"], |
||
33 | 203 => ["dBASE IV", "dBASE 5"], |
||
34 | 229 => ["SMT"], |
||
35 | 235 => ["dBASE IV", "dBASE 5"], |
||
36 | 245 => ["FoxPro"], |
||
37 | 251 => ["FoxBASE"] |
||
38 | ]; |
||
39 | private $memo = [ |
||
40 | "versions" => [131, 139, 140, 203, 229, 235, 245, 251], |
||
41 | "formats" => [ |
||
42 | "dbt" => [131, 139, 140, 203, 235, 251], |
||
43 | "fpt" => [245, 48, 49, 50], |
||
44 | "smt" => [229] |
||
45 | ] |
||
46 | ]; |
||
47 | |||
48 | private $charsets = [ |
||
49 | 0 => 866, //If charset not defined |
||
50 | 1 => 437, 2 => 850, 3 => 1252, 4 => 10000, 8 => 865, |
||
51 | 9 => 437, 10 => 850, 11 => 437, 13 => 437, 14 => 850, |
||
52 | 15 => 437, 16 => 850, 17 => 437, 18 => 850, 19 => 932, |
||
53 | 20 => 850, 21 => 850, 22 => 437, 23 => 850, 24 => 437, |
||
54 | 25 => 437, 26 => 850, 27 => 437, 28 => 863, 29 => 850, |
||
55 | 31 => 852, 34 => 852, 35 => 852, 36 => 860, 37 => 850, |
||
56 | 38 => 866, 55 => 850, 64 => 852, 77 => 936, 78 => 949, |
||
57 | 79 => 950, 80 => 874, 88 => 1252, 89 => 1252, 100 => 852, |
||
58 | 101 => 866, 102 => 865, 103 => 861, 104 => 895, 105 => 866, |
||
59 | 106 => 737, 107 => 857, 108 => 863, 120 => 950, 121 => 949, |
||
60 | 122 => 936, 123 => 932, 124 => 874, 134 => 737, 135 => 852, |
||
61 | 136 => 857, 150 => 10007, 151 => 10029, 152 => 10006, 200 => 1250, |
||
62 | 201 => 1251, 202 => 1254, 203 => 1253, 204 => 1257 |
||
63 | ]; |
||
64 | private $dbase7 = false, $v_foxpro = false; |
||
65 | |||
66 | /** |
||
67 | * @throws Exception |
||
68 | */ |
||
69 | public function __construct($dbPath, $charset = null){ |
||
70 | $this->db = $dbPath; |
||
71 | if (!is_null($charset)) { |
||
72 | if (!is_numeric($charset)) { |
||
73 | throw new Exception("Set not correct charset. Allows only digits."); |
||
74 | } |
||
75 | $this->charsets[0] = $charset; |
||
76 | } |
||
77 | $this->open(); |
||
78 | } |
||
79 | |||
80 | public function __destruct() { |
||
81 | $this->close(); |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * @throws Exception |
||
86 | */ |
||
87 | private function open() { |
||
88 | if (!file_exists($this->db)) { |
||
89 | throw new Exception(sprintf('File %s cannot be found', $this->db)); |
||
90 | } |
||
91 | $this->fp = fopen($this->db, "rb"); |
||
92 | } |
||
93 | |||
94 | public function getHeaders() { |
||
95 | if (!$this->error && is_null($this->headers)) { |
||
96 | $this->readHeaders(); |
||
97 | } |
||
98 | return $this->headers; |
||
99 | } |
||
100 | |||
101 | public function getColumns() { |
||
102 | $this->getHeaders(); |
||
103 | if (!$this->error && is_null($this->columns)) { |
||
104 | $this->readTableHeaders(); |
||
105 | } |
||
106 | return $this->columns; |
||
107 | } |
||
108 | |||
109 | public function getData() { |
||
110 | $this->getColumns(); |
||
111 | return $this->fp; |
||
112 | } |
||
113 | |||
114 | public function close() { |
||
115 | if (get_resource_type($this->fp) === "file") { |
||
116 | fclose($this->fp); |
||
117 | } |
||
118 | } |
||
119 | |||
120 | private function readHeaders() { |
||
168 | } |
||
169 | |||
170 | private function readTableHeaders() { |
||
171 | if (!$this->error && is_null($this->headers)) { |
||
172 | $this->readHeaders(); |
||
173 | } |
||
174 | if (!$this->error) { |
||
175 | for ($i = 0; $i < $this->headers["columns"]; $i++) { |
||
176 | $data = fread($this->fp, ($this->dbase7) ? 48 : 32); |
||
177 | if ($this->dbase7) { |
||
178 | $this->columns[$i] = [ |
||
179 | "name" => strtolower(trim(substr($data, 0, 32))), |
||
180 | "type" => $data[32], |
||
181 | "length" => unpack("C", $data[33])[1], |
||
182 | "decimal" => unpack("C", $data[34])[1], |
||
183 | "mdx_flag" => unpack("C", $data[37])[1], |
||
184 | "auto_increment" => unpack("L", substr($data, 40, 4))[1] |
||
185 | ]; |
||
186 | } |
||
187 | else { |
||
188 | $this->columns[$i] = [ |
||
189 | "name" => strtolower(trim(substr($data, 0, 11))), |
||
190 | "type" => $data[11], |
||
191 | "length" => unpack("C", $data[16])[1], |
||
192 | "decimal" => unpack("C", $data[17])[1], |
||
193 | "mdx_flag" => unpack("C", $data[31])[1], |
||
194 | ]; |
||
195 | if ($this->v_foxpro) { |
||
196 | $this->columns[$i]["flag"] = unpack("C", $data[18])[1]; |
||
197 | $this->columns[$i]["system"] = ($this->columns[$i]["flag"] == 1); |
||
198 | $this->columns[$i]["has_null"] = in_array($this->columns[$i]["flag"], [2, 6]); |
||
199 | $this->columns[$i]["binary"] = in_array($this->columns[$i]["flag"], [4, 6]); |
||
200 | $this->columns[$i]["auto_increment"] = ($this->columns[$i]["flag"] == 12); |
||
201 | if ($this->columns[$i]["auto_increment"]) { |
||
202 | $this->columns[$i]["auto_increment_next"] = unpack("L", substr($data, 19, 4))[1]; |
||
203 | $this->columns[$i]["auto_increment_step"] = unpack("C", $data[23])[1]; |
||
204 | } |
||
205 | } |
||
206 | else { |
||
207 | $this->columns[$i]["mdx_flag"] = unpack("C", $data[31])[1]; |
||
208 | } |
||
209 | } |
||
210 | if ($this->columns[$i]["type"] == "C") { |
||
211 | $this->columns[$i]["length"] = unpack("S", substr($data, ($this->dbase7) ? 33 : 16, 2))[1]; |
||
212 | $this->columns[$i]["decimal"] = 0; |
||
213 | } |
||
214 | } |
||
215 | } |
||
216 | $terminal_byte = unpack("C", fread($this->fp, 1))[1]; |
||
217 | if ($terminal_byte != 13) { |
||
218 | $this->error = true; |
||
219 | $this->error_info = "Not correct DBF file by columns"; |
||
220 | } |
||
221 | if ($this->v_foxpro) { |
||
222 | fread($this->fp, 263); |
||
223 | } |
||
224 | } |
||
225 | |||
226 | private function getDate($data) { |
||
227 | return $data[3].".".$data[2].".".($data[1] > 70 ? 1900 + $data[1] : 2000 + $data[1]); |
||
228 | } |
||
229 | |||
230 | private function getMemoFile($file) { |
||
231 | foreach ($this->memo["formats"] as $format => $versions) { |
||
232 | if (in_array($this->headers["version"], $versions)) { |
||
233 | return $this->fileExists($file.".".$format); |
||
234 | } |
||
235 | } |
||
236 | return false; |
||
237 | } |
||
238 | |||
239 | private function fileExists($fileName) { |
||
254 | } |
||
255 | } |
||
256 |