1<?php 2/** 3 * Source report for PHP_CodeSniffer. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Gabriele Santini <gsantini@sqli.com> 10 * @author Greg Sherwood <gsherwood@squiz.net> 11 * @copyright 2009-2014 SQLI <www.sqli.com> 12 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 13 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 14 * @link http://pear.php.net/package/PHP_CodeSniffer 15 */ 16 17/** 18 * Source report for PHP_CodeSniffer. 19 * 20 * PHP version 5 21 * 22 * @category PHP 23 * @package PHP_CodeSniffer 24 * @author Gabriele Santini <gsantini@sqli.com> 25 * @author Greg Sherwood <gsherwood@squiz.net> 26 * @copyright 2009-2014 SQLI <www.sqli.com> 27 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 28 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 29 * @version Release: @package_version@ 30 * @link http://pear.php.net/package/PHP_CodeSniffer 31 */ 32class PHP_CodeSniffer_Reports_Source implements PHP_CodeSniffer_Report 33{ 34 35 /** 36 * A cache of source stats collected during the run. 37 * 38 * @var array 39 */ 40 private $_sourceCache = array(); 41 42 43 /** 44 * Generate a partial report for a single processed file. 45 * 46 * Function should return TRUE if it printed or stored data about the file 47 * and FALSE if it ignored the file. Returning TRUE indicates that the file and 48 * its data should be counted in the grand totals. 49 * 50 * @param array $report Prepared report data. 51 * @param PHP_CodeSniffer_File $phpcsFile The file being reported on. 52 * @param boolean $showSources Show sources? 53 * @param int $width Maximum allowed line width. 54 * 55 * @return boolean 56 */ 57 public function generateFileReport( 58 $report, 59 PHP_CodeSniffer_File $phpcsFile, 60 $showSources=false, 61 $width=80 62 ) { 63 if ($report['errors'] === 0 && $report['warnings'] === 0) { 64 // Nothing to print. 65 return false; 66 } 67 68 foreach ($report['messages'] as $line => $lineErrors) { 69 foreach ($lineErrors as $column => $colErrors) { 70 foreach ($colErrors as $error) { 71 $source = $error['source']; 72 if (isset($this->_sourceCache[$source]) === false) { 73 if ($showSources === true) { 74 $parts = null; 75 $sniff = $source; 76 } else { 77 $parts = explode('.', $source); 78 if ($parts[0] === 'Internal') { 79 $parts[2] = $parts[1]; 80 $parts[1] = ''; 81 } 82 83 $parts[1] = $this->makeFriendlyName($parts[1]); 84 85 $sniff = $this->makeFriendlyName($parts[2]); 86 if (isset($parts[3]) === true) { 87 $name = $this->makeFriendlyName($parts[3]); 88 $name[0] = strtolower($name[0]); 89 $sniff .= ' '.$name; 90 unset($parts[3]); 91 } 92 93 $parts[2] = $sniff; 94 }//end if 95 96 $this->_sourceCache[$source] = array( 97 'count' => 1, 98 'fixable' => $error['fixable'], 99 'parts' => $parts, 100 'strlen' => strlen($sniff), 101 ); 102 } else { 103 $this->_sourceCache[$source]['count']++; 104 }//end if 105 }//end foreach 106 }//end foreach 107 }//end foreach 108 109 return true; 110 111 }//end generateFileReport() 112 113 114 /** 115 * Prints the source of all errors and warnings. 116 * 117 * @param string $cachedData Any partial report data that was returned from 118 * generateFileReport during the run. 119 * @param int $totalFiles Total number of files processed during the run. 120 * @param int $totalErrors Total number of errors found during the run. 121 * @param int $totalWarnings Total number of warnings found during the run. 122 * @param int $totalFixable Total number of problems that can be fixed. 123 * @param boolean $showSources Show sources? 124 * @param int $width Maximum allowed line width. 125 * @param boolean $toScreen Is the report being printed to screen? 126 * 127 * @return void 128 */ 129 public function generate( 130 $cachedData, 131 $totalFiles, 132 $totalErrors, 133 $totalWarnings, 134 $totalFixable, 135 $showSources=false, 136 $width=80, 137 $toScreen=true 138 ) { 139 if (empty($this->_sourceCache) === true) { 140 // Nothing to show. 141 return; 142 } 143 144 // Make sure the report width isn't too big. 145 $maxLength = 0; 146 foreach ($this->_sourceCache as $source => $data) { 147 $maxLength = max($maxLength, $data['strlen']); 148 } 149 150 if ($showSources === true) { 151 $width = min($width, ($maxLength + 11)); 152 } else { 153 $width = min($width, ($maxLength + 41)); 154 } 155 156 $width = max($width, 70); 157 158 asort($this->_sourceCache); 159 $this->_sourceCache = array_reverse($this->_sourceCache); 160 161 echo PHP_EOL."\033[1mPHP CODE SNIFFER VIOLATION SOURCE SUMMARY\033[0m".PHP_EOL; 162 echo str_repeat('-', $width).PHP_EOL."\033[1m"; 163 if ($showSources === true) { 164 if ($totalFixable > 0) { 165 echo ' SOURCE'.str_repeat(' ', ($width - 15)).'COUNT'.PHP_EOL; 166 } else { 167 echo 'SOURCE'.str_repeat(' ', ($width - 11)).'COUNT'.PHP_EOL; 168 } 169 } else { 170 if ($totalFixable > 0) { 171 echo ' STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 44)).'COUNT'.PHP_EOL; 172 } else { 173 echo 'STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 40)).'COUNT'.PHP_EOL; 174 } 175 } 176 177 echo "\033[0m".str_repeat('-', $width).PHP_EOL; 178 179 $fixableSources = 0; 180 181 if ($showSources === true) { 182 $maxSniffWidth = ($width - 7); 183 } else { 184 $maxSniffWidth = ($width - 37); 185 } 186 187 if ($totalFixable > 0) { 188 $maxSniffWidth -= 4; 189 } 190 191 foreach ($this->_sourceCache as $source => $sourceData) { 192 if ($totalFixable > 0) { 193 echo '['; 194 if ($sourceData['fixable'] === true) { 195 echo 'x'; 196 $fixableSources++; 197 } else { 198 echo ' '; 199 } 200 201 echo '] '; 202 } 203 204 if ($showSources === true) { 205 if ($sourceData['strlen'] > $maxSniffWidth) { 206 $source = substr($source, 0, $maxSniffWidth); 207 } 208 209 echo $source; 210 if ($totalFixable > 0) { 211 echo str_repeat(' ', ($width - 9 - strlen($source))); 212 } else { 213 echo str_repeat(' ', ($width - 5 - strlen($source))); 214 } 215 } else { 216 $parts = $sourceData['parts']; 217 218 if (strlen($parts[0]) > 8) { 219 $parts[0] = substr($parts[0], 0, ((strlen($parts[0]) - 8) * -1)); 220 } 221 222 echo $parts[0].str_repeat(' ', (10 - strlen($parts[0]))); 223 224 $category = $parts[1]; 225 if (strlen($category) > 18) { 226 $category = substr($category, 0, ((strlen($category) - 18) * -1)); 227 } 228 229 echo $category.str_repeat(' ', (20 - strlen($category))); 230 231 $sniff = $parts[2]; 232 if (strlen($sniff) > $maxSniffWidth) { 233 $sniff = substr($sniff, 0, $maxSniffWidth); 234 } 235 236 if ($totalFixable > 0) { 237 echo $sniff.str_repeat(' ', ($width - 39 - strlen($sniff))); 238 } else { 239 echo $sniff.str_repeat(' ', ($width - 35 - strlen($sniff))); 240 } 241 }//end if 242 243 echo $sourceData['count'].PHP_EOL; 244 }//end foreach 245 246 echo str_repeat('-', $width).PHP_EOL; 247 echo "\033[1m".'A TOTAL OF '.($totalErrors + $totalWarnings).' SNIFF VIOLATION'; 248 if (($totalErrors + $totalWarnings) > 1) { 249 echo 'S'; 250 } 251 252 echo ' WERE FOUND IN '.count($this->_sourceCache).' SOURCE'; 253 if (count($this->_sourceCache) !== 1) { 254 echo 'S'; 255 } 256 257 echo "\033[0m"; 258 259 if ($totalFixable > 0) { 260 echo PHP_EOL.str_repeat('-', $width).PHP_EOL; 261 echo "\033[1mPHPCBF CAN FIX THE $fixableSources MARKED SOURCES AUTOMATICALLY ($totalFixable VIOLATIONS IN TOTAL)\033[0m"; 262 } 263 264 echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL; 265 266 if ($toScreen === true && PHP_CODESNIFFER_INTERACTIVE === false) { 267 PHP_CodeSniffer_Reporting::printRunTime(); 268 } 269 270 }//end generate() 271 272 273 /** 274 * Converts a camel caps name into a readable string. 275 * 276 * @param string $name The camel caps name to convert. 277 * 278 * @return string 279 */ 280 public function makeFriendlyName($name) 281 { 282 if (trim($name) === '') { 283 return ''; 284 } 285 286 $friendlyName = ''; 287 $length = strlen($name); 288 289 $lastWasUpper = false; 290 $lastWasNumeric = false; 291 for ($i = 0; $i < $length; $i++) { 292 if (is_numeric($name[$i]) === true) { 293 if ($lastWasNumeric === false) { 294 $friendlyName .= ' '; 295 } 296 297 $lastWasUpper = false; 298 $lastWasNumeric = true; 299 } else { 300 $lastWasNumeric = false; 301 302 $char = strtolower($name[$i]); 303 if ($char === $name[$i]) { 304 // Lowercase. 305 $lastWasUpper = false; 306 } else { 307 // Uppercase. 308 if ($lastWasUpper === false) { 309 $friendlyName .= ' '; 310 if ($i < ($length - 1)) { 311 $next = $name[($i + 1)]; 312 if (strtolower($next) === $next) { 313 // Next char is lowercase so it is a word boundary. 314 $name[$i] = strtolower($name[$i]); 315 } 316 } 317 } 318 319 $lastWasUpper = true; 320 } 321 }//end if 322 323 $friendlyName .= $name[$i]; 324 }//end for 325 326 $friendlyName = trim($friendlyName); 327 $friendlyName[0] = strtoupper($friendlyName[0]); 328 329 return $friendlyName; 330 331 }//end makeFriendlyName() 332 333 334}//end class 335