1<?php
2/**
3 * CBF report for PHP_CodeSniffer.
4 *
5 * This report implements the various auto-fixing features of the
6 * PHPCBF script and is not intended (or allowed) to be selected as a
7 * report from the command line.
8 *
9 * @author    Greg Sherwood <gsherwood@squiz.net>
10 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
11 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
12 */
13
14namespace PHP_CodeSniffer\Reports;
15
16use PHP_CodeSniffer\Exceptions\DeepExitException;
17use PHP_CodeSniffer\Files\File;
18use PHP_CodeSniffer\Util;
19
20class Cbf implements Report
21{
22
23
24    /**
25     * Generate a partial report for a single processed file.
26     *
27     * Function should return TRUE if it printed or stored data about the file
28     * and FALSE if it ignored the file. Returning TRUE indicates that the file and
29     * its data should be counted in the grand totals.
30     *
31     * @param array                 $report      Prepared report data.
32     * @param \PHP_CodeSniffer\File $phpcsFile   The file being reported on.
33     * @param bool                  $showSources Show sources?
34     * @param int                   $width       Maximum allowed line width.
35     *
36     * @return bool
37     * @throws \PHP_CodeSniffer\Exceptions\DeepExitException
38     */
39    public function generateFileReport($report, File $phpcsFile, $showSources=false, $width=80)
40    {
41        $errors = $phpcsFile->getFixableCount();
42        if ($errors !== 0) {
43            if (PHP_CODESNIFFER_VERBOSITY > 0) {
44                ob_end_clean();
45                $startTime = microtime(true);
46                echo "\t=> Fixing file: $errors/$errors violations remaining";
47                if (PHP_CODESNIFFER_VERBOSITY > 1) {
48                    echo PHP_EOL;
49                }
50            }
51
52            $fixed = $phpcsFile->fixer->fixFile();
53        }
54
55        if ($phpcsFile->config->stdin === true) {
56            // Replacing STDIN, so output current file to STDOUT
57            // even if nothing was fixed. Exit here because we
58            // can't process any more than 1 file in this setup.
59            $fixedContent = $phpcsFile->fixer->getContents();
60            throw new DeepExitException($fixedContent, 1);
61        }
62
63        if ($errors === 0) {
64            return false;
65        }
66
67        if (PHP_CODESNIFFER_VERBOSITY > 0) {
68            if ($fixed === false) {
69                echo 'ERROR';
70            } else {
71                echo 'DONE';
72            }
73
74            $timeTaken = ((microtime(true) - $startTime) * 1000);
75            if ($timeTaken < 1000) {
76                $timeTaken = round($timeTaken);
77                echo " in {$timeTaken}ms".PHP_EOL;
78            } else {
79                $timeTaken = round(($timeTaken / 1000), 2);
80                echo " in $timeTaken secs".PHP_EOL;
81            }
82        }
83
84        if ($fixed === true) {
85            // The filename in the report may be truncated due to a basepath setting
86            // but we are using it for writing here and not display,
87            // so find the correct path if basepath is in use.
88            $newFilename = $report['filename'].$phpcsFile->config->suffix;
89            if ($phpcsFile->config->basepath !== null) {
90                $newFilename = $phpcsFile->config->basepath.DIRECTORY_SEPARATOR.$newFilename;
91            }
92
93            $newContent = $phpcsFile->fixer->getContents();
94            file_put_contents($newFilename, $newContent);
95
96            if (PHP_CODESNIFFER_VERBOSITY > 0) {
97                if ($newFilename === $report['filename']) {
98                    echo "\t=> File was overwritten".PHP_EOL;
99                } else {
100                    echo "\t=> Fixed file written to ".basename($newFilename).PHP_EOL;
101                }
102            }
103        }
104
105        if (PHP_CODESNIFFER_VERBOSITY > 0) {
106            ob_start();
107        }
108
109        $errorCount   = $phpcsFile->getErrorCount();
110        $warningCount = $phpcsFile->getWarningCount();
111        $fixableCount = $phpcsFile->getFixableCount();
112        $fixedCount   = ($errors - $fixableCount);
113        echo $report['filename'].">>$errorCount>>$warningCount>>$fixableCount>>$fixedCount".PHP_EOL;
114
115        return $fixed;
116
117    }//end generateFileReport()
118
119
120    /**
121     * Prints a summary of fixed files.
122     *
123     * @param string $cachedData    Any partial report data that was returned from
124     *                              generateFileReport during the run.
125     * @param int    $totalFiles    Total number of files processed during the run.
126     * @param int    $totalErrors   Total number of errors found during the run.
127     * @param int    $totalWarnings Total number of warnings found during the run.
128     * @param int    $totalFixable  Total number of problems that can be fixed.
129     * @param bool   $showSources   Show sources?
130     * @param int    $width         Maximum allowed line width.
131     * @param bool   $interactive   Are we running in interactive mode?
132     * @param bool   $toScreen      Is the report being printed to screen?
133     *
134     * @return void
135     */
136    public function generate(
137        $cachedData,
138        $totalFiles,
139        $totalErrors,
140        $totalWarnings,
141        $totalFixable,
142        $showSources=false,
143        $width=80,
144        $interactive=false,
145        $toScreen=true
146    ) {
147        $lines = explode(PHP_EOL, $cachedData);
148        array_pop($lines);
149
150        if (empty($lines) === true) {
151            echo PHP_EOL.'No fixable errors were found'.PHP_EOL;
152            return;
153        }
154
155        $reportFiles = [];
156        $maxLength   = 0;
157        $totalFixed  = 0;
158        $failures    = 0;
159
160        foreach ($lines as $line) {
161            $parts   = explode('>>', $line);
162            $fileLen = strlen($parts[0]);
163            $reportFiles[$parts[0]] = [
164                'errors'   => $parts[1],
165                'warnings' => $parts[2],
166                'fixable'  => $parts[3],
167                'fixed'    => $parts[4],
168                'strlen'   => $fileLen,
169            ];
170
171            $maxLength = max($maxLength, $fileLen);
172
173            $totalFixed += $parts[4];
174
175            if ($parts[3] > 0) {
176                $failures++;
177            }
178        }
179
180        $width = min($width, ($maxLength + 21));
181        $width = max($width, 70);
182
183        echo PHP_EOL."\033[1m".'PHPCBF RESULT SUMMARY'."\033[0m".PHP_EOL;
184        echo str_repeat('-', $width).PHP_EOL;
185        echo "\033[1m".'FILE'.str_repeat(' ', ($width - 20)).'FIXED  REMAINING'."\033[0m".PHP_EOL;
186        echo str_repeat('-', $width).PHP_EOL;
187
188        foreach ($reportFiles as $file => $data) {
189            $padding = ($width - 18 - $data['strlen']);
190            if ($padding < 0) {
191                $file    = '...'.substr($file, (($padding * -1) + 3));
192                $padding = 0;
193            }
194
195            echo $file.str_repeat(' ', $padding).'  ';
196
197            if ($data['fixable'] > 0) {
198                echo "\033[31mFAILED TO FIX\033[0m".PHP_EOL;
199                continue;
200            }
201
202            $remaining = ($data['errors'] + $data['warnings']);
203
204            if ($data['fixed'] !== 0) {
205                echo $data['fixed'];
206                echo str_repeat(' ', (7 - strlen((string) $data['fixed'])));
207            } else {
208                echo '0      ';
209            }
210
211            if ($remaining !== 0) {
212                echo $remaining;
213            } else {
214                echo '0';
215            }
216
217            echo PHP_EOL;
218        }//end foreach
219
220        echo str_repeat('-', $width).PHP_EOL;
221        echo "\033[1mA TOTAL OF $totalFixed ERROR";
222        if ($totalFixed !== 1) {
223            echo 'S';
224        }
225
226        $numFiles = count($reportFiles);
227        echo ' WERE FIXED IN '.$numFiles.' FILE';
228        if ($numFiles !== 1) {
229            echo 'S';
230        }
231
232        echo "\033[0m";
233
234        if ($failures > 0) {
235            echo PHP_EOL.str_repeat('-', $width).PHP_EOL;
236            echo "\033[1mPHPCBF FAILED TO FIX $failures FILE";
237            if ($failures !== 1) {
238                echo 'S';
239            }
240
241            echo "\033[0m";
242        }
243
244        echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL;
245
246        if ($toScreen === true && $interactive === false) {
247            Util\Timing::printRunTime();
248        }
249
250    }//end generate()
251
252
253}//end class
254