Complex classes like Component 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 Component, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | class Component |
||
16 | { |
||
17 | const PREG_TYPES = 'jpe?g|gif|png|ico|js|css|pdf|ttf|otf|svg|eot|woff2?|swf|tar|t?gz|g?zip|csv|xls?x?|word|docx?|pptx?|psd|ogg|wav|mp3|mp4|mpeg?|mpg|mov|qt'; |
||
18 | public static $instance; // made public to facilitate testing |
||
19 | public static $not_found = array(); |
||
20 | public static $urls = array(); |
||
21 | private $cached = null; |
||
22 | private $db = null; |
||
23 | |||
24 | /** |
||
25 | * Prepares a Symfony Response for you to send. |
||
26 | * |
||
27 | * @param string $file Either a file location, or the type of file you are sending eg. html, txt, less, scss, json, xml, rdf, rss, atom, js, css |
||
28 | * @param array|string $options An array of options if ``$file`` is a location, or the string of data you want to send. The available options are: |
||
29 | * |
||
30 | * - '**name**' - changes a downloadable asset's file name |
||
31 | * - |
||
32 | * - |
||
33 | * |
||
34 | * @return object A Symfony\Component\HttpFoundation\Response |
||
35 | */ |
||
36 | 8 | public static function dispatch($file, $options = array()) |
|
110 | |||
111 | 6 | public static function cached($dir, array $glide = array()) |
|
225 | |||
226 | 2 | public static function urls($html) |
|
318 | |||
319 | 8 | public static function mime($type) |
|
320 | { |
||
321 | 8 | $mime = null; |
|
322 | 8 | $single = (is_array($type)) ? false : true; |
|
323 | 8 | if (is_array($type)) { |
|
324 | 1 | $type = array_shift($type); |
|
325 | 1 | } |
|
326 | 8 | switch (strtolower($type)) { |
|
327 | 8 | case 'html': |
|
328 | 3 | $mime = array('text/html', 'application/xhtml+xml', 'text/plain'); |
|
329 | 3 | break; |
|
330 | 8 | case 'txt': |
|
331 | 2 | $mime = array('text/plain'); |
|
332 | 2 | break; |
|
333 | 8 | case 'less': |
|
334 | 1 | $mime = array('text/x-less', 'text/css', 'text/plain', 'application/octet-stream'); |
|
335 | 1 | break; |
|
336 | 8 | case 'scss': |
|
337 | 1 | $mime = array('text/css', 'text/plain', 'application/octet-stream'); |
|
338 | 1 | break; |
|
339 | 8 | case 'json': |
|
340 | 1 | $mime = array('application/json', 'application/x-json', 'text/json', 'text/plain'); |
|
341 | 1 | break; |
|
342 | 8 | case 'xml': |
|
343 | 3 | $mime = array('application/xml', 'application/x-xml', 'text/xml', 'text/plain'); |
|
344 | 3 | break; |
|
345 | 6 | case 'rdf': |
|
346 | 1 | $mime = array('application/rdf+xml'); |
|
347 | 1 | break; |
|
348 | 6 | case 'rss': |
|
349 | 2 | $mime = array('application/rss+xml'); |
|
350 | 2 | break; |
|
351 | 5 | case 'atom': |
|
352 | 1 | $mime = array('application/atom+xml'); |
|
353 | 1 | break; |
|
354 | 5 | case 'jpeg': |
|
355 | 5 | case 'jpg': |
|
356 | 2 | $mime = array('image/jpeg', 'image/pjpeg'); |
|
357 | 2 | break; |
|
358 | 5 | case 'gif': |
|
359 | 1 | $mime = array('image/gif'); |
|
360 | 1 | break; |
|
361 | 5 | case 'png': |
|
362 | 1 | $mime = array('image/png', 'image/x-png'); |
|
363 | 1 | break; |
|
364 | 5 | case 'ico': |
|
365 | 1 | $mime = array('image/x-icon', 'image/vnd.microsoft.icon'); |
|
366 | 1 | break; |
|
367 | 5 | case 'js': |
|
368 | 2 | $mime = array('application/javascript', 'application/x-javascript', 'text/javascript', 'text/plain'); |
|
369 | 2 | break; |
|
370 | 4 | case 'css': |
|
371 | 2 | $mime = array('text/css', 'text/plain'); |
|
372 | 2 | break; |
|
373 | 3 | case 'pdf': |
|
374 | 1 | $mime = array('application/pdf', 'application/force-download', 'application/x-download', 'binary/octet-stream'); |
|
375 | 1 | break; |
|
376 | 3 | case 'ttf': |
|
377 | 1 | $mime = array('application/font-sfnt', 'application/font-ttf', 'application/x-font-ttf', 'font/ttf', 'font/truetype', 'application/octet-stream'); |
|
378 | 1 | break; |
|
379 | 3 | case 'otf': |
|
380 | 1 | $mime = array('application/font-sfnt', 'application/font-otf', 'application/x-font-otf', 'font/opentype', 'application/octet-stream'); |
|
381 | 1 | break; |
|
382 | 3 | case 'svg': |
|
383 | 1 | $mime = array('image/svg+xml', 'application/xml', 'text/xml'); |
|
384 | 1 | break; |
|
385 | 3 | case 'eot': |
|
386 | 1 | $mime = array('application/vnd.ms-fontobject', 'application/octet-stream'); |
|
387 | 1 | break; |
|
388 | 3 | case 'woff': |
|
389 | 1 | $mime = array('application/font-woff', 'application/x-woff', 'application/x-font-woff', 'font/x-woff', 'application/octet-stream'); |
|
390 | 1 | break; |
|
391 | 3 | case 'woff2': |
|
392 | 1 | $mime = array('application/font-woff2', 'font/woff2', 'application/octet-stream'); |
|
393 | 1 | break; |
|
394 | 3 | case 'swf': |
|
395 | 1 | $mime = array('application/x-shockwave-flash'); |
|
396 | 1 | break; |
|
397 | 3 | case 'tar': |
|
398 | 1 | $mime = array('application/x-tar'); |
|
399 | 1 | break; |
|
400 | 3 | case 'tgz': |
|
401 | 1 | $mime = array('application/x-tar', 'application/x-gzip-compressed'); |
|
402 | 1 | break; |
|
403 | 3 | case 'gz': |
|
404 | 3 | case 'gzip': |
|
405 | 1 | $mime = array('application/x-gzip'); |
|
406 | 1 | break; |
|
407 | 3 | case 'zip': |
|
408 | 1 | $mime = array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'); |
|
409 | 1 | break; |
|
410 | 3 | case 'csv': |
|
411 | 3 | $mime = array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel', 'text/plain'); |
|
412 | 3 | break; |
|
413 | 2 | case 'xl': |
|
414 | 1 | $mime = array('application/excel'); |
|
415 | 1 | break; |
|
416 | 2 | case 'xls': |
|
417 | 1 | $mime = array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'); |
|
418 | 1 | break; |
|
419 | 2 | case 'xlsx': |
|
420 | 1 | $mime = array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword', 'application/x-zip'); |
|
421 | 1 | break; |
|
422 | 2 | case 'word': |
|
423 | 1 | $mime = array('application/msword', 'application/octet-stream'); |
|
424 | 1 | break; |
|
425 | 2 | case 'doc': |
|
426 | 1 | $mime = array('application/msword', 'application/vnd.ms-office'); |
|
427 | 1 | break; |
|
428 | 2 | case 'docx': |
|
429 | 1 | $mime = array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword', 'application/x-zip'); |
|
430 | 1 | break; |
|
431 | 2 | case 'ppt': |
|
432 | 1 | $mime = array('application/powerpoint', 'application/vnd.ms-powerpoint', 'application/vnd.ms-office', 'application/msword'); |
|
433 | 1 | break; |
|
434 | 2 | case 'pptx': |
|
435 | 1 | $mime = array('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-zip', 'application/zip'); |
|
436 | 1 | break; |
|
437 | 2 | case 'psd': |
|
438 | 1 | $mime = array('application/x-photoshop', 'image/vnd.adobe.photoshop'); |
|
439 | 1 | break; |
|
440 | 2 | case 'ogg': |
|
441 | 1 | $mime = array('audio/ogg'); |
|
442 | 1 | break; |
|
443 | 2 | case 'wav': |
|
444 | 1 | $mime = array('audio/x-wav', 'audio/wave', 'audio/wav'); |
|
445 | 1 | break; |
|
446 | 2 | case 'mp3': |
|
447 | 1 | $mime = array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'); |
|
448 | 1 | break; |
|
449 | 2 | case 'mp4': |
|
450 | 1 | $mime = array('video/mp4'); |
|
451 | 1 | break; |
|
452 | 2 | case 'mpe': |
|
453 | 2 | case 'mpeg': |
|
454 | 2 | case 'mpg': |
|
455 | 1 | $mime = array('video/mpeg'); |
|
456 | 1 | break; |
|
457 | 2 | case 'mov': |
|
458 | 2 | case 'qt': |
|
459 | 1 | $mime = array('video/quicktime'); |
|
460 | 1 | break; |
|
461 | 8 | } |
|
462 | |||
463 | 8 | return ($mime && $single) ? array_shift($mime) : $mime; |
|
464 | } |
||
465 | |||
466 | 1 | private function css($file, $row) |
|
511 | |||
512 | 2 | private function paths(&$cache) |
|
513 | { |
||
514 | 2 | $page = Page::html(); |
|
515 | 2 | $count = 0; |
|
516 | 2 | foreach ($cache as $dir => $files) { |
|
517 | 2 | $count += count($files); |
|
518 | 2 | } |
|
519 | 2 | $ids = $this->ids($count); |
|
520 | 2 | $insert = array(); |
|
521 | 2 | $update = array(); |
|
522 | 2 | $stmt = $this->db->prepare(array( |
|
523 | 2 | 'SELECT f.id AS file_id, f.updated, p.tiny, p.id AS path_id', |
|
524 | 2 | 'FROM files AS f INNER JOIN paths AS p ON f.id = p.file_id', |
|
525 | 2 | 'WHERE f.file = ? AND f.query = ?', |
|
526 | 2 | ), 'assoc'); |
|
527 | 2 | foreach ($cache as $dir => $files) { |
|
528 | 2 | foreach ($files as $path => $tiny) { |
|
529 | 2 | list($file, $query) = explode('?', $path.'?'); |
|
530 | 2 | $file = $page->dir[$dir].$file; |
|
531 | 2 | $updated = filemtime($file); |
|
532 | 2 | $this->db->execute($stmt, array($file, $query)); |
|
533 | 2 | if ($row = $this->db->fetch($stmt)) { |
|
534 | 2 | if ($row['updated'] == $updated) { |
|
535 | 2 | $tiny = $row['tiny']; |
|
536 | 2 | } else { |
|
537 | 1 | list($path_id, $tiny) = each($ids); |
|
538 | 1 | $update[$row['file_id']] = array($path_id, $updated); |
|
539 | } |
||
540 | 2 | } else { |
|
541 | 2 | list($path_id, $tiny) = each($ids); |
|
542 | 2 | $insert[] = array($path_id, $file, $query, $updated); |
|
543 | } |
||
544 | 2 | $cache[$dir][$path] = $tiny; |
|
545 | 2 | } |
|
546 | 2 | } |
|
547 | 2 | $this->db->close($stmt); |
|
548 | 2 | if (empty($insert) && empty($update)) { |
|
549 | 1 | return; |
|
550 | } |
||
551 | 2 | $this->db->exec('BEGIN IMMEDIATE'); |
|
552 | 2 | $paths = array(); |
|
553 | 2 | if (!empty($insert)) { |
|
554 | 2 | $stmt = $this->db->insert('files', array('path_id', 'file', 'query', 'updated')); |
|
555 | 2 | foreach ($insert as $array) { |
|
556 | 2 | $paths[$array[0]] = $this->db->insert($stmt, $array); |
|
557 | 2 | } |
|
558 | 2 | $this->db->close($stmt); |
|
559 | 2 | } |
|
560 | 2 | if (!empty($update)) { |
|
561 | 1 | $stmt = $this->db->update('files', 'id', array('path_id', 'updated')); |
|
562 | 1 | foreach ($update as $file_id => $array) { |
|
563 | 1 | $this->db->update($stmt, $file_id, $array); |
|
564 | 1 | $paths[$array[0]] = $file_id; |
|
565 | 1 | } |
|
566 | 1 | $this->db->close($stmt); |
|
567 | 1 | } |
|
568 | 2 | if (!empty($paths)) { |
|
569 | 2 | $stmt = $this->db->update('paths', 'id', array('file_id')); |
|
570 | 2 | foreach ($paths as $path_id => $file_id) { |
|
571 | 2 | $this->db->update($stmt, $path_id, array($file_id)); |
|
572 | 2 | } |
|
573 | 2 | $this->db->close($stmt); |
|
574 | 2 | } |
|
575 | 2 | $this->db->exec('COMMIT'); |
|
576 | |||
577 | 2 | return; |
|
578 | } |
||
579 | |||
580 | 2 | private function ids($count) |
|
581 | { |
||
582 | 2 | $ids = array(); |
|
583 | 2 | if ($stmt = $this->db->query(array( |
|
584 | 2 | 'SELECT id, tiny', |
|
585 | 2 | 'FROM paths', |
|
586 | 2 | 'WHERE file_id = ?', |
|
587 | 2 | 'ORDER BY id DESC LIMIT '.$count, |
|
588 | 2 | ), 0, 'row')) { |
|
589 | 2 | while (list($id, $tiny) = $this->db->fetch($stmt)) { |
|
590 | 2 | $ids[$id] = $tiny; |
|
591 | 2 | } |
|
592 | 2 | $this->db->close($stmt); |
|
593 | 2 | } |
|
594 | 2 | if (count($ids) == $count) { |
|
595 | 2 | return $ids; |
|
596 | } |
||
597 | 1 | $this->db->exec('BEGIN IMMEDIATE'); |
|
598 | 1 | $stmt = $this->db->insert('OR IGNORE INTO paths', array('tiny')); |
|
599 | 1 | $string = '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
|
600 | 1 | for ($i = 0; $i < $count + 100; ++$i) { |
|
601 | 1 | $tiny_id = ''; // 60 (characters) ^ 5 (length) gives 777,600,000 possible combinations |
|
602 | 1 | while (strlen($tiny_id) < 5) { |
|
603 | 1 | $tiny_id .= $string[mt_rand(0, 60)]; |
|
604 | 1 | } |
|
605 | 1 | $this->db->insert($stmt, array($tiny_id)); |
|
606 | 1 | } |
|
607 | 1 | $this->db->close($stmt); |
|
608 | 1 | $this->db->exec('COMMIT'); |
|
609 | |||
610 | 1 | return $this->ids($count); |
|
611 | } |
||
612 | |||
613 | 6 | private function openDatabase() |
|
633 | |||
634 | 6 | private function closeDatabase() |
|
641 | |||
642 | 6 | private function __construct() |
|
645 | } |
||
646 |
If you define a variable conditionally, it can happen that it is not defined for all execution paths.
Let’s take a look at an example:
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.
Available Fixes
Check for existence of the variable explicitly:
Define a default value for the variable:
Add a value for the missing path: