Complex classes like Phone 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 Phone, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
39 | class Phone extends Forms\Controls\TextInput |
||
40 | { |
||
41 | /** |
||
42 | * Define filed attributes |
||
43 | */ |
||
44 | 1 | const FIELD_COUNTRY = 'country'; |
|
45 | const FIELD_NUMBER = 'number'; |
||
46 | |||
47 | /** |
||
48 | * @var IPub\Phone\Phone |
||
49 | */ |
||
50 | private $phoneUtils; |
||
51 | |||
52 | /** |
||
53 | * List of allowed countries |
||
54 | * |
||
55 | * @var array |
||
56 | */ |
||
57 | private $allowedCountries = []; |
||
58 | |||
59 | /** |
||
60 | * List of allowed phone types |
||
61 | * |
||
62 | 1 | * @var array |
|
63 | */ |
||
64 | private $allowedTypes = []; |
||
65 | |||
66 | /** |
||
67 | * @var string|NULL |
||
68 | */ |
||
69 | private $number = NULL; |
||
70 | |||
71 | /** |
||
72 | * @var string|NULL |
||
73 | */ |
||
74 | private $country = NULL; |
||
75 | |||
76 | /** |
||
77 | * @var string |
||
78 | */ |
||
79 | private $defaultCountry; |
||
80 | |||
81 | /** |
||
82 | * @var bool |
||
83 | */ |
||
84 | private static $registered = FALSE; |
||
85 | |||
86 | /** |
||
87 | * @param PhoneUtils $phoneUtils |
||
88 | * @param string|NULL $label |
||
89 | 1 | * @param int|NULL $maxLength |
|
90 | */ |
||
91 | public function __construct(PhoneUtils $phoneUtils, $label = NULL, $maxLength = NULL) |
||
97 | 1 | ||
98 | /** |
||
99 | 1 | * @param array $countries |
|
100 | 1 | * |
|
101 | * @return $this |
||
102 | * |
||
103 | * @throws Exceptions\NoValidCountryException |
||
104 | */ |
||
105 | public function setAllowedCountries(array $countries = []) |
||
125 | 1 | ||
126 | /** |
||
127 | 1 | * @param string $country |
|
128 | * |
||
129 | * @return $this |
||
130 | * |
||
131 | * @throws Exceptions\NoValidCountryException |
||
132 | */ |
||
133 | 1 | public function addAllowedCountry($country) |
|
150 | |||
151 | /** |
||
152 | 1 | * @return array |
|
153 | */ |
||
154 | public function getAllowedCountries() |
||
163 | |||
164 | 1 | /** |
|
165 | * @param string|NULL $country |
||
166 | * |
||
167 | * @return $this |
||
168 | * |
||
169 | * @throws Exceptions\NoValidCountryException |
||
170 | */ |
||
171 | public function setDefaultCountry($country = NULL) |
||
184 | 1 | ||
185 | /** |
||
186 | 1 | * @param array $types |
|
187 | * |
||
188 | * @return $this |
||
189 | 1 | * |
|
190 | 1 | * @throws Exceptions\NoValidTypeException |
|
191 | */ |
||
192 | public function setAllowedPhoneTypes(array $types = []) |
||
207 | |||
208 | /** |
||
209 | * @param string $type |
||
210 | * |
||
211 | * @return $this |
||
212 | * |
||
213 | * @throws Exceptions\NoValidTypeException |
||
214 | */ |
||
215 | public function addAllowedPhoneType($type) |
||
225 | 1 | ||
226 | /** |
||
227 | 1 | * @return array |
|
228 | */ |
||
229 | public function getAllowedPhoneTypes() |
||
233 | |||
234 | /** |
||
235 | 1 | * @param string |
|
236 | * |
||
237 | * @return $this |
||
238 | * |
||
239 | * @throws Exceptions\InvalidArgumentException |
||
240 | */ |
||
241 | public function setValue($value) |
||
263 | 1 | ||
264 | /** |
||
265 | 1 | * @return IPub\Phone\Entities\Phone|NULL |
|
266 | */ |
||
267 | public function getValue() |
||
286 | 1 | ||
287 | /** |
||
288 | * Loads HTTP data |
||
289 | * |
||
290 | * @return void |
||
291 | */ |
||
292 | public function loadHttpData() |
||
300 | |||
301 | /** |
||
302 | * @return Utils\Html |
||
303 | */ |
||
304 | public function getControl() |
||
309 | 1 | ||
310 | /** |
||
311 | * @param string $key |
||
312 | * |
||
313 | * @return Utils\Html |
||
314 | * |
||
315 | * @throws Exceptions\InvalidArgumentException |
||
316 | */ |
||
317 | 1 | public function getControlPart($key) |
|
318 | { |
||
319 | 1 | $name = $this->getHtmlName(); |
|
320 | |||
321 | // Try to get translator |
||
322 | 1 | $translator = $this->getTranslator(); |
|
323 | |||
324 | if ($translator instanceof Localization\ITranslator && method_exists($translator, 'getLocale') === TRUE) { |
||
325 | 1 | try { |
|
326 | 1 | $locale = $translator->getLocale(); |
|
|
|||
327 | 1 | ||
328 | 1 | } catch (\Exception $ex) { |
|
329 | 1 | $locale = 'en_US'; |
|
330 | } |
||
331 | 1 | ||
332 | } else { |
||
333 | 1 | $locale = 'en_US'; |
|
334 | 1 | } |
|
335 | 1 | ||
336 | 1 | if ($key === static::FIELD_COUNTRY) { |
|
337 | 1 | $control = Forms\Helpers::createSelectBox( |
|
338 | 1 | array_reduce($this->getAllowedCountries(), function (array $result, $row) use ($locale) { |
|
339 | $countryName = geocoding\Locale::getDisplayRegion( |
||
340 | 1 | geocoding\Locale::countryCodeToLocale($row), |
|
341 | 1 | $locale |
|
342 | ); |
||
343 | 1 | ||
344 | $result[$row] = Utils\Html::el('option') |
||
345 | 1 | ->setText('+' . $this->phoneUtils->getCountryCodeForCountry($row) . ' ('. $countryName . ')') |
|
346 | ->addAttributes([ |
||
347 | 'data-mask' => preg_replace('/[0-9]/', '9', $this->phoneUtils->getExampleNationalNumber($row)), |
||
348 | 1 | ]) |
|
349 | 1 | ->value($row); |
|
350 | 1 | ||
351 | 1 | return $result; |
|
352 | 1 | }, []), |
|
353 | 1 | [ |
|
354 | 'selected?' => $this->country === NULL ? $this->defaultCountry : $this->country, |
||
355 | 1 | ] |
|
356 | ); |
||
357 | |||
358 | $control |
||
359 | 1 | ->name($name . '[' . static::FIELD_COUNTRY . ']') |
|
360 | ->id($this->getHtmlId() . '-' . static::FIELD_COUNTRY) |
||
361 | 1 | ->{'data-ipub-forms-phone'}('') |
|
362 | 1 | ->{'data-settings'}(json_encode([ |
|
363 | 'field' => $name . '[' . static::FIELD_NUMBER . ']' |
||
364 | 1 | ])); |
|
365 | |||
366 | if ($this->isDisabled()) { |
||
367 | 1 | $control->disabled(TRUE); |
|
368 | 1 | } |
|
369 | 1 | ||
370 | 1 | return $control; |
|
371 | 1 | ||
372 | } else if ($key === static::FIELD_NUMBER) { |
||
373 | 1 | $control = Utils\Html::el('input'); |
|
374 | |||
375 | $control->addAttributes([ |
||
376 | 'name' => $name . '[' . static::FIELD_NUMBER . ']', |
||
377 | 1 | 'id' => $this->getHtmlId() . '-' . static::FIELD_NUMBER, |
|
378 | 'value' => $this->number, |
||
379 | 'type' => 'text', |
||
380 | |||
381 | 'data-nette-rules' => Nette\Forms\Helpers::exportRules($this->rules) ?: NULL, |
||
382 | ]); |
||
383 | |||
384 | if ($this->isDisabled()) { |
||
385 | $control->disabled(TRUE); |
||
386 | } |
||
387 | |||
388 | return $control; |
||
389 | } |
||
390 | |||
391 | throw new Exceptions\InvalidArgumentException('Part ' . $key . ' does not exist.'); |
||
392 | } |
||
393 | |||
394 | /** |
||
395 | * @return NULL |
||
396 | */ |
||
397 | public function getLabelPart() |
||
401 | 1 | ||
402 | /** |
||
403 | 1 | * @param string $country |
|
404 | 1 | * |
|
405 | * @return string |
||
406 | * |
||
407 | 1 | * @throws Exceptions\NoValidCountryException |
|
408 | */ |
||
409 | protected function validateCountry($country) |
||
421 | 1 | ||
422 | /** |
||
423 | 1 | * @param string $type |
|
424 | 1 | * |
|
425 | * @return string |
||
426 | * |
||
427 | * @throws Exceptions\NoValidTypeException |
||
428 | */ |
||
429 | protected function validateType($type) |
||
441 | |||
442 | 1 | /** |
|
443 | * @param PhoneUtils $phoneUtils |
||
444 | 1 | * @param string $method |
|
445 | 1 | */ |
|
446 | 1 | public static function register(PhoneUtils $phoneUtils, $method = 'addPhone') |
|
465 | } |
||
466 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.