Chris@17: Chris@17: * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) Chris@17: * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence Chris@17: */ Chris@17: Chris@17: namespace PHP_CodeSniffer\Reports; Chris@17: Chris@17: use PHP_CodeSniffer\Files\File; Chris@17: use PHP_CodeSniffer\Util\Timing; Chris@17: Chris@17: class Source implements Report Chris@17: { Chris@17: Chris@17: Chris@17: /** Chris@17: * Generate a partial report for a single processed file. Chris@17: * Chris@17: * Function should return TRUE if it printed or stored data about the file Chris@17: * and FALSE if it ignored the file. Returning TRUE indicates that the file and Chris@17: * its data should be counted in the grand totals. Chris@17: * Chris@17: * @param array $report Prepared report data. Chris@17: * @param \PHP_CodeSniffer\File $phpcsFile The file being reported on. Chris@17: * @param bool $showSources Show sources? Chris@17: * @param int $width Maximum allowed line width. Chris@17: * Chris@17: * @return bool Chris@17: */ Chris@17: public function generateFileReport($report, File $phpcsFile, $showSources=false, $width=80) Chris@17: { Chris@17: if ($report['errors'] === 0 && $report['warnings'] === 0) { Chris@17: // Nothing to print. Chris@17: return false; Chris@17: } Chris@17: Chris@17: $sources = []; Chris@17: Chris@17: foreach ($report['messages'] as $line => $lineErrors) { Chris@17: foreach ($lineErrors as $column => $colErrors) { Chris@17: foreach ($colErrors as $error) { Chris@17: $src = $error['source']; Chris@17: if (isset($sources[$src]) === false) { Chris@17: $sources[$src] = [ Chris@17: 'fixable' => (int) $error['fixable'], Chris@17: 'count' => 1, Chris@17: ]; Chris@17: } else { Chris@17: $sources[$src]['count']++; Chris@17: } Chris@17: } Chris@17: } Chris@17: } Chris@17: Chris@17: foreach ($sources as $source => $data) { Chris@17: echo $source.'>>'.$data['fixable'].'>>'.$data['count'].PHP_EOL; Chris@17: } Chris@17: Chris@17: return true; Chris@17: Chris@17: }//end generateFileReport() Chris@17: Chris@17: Chris@17: /** Chris@17: * Prints the source of all errors and warnings. Chris@17: * Chris@17: * @param string $cachedData Any partial report data that was returned from Chris@17: * generateFileReport during the run. Chris@17: * @param int $totalFiles Total number of files processed during the run. Chris@17: * @param int $totalErrors Total number of errors found during the run. Chris@17: * @param int $totalWarnings Total number of warnings found during the run. Chris@17: * @param int $totalFixable Total number of problems that can be fixed. Chris@17: * @param bool $showSources Show sources? Chris@17: * @param int $width Maximum allowed line width. Chris@17: * @param bool $interactive Are we running in interactive mode? Chris@17: * @param bool $toScreen Is the report being printed to screen? Chris@17: * Chris@17: * @return void Chris@17: */ Chris@17: public function generate( Chris@17: $cachedData, Chris@17: $totalFiles, Chris@17: $totalErrors, Chris@17: $totalWarnings, Chris@17: $totalFixable, Chris@17: $showSources=false, Chris@17: $width=80, Chris@17: $interactive=false, Chris@17: $toScreen=true Chris@17: ) { Chris@17: $lines = explode(PHP_EOL, $cachedData); Chris@17: array_pop($lines); Chris@17: Chris@17: if (empty($lines) === true) { Chris@17: return; Chris@17: } Chris@17: Chris@17: $sources = []; Chris@17: $maxLength = 0; Chris@17: Chris@17: foreach ($lines as $line) { Chris@17: $parts = explode('>>', $line); Chris@17: $source = $parts[0]; Chris@17: $fixable = (bool) $parts[1]; Chris@17: $count = $parts[2]; Chris@17: Chris@17: if (isset($sources[$source]) === false) { Chris@17: if ($showSources === true) { Chris@17: $parts = null; Chris@17: $sniff = $source; Chris@17: } else { Chris@17: $parts = explode('.', $source); Chris@17: if ($parts[0] === 'Internal') { Chris@17: $parts[2] = $parts[1]; Chris@17: $parts[1] = ''; Chris@17: } Chris@17: Chris@17: $parts[1] = $this->makeFriendlyName($parts[1]); Chris@17: Chris@17: $sniff = $this->makeFriendlyName($parts[2]); Chris@17: if (isset($parts[3]) === true) { Chris@17: $name = $this->makeFriendlyName($parts[3]); Chris@17: $name[0] = strtolower($name[0]); Chris@17: $sniff .= ' '.$name; Chris@17: unset($parts[3]); Chris@17: } Chris@17: Chris@17: $parts[2] = $sniff; Chris@17: }//end if Chris@17: Chris@17: $maxLength = max($maxLength, strlen($sniff)); Chris@17: Chris@17: $sources[$source] = [ Chris@17: 'count' => $count, Chris@17: 'fixable' => $fixable, Chris@17: 'parts' => $parts, Chris@17: ]; Chris@17: } else { Chris@17: $sources[$source]['count'] += $count; Chris@17: }//end if Chris@17: }//end foreach Chris@17: Chris@17: if ($showSources === true) { Chris@17: $width = min($width, ($maxLength + 11)); Chris@17: } else { Chris@17: $width = min($width, ($maxLength + 41)); Chris@17: } Chris@17: Chris@17: $width = max($width, 70); Chris@17: Chris@17: // Sort the data based on counts and source code. Chris@17: $sourceCodes = array_keys($sources); Chris@17: $counts = []; Chris@17: foreach ($sources as $source => $data) { Chris@17: $counts[$source] = $data['count']; Chris@17: } Chris@17: Chris@17: array_multisort($counts, SORT_DESC, $sourceCodes, SORT_ASC, SORT_NATURAL, $sources); Chris@17: Chris@17: echo PHP_EOL."\033[1mPHP CODE SNIFFER VIOLATION SOURCE SUMMARY\033[0m".PHP_EOL; Chris@17: echo str_repeat('-', $width).PHP_EOL."\033[1m"; Chris@17: if ($showSources === true) { Chris@17: if ($totalFixable > 0) { Chris@17: echo ' SOURCE'.str_repeat(' ', ($width - 15)).'COUNT'.PHP_EOL; Chris@17: } else { Chris@17: echo 'SOURCE'.str_repeat(' ', ($width - 11)).'COUNT'.PHP_EOL; Chris@17: } Chris@17: } else { Chris@17: if ($totalFixable > 0) { Chris@17: echo ' STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 44)).'COUNT'.PHP_EOL; Chris@17: } else { Chris@17: echo 'STANDARD CATEGORY SNIFF'.str_repeat(' ', ($width - 40)).'COUNT'.PHP_EOL; Chris@17: } Chris@17: } Chris@17: Chris@17: echo "\033[0m".str_repeat('-', $width).PHP_EOL; Chris@17: Chris@17: $fixableSources = 0; Chris@17: Chris@17: if ($showSources === true) { Chris@17: $maxSniffWidth = ($width - 7); Chris@17: } else { Chris@17: $maxSniffWidth = ($width - 37); Chris@17: } Chris@17: Chris@17: if ($totalFixable > 0) { Chris@17: $maxSniffWidth -= 4; Chris@17: } Chris@17: Chris@17: foreach ($sources as $source => $sourceData) { Chris@17: if ($totalFixable > 0) { Chris@17: echo '['; Chris@17: if ($sourceData['fixable'] === true) { Chris@17: echo 'x'; Chris@17: $fixableSources++; Chris@17: } else { Chris@17: echo ' '; Chris@17: } Chris@17: Chris@17: echo '] '; Chris@17: } Chris@17: Chris@17: if ($showSources === true) { Chris@17: if (strlen($source) > $maxSniffWidth) { Chris@17: $source = substr($source, 0, $maxSniffWidth); Chris@17: } Chris@17: Chris@17: echo $source; Chris@17: if ($totalFixable > 0) { Chris@17: echo str_repeat(' ', ($width - 9 - strlen($source))); Chris@17: } else { Chris@17: echo str_repeat(' ', ($width - 5 - strlen($source))); Chris@17: } Chris@17: } else { Chris@17: $parts = $sourceData['parts']; Chris@17: Chris@17: if (strlen($parts[0]) > 8) { Chris@17: $parts[0] = substr($parts[0], 0, ((strlen($parts[0]) - 8) * -1)); Chris@17: } Chris@17: Chris@17: echo $parts[0].str_repeat(' ', (10 - strlen($parts[0]))); Chris@17: Chris@17: $category = $parts[1]; Chris@17: if (strlen($category) > 18) { Chris@17: $category = substr($category, 0, ((strlen($category) - 18) * -1)); Chris@17: } Chris@17: Chris@17: echo $category.str_repeat(' ', (20 - strlen($category))); Chris@17: Chris@17: $sniff = $parts[2]; Chris@17: if (strlen($sniff) > $maxSniffWidth) { Chris@17: $sniff = substr($sniff, 0, $maxSniffWidth); Chris@17: } Chris@17: Chris@17: if ($totalFixable > 0) { Chris@17: echo $sniff.str_repeat(' ', ($width - 39 - strlen($sniff))); Chris@17: } else { Chris@17: echo $sniff.str_repeat(' ', ($width - 35 - strlen($sniff))); Chris@17: } Chris@17: }//end if Chris@17: Chris@17: echo $sourceData['count'].PHP_EOL; Chris@17: }//end foreach Chris@17: Chris@17: echo str_repeat('-', $width).PHP_EOL; Chris@17: echo "\033[1m".'A TOTAL OF '.($totalErrors + $totalWarnings).' SNIFF VIOLATION'; Chris@17: if (($totalErrors + $totalWarnings) > 1) { Chris@17: echo 'S'; Chris@17: } Chris@17: Chris@17: echo ' WERE FOUND IN '.count($sources).' SOURCE'; Chris@17: if (count($sources) !== 1) { Chris@17: echo 'S'; Chris@17: } Chris@17: Chris@17: echo "\033[0m"; Chris@17: Chris@17: if ($totalFixable > 0) { Chris@17: echo PHP_EOL.str_repeat('-', $width).PHP_EOL; Chris@17: echo "\033[1mPHPCBF CAN FIX THE $fixableSources MARKED SOURCES AUTOMATICALLY ($totalFixable VIOLATIONS IN TOTAL)\033[0m"; Chris@17: } Chris@17: Chris@17: echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL; Chris@17: Chris@17: if ($toScreen === true && $interactive === false) { Chris@17: Timing::printRunTime(); Chris@17: } Chris@17: Chris@17: }//end generate() Chris@17: Chris@17: Chris@17: /** Chris@17: * Converts a camel caps name into a readable string. Chris@17: * Chris@17: * @param string $name The camel caps name to convert. Chris@17: * Chris@17: * @return string Chris@17: */ Chris@17: public function makeFriendlyName($name) Chris@17: { Chris@17: if (trim($name) === '') { Chris@17: return ''; Chris@17: } Chris@17: Chris@17: $friendlyName = ''; Chris@17: $length = strlen($name); Chris@17: Chris@17: $lastWasUpper = false; Chris@17: $lastWasNumeric = false; Chris@17: for ($i = 0; $i < $length; $i++) { Chris@17: if (is_numeric($name[$i]) === true) { Chris@17: if ($lastWasNumeric === false) { Chris@17: $friendlyName .= ' '; Chris@17: } Chris@17: Chris@17: $lastWasUpper = false; Chris@17: $lastWasNumeric = true; Chris@17: } else { Chris@17: $lastWasNumeric = false; Chris@17: Chris@17: $char = strtolower($name[$i]); Chris@17: if ($char === $name[$i]) { Chris@17: // Lowercase. Chris@17: $lastWasUpper = false; Chris@17: } else { Chris@17: // Uppercase. Chris@17: if ($lastWasUpper === false) { Chris@17: $friendlyName .= ' '; Chris@17: if ($i < ($length - 1)) { Chris@17: $next = $name[($i + 1)]; Chris@17: if (strtolower($next) === $next) { Chris@17: // Next char is lowercase so it is a word boundary. Chris@17: $name[$i] = strtolower($name[$i]); Chris@17: } Chris@17: } Chris@17: } Chris@17: Chris@17: $lastWasUpper = true; Chris@17: } Chris@17: }//end if Chris@17: Chris@17: $friendlyName .= $name[$i]; Chris@17: }//end for Chris@17: Chris@17: $friendlyName = trim($friendlyName); Chris@17: $friendlyName[0] = strtoupper($friendlyName[0]); Chris@17: Chris@17: return $friendlyName; Chris@17: Chris@17: }//end makeFriendlyName() Chris@17: Chris@17: Chris@17: }//end class