Passed
Push — master ( d9e5dd...36764d )
by Spuds
01:07 queued 26s
created

Command::run()   F

Complexity

Conditions 15
Paths 324

Size

Total Lines 113
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 15
eloc 72
dl 0
loc 113
rs 3.5333
c 1
b 0
f 0
nc 324
nop 0

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
3
namespace tubalmartin\CssMin;
4
5
class Command
6
{
7
    const SUCCESS_EXIT = 0;
8
    const FAILURE_EXIT = 1;
9
    
10
    protected $stats = array();
11
    
12
    public static function main()
13
    {
14
        $command = new self;
15
        $command->run();
16
    }
17
18
    public function run()
19
    {
20
        $opts = getopt(
21
            'hi:o:',
22
            array(
23
                'help',
24
                'input:',
25
                'output:',
26
                'dry-run',
27
                'keep-sourcemap',
28
                'keep-sourcemap-comment',
29
                'linebreak-position:',
30
                'memory-limit:',
31
                'pcre-backtrack-limit:',
32
                'pcre-recursion-limit:',
33
                'remove-important-comments'
34
            )
35
        );
36
37
        $help = $this->getOpt(array('h', 'help'), $opts);
38
        $input = $this->getOpt(array('i', 'input'), $opts);
39
        $output = $this->getOpt(array('o', 'output'), $opts);
40
        $dryrun = $this->getOpt('dry-run', $opts);
41
        $keepSourceMapComment = $this->getOpt(array('keep-sourcemap', 'keep-sourcemap-comment'), $opts);
42
        $linebreakPosition = $this->getOpt('linebreak-position', $opts);
43
        $memoryLimit = $this->getOpt('memory-limit', $opts);
44
        $backtrackLimit = $this->getOpt('pcre-backtrack-limit', $opts);
45
        $recursionLimit = $this->getOpt('pcre-recursion-limit', $opts);
46
        $removeImportantComments = $this->getOpt('remove-important-comments', $opts);
47
48
        if (!is_null($help)) {
49
            $this->showHelp();
50
            die(self::SUCCESS_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
51
        }
52
53
        if (is_null($input)) {
54
            fwrite(STDERR, '-i <file> argument is missing' . PHP_EOL);
55
            $this->showHelp();
56
            die(self::FAILURE_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
57
        }
58
59
        if (!is_readable($input)) {
60
            fwrite(STDERR, 'Input file is not readable' . PHP_EOL);
61
            die(self::FAILURE_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
62
        }
63
64
        $css = file_get_contents($input);
65
66
        if ($css === false) {
67
            fwrite(STDERR, 'Input CSS code could not be retrieved from input file' . PHP_EOL);
68
            die(self::FAILURE_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
69
        }
70
        
71
        $this->setStat('original-size', strlen($css));
72
        
73
        $cssmin = new Minifier;
74
75
        if (!is_null($keepSourceMapComment)) {
76
            $cssmin->keepSourceMapComment();
77
        }
78
79
        if (!is_null($removeImportantComments)) {
80
            $cssmin->removeImportantComments();
81
        }
82
83
        if (!is_null($linebreakPosition)) {
84
            $cssmin->setLineBreakPosition($linebreakPosition);
85
        }
86
        
87
        if (!is_null($memoryLimit)) {
88
            $cssmin->setMemoryLimit($memoryLimit);
89
        }
90
91
        if (!is_null($backtrackLimit)) {
92
            $cssmin->setPcreBacktrackLimit($backtrackLimit);
93
        }
94
95
        if (!is_null($recursionLimit)) {
96
            $cssmin->setPcreRecursionLimit($recursionLimit);
97
        }
98
        
99
        $this->setStat('compression-time-start', microtime(true));
100
        
101
        $css = $cssmin->run($css);
102
103
        $this->setStat('compression-time-end', microtime(true));
104
        $this->setStat('peak-memory-usage', memory_get_peak_usage(true));
105
        $this->setStat('compressed-size', strlen($css));
106
        
107
        if (!is_null($dryrun)) {
108
            $this->showStats();
109
            die(self::SUCCESS_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
110
        }
111
112
        if (is_null($output)) {
113
            fwrite(STDOUT, $css . PHP_EOL);
114
            $this->showStats();
115
            die(self::SUCCESS_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
116
        }
117
118
        if (!is_writable(dirname($output))) {
119
            fwrite(STDERR, 'Output file is not writable' . PHP_EOL);
120
            die(self::FAILURE_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
121
        }
122
123
        if (file_put_contents($output, $css) === false) {
124
            fwrite(STDERR, 'Compressed CSS code could not be saved to output file' . PHP_EOL);
125
            die(self::FAILURE_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
126
        }
127
128
        $this->showStats();
129
130
        die(self::SUCCESS_EXIT);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
131
    }
132
133
    protected function getOpt($opts, $options)
134
    {
135
        $value = null;
136
137
        if (is_string($opts)) {
138
            $opts = array($opts);
139
        }
140
141
        foreach ($opts as $opt) {
142
            if (array_key_exists($opt, $options)) {
143
                $value = $options[$opt];
144
                break;
145
            }
146
        }
147
148
        return $value;
149
    }
150
    
151
    protected function setStat($statName, $statValue)
152
    {
153
        $this->stats[$statName] = $statValue;
154
    }
155
    
156
    protected function formatBytes($size, $precision = 2)
157
    {
158
        $base = log($size, 1024);
159
        $suffixes = array('B', 'K', 'M', 'G', 'T');
160
        return round(pow(1024, $base - floor($base)), $precision) .' '. $suffixes[floor($base)];
161
    }
162
    
163
    protected function formatMicroSeconds($microSecs, $precision = 2)
164
    {
165
        // ms
166
        $time = round($microSecs * 1000, $precision);
167
        
168
        if ($time >= 60 * 1000) {
169
            $time = round($time / 60 * 1000, $precision) .' m'; // m
170
        } elseif ($time >= 1000) {
171
            $time = round($time / 1000, $precision) .' s'; // s
172
        } else {
173
            $time .= ' ms';
174
        }
175
        
176
        return $time;
177
    }
178
    
179
    protected function showStats()
180
    {
181
        $spaceSavings = round((1 - ($this->stats['compressed-size'] / $this->stats['original-size'])) * 100, 2);
182
        $compressionRatio = round($this->stats['original-size'] / $this->stats['compressed-size'], 2);
183
        $compressionTime = $this->formatMicroSeconds(
184
            $this->stats['compression-time-end'] - $this->stats['compression-time-start']
185
        );
186
        $peakMemoryUsage = $this->formatBytes($this->stats['peak-memory-usage']);
187
        
188
        print <<<EOT
189
        
190
------------------------------
191
CSSMIN STATS        
192
------------------------------ 
193
Space savings:       {$spaceSavings} %       
194
Compression ratio:   {$compressionRatio}:1
195
Compression time:    $compressionTime
196
Peak memory usage:   $peakMemoryUsage
197
198
199
EOT;
200
    }
201
202
    protected function showHelp()
203
    {
204
        print <<<'EOT'
205
Usage: cssmin [options] -i <file> [-o <file>]
206
  
207
  -i|--input <file>              File containing uncompressed CSS code.
208
  -o|--output <file>             File to use to save compressed CSS code.
209
    
210
Options:
211
    
212
  -h|--help                      Prints this usage information.
213
  --dry-run                      Performs a dry run displaying statistics.
214
  --keep-sourcemap[-comment]     Keeps the sourcemap special comment in the output.
215
  --linebreak-position <pos>     Splits long lines after a specific column in the output.
216
  --memory-limit <limit>         Sets the memory limit for this script.
217
  --pcre-backtrack-limit <limit> Sets the PCRE backtrack limit for this script.
218
  --pcre-recursion-limit <limit> Sets the PCRE recursion limit for this script.
219
  --remove-important-comments    Removes !important comments from output.
220
221
EOT;
222
    }
223
}
224