PageRenderTime 58ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/Lib/Report.php

http://github.com/robotis/PHPLinter
PHP | 369 lines | 299 code | 1 blank | 69 comment | 13 complexity | cbea0b39fd0fee459f45c840b7871299 MD5 | raw file
Possible License(s): GPL-3.0
  1. <?php
  2. /**
  3. ----------------------------------------------------------------------+
  4. * @desc Report generator
  5. * @file Report.php
  6. * @author J?hann T. Mar?usson <jtm@robot.is>
  7. * @package phplinter
  8. * @copyright
  9. * phplinter is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. ----------------------------------------------------------------------+
  23. */
  24. namespace PHPLinter;
  25. class Report {
  26. /* @var String */
  27. protected $output_dir;
  28. /* @var int */
  29. protected $options;
  30. /**
  31. ----------------------------------------------------------------------+
  32. * @desc Create report
  33. * @param $output_dir String (Path)
  34. ----------------------------------------------------------------------+
  35. */
  36. public function __construct($output_dir=null, $OPTIONS=null) {
  37. if(empty($output_dir)) {
  38. $this->output_dir = dirname(__FILE__) . '/' . 'html_report/';
  39. } else {
  40. $this->output_dir = $output_dir;
  41. }
  42. $this->options = $OPTIONS;
  43. }
  44. /**
  45. ----------------------------------------------------------------------+
  46. * @desc Derive final score for one file
  47. * @param $penalty Float
  48. ----------------------------------------------------------------------+
  49. */
  50. public function score($penalty, $num=null) {
  51. if($penalty === false)
  52. return "No score available\n";
  53. $full = (is_numeric($num))
  54. ? ($num * SCORE_FULL) : SCORE_FULL;
  55. return sprintf("Score: %.2f out of %.2f\n",
  56. ($full + $penalty), $full);
  57. }
  58. /**
  59. ----------------------------------------------------------------------+
  60. * @desc Derive final score for one file
  61. * @param $penalty Float
  62. ----------------------------------------------------------------------+
  63. */
  64. public function average($penalty, $num) {
  65. $full = $num * SCORE_FULL;
  66. return sprintf("Average score: %.2f\n",
  67. (($full + $penalty) / $num));
  68. }
  69. /**
  70. ----------------------------------------------------------------------+
  71. * @desc Color format for bash shell.
  72. * colors = black/red/green/brown
  73. * blue/purple/cyan/white
  74. * attrs = 1-8
  75. * @param String
  76. * @param String
  77. * @param Mixed color OR array(attr, color)
  78. * @param Bool
  79. * @param Int
  80. * @return String
  81. ----------------------------------------------------------------------+
  82. */
  83. public function color($msg, $color="black", $nl=false) {
  84. if($this->options & OPT_USE_COLOR) {
  85. $attr = 0;
  86. if(is_array($color)) {
  87. $attr = intval($color[0]);
  88. $color = $color[1];
  89. }
  90. $tpl = "\033[%d;%dm%s\033[0m";
  91. if($nl) $tpl .= "\n";
  92. $codes = array(
  93. 'black' => 30, 'red' => 31, 'green' => 32,
  94. 'brown' => 33, 'blue' => 34, 'purple' => 35,
  95. 'cyan' => 36, 'white' => 37
  96. );
  97. if(!isset($codes[$color])) $color = 'black';
  98. return sprintf($tpl, $attr, $codes[$color], $msg);
  99. }
  100. return $msg;
  101. }
  102. /**
  103. ----------------------------------------------------------------------+
  104. * @desc CLI report
  105. * @param $report Array
  106. ----------------------------------------------------------------------+
  107. */
  108. public function toCli($report, $format="| {F} | {M} | `{W}` Line: {L}\n") {
  109. $fcolors = array(
  110. 'E' => 'red', 'W' => 'blue', 'C' =>'brown', 'D' => array(1, 'brown'),
  111. 'I' => 'green', 'R' => 'purple', 'S' => 'cyan', 'F' => array(1, 'black')
  112. );
  113. foreach($report as $_) {
  114. $out = str_replace('{F}', $this->color(str_pad($_['flag'], 3),
  115. $fcolors[$_['flag'][0]]), $format);
  116. $out = str_replace('{M}', str_pad($_['message'], 50), $out);
  117. $out = str_replace('{W}', $_['where'], $out);
  118. $out = str_replace('{L}', $_['line'], $out);
  119. echo $out;
  120. }
  121. }
  122. /**
  123. ----------------------------------------------------------------------+
  124. * @desc HTML Report
  125. * @param $report Array
  126. * @param $penaltys Array
  127. ----------------------------------------------------------------------+
  128. */
  129. public function toHtml($root, $report, $penaltys) {
  130. $this->root = realpath($root);
  131. if(file_exists($this->output_dir)) {
  132. $output_dir = realpath($this->output_dir);
  133. if(!($this->options & OPT_OVERWRITE_REPORT)) {
  134. die("`$output_dir` not empty, aborting...\n");
  135. }
  136. if($this->options & OPT_VERBOSE)
  137. echo "Emptying `$output_dir`\n";
  138. Path::del_recursive($this->output_dir);
  139. }
  140. if($this->options & OPT_VERBOSE)
  141. echo "Creating `$this->output_dir`\n";
  142. if(!file_exists($this->output_dir) && !mkdir($this->output_dir, 0775)) {
  143. die("Unable to create `$this->output_dir`...\n");
  144. }
  145. $this->output_dir = realpath($this->output_dir);
  146. Path::write_file($this->output_dir . '/html_report.css', $this->css());
  147. foreach($report as $file => $rep) {
  148. $out = '<div class="wrapper"><table border="1" cellpadding="0" cellspacing="0">';
  149. $content = '';
  150. foreach($rep as $_) {
  151. $content .= '<tr>';
  152. $content .= '<td align="center" class="fl_';
  153. $content .= $_['flag'][0].'">'.$_['flag'].'</td>';
  154. $content .= '<td class="message">'.$_['message'].'</td>';
  155. $content .= "<td class=\"where\">'`{$_['where']}` Line: {$_['line']}</td>\n";
  156. $content .= '</tr>';
  157. }
  158. $out .= '<tr>';
  159. $score = (SCORE_FULL + $penaltys[$file]);
  160. $class = $this->get_score_class($score);
  161. $out .= '<td colspan="2" align="center" class="'.$class.'">';
  162. $out .= sprintf('Score: %.2f', $score);
  163. $out .= '</td>';
  164. $parts = explode('/', $file);
  165. $rfile = array_pop($parts);
  166. $depth = count($parts);
  167. $path = $depth > 1
  168. ? implode('/', $parts)
  169. : '';
  170. $path = substr(realpath($path), strlen($this->root));
  171. $out .= '<td class="filename">';
  172. $out .= "$path/$rfile";
  173. $out .= '</td></tr>';
  174. $out .= $content;
  175. $out .= '</table></div>';
  176. $dir = $this->output_dir . $path;
  177. if(!file_exists($dir)
  178. && !mkdir($dir, 0775, true)) {
  179. die("Unable to create `$dir`...\n");
  180. }
  181. $pp = explode('/', substr(realpath(implode('/', $parts)), strlen($this->root)));
  182. $ofile = $dir . '/' . strtr($rfile, './', '__').'.html';
  183. if($this->options & OPT_VERBOSE)
  184. echo "Wrote to file `$ofile`\n";
  185. Path::write_file($ofile, $this->html($out, count($pp)));
  186. $url['phplinter___file'] = $file;
  187. $url['phplinter___url'] = strtr($rfile, './', '__').'.html';
  188. $url['phplinter___sort'] = strtolower($url['phplinter___url']);
  189. $this->parts($pp, $url, $urls);
  190. }
  191. $urls = $this->sort($urls);
  192. $this->output_indexes($urls, $penaltys);
  193. }
  194. /**
  195. ----------------------------------------------------------------------+
  196. * @desc Create index files for report
  197. * @return String
  198. ----------------------------------------------------------------------+
  199. */
  200. protected function css() {
  201. return file_get_contents(dirname(__FILE__) . '/../html_report.css');
  202. }
  203. /**
  204. ----------------------------------------------------------------------+
  205. * @desc Create index files for report
  206. * @param $urls Array
  207. * @param $penaltys Array
  208. * @param $path String
  209. * @param $depth int
  210. * @return Array
  211. ----------------------------------------------------------------------+
  212. */
  213. protected function output_indexes($urls, $penaltys, $path='', $depth=0) {
  214. $out = '<div class="wrapper"><table border="1" cellpadding="0" cellspacing="0">';
  215. $out .= '<tr><td align="center">'.date("d / M / Y").'</td>';
  216. $out .= '<td colspan="2" align="center">'.$this->root.'</td></tr>';
  217. $content = '';
  218. $total = 0; $num = 0;
  219. foreach($urls as $k => $_) {
  220. $content .= '<tr>';
  221. if(isset($_['phplinter___file'])) {
  222. $score = (SCORE_FULL + $penaltys[$_['phplinter___file']]);
  223. $total += $score;
  224. $num++;
  225. $class = $this->get_score_class($score);
  226. $content .= '<td class="'.$class.'">'.sprintf('%.2f', $score).'</td>';
  227. $limit = $score == 10 ? 'perfect' : 'limit';
  228. $content .= '<td class="'.$limit.'">'.sprintf('%.2f', SCORE_FULL).'</td>';
  229. $content .= '<td><a href="'.$_['phplinter___url'].'">'.substr(realpath($_['phplinter___file']),
  230. strlen($this->root . $path))
  231. . '</a></td>';
  232. } else {
  233. list($ototal, $onum) = $this->output_indexes($urls[$k], $penaltys,
  234. $path . $k.'/', $depth+1);
  235. $avarage = ($ototal / $onum);
  236. $class = $this->get_score_class($avarage);
  237. $content .= sprintf('<td colspan="2" class="%s">Average: %.2f</td>',
  238. $class, $avarage);
  239. $content .= '<td class="folder"><a href="'.$k.'">'.$k.'</a></td>';
  240. $total += $ototal;
  241. $num += $onum;
  242. }
  243. $content .= '</tr>';
  244. }
  245. $out .= '<tr>';
  246. $avarage = ($total / $num);
  247. $class = $this->get_score_class($avarage);
  248. $out .= sprintf('<td colspan="2" align="center" class="%s">Average: %.2f</td>'
  249. ,$class, $avarage);
  250. $out .= '<td>'.$path.'</td>';
  251. $out .= '</tr>';
  252. $out .= $content;
  253. $out .= '</table></div>';
  254. $path = ($path == '/')
  255. ? $this->output_dir
  256. : $path;
  257. $dir = ($path == $this->output_dir)
  258. ? $path
  259. : $this->output_dir . $path;
  260. $dir = (!empty($dir) && $dir[strlen($dir)-1] == '/')
  261. ? $dir : $dir . '/';
  262. if(!empty($path)) {
  263. $file = $dir . 'index.html';
  264. Path::write_file($file, $this->html($out, $depth));
  265. if($this->options & OPT_VERBOSE)
  266. echo "Wrote to file `$file`\n";
  267. }
  268. $this->dirs[] = $dir;
  269. return array($total, $num);
  270. }
  271. /**
  272. ----------------------------------------------------------------------+
  273. * @desc CSS Class for score
  274. * @param $score float
  275. * @return String
  276. ----------------------------------------------------------------------+
  277. */
  278. protected function get_score_class($score) {
  279. if($score < 0)
  280. return 'terrible';
  281. elseif($score < 5)
  282. return 'bad';
  283. elseif($score < 7)
  284. return 'average';
  285. elseif($score < 9)
  286. return 'good';
  287. elseif($score < 10)
  288. return 'vgood';
  289. return 'perfect';
  290. }
  291. /**
  292. ----------------------------------------------------------------------+
  293. * @desc Fills in the correct directorys
  294. * @param $parts Array
  295. * @param $url Array
  296. * @param $urls Reference (Array)
  297. ----------------------------------------------------------------------+
  298. */
  299. protected function parts($parts, $url, &$urls) {
  300. if(empty($parts)) return;
  301. $part = array_shift($parts);
  302. if(!isset($urls[$part])) {
  303. $urls[$part] = array();
  304. }
  305. if(empty($parts)) {
  306. $urls[$part][] = $url;
  307. } else $this->parts($parts, $url, $urls[$part]);
  308. }
  309. /**
  310. ----------------------------------------------------------------------+
  311. * @desc Sort the result array
  312. * @param Array
  313. * @return Array
  314. ----------------------------------------------------------------------+
  315. */
  316. protected function sort($urls) {
  317. $files = array();
  318. $dirs = array();
  319. foreach($urls as $k => $_) {
  320. if(isset($_['phplinter___sort']))
  321. $files[] = $_;
  322. else $dirs[$k] = $_;
  323. }
  324. if(!empty($dirs)) {
  325. uksort($dirs, function($a, $b) {
  326. return strtolower($a) > strtolower($b);
  327. });
  328. }
  329. if(!empty($files)) {
  330. foreach($files as $_) $arr[] = $_['phplinter___sort'];
  331. array_multisort($files, SORT_ASC, $arr);
  332. }
  333. $urls = array_merge($dirs, $files);
  334. foreach($urls as $k => $_) {
  335. if(!is_numeric($k)) {
  336. $urls[$k] = $this->sort($urls[$k]);
  337. }
  338. }
  339. return $urls;
  340. }
  341. /**
  342. ----------------------------------------------------------------------+
  343. * @desc Create HTML report
  344. * @param $content HTML
  345. * @param $depth int
  346. * @return HTML
  347. ----------------------------------------------------------------------+
  348. */
  349. protected function html($content, $depth=0) {
  350. $r = str_pad('', ($depth-1)*3, '../');
  351. $out = "<!DOCTYPE html>\n";
  352. $out .= "<html>\n";
  353. $out .= "<head>\n";
  354. $out .= '<link rel="stylesheet" type="text/css" href="'.$r.'html_report.css"/>';
  355. $out .= "</head>\n";
  356. $out .= "<body>\n";
  357. $out .= $content;
  358. $out .= "</body>\n";
  359. $out .= '</html>';
  360. return $out;
  361. }
  362. }