Completed
Push — master ( 31aac0...2b5b42 )
by Greg
10s
created

WordWrapper::columnAutowidth()   C

Complexity

Conditions 15
Paths 72

Size

Total Lines 76
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 76
rs 5.257
cc 15
eloc 35
nc 72
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Consolidation\OutputFormatters\Transformations;
3
4
class WordWrapper
5
{
6
    protected $width;
7
8
    public function __construct($width)
9
    {
10
        $this->width = $width;
11
    }
12
13
    /**
14
     * Wrap the cells in each part of the provided data table
15
     * @param array $rows
16
     * @return array
17
     */
18
    public function wrap($rows, $widths = [])
19
    {
20
        // If the width was not set, then disable wordwrap.
21
        if (!$this->width) {
22
            return $rows;
23
        }
24
25
        // Calculate the column widths to use based on the content.
26
        $auto_widths = $this->columnAutowidth($rows, $widths);
27
28
        // Do wordwrap on all cells.
29
        $newrows = array();
30
        foreach ($rows as $rowkey => $row) {
31
            foreach ($row as $colkey => $cell) {
32
                $newrows[$rowkey][$colkey] = $this->wrapCell($cell, $auto_widths[$colkey]);
33
            }
34
        }
35
36
        return $newrows;
37
    }
38
39
    /**
40
     * Wrap one cell.  Guard against modifying non-strings and
41
     * then call through to wordwrap().
42
     *
43
     * @param mixed $cell
44
     * @param string $cellWidth
45
     * @return mixed
46
     */
47
    protected function wrapCell($cell, $cellWidth)
48
    {
49
        if (!is_string($cell)) {
50
            return $cell;
51
        }
52
        return wordwrap($cell, $cellWidth, "\n", true);
53
    }
54
55
    /**
56
     * Determine the best fit for column widths. Ported from Drush.
57
     *
58
     * @param array $rows The rows to use for calculations.
59
     * @param array $widths Manually specified widths of each column
60
     *   (in characters) - these will be left as is.
61
     */
62
    protected function columnAutowidth($rows, $widths)
63
    {
64
        $auto_widths = $widths;
65
66
        // First we determine the distribution of row lengths in each column.
67
        // This is an array of descending character length keys (i.e. starting at
68
        // the rightmost character column), with the value indicating the number
69
        // of rows where that character column is present.
70
        $col_dist = array();
71
        foreach ($rows as $rowkey => $row) {
72
            foreach ($row as $col_id => $cell) {
73
                if (empty($widths[$col_id])) {
74
                    $length = strlen($cell);
75
                    if ($length == 0) {
76
                        $col_dist[$col_id][0] = 0;
77
                    }
78
                    while ($length > 0) {
79
                        if (!isset($col_dist[$col_id][$length])) {
80
                            $col_dist[$col_id][$length] = 0;
81
                        }
82
                        $col_dist[$col_id][$length]++;
83
                        $length--;
84
                    }
85
                }
86
            }
87
        }
88
        foreach ($col_dist as $col_id => $count) {
89
            // Sort the distribution in decending key order.
90
            krsort($col_dist[$col_id]);
91
            // Initially we set all columns to their "ideal" longest width
92
            // - i.e. the width of their longest column.
93
            $auto_widths[$col_id] = max(array_keys($col_dist[$col_id]));
94
        }
95
96
        // We determine what width we have available to use, and what width the
97
        // above "ideal" columns take up.
98
        $available_width = $this->width - (count($auto_widths) * 2);
99
        $auto_width_current = array_sum($auto_widths);
100
101
        // If we need to reduce a column so that we can fit the space we use this
102
        // loop to figure out which column will cause the "least wrapping",
103
        // (relative to the other columns) and reduce the width of that column.
104
        while ($auto_width_current > $available_width) {
105
            $count = 0;
106
            $width = 0;
107
            foreach ($col_dist as $col_id => $counts) {
108
                // If we are just starting out, select the first column.
109
                if ($count == 0 ||
110
                 // OR: if this column would cause less wrapping than the currently
111
                 // selected column, then select it.
112
                 (current($counts) < $count) ||
113
                 // OR: if this column would cause the same amount of wrapping, but is
114
                 // longer, then we choose to wrap the longer column (proportionally
115
                 // less wrapping, and helps avoid triple line wraps).
116
                 (current($counts) == $count && key($counts) > $width)) {
117
                    // Select the column number, and record the count and current width
118
                    // for later comparisons.
119
                    $column = $col_id;
120
                    $count = current($counts);
121
                    $width = key($counts);
122
                }
123
            }
124
            if ($width <= 1) {
125
                // If we have reached a width of 1 then give up, so wordwrap can still progress.
126
                break;
127
            }
128
            // Reduce the width of the selected column.
129
            $auto_widths[$column]--;
0 ignored issues
show
Bug introduced by
The variable $column does not seem to be defined for all execution paths leading up to this point.

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:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

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

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
130
            // Reduce our overall table width counter.
131
            $auto_width_current--;
132
            // Remove the corresponding data from the disctribution, so next time
133
            // around we use the data for the row to the left.
134
            unset($col_dist[$column][$width]);
135
        }
136
        return $auto_widths;
137
    }
138
}
139