Completed
Push — master ( a9b611...61b36b )
by Matthew
05:54 queued 04:26
created

ColumnUtil   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 43
eloc 109
c 2
b 1
f 0
dl 0
loc 190
rs 8.96

4 Methods

Rating   Name   Duplication   Size   Complexity  
A createCacheFilename() 0 24 5
B populateCacheFile() 0 35 9
A cacheClassesFromFile() 0 6 2
F extractClassesFromFile() 0 91 27

How to fix   Complexity   

Complex Class

Complex classes like ColumnUtil 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 ColumnUtil, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Dtc\GridBundle\Util;
4
5
use Dtc\GridBundle\Annotation\Action;
6
use Symfony\Component\Yaml\Yaml;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Yaml\Yaml was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Exception;
8
9
class ColumnUtil
10
{
11
    /**
12
     * @param $cacheDir
13
     * @param $fqn
14
     *
15
     * @return string
16
     *
17
     * @throws Exception
18
     */
19
    public static function createCacheFilename($cacheDir, $fqn)
20
    {
21
        $directory = $cacheDir.'/DtcGridBundle';
22
        $umask = decoct(umask());
23
        $umask = str_pad($umask, 4, '0', STR_PAD_LEFT);
24
25
        // Is there a better way to do this?
26
        $permissions = '0777';
27
        $permissions[1] = intval($permissions[1]) - intval($umask[1]);
28
        $permissions[2] = intval($permissions[2]) - intval($umask[2]);
29
        $permissions[3] = intval($permissions[3]) - intval($umask[3]);
30
31
        $name = str_replace('\\', DIRECTORY_SEPARATOR, $fqn);
32
        $name = ltrim($name, DIRECTORY_SEPARATOR);
33
        $filename = $directory.DIRECTORY_SEPARATOR.$name.'.php';
34
35
        if (($dir = dirname($filename)) && !is_dir($dir) && !mkdir($dir, octdec($permissions), true)) {
0 ignored issues
show
Bug introduced by
It seems like octdec($permissions) can also be of type double; however, parameter $mode of mkdir() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

35
        if (($dir = dirname($filename)) && !is_dir($dir) && !mkdir($dir, /** @scrutinizer ignore-type */ octdec($permissions), true)) {
Loading history...
36
            throw new Exception("Can't create: ".$dir);
37
        }
38
        if (!is_writable($dir)) {
39
            throw new Exception("Can't write to: $dir");
40
        }
41
42
        return $filename;
43
    }
44
45
    /**
46
     * @param string $filename
47
     * @param array  $classInfo
48
     */
49
    public static function populateCacheFile($filename, array $classInfo)
50
    {
51
        $columns = isset($classInfo['columns']) ? $classInfo['columns'] : [];
52
        $sort = isset($classInfo['sort']) ? $classInfo['sort'] : [];
53
54
        if ($columns) {
55
            $output = "<?php\nreturn array('columns' => array(\n";
56
            foreach ($columns as $field => $info) {
57
                $class = $info['class'];
58
                $output .= "'$field' => new $class(";
59
                $first = true;
60
                foreach ($info['arguments'] as $argument) {
61
                    if ($first) {
62
                        $first = false;
63
                    } else {
64
                        $output .= ',';
65
                    }
66
                    $output .= var_export($argument, true);
67
                }
68
                $output .= '),';
69
            }
70
            $output .= "), 'sort' => array(";
71
            foreach ($sort as $key => $value) {
72
                $output .= "'$key'".' => ';
73
                if (null === $value) {
74
                    $output .= 'null,';
75
                } else {
76
                    $output .= "'$value',";
77
                }
78
            }
79
            $output .= "));\n";
80
        } else {
81
            $output = "<?php\nreturn false;\n";
82
        }
83
        file_put_contents($filename, $output);
84
    }
85
86
    /**
87
     * @param string $cacheDir
88
     * @param string $filename
89
     *
90
     * @throws Exception
91
     */
92
    public static function cacheClassesFromFile($cacheDir, $filename)
93
    {
94
        $classes = self::extractClassesFromFile($filename);
95
        foreach ($classes as $class => $columnInfo) {
96
            $filename = ColumnUtil::createCacheFilename($cacheDir, $class);
97
            self::populateCacheFile($filename, $columnInfo);
98
        }
99
    }
100
101
    /**
102
     * @param string $filename
103
     *
104
     * @return array
105
     *
106
     * @throws Exception
107
     */
108
    public static function extractClassesFromFile($filename)
109
    {
110
        // @TODO probably break this into multiple functions
111
        if (!is_readable($filename)) {
112
            throw new Exception("Can't read {$filename}");
113
        }
114
        $stat = stat($filename);
115
        $result = Yaml::parseFile($filename);
116
        if (!$result && $stat['size'] > 0) {
117
            throw new Exception("Can't parse data from {$filename}");
118
        }
119
120
        $classes = [];
121
        foreach ($result as $class => $info) {
122
            if (!isset($info['columns'])) {
123
                // @TODO some kind of warning here - or try to read using reflection?
124
                continue;
125
            }
126
            $class = ltrim($class, '\\');
127
            if (!class_exists($class)) {
128
                throw new Exception("$class - class does not exist");
129
            }
130
            $classes[$class]['columns'] = [];
131
            foreach ($info['columns'] as $name => $columnDef) {
132
                $label = isset($columnDef['label']) ? $columnDef['label'] : CamelCase::fromCamelCase($name);
133
                $column = ['class' => '\Dtc\GridBundle\Grid\Column\GridColumn', 'arguments' => [$name, $label]];
134
                $column['arguments'][] = isset($columnDef['formatter']) ? $columnDef['formatter'] : null;
135
                if (isset($columnDef['sortable'])) {
136
                    $column['arguments'][] = ['sortable' => $columnDef['sortable'] ? true : false];
137
                } else {
138
                    $column['arguments'][] = [];
139
                }
140
                $column['arguments'][] = isset($columnDef['searchable']) ? ($columnDef['searchable'] ? true : false) : false;
141
                $column['arguments'][] = null;
142
                $classes[$class]['columns'][$name] = $column;
143
            }
144
145
            if (isset($info['actions'])) {
146
                $field = '\$-action';
147
                $actionArgs = [$field];
148
                $actionDefs = [];
149
                /* @var Action $action */
150
                foreach ($info['actions'] as $action) {
151
                    if (!isset($action['label'])) {
152
                        throw new Exception("$class - action definition missing 'label' ".print_r($action, true));
153
                    }
154
                    if (!isset($action['route'])) {
155
                        throw new Exception("$class - action definition missing 'route' ".print_r($action, true));
156
                    }
157
                    $actionDef = ['label' => $action['label'], 'route' => $action['route']];
158
                    if (isset($action['onclick'])) {
159
                        $actionDef['onclick'] = $action['onclick'];
160
                    }
161
                    if (isset($action['button_class'])) {
162
                        $actionDef['button_class'] = $action['button_class'];
163
                    }
164
165
                    switch ($action['type']) {
166
                        case 'show':
167
                            $actionDef['action'] = 'show';
168
                            break;
169
                        case 'delete':
170
                            $actionDef['action'] = 'delete';
171
                            break;
172
                        default:
173
174
                    }
175
                    $actionDefs[] = $actionDef;
176
                }
177
                $actionArgs[] = $actionDefs;
178
                $classes[$class]['columns'][$field] = ['class' => '\Dtc\GridBundle\Grid\Column\ActionGridColumn', 'arguments' => $actionArgs];
179
            }
180
            if (isset($info['sort'])) {
181
                foreach ($info['sort'] as $key => $value) {
182
                    if (!isset($info['columns'][$key])) {
183
                        throw new Exception("$class - can't find sort column $key in list of columns.");
184
                    }
185
                    switch ($value) {
186
                        case 'ASC':
187
                            break;
188
                        case 'DESC':
189
                            break;
190
                        default:
191
                            throw new Exception("$class - sort type should be ASC or DESC instead of $value.");
192
                    }
193
                }
194
                $classes[$class]['sort'] = $info['sort'];
195
            }
196
        }
197
198
        return $classes;
199
    }
200
}
201