GridFieldColumnDateFormatter::augmentColumns()   B
last analyzed

Complexity

Conditions 9
Paths 10

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 7.4698
c 0
b 0
f 0
cc 9
nc 10
nop 2

How to fix   Long Method   

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
3
namespace SilverStripe\GridFieldAddOns;
4
5
use SilverStripe\Core\ClassInfo;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\ORM\FieldType\DBDate;
8
use SilverStripe\Forms\GridField\GridField;
9
use SilverStripe\Forms\GridField\GridFieldDataColumns;
10
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
11
use SilverStripe\Forms\GridField\GridField_ColumnProvider;
12
use SilverStripe\Core\Config\Configurable;
13
14
/**
15
 * Component that converts all date columns in the existing GridField into the
16
 * chosen format (by default it uses DateTime::Nice()).
17
 */
18
class GridFieldColumnDateFormatter implements GridField_ColumnProvider
19
{
20
    use Configurable;
21
22
    /**
23
     * `GridField` we are working with
24
     *
25
     * @var GridField
26
     */
27
    protected $grid_field;
28
29
    /**
30
     * Overwrite the date format (provided by config)
31
     * for this instance
32
     *
33
     * @var string
34
     */
35
    protected $date_type;
36
37
    /**
38
     * The date formatting method to use (this corresponds
39
     * to a Date method on the Date/DateTime data type).
40
     *
41
     * @var string
42
     */
43
    private static $default_date_type = ".Nice";
44
45
    /**
46
     * Find the column/header provider for this gridfield and then augment the
47
     * columns so that any dates are re-formatted.
48
     *
49
     * @param GridField $gridField Current gridfield
0 ignored issues
show
Bug introduced by
There is no parameter named $gridField. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
50
     * @param array     $columns   List reference of all column names.
51
     *
52
     * @return null
53
     */
54
    public function augmentColumns($grid_field, &$columns)
55
    {
56
        $this->setGridField($grid_field);
57
        $config = $grid_field->getConfig();
58
        $db = Config::inst()->get($grid_field->getModelClass(), "db");
0 ignored issues
show
Unused Code introduced by
$db is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
59
        $fields = $this->findDateFields();
60
61
        // Does the current grid have an action column?
62
        $has_actions = in_array('Actions', $columns);
63
64
        // First setup columns
65
        foreach ($config->getComponents() as $component) {
66
            $is_header = ($component instanceof GridFieldSortableHeader);
67
            $is_columns = $this->isColumnProvider($component);
68
69
            // If we are working with a set of data columns, look for
70
            // date/datetime columns
71
            if ($is_columns && method_exists($component, "getDisplayFields")) {
72
                $display_fields = $component->getDisplayFields($grid_field);
73
                foreach ($fields as $field) {
74
                    $display_fields = $this->changeKeys(
75
                        $field["Sort"],
76
                        $field["Column"],
77
                        $display_fields
78
                    );
79
                }
80
                $component->setDisplayFields($display_fields);
81
                $columns = array_keys($display_fields);
82
83
                // Ensure actions are added back in (if unset)
84
                if ($has_actions && !in_array('Actions', $columns)) {
85
                    $columns[] = 'Actions';
86
                }
87
            }
88
89
            // If we are working with sortable headers, look for
90
            // date/datetime columns
91
            if ($is_header) {
92
                $sort_fields = [];
93
                foreach ($fields as $field) {
94
                    $sort_fields[$field["Column"]] = $field["Sort"];
95
                }
96
97
                // Merge new sort options, retaining any existing defined custom sorting
98
                $component->setFieldSorting(
99
                    array_merge(
100
                        $sort_fields,
101
                        $component->getFieldSorting()
102
                    )
103
                );
104
            }
105
        }
106
    }
107
108
    /**
109
     * Create an array of fields, titles and values that we
110
     * use to setup sortable fields in the following format:
111
     *
112
     * - Title (the human readable name of the column)
113
     * - Column (the actual field used to display data)
114
     * - Sort (DB the column used to sort the data)
115
     *
116
     * @return array
117
     */
118
    protected function findDateFields()
119
    {
120
        $grid_field = $this->getGridField();
121
        $config = $grid_field->getConfig();
122
        $class = $grid_field->getModelClass();
123
        $obj = $class::singleton();
124
        $fields = [];
125
126
        // First setup columns
127
        foreach ($config->getComponents() as $component) {
128
            // If we are working with a set of data columns, look for
129
            // date/datetime columns
130
            if ($this->isColumnProvider($component) && method_exists($component, "getDisplayFields")) {
131
                foreach ($component->getDisplayFields($grid_field) as $k => $v) {
132
                    $field = $obj->dbObject($k);
133
                    if (isset($field) && $field instanceof DBDate) {
134
                        $fields[] = [
135
                            "Title" => $v,
136
                            "Column" => $k . $this->getDateType(),
137
                            "Sort" => $k
138
                        ];
139
                    }
140
                }
141
            }
142
        }
143
144
        return $fields;
145
    }
146
147
    /**
148
     * Is the provided component a `GridField_ColumnProvider`?
149
     *
150
     * @param object $component The current component
151
     *
152
     * @return boolean
153
     */
154
    protected function isColumnProvider($component)
155
    {
156
        $class = is_object($component) ? get_class($component) : $component;
157
        return ClassInfo::classImplements(
158
            $class,
159
            GridField_ColumnProvider::class
160
        );
161
    }
162
163
    /**
164
     * Change the array keys on the provided array to the provided alternative
165
     * (thanks to: https://stackoverflow.com/a/14227644/4161644)
166
     *
167
     * @param string $original Original key
168
     * @param string $new      New key
169
     * @param array  $array    Haystack array
170
     *
171
     * @return array
172
     */
173
    protected function changeKeys($original, $new, &$array)
174
    {
175
        foreach ($array as $k => $v) {
176
            $res[$k === $original ? $new : $k] = $v;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$res was never initialized. Although not strictly required by PHP, it is generally a good practice to add $res = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
177
        }
178
        return $res;
0 ignored issues
show
Bug introduced by
The variable $res 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...
179
    }
180
181
    /**
182
     * Get `GridField` we are working with
183
     *
184
     * @return  GridField
185
     */
186
    public function getGridField()
187
    {
188
        return $this->grid_field;
189
    }
190
191
    /**
192
     * Set `GridField` we are working with
193
     *
194
     * @param GridField $grid_field `GridField` we are working with
195
     *
196
     * @return self
197
     */
198
    public function setGridField(GridField $grid_field)
199
    {
200
        $this->grid_field = $grid_field;
201
202
        return $this;
203
    }
204
205
    /**
206
     * Get type for this instance
207
     *
208
     * @return string
209
     */
210
    public function getDateType()
211
    {
212
        if (!empty($this->date_type)) {
213
            return $this->date_type;
214
        } else {
215
            return $this->config()->default_date_type;
216
        }
217
    }
218
219
    /**
220
     * Set type for this instance
221
     *
222
     * @param string $date_type for this instance
223
     *
224
     * @return self
225
     */
226
    public function setDateType(string $date_type)
227
    {
228
        $this->date_type = $date_type;
229
        return $this;
230
    }
231
232
    /**
233
     * Component doesn't provide columns
234
     *
235
     * @param GridField $gridField Current GridField
236
     *
237
     * @return array
238
     */
239
    public function getColumnsHandled($gridField)
240
    {
241
        return array();
242
    }
243
244
    /**
245
     * Component doesn't provide columns
246
     *
247
     * @param GridField $gridField Current GridField
248
     *
249
     * @return array
250
     */
251
    public function getColumnMetadata($gridField, $columnName)
252
    {
253
        return array();
254
    }
255
256
    /**
257
     * Component doesn't provide columns
258
     *
259
     * @param GridField $gridField Current GridField
260
     *
261
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
262
     */
263
    public function getColumnContent($gridField, $record, $columnName)
264
    {
265
        return false;
266
    }
267
268
    /**
269
     * Component doesn't provide columns
270
     *
271
     * @param GridField $gridField Current GridField
272
     *
273
     * @return array
274
     */
275
    public function getColumnAttributes($gridField, $record, $columnName)
276
    {
277
        return array();
278
    }
279
}
280