├── .gitignore ├── .travis.yml ├── Command ├── AnalyzeLaunchCommand.php ├── AnalyzeReadCommand.php └── InitCommand.php ├── Controller └── MainController.php ├── DependencyInjection ├── Configuration.php └── JDPhpProjectAnalyzerExtension.php ├── Entities └── Analyze.php ├── JDPhpProjectAnalyzerBundle.php ├── Manager ├── ProjectAnalyzer.php └── ScriptManager.php ├── README.md ├── Resources ├── _phar │ ├── CodeSniffer.conf │ ├── atoum.phar │ ├── behat.phar │ ├── csStandard │ │ └── Symfony2 │ │ │ ├── Sniffs │ │ │ ├── Arrays │ │ │ │ └── MultiLineArrayCommaSniff.php │ │ │ ├── Classes │ │ │ │ ├── MultipleClassesOneFileSniff.php │ │ │ │ └── PropertyDeclarationSniff.php │ │ │ ├── Commenting │ │ │ │ ├── ClassCommentSniff.php │ │ │ │ └── FunctionCommentSniff.php │ │ │ ├── Formatting │ │ │ │ └── BlankLineBeforeReturnSniff.php │ │ │ ├── Functions │ │ │ │ └── ScopeOrderSniff.php │ │ │ ├── NamingConventions │ │ │ │ └── ValidClassNameSniff.php │ │ │ ├── Objects │ │ │ │ └── ObjectInstantiationSniff.php │ │ │ ├── Scope │ │ │ │ └── MethodScopeSniff.php │ │ │ └── WhiteSpace │ │ │ │ ├── AssignmentSpacingSniff.php │ │ │ │ ├── BinaryOperatorSpacingSniff.php │ │ │ │ ├── CommaSpacingSniff.php │ │ │ │ └── DiscourageFitzinatorSniff.php │ │ │ ├── Tests │ │ │ ├── Arrays │ │ │ │ ├── MultiLineArrayCommaUnitTest.inc │ │ │ │ └── MultiLineArrayCommaUnitTest.php │ │ │ ├── Formatting │ │ │ │ ├── BlankLineBeforeReturnUnitTest.inc │ │ │ │ └── BlankLineBeforeReturnUnitTest.php │ │ │ └── Objects │ │ │ │ ├── ObjectInstantiationUnitTest.inc │ │ │ │ └── ObjectInstantiationUnitTest.php │ │ │ └── ruleset.xml │ ├── phpunit.phar │ ├── security-checker.phar │ └── update.sh ├── config │ ├── routing.yml │ └── services.yml ├── doc │ └── index.rst ├── public │ ├── css │ │ ├── bootstrap.min.css │ │ └── pa.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── img │ │ ├── Shield_Green.png │ │ ├── Shield_Red.png │ │ ├── favicon.ico │ │ ├── loading.gif │ │ └── question.png │ └── js │ │ ├── bootstrap.min.js │ │ ├── highcharts.js │ │ ├── histo.js │ │ ├── jquery-2.1.0.min.js │ │ ├── pa.js │ │ └── tooltip.js ├── sh │ ├── cbf.tpl.sh │ ├── count.tpl.sh │ ├── cpd.tpl.sh │ ├── cs.tpl.sh │ ├── depend.tpl.sh │ ├── docs.tpl.sh │ ├── footer.tpl.sh │ ├── header.tpl.sh │ ├── install.sh │ ├── loc.tpl.sh │ ├── md.tpl.sh │ ├── security.tpl.sh │ ├── test.tpl.sh │ ├── testAtoum.tpl.sh │ └── testPhpUnit.tpl.sh ├── translations │ ├── messages.en.yml │ └── messages.fr.yml └── views │ └── Main │ ├── Modal │ ├── cmd.html.twig │ ├── cmdManuelle.html.twig │ ├── cmdRep.html.twig │ └── rapport.html.twig │ ├── blockReportDetail.html.twig │ ├── btnDetail.html.twig │ ├── detail.html.twig │ ├── header.html.twig │ ├── index.html.twig │ ├── lanceur.html.twig │ ├── lien.html.twig │ ├── options.html.twig │ ├── qualite.html.twig │ ├── quantite.html.twig │ └── res.html.twig ├── Tests ├── Fixtures │ └── Traits │ │ └── visualizer.txt └── Traits │ ├── ScoreCalculatorTest.php │ └── ViewHelperTest.php ├── Traits ├── ParamReader.php ├── ScoreCalculator.php ├── ScriptBuilder.php └── ViewHelper.php ├── composer.json ├── composer.lock ├── phpunit.xml └── ppaIndex.png /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | vendor 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 7.0 6 | - 7.1 7 | 8 | matrix: 9 | include: 10 | - php: 7.0 11 | env: 12 | - COVERALLS=1 13 | - PHPCS=1 14 | 15 | before_install: 16 | - wget http://getcomposer.org/composer.phar 17 | 18 | before_script: 19 | - php composer.phar update 20 | 21 | script: 22 | - bin/simple-phpunit -c phpunit.xml 23 | - bin/phpcs --standard=PSR2 --extensions=php Entities Manager Command Controller DependencyInjection Traits 24 | 25 | notifications: 26 | email: 27 | - jd.labails@gmail.com 28 | -------------------------------------------------------------------------------- /Command/AnalyzeLaunchCommand.php: -------------------------------------------------------------------------------- 1 | setName('ppa:analyse:launch') 22 | ->setDescription('Launch the analysis') 23 | ; 24 | } 25 | 26 | /** 27 | * Execution 28 | * 29 | * @param InputInterface $input 30 | * @param OutputInterface $output 31 | * 32 | * @return type 33 | */ 34 | protected function execute(InputInterface $input, OutputInterface $output) 35 | { 36 | $res = $this->getContainer()->get('jd_ppa.scriptManager')->lancerAnalyse(); 37 | 38 | $output->writeln($res); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Command/AnalyzeReadCommand.php: -------------------------------------------------------------------------------- 1 | setName('ppa:analyse:read') 22 | ->setDescription('Read the last analysis') 23 | ; 24 | } 25 | 26 | /** 27 | * Execution 28 | * 29 | * @param InputInterface $input 30 | * @param OutputInterface $output 31 | * 32 | * @return type 33 | */ 34 | protected function execute(InputInterface $input, OutputInterface $output) 35 | { 36 | $projectAnalyzer = $this->getContainer()->get('jd_ppa.projectAnalyzer'); 37 | 38 | if ($projectAnalyzer->isAnalyzeInProgress()) { 39 | $output->writeln('AIP'); 40 | return; 41 | } 42 | 43 | $output->writeln(json_encode($projectAnalyzer->getAnalyze()->jsonSerialize())); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Command/InitCommand.php: -------------------------------------------------------------------------------- 1 | setName('ppa:init') 22 | ->setDescription('Init directories for report') 23 | ; 24 | } 25 | 26 | /** 27 | * Execution 28 | * 29 | * @param InputInterface $input 30 | * @param OutputInterface $output 31 | * 32 | * @return type 33 | */ 34 | protected function execute(InputInterface $input, OutputInterface $output) 35 | { 36 | $reflClass = new \ReflectionClass(get_class($this)); 37 | $dirPath = dirname($reflClass->getFileName()); 38 | 39 | $installerPath = $dirPath . '/../Resources/sh/install.sh'; 40 | $reportPath = $this->getContainer()->getParameter('kernel.root_dir') . '/../web/ppa'; 41 | 42 | if (!is_executable($installerPath)) { 43 | chmod($installerPath, 0755); 44 | if (!is_executable($installerPath)) { 45 | $output->writeln(basename($installerPath) . ' non executable'); 46 | 47 | return; 48 | } 49 | } 50 | 51 | $question = new Question('Please enter your web server user [www-data:www-data] :', 'www-data:www-data'); 52 | $webServer = $this->getHelperSet()->get('question')->ask($input, $output, $question); 53 | 54 | $outputExec = []; 55 | exec($installerPath. ' ' . $webServer . ' ' . $reportPath, $outputExec); 56 | $outputExec[] = "\nInstallation done"; 57 | $output->writeln($outputExec); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Controller/MainController.php: -------------------------------------------------------------------------------- 1 | get('jd_ppa.projectAnalyzer'); 22 | 23 | return $this->render('JDPhpProjectAnalyzerBundle:Main:index.html.twig', [ 24 | 'projectAnalyzer' => $projectAnalyzer, 25 | 'params' => $this->getParameter('jd.ppa.global'), 26 | ]); 27 | } 28 | 29 | /** 30 | * Display phpinfo 31 | * @Route("/ppa/phpinfo") 32 | * @return Response 33 | */ 34 | public function phpinfoAction() 35 | { 36 | return $this->render('JDPhpProjectAnalyzerBundle:Main:res.html.twig', ['res' => phpinfo()]); 37 | } 38 | 39 | /** 40 | * Launch analysis 41 | * @Route("/ppa/analyze") 42 | * @return Response 43 | */ 44 | public function analyzeAction() 45 | { 46 | return $this->render( 47 | 'JDPhpProjectAnalyzerBundle:Main:res.html.twig', 48 | ['res' => $this->get('jd_ppa.scriptManager')->lancerAnalyse()] 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | root('jd_php_project_analyzer'); 20 | 21 | $rootNode 22 | ->children() 23 | ->scalarNode('title')->defaultValue('Your project')->end() 24 | ->scalarNode('description')->defaultNull()->end() 25 | ->scalarNode('gitRepositoryURL')->defaultNull()->end() 26 | ->scalarNode('srcPath')->isRequired()->cannotBeEmpty()->end() 27 | 28 | ->booleanNode('count')->defaultTrue()->end() 29 | ->booleanNode('cpd')->defaultTrue()->end() 30 | ->arrayNode('cs') 31 | ->children() 32 | ->booleanNode('enable')->defaultTrue()->end() 33 | ->scalarNode('standard')->defaultValue('PSR2')->cannotBeEmpty()->end() 34 | ->end() 35 | ->end() 36 | ->booleanNode('depend')->defaultTrue()->end() 37 | ->booleanNode('security')->defaultTrue()->end() 38 | ->booleanNode('loc')->defaultTrue()->end() 39 | 40 | ->arrayNode('md') 41 | ->children() 42 | ->booleanNode('enable')->defaultTrue()->end() 43 | ->arrayNode('rules') 44 | ->children() 45 | ->booleanNode('cleancode')->defaultTrue()->end() 46 | ->booleanNode('codesize')->defaultTrue()->end() 47 | ->booleanNode('controversial')->defaultTrue()->end() 48 | ->booleanNode('design')->defaultTrue()->end() 49 | ->booleanNode('naming')->defaultTrue()->end() 50 | ->booleanNode('unusedcode')->defaultTrue()->end() 51 | ->end() 52 | ->end() 53 | ->end() 54 | ->end() 55 | 56 | ->booleanNode('docs')->defaultTrue()->end() 57 | ->arrayNode('test') 58 | ->children() 59 | ->booleanNode('enable')->defaultTrue()->end() 60 | ->scalarNode('lib')->defaultValue('phpunit')->cannotBeEmpty()->end() 61 | ->scalarNode('phpunitTestSuite')->end() 62 | ->scalarNode('phpunitTestConfig')->end() 63 | ->scalarNode('atoumPath')->end() 64 | ->scalarNode('atoumTestDir')->end() 65 | ->end() 66 | ->end() 67 | 68 | ->arrayNode('score') 69 | ->children() 70 | ->booleanNode('enable')->defaultTrue()->end() 71 | ->scalarNode('csWeight')->defaultValue('100')->cannotBeEmpty()->end() 72 | ->scalarNode('cpWeight')->defaultValue('100')->cannotBeEmpty()->end() 73 | ->scalarNode('scWeight')->defaultValue('100')->cannotBeEmpty()->end() 74 | ->scalarNode('testWeight')->defaultValue('100')->cannotBeEmpty()->end() 75 | ->scalarNode('locWeight')->defaultValue('100')->cannotBeEmpty()->end() 76 | ->scalarNode('projectSize')->defaultValue('medium')->cannotBeEmpty()->end() 77 | ->end() 78 | ->end() 79 | 80 | ->end(); 81 | 82 | return $treeBuilder; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /DependencyInjection/JDPhpProjectAnalyzerExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 24 | 25 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 26 | $loader->load('services.yml'); 27 | 28 | $this->addConfigToParameter('jd.ppa', $config, $container); 29 | $container->setParameter('jd.ppa.global', $config); 30 | } 31 | 32 | private function addConfigToParameter($prefix, array $config, ContainerBuilder $container) 33 | { 34 | foreach ($config as $k => $v) { 35 | $paramName = $prefix.'.'.$k; 36 | if (!is_array($v)) { 37 | $container->setParameter($paramName, $v); 38 | } else { 39 | $this->addConfigToParameter($paramName, $v, $container); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Entities/Analyze.php: -------------------------------------------------------------------------------- 1 | 11 | * 12 | * @ORM\Table(name="ppa_analyse") 13 | * @ORM\Entity() 14 | */ 15 | class Analyze 16 | { 17 | /** 18 | * @var integer 19 | * 20 | * @ORM\Column(name="id", type="integer") 21 | * @ORM\Id 22 | * @ORM\GeneratedValue(strategy="AUTO") 23 | */ 24 | private $id; 25 | 26 | /** 27 | * @var \DateTime 28 | * 29 | * @ORM\Column(name="analyzed_at", type="datetime") 30 | */ 31 | private $dateTime; 32 | 33 | /** 34 | * @var boolean 35 | * 36 | * @ORM\Column(name="tu_success", type="boolean", nullable=true, options={"default":false}) 37 | */ 38 | private $tuSuccess; 39 | 40 | /** 41 | * @var boolean 42 | * 43 | * @ORM\Column(name="cs_success", type="boolean", nullable=true, options={"default":false}) 44 | */ 45 | private $csSuccess; 46 | 47 | /** 48 | * @var boolean 49 | * 50 | * @ORM\Column(name="cp_success", type="boolean", nullable=true, options={"default":false}) 51 | */ 52 | private $cpSuccess; 53 | 54 | /** 55 | * @var boolean 56 | * 57 | * @ORM\Column(name="security_success", type="boolean", nullable=true, options={"default":false}) 58 | */ 59 | private $securitySuccess; 60 | 61 | /** 62 | * @var integer 63 | * 64 | * @ORM\Column(name="loc", type="integer", nullable=true) 65 | */ 66 | private $loc; 67 | 68 | /** 69 | * @var integer 70 | * 71 | * @ORM\Column(name="score", type="integer", nullable=true) 72 | */ 73 | private $score; 74 | 75 | /** 76 | * @var float 77 | * 78 | * @ORM\Column(name="cov", type="double(4,2)", nullable=true) 79 | */ 80 | private $cov; 81 | 82 | /** 83 | * @var integer 84 | * 85 | * @ORM\Column(name="exec_time", type="integer", nullable=true) 86 | */ 87 | private $execTime; 88 | 89 | /** 90 | * @var integer 91 | * 92 | * @ORM\Column(name="nb_bundles", type="integer", nullable=true) 93 | */ 94 | private $nbBundles; 95 | 96 | /** 97 | * @var integer 98 | * 99 | * @ORM\Column(name="nb_dir", type="integer", nullable=true) 100 | */ 101 | private $nbDir; 102 | 103 | /** 104 | * @var integer 105 | * 106 | * @ORM\Column(name="nb_file", type="integer", nullable=true) 107 | */ 108 | private $nbFile; 109 | 110 | /** 111 | * @var integer 112 | * 113 | * @ORM\Column(name="nb_php_file", type="integer", nullable=true) 114 | */ 115 | private $nbPhpFile; 116 | 117 | /** 118 | * @var integer 119 | * 120 | * @ORM\Column(name="nb_css_file", type="integer", nullable=true) 121 | */ 122 | private $nbCSSFile; 123 | 124 | /** 125 | * @var integer 126 | * 127 | * @ORM\Column(name="nb_css_lib", type="integer", nullable=true) 128 | */ 129 | private $nbCSSLib; 130 | 131 | /** 132 | * @var integer 133 | * 134 | * @ORM\Column(name="loc", type="integer", nullable=true) 135 | */ 136 | private $nbJSFile; 137 | 138 | /** 139 | * @var integer 140 | * 141 | * @ORM\Column(name="nb_js_lib", type="integer", nullable=true) 142 | */ 143 | private $nbJSLib; 144 | 145 | /** 146 | * @var integer 147 | * 148 | * @ORM\Column(name="nb_twig", type="integer", nullable=true) 149 | */ 150 | private $nbTwig; 151 | 152 | /** 153 | * @var integer 154 | * 155 | * @ORM\Column(name="nb_namespace", type="integer", nullable=true) 156 | */ 157 | private $nbNamespace; 158 | 159 | /** 160 | * @var integer 161 | * 162 | * @ORM\Column(name="nb_classes", type="integer", nullable=true) 163 | */ 164 | private $nbClasses; 165 | 166 | /** 167 | * @var integer 168 | * 169 | * @ORM\Column(name="nb_method", type="integer", nullable=true) 170 | */ 171 | private $nbMethod; 172 | 173 | /** 174 | * @var string 175 | * 176 | * @ORM\Column(name="lang", type="string", nullable=true) 177 | */ 178 | private $lang; 179 | 180 | /** 181 | * @var string 182 | * 183 | * @ORM\Column(name="symfony_version", type="string", nullable=true) 184 | */ 185 | private $symfonyVersion; 186 | 187 | 188 | /** 189 | * Get id 190 | * 191 | * @return integer 192 | */ 193 | public function getId() 194 | { 195 | return $this->id; 196 | } 197 | 198 | /** 199 | * Set dateTime 200 | * 201 | * @param \DateTime $dateTime 202 | * @return analyze 203 | */ 204 | public function setDateTime($dateTime) 205 | { 206 | $this->dateTime = $dateTime; 207 | 208 | return $this; 209 | } 210 | 211 | /** 212 | * Get dateTime 213 | * 214 | * @return \DateTime 215 | */ 216 | public function getDateTime() 217 | { 218 | return $this->dateTime; 219 | } 220 | 221 | /** 222 | * Retourne une date lisible formaté selon la lang. 223 | * 224 | * @return string 225 | */ 226 | public function getReadableDateTime() 227 | { 228 | if ($this->lang == 'fr') { 229 | return date('d/m/y à H:i', $this->dateTime); 230 | } 231 | 232 | return date('Y-m-d H:i', $this->dateTime); 233 | } 234 | 235 | /** 236 | * Retourne une date formaté js utc 237 | * 238 | * @return string 239 | */ 240 | public function getDateTimeUTC() 241 | { 242 | return ($this->dateTime * 1000) - (strtotime('02-01-1970 00:00:00') * 1000); 243 | } 244 | 245 | /** 246 | * Set tuSuccess 247 | * 248 | * @param boolean $tuSuccess 249 | * @return analyze 250 | */ 251 | public function setTuSuccess($tuSuccess) 252 | { 253 | $this->tuSuccess = $tuSuccess; 254 | 255 | return $this; 256 | } 257 | 258 | /** 259 | * Get tuSuccess 260 | * 261 | * @return boolean 262 | */ 263 | public function getTuSuccess() 264 | { 265 | return $this->tuSuccess; 266 | } 267 | 268 | /** 269 | * Set csSuccess 270 | * 271 | * @param boolean $csSuccess 272 | * @return analyze 273 | */ 274 | public function setCsSuccess($csSuccess) 275 | { 276 | $this->csSuccess = $csSuccess; 277 | 278 | return $this; 279 | } 280 | 281 | /** 282 | * Get csSuccess 283 | * 284 | * @return boolean 285 | */ 286 | public function getCsSuccess() 287 | { 288 | return $this->csSuccess; 289 | } 290 | 291 | /** 292 | * Set cpSuccess 293 | * 294 | * @param boolean $cpSuccess 295 | * @return analyze 296 | */ 297 | public function setCpSuccess($cpSuccess) 298 | { 299 | $this->cpSuccess = $cpSuccess; 300 | 301 | return $this; 302 | } 303 | 304 | /** 305 | * Get cpSuccess 306 | * 307 | * @return boolean 308 | */ 309 | public function getCpSuccess() 310 | { 311 | return $this->cpSuccess; 312 | } 313 | 314 | /** 315 | * Set securitySuccess 316 | * 317 | * @param boolean $securitySuccess 318 | * @return analyze 319 | */ 320 | public function setSecuritySuccess($securitySuccess) 321 | { 322 | $this->securitySuccess = $securitySuccess; 323 | 324 | return $this; 325 | } 326 | 327 | /** 328 | * Get securitySuccess 329 | * 330 | * @return boolean 331 | */ 332 | public function getSecuritySuccess() 333 | { 334 | return $this->securitySuccess; 335 | } 336 | 337 | /** 338 | * Set loc 339 | * 340 | * @param integer $loc 341 | * @return analyze 342 | */ 343 | public function setLoc($loc) 344 | { 345 | $this->loc = $loc; 346 | 347 | return $this; 348 | } 349 | 350 | /** 351 | * Get loc 352 | * 353 | * @return integer 354 | */ 355 | public function getLoc() 356 | { 357 | return $this->loc; 358 | } 359 | 360 | /** 361 | * Set score 362 | * 363 | * @param integer $score 364 | * @return analyze 365 | */ 366 | public function setScore($score) 367 | { 368 | $this->score = $score; 369 | 370 | return $this; 371 | } 372 | 373 | /** 374 | * Get score 375 | * 376 | * @return integer 377 | */ 378 | public function getScore() 379 | { 380 | return $this->score; 381 | } 382 | 383 | /** 384 | * Set cov 385 | * 386 | * @param float $cov 387 | * @return analyze 388 | */ 389 | public function setCov($cov) 390 | { 391 | $this->cov = $cov; 392 | 393 | return $this; 394 | } 395 | 396 | /** 397 | * Get cov 398 | * 399 | * @return float 400 | */ 401 | public function getCov() 402 | { 403 | return $this->cov; 404 | } 405 | 406 | /** 407 | * Set execTime 408 | * 409 | * @param integer $execTime 410 | * @return analyze 411 | */ 412 | public function setExecTime($execTime) 413 | { 414 | $this->execTime = $execTime; 415 | 416 | return $this; 417 | } 418 | 419 | /** 420 | * Get execTime 421 | * 422 | * @return integer 423 | */ 424 | public function getExecTime() 425 | { 426 | return $this->execTime; 427 | } 428 | 429 | /** 430 | * Get execTime in a human readable way 431 | * 432 | * @return integer 433 | */ 434 | public function getReadableExecTime() 435 | { 436 | if ($this->execTime > 120) { 437 | return round($this->execTime / 60, 0, PHP_ROUND_HALF_DOWN) . ' min ' . ($this->execTime % 60) . ' sec '; 438 | } 439 | 440 | return $this->execTime . ' sec'; 441 | } 442 | 443 | /** 444 | * Set nbBundles 445 | * 446 | * @param integer $nbBundles 447 | * @return analyze 448 | */ 449 | public function setNbBundles($nbBundles) 450 | { 451 | $this->nbBundles = (int)$nbBundles; 452 | 453 | return $this; 454 | } 455 | 456 | /** 457 | * Get nbBundles 458 | * 459 | * @return integer 460 | */ 461 | public function getNbBundles() 462 | { 463 | return $this->nbBundles; 464 | } 465 | 466 | /** 467 | * Set nbDir 468 | * 469 | * @param integer $nbDir 470 | * @return analyze 471 | */ 472 | public function setNbDir($nbDir) 473 | { 474 | $this->nbDir = (int)$nbDir; 475 | 476 | return $this; 477 | } 478 | 479 | /** 480 | * Get nbDir 481 | * 482 | * @return integer 483 | */ 484 | public function getNbDir() 485 | { 486 | return $this->nbDir; 487 | } 488 | 489 | /** 490 | * Set nbFile 491 | * 492 | * @param integer $nbFile 493 | * @return analyze 494 | */ 495 | public function setNbFile($nbFile) 496 | { 497 | $this->nbFile = (int)$nbFile; 498 | 499 | return $this; 500 | } 501 | 502 | /** 503 | * Get nbFile 504 | * 505 | * @return integer 506 | */ 507 | public function getNbFile() 508 | { 509 | return $this->nbFile; 510 | } 511 | 512 | /** 513 | * Set nbPhpFile 514 | * 515 | * @param integer $nbPhpFile 516 | * @return analyze 517 | */ 518 | public function setNbPhpFile($nbPhpFile) 519 | { 520 | $this->nbPhpFile = (int)$nbPhpFile; 521 | 522 | return $this; 523 | } 524 | 525 | /** 526 | * Get nbPhpFile 527 | * 528 | * @return integer 529 | */ 530 | public function getNbPhpFile() 531 | { 532 | return $this->nbPhpFile; 533 | } 534 | 535 | /** 536 | * Set nbCSSFile 537 | * 538 | * @param integer $nbCSSFile 539 | * @return analyze 540 | */ 541 | public function setNbCSSFile($nbCSSFile) 542 | { 543 | $this->nbCSSFile = (int)$nbCSSFile; 544 | 545 | return $this; 546 | } 547 | 548 | /** 549 | * Get nbCSSFile 550 | * 551 | * @return integer 552 | */ 553 | public function getNbCSSFile() 554 | { 555 | return $this->nbCSSFile; 556 | } 557 | 558 | /** 559 | * Set nbCSSLib 560 | * 561 | * @param integer $nbCSSLib 562 | * @return analyze 563 | */ 564 | public function setNbCSSLib($nbCSSLib) 565 | { 566 | $this->nbCSSLib = (int)$nbCSSLib; 567 | 568 | return $this; 569 | } 570 | 571 | /** 572 | * Get nbCSSLib 573 | * 574 | * @return integer 575 | */ 576 | public function getNbCSSLib() 577 | { 578 | return $this->nbCSSLib; 579 | } 580 | 581 | /** 582 | * Set nbJSFile 583 | * 584 | * @param integer $nbJSFile 585 | * @return analyze 586 | */ 587 | public function setNbJSFile($nbJSFile) 588 | { 589 | $this->nbJSFile = (int)$nbJSFile; 590 | 591 | return $this; 592 | } 593 | 594 | /** 595 | * Get nbJSFile 596 | * 597 | * @return integer 598 | */ 599 | public function getNbJSFile() 600 | { 601 | return $this->nbJSFile; 602 | } 603 | 604 | /** 605 | * Set nbJSLib 606 | * 607 | * @param integer $nbJSLib 608 | * @return analyze 609 | */ 610 | public function setNbJSLib($nbJSLib) 611 | { 612 | $this->nbJSLib = (int)$nbJSLib; 613 | 614 | return $this; 615 | } 616 | 617 | /** 618 | * Get nbJSLib 619 | * 620 | * @return integer 621 | */ 622 | public function getNbJSLib() 623 | { 624 | return $this->nbJSLib; 625 | } 626 | 627 | /** 628 | * Set nbTwig 629 | * 630 | * @param integer $nbTwig 631 | * @return analyze 632 | */ 633 | public function setNbTwig($nbTwig) 634 | { 635 | $this->nbTwig = (int)$nbTwig; 636 | 637 | return $this; 638 | } 639 | 640 | /** 641 | * Get nbTwig 642 | * 643 | * @return integer 644 | */ 645 | public function getNbTwig() 646 | { 647 | return $this->nbTwig; 648 | } 649 | 650 | /** 651 | * Set nbNamespace 652 | * 653 | * @param integer $nbNamespace 654 | * @return analyze 655 | */ 656 | public function setNbNamespace($nbNamespace) 657 | { 658 | $this->nbNamespace = (int)$nbNamespace; 659 | 660 | return $this; 661 | } 662 | 663 | /** 664 | * Get nbNamespace 665 | * 666 | * @return integer 667 | */ 668 | public function getNbNamespace() 669 | { 670 | return $this->nbNamespace; 671 | } 672 | 673 | /** 674 | * Set nbClasses 675 | * 676 | * @param integer $nbClasses 677 | * @return analyze 678 | */ 679 | public function setNbClasses($nbClasses) 680 | { 681 | $this->nbClasses = (int)$nbClasses; 682 | 683 | return $this; 684 | } 685 | 686 | /** 687 | * Get nbClasses 688 | * 689 | * @return integer 690 | */ 691 | public function getNbClasses() 692 | { 693 | return $this->nbClasses; 694 | } 695 | 696 | /** 697 | * Set nbMethod 698 | * 699 | * @param integer $nbMethod 700 | * @return analyze 701 | */ 702 | public function setNbMethod($nbMethod) 703 | { 704 | $this->nbMethod = (int)$nbMethod; 705 | 706 | return $this; 707 | } 708 | 709 | /** 710 | * Get nbMethod 711 | * 712 | * @return integer 713 | */ 714 | public function getNbMethod() 715 | { 716 | return $this->nbMethod; 717 | } 718 | 719 | /** 720 | * Set lang 721 | * 722 | * @param string $lang 723 | * @return analyze 724 | */ 725 | public function setLang($lang) 726 | { 727 | $this->lang = $lang; 728 | 729 | return $this; 730 | } 731 | 732 | /** 733 | * Get lang 734 | * 735 | * @return string 736 | */ 737 | public function getLang() 738 | { 739 | return $this->lang; 740 | } 741 | 742 | /** 743 | * Serialize this 744 | * @return type 745 | */ 746 | public function jsonSerialize() 747 | { 748 | return get_object_vars($this); 749 | } 750 | 751 | /** 752 | * Set an Analyse object from an array 753 | * @param array $data 754 | */ 755 | public function setFromArray($data) 756 | { 757 | foreach ($data as $key => $value) { 758 | $this->{$key} = $value; 759 | } 760 | } 761 | 762 | /** 763 | * @return string 764 | */ 765 | public function getSymfonyVersion() 766 | { 767 | return $this->symfonyVersion; 768 | } 769 | 770 | /** 771 | * @param string $symfonyVersion 772 | * @return Analyze 773 | */ 774 | public function setSymfonyVersion($symfonyVersion) 775 | { 776 | $this->symfonyVersion = $symfonyVersion; 777 | return $this; 778 | } 779 | } 780 | -------------------------------------------------------------------------------- /JDPhpProjectAnalyzerBundle.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class ProjectAnalyzer 16 | { 17 | use Traits\ViewHelper, Traits\ScoreCalculator, Traits\ParamReader; 18 | 19 | private $dirRoot; 20 | private $parameters; 21 | private $reportPath; 22 | 23 | private $oAnalyze; 24 | private $qualityInfo; 25 | private $testInfo; 26 | 27 | private $translator; 28 | 29 | /** 30 | * Init ppa 31 | * @param type $configGlobale 32 | * @param Translator $translator 33 | */ 34 | public function __construct($configGlobale, TranslatorInterface $translator, $rootDir) 35 | { 36 | // traduction 37 | $this->translator = $translator; 38 | 39 | // web ppa path 40 | $this->dirRoot = $rootDir.'/web/ppa'; 41 | 42 | // report path 43 | $this->reportPath = $this->dirRoot.'/reports'; 44 | 45 | // parameters 46 | $this->parameters = $configGlobale; 47 | 48 | // l'objet analyse 49 | $this->oAnalyze = new Analyze(); 50 | $this->oAnalyze 51 | ->setLang($translator->getLocale()) 52 | ->setSymfonyVersion($this->getSymfonyVersion()) 53 | ->setNbNamespace($this->extractFromLoc('namespaces')) 54 | ->setNbClasses($this->extractFromLoc('classes')) 55 | ->setNbMethod($this->extractFromLoc('methods')) 56 | ->setLoc((int) $this->extractFromLoc('loc')); 57 | 58 | // Exploits analysis 59 | $this->count(); 60 | $this->setSecurityInfo(); 61 | $this->setQualityInfo(); 62 | $this->setAnalysisTimeInfo(); 63 | $this->exploitTestReport(); 64 | $this->calculateScore(); 65 | } 66 | 67 | /** 68 | * il faudra mettre la trad 69 | * 70 | * @return type 71 | */ 72 | public function getTabAvailableAnalysis() 73 | { 74 | return [ 75 | 'test' => 'details.libelle.test', 76 | 'md' => 'details.libelle.phpmd', 77 | 'cpd' => 'details.libelle.phpcpd', 78 | 'cs' => 'details.libelle.cs', 79 | 'loc' => 'details.libelle.phploc', 80 | 'docs' => 'details.libelle.phpdoc', 81 | 'depend' => 'details.libelle.phpdepend', 82 | 'security' => 'details.libelle.security', 83 | ]; 84 | } 85 | 86 | /** 87 | * Retourne l'objet analyse 88 | * @return analyze 89 | */ 90 | public function getAnalyze() 91 | { 92 | // lorsque cette methode est appelee, on en profite pour historiser si enable 93 | if ($this->isEnable('histo', true)) { 94 | $this->historise(); 95 | } 96 | 97 | return $this->oAnalyze; 98 | } 99 | 100 | /** 101 | * Retourne les infos pour la vue sur les tests 102 | * 103 | * @return array 104 | */ 105 | public function getTestInfo() 106 | { 107 | return $this->testInfo; 108 | } 109 | 110 | /** 111 | * Retroune les infos pour la vue sur les metriques de qualité 112 | * @return type 113 | */ 114 | public function getQualityInfo() 115 | { 116 | return $this->qualityInfo; 117 | } 118 | 119 | /** 120 | * Vérifie si une analyse est en cours par présence du jeton 121 | * @return type 122 | */ 123 | public function isAnalyzeInProgress() 124 | { 125 | return file_exists($this->dirRoot.'/jetons/jetonAnalyse'); 126 | } 127 | 128 | /** 129 | * Recupere le contenu du rapport 130 | * 131 | * @param string $file chemin du fichier 132 | * 133 | * @return array($txt, $vide) contenu du rapport et boolean si vide ou pas 134 | */ 135 | public function getReport($file) 136 | { 137 | $txt = $this->translator->trans('details.noReport').' :('; 138 | $vide = false; 139 | if (file_exists($file)) { 140 | $txt = file_get_contents($file); 141 | 142 | if (trim($txt) == '') { 143 | $vide = true; 144 | $txt = $this->translator->trans('details.emptyReport').' :D'; 145 | } 146 | } 147 | 148 | return [$txt, $vide]; 149 | } 150 | 151 | /** 152 | * Set info from security analysis 153 | */ 154 | protected function setSecurityInfo() 155 | { 156 | $securityAnalyse = $this->analyzeReport('SECURITY', false, '[OK] 0 packages have known vulnerabilities'); 157 | 158 | $this->oAnalyze->setSecuritySuccess($securityAnalyse['SECURITY']['summary'] === 'ok'); 159 | } 160 | 161 | protected function getSymfonyVersion() 162 | { 163 | $reportFilePath = $this->reportPath.'/SYMFONY/report.txt'; 164 | $report = $this->getReport($reportFilePath); 165 | 166 | return substr($report[0], 8, 5); 167 | } 168 | 169 | /** 170 | * Set info from quality analysis 171 | */ 172 | protected function setQualityInfo() 173 | { 174 | $csAnalyse = $this->analyzeReport('CS'); 175 | 176 | $this->oAnalyze->setCsSuccess($csAnalyse['CS']['summary'] === 'ok'); 177 | 178 | $ccMethod = number_format((float) $this->extractFromLoc('ccnByNom'), 2, ',', ' '); 179 | 180 | $this->qualityInfo = 181 | $csAnalyse + 182 | $this->analyzeReport('MD') + 183 | $this->analyzeReport('CPD', false, '0.00% duplicated lines') + 184 | ['ccMethod' => $ccMethod] 185 | ; 186 | } 187 | 188 | /** 189 | * Exploit les rapports de test unitaire 190 | * @return type 191 | */ 192 | protected function exploitTestReport() 193 | { 194 | $res = [ 195 | 'ok' => false, 196 | 'nbTest' => '/', 197 | 'nbAssertions' => '/', 198 | 'date' => '/', 199 | 'exeTime' => '/', 200 | 'exeMem' => '/', 201 | 'dateTimeCC' => '/', 202 | 'ccClasse' => '/', 203 | 'ccMethod' => '/', 204 | 'ccLine' => '/', 205 | 'report' => '', 206 | 'cmd' => '', 207 | 'cmdManuelle' => '', 208 | ]; 209 | 210 | $testReportFile = $this->reportPath.'/TEST/report.txt'; 211 | if (file_exists($testReportFile)) { 212 | $res['report'] = $this->adaptPhpUnitReport($testReportFile); 213 | 214 | $res['date'] = $this->getDateGeneration($testReportFile); 215 | 216 | $lines = file($testReportFile); 217 | 218 | if ($this->parameters['test']['lib'] == 'phpunit') { 219 | foreach ($lines as $l) { 220 | // si on est sur la ligne des metrique d'execution du test 221 | // Time: 6.8 minutes, Memory: 141.00Mb 222 | if (strpos($l, 'Time') !== false && strpos($l, 'Memory') !== false) { 223 | list($t, $m) = explode(',', $l); 224 | $res['exeTime'] = explode(':', $t)[1]; 225 | $res['exeMem'] = explode(':', $m)[1]; 226 | } 227 | 228 | // output of test : "OK (40 tests, 123 assertions) " 229 | if (stripos($l, 'test') !== false && stripos($l, 'assertion') !== false) { 230 | $res['ok'] = strpos($l, 'OK') !== false; 231 | 232 | if ($res['ok']) { 233 | list($t, $a) = explode(',', $l); 234 | 235 | $nb = explode('(', $t)[1]; 236 | $res['nbTest'] = str_ireplace('tests', '', $nb); 237 | 238 | $nb = explode(')', $a)[0]; 239 | $res['nbAssertions'] = str_ireplace('assertions', '', $nb); 240 | } else { 241 | $lineTab = explode(',', $l); 242 | 243 | $res['nbTest'] = explode(':', $lineTab[0])[1]; 244 | 245 | $res['nbAssertions'] = explode(':', $lineTab[1])[1]; 246 | } 247 | } 248 | } 249 | 250 | $covReportFile = $this->reportPath.'/TEST/coverage.txt'; 251 | if (file_exists($covReportFile)) { 252 | $res['dateTimeCC'] = $this->getReadableDateTime(filemtime($covReportFile)); 253 | 254 | $lines = file($covReportFile); 255 | foreach ($lines as $k => $v) { 256 | if (strpos($v, 'Summary:') !== false) { 257 | $res['ccClasse'] = explode(':', $lines[$k+1])[1]; 258 | $res['ccMethod'] = explode(':', $lines[$k+2])[1]; 259 | $res['ccLine'] = explode(':', $lines[$k+3])[1]; 260 | $res['ccLine'] = explode('(', $res['ccLine'])[0]; 261 | 262 | break; 263 | } 264 | } 265 | } 266 | } // phpunit 267 | 268 | if ($this->parameters['test']['lib'] == 'atoum' && count($lines) > 2) { 269 | $runningDurationLine = self::findAtoumRunningDuration($lines); 270 | 271 | $res['exeTime'] = explode(':', $lines[$runningDurationLine])[1]; 272 | 273 | //Success (4 tests, 40/40 methods, 0 void method, 0 skipped method, 265 assertions)! 274 | $line = $lines[$runningDurationLine+1]; 275 | $res['ok'] = strpos($line, 'Success') !== false; 276 | if ($res['ok']) { 277 | $items = explode(',', $line); 278 | 279 | $nb = explode('(', $items[0])[1]; 280 | $res['nbTest'] = str_ireplace('tests', '', $nb); 281 | 282 | $res['nbAssertions'] = str_ireplace('assertions)!', '', array_pop($items)); 283 | 284 | foreach ($lines as $l) { 285 | if (strpos($l, 'Code coverage value:') !== false) { 286 | $res['ccLine'] = str_ireplace('> Code coverage value: ', '', $l); 287 | } 288 | } 289 | 290 | $res['dateTimeCC'] = $this->getReadableDateTime(filemtime($testReportFile)); 291 | } else { 292 | } 293 | } // atoum 294 | } 295 | 296 | $cmdFile = $this->reportPath.'/TEST/cmd.txt'; 297 | if (file_exists($cmdFile)) { 298 | $res['cmd'] = file_get_contents($cmdFile); 299 | } 300 | 301 | $cmdManuelleFile = $this->reportPath.'/TEST/cmdManuelle.txt'; 302 | if (file_exists($cmdManuelleFile)) { 303 | $res['cmdManuelle'] = file_get_contents($cmdManuelleFile); 304 | } 305 | 306 | $this->oAnalyze 307 | ->setTuSuccess($res['ok']) 308 | ->setCov($res['ccLine']); 309 | 310 | $this->testInfo = $res; 311 | } 312 | 313 | /** 314 | * Read analysis reports 315 | * @return array 316 | */ 317 | public function getReportInfo() 318 | { 319 | $tabReports = array('MD', 'CS', 'CPD', 'DEPEND', 'LOC', 'DOCS', 'SECURITY', 'SYMFONY'); 320 | 321 | foreach ($tabReports as $report) { 322 | list($reportTxt, $vide) = $this->getReport($this->reportPath.'/'.$report.'/report.txt'); 323 | $res[$report] = [ 324 | 'date' => $this->getDateGeneration($this->reportPath.'/'.$report.'/report.txt'), 325 | 'report' => $reportTxt, 326 | 'ok' => $vide, 327 | ]; 328 | 329 | if ($report == 'CPD') { 330 | $res[$report]['ok'] = strpos($reportTxt, '0.00% duplicated lines') !== false; 331 | } 332 | 333 | $cmdFile = $this->reportPath.'/'.$report.'/cmd.txt'; 334 | $res[$report]['cmd'] = ''; 335 | if (file_exists($cmdFile)) { 336 | $res[$report]['cmd'] = file_get_contents($cmdFile); 337 | } 338 | 339 | $cmdManuelleFile = $this->reportPath.'/'.$report.'/cmdManuelle.txt'; 340 | $res[$report]['cmdManuelle'] = ''; 341 | if (file_exists($cmdManuelleFile)) { 342 | $res[$report]['cmdManuelle'] = file_get_contents($cmdManuelleFile); 343 | } 344 | 345 | if ($report == 'CS') { 346 | $cmdRepFile = $this->reportPath.'/'.$report.'/cmdRep.txt'; 347 | $res[$report]['cmdRep'] = ''; 348 | if (file_exists($cmdRepFile)) { 349 | $res[$report]['cmdRep'] = file_get_contents($cmdRepFile); 350 | } 351 | } 352 | } 353 | 354 | return $res; 355 | } 356 | 357 | /** 358 | * Retourn une tableau associatif avec les comptage de fichiers 359 | * 360 | * @return type 361 | */ 362 | protected function count() 363 | { 364 | $nbCSS = $this->getCountFile('nbCSS.txt'); 365 | $nbLibCSS = $this->getCountFile('nbLibCSS.txt'); 366 | $nbJS = $this->getCountFile('nbJS.txt'); 367 | $nbLibJS = $this->getCountFile('nbLibJS.txt'); 368 | 369 | $this->oAnalyze 370 | ->setNbDir($this->getCountFile('nbDossier.txt')) 371 | ->setNbBundles($this->getCountFile('nbBundle.txt')) 372 | ->setNbFile($this->getCountFile('nbFichier.txt')) 373 | ->setNbPhpFile($this->getCountFile('nbPHP.txt')) 374 | ->setNbTwig($this->getCountFile('nbTwig.txt')) 375 | ->setNbCSSFile($nbCSS - $nbLibCSS) 376 | ->setNbCSSLib($nbLibCSS) 377 | ->setNbJSFile($nbJS - $nbLibJS) 378 | ->setNbJSLib($nbLibJS); 379 | } 380 | 381 | /** 382 | * Extract info from phploc report 383 | * @param type $param 384 | * @return type 385 | */ 386 | protected function extractFromLoc($param) 387 | { 388 | return $this->extractFromXmlReport($param, '/LOC/phploc.xml'); 389 | } 390 | 391 | /** 392 | * Recupere le contenu d'un count file 393 | * @param type $file 394 | * @return type 395 | */ 396 | protected function getCountFile($file) 397 | { 398 | $txt = ''; 399 | $path = $this->reportPath.'/COUNT/'.$file; 400 | if (file_exists($path)) { 401 | $txt = file_get_contents($path); 402 | } 403 | 404 | return trim($txt); 405 | } 406 | 407 | /** 408 | * Renvoi la date de derniere modif du fichier 409 | * 410 | * @param type $file 411 | * 412 | * @return string 413 | */ 414 | protected function getDateGeneration($file) 415 | { 416 | if (file_exists($file)) { 417 | return $this->translator->trans('details.generatedOn').' '.$this->getReadableDateTime(filemtime($file)); 418 | } 419 | 420 | return $this->translator->trans('details.notGenerated'); 421 | } 422 | 423 | /** 424 | * Analysis un rapport 425 | * 426 | * @param type $prefix 427 | * @param type $goodIfEmpty 428 | * @param type $goodIfContains 429 | * 430 | * @return type 431 | */ 432 | protected function analyzeReport($prefix, $goodIfEmpty = true, $goodIfContains = '') 433 | { 434 | $res = []; 435 | $txt = ''; 436 | $report = $this->reportPath.'/'.$prefix.'/report.txt'; 437 | if (file_exists($report)) { 438 | $txt = trim(file_get_contents($report)); 439 | } 440 | 441 | $res[$prefix] = ['report' => $txt, 'summary' => 'ko']; 442 | 443 | if (($goodIfEmpty && $txt == '') || (!empty($goodIfContains) && strpos($txt, $goodIfContains) !== false)) { 444 | $res[$prefix]['summary'] = 'ok'; 445 | } 446 | 447 | // cas particulier de mess detector 448 | if ($prefix == 'MD') { 449 | $res['cc10'] = substr_count($txt, 'has a Cyclomatic Complexity of'); 450 | } 451 | 452 | return $res; 453 | } 454 | 455 | /** 456 | * Extrait une info d'un xml et la renvoi 457 | * 458 | * @param string $cle balise xml recherchee 459 | * @param string $reportFilePath chemin à l'intéreur du dossier report 460 | * 461 | * @return string 462 | */ 463 | protected function extractFromXmlReport($cle, $reportFilePath) 464 | { 465 | $file = $this->reportPath.$reportFilePath; 466 | if (file_exists($file)) { 467 | $xml = simplexml_load_file($file); 468 | 469 | return $xml->$cle; 470 | } 471 | 472 | return ''; 473 | } 474 | 475 | /** 476 | * Lit la date et le temps d'execution de l'analyse 477 | */ 478 | protected function setAnalysisTimeInfo() 479 | { 480 | $file = $this->dirRoot.'/jetons/timeAnalyse'; 481 | if (file_exists($file)) { 482 | $this->oAnalyze 483 | ->setDateTime(filemtime($file)) 484 | ->setExecTime((int) file_get_contents($file)); 485 | } 486 | } 487 | 488 | protected static function findAtoumRunningDuration(array $lines) 489 | { 490 | foreach ($lines as $index => $line) { 491 | if (strpos($line, 'Running duration:')) { 492 | return $index; 493 | } 494 | } 495 | 496 | return false; 497 | } 498 | } 499 | -------------------------------------------------------------------------------- /Manager/ScriptManager.php: -------------------------------------------------------------------------------- 1 | dirRoot = $rootDir.'/web/ppa/'; 32 | $this->dirBin = $rootDir.'/bin/'; 33 | $this->jetonAnalysePath = $this->dirRoot.'/jetons/jetonAnalyse'; 34 | $this->shDirPath = $this->dirRoot.'/sh'; 35 | 36 | $reflClass = new \ReflectionClass(get_class($this)); 37 | $this->tplShDirPath = dirname($reflClass->getFileName()).'/../Resources/sh'; 38 | 39 | $this->parameters = $configGlobale; 40 | } 41 | 42 | /** 43 | * Lance le shell d'analyse en tache de fond 44 | * 45 | * @return string état lisible de l'analyse 46 | */ 47 | public function lancerAnalyse() 48 | { 49 | // si une analyse est en cours on dégage 50 | if (file_exists($this->jetonAnalysePath)) { 51 | return 'Analyse en cours'; 52 | } 53 | 54 | // si on demande ou on en est et qu'on s'est pas encore fait degagé alors c fini 55 | if (filter_input(INPUT_GET, 'statut') == 1) { 56 | return 'ok'; 57 | } 58 | 59 | // si on arrive là on doit lancer l'analyse selon la config 60 | $this->paShPath = $this->shDirPath.'/pa.sh'; 61 | $this->createAnalysis(); 62 | 63 | // lancement unitaire : le sh à lancer n'est pas la meme 64 | if (filter_input(INPUT_POST, 'one') != '') { 65 | $this->paShPath = $this->dirRoot.'/sh/one/'.filter_input(INPUT_POST, 'one').'.sh'; 66 | } 67 | 68 | // on vérifie qu'on peut executer le sh 69 | if (!is_executable($this->paShPath)) { 70 | chmod($this->paShPath, 0777); 71 | if (!is_executable($this->paShPath)) { 72 | return basename($this->paShPath).' non executable'; 73 | } 74 | } 75 | 76 | // on init le text de feedback 77 | $txt = 'Analyse '; 78 | 79 | // on init la commande 80 | $cmd = $this->paShPath; 81 | 82 | // l'option de generation de doc est débrailler pour le moment 83 | if (filter_input(INPUT_POST, 'genDoc') == 1) { 84 | $cmd .= ' -d '; 85 | $txt .= ' avec génération de doc '; 86 | } 87 | 88 | // on gere l'option du code coverage 89 | if (filter_input(INPUT_POST, 'genCC') == 1) { 90 | $cmd .= ' -c '; 91 | $txt .= 'avec code coverage'; 92 | } 93 | 94 | // on lance l'analyse, c'est à dire le sh 95 | exec('nohup '.$cmd.' > '.$this->dirRoot.'/jetons/output.log 2> '.$this->dirRoot.'/jetons/error.log &'); 96 | 97 | return $txt.' lancée ('.$cmd.')'; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Php Project Analyzer Bundle 2 | 3 | Gives you consolidated views of analysis results. 4 | 5 | 6 | [![Build Status](https://travis-ci.org/jdlabails/PhpProjectAnalyzerBundle.svg?branch=master)](https://travis-ci.org/jdlabails/PhpProjectAnalyzerBundle) 7 | [![Total Downloads](https://poser.pugx.org/jdlabails/php-project-analyzer-bundle/d/total.png)](https://packagist.org/packages/jdlabails/php-project-analyzer-bundle) 8 | [![Latest Stable Version](https://poser.pugx.org/jdlabails/php-project-analyzer-bundle/v/stable.png)](https://packagist.org/packages/jdlabails/php-project-analyzer-bundle) 9 | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/3b03dad9-01a6-4d9e-8cb5-72a2fc8190dc/mini.png)](https://insight.sensiolabs.com/projects/3b03dad9-01a6-4d9e-8cb5-72a2fc8190dc) 10 | 11 | 12 | It give a view like : 13 | 14 | ![](https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/master/ppaIndex.png) 15 | 16 | 17 | ### Features 18 | - Aggregate php analysis metrics 19 | - Offer user-friendly interface 20 | - Execute quick scan of your project 21 | - English or French interfaces 22 | - Links with code coverage report 23 | - Scoring based on quantity and quality metrics 24 | - Enable PhpUnit or Atoum unit tests 25 | - Security checker available 26 | 27 | 28 | It executes 29 | - Php Mess Detector 30 | - Php Unit Tests 31 | - Atoum tests 32 | - Php Code Sniffer ( + reparation tool via phpcbf) 33 | - Copy-paste detector 34 | - Php Depend 35 | - Php Loc 36 | 37 | And parses their report to give a nice view for rapid analysis of your project. 38 | 39 | ### Install 40 | - composer require jdlabails/php-project-analyzer-bundle --dev 41 | - add bundle to kernel 42 | ```php 43 | /* app/AppKernel.php */ 44 | public function registerBundles() 45 | { 46 | // ... 47 | $bundles[] = new JD\PhpProjectAnalyzerBundle\JDPhpProjectAnalyzerBundle(); 48 | // ... 49 | } 50 | ``` 51 | - Add routing 52 | ```yaml 53 | # app/config/routing.yml 54 | ppa: 55 | resource: '@JDPhpProjectAnalyzerBundle/Resources/config/routing.yml' 56 | ``` 57 | - Add security exception 58 | ```yaml 59 | access_control: 60 | # PPA 61 | - { path: "^(/[a-z]{2})?/ppa(/[a-z]*)?", roles: IS_AUTHENTICATED_ANONYMOUSLY } 62 | ``` 63 | 64 | - Set your config 65 | 66 | ```yml 67 | framework: 68 | translator: { fallback: %locale% } 69 | 70 | jd_php_project_analyzer: 71 | title: Php project analyzer 72 | description: It's a ouaaaouhh project ! 73 | 74 | gitRepositoryURL: https://github.com/jdlabails/PhpProjectAnalyzerBundle 75 | 76 | # directory to analyze 77 | srcPath : /home/jd/Dev/ppa/src/JD 78 | 79 | # quantitative metric 80 | count : true 81 | 82 | # quality metric : copy-paste 83 | cpd : true 84 | 85 | # quality metric : code sniffer 86 | cs : 87 | enable: true 88 | standard: PSR2 89 | 90 | # security checker 91 | security: true 92 | 93 | # quality metric : phpdepend 94 | depend : true 95 | 96 | # quality metric : phploc 97 | loc : true 98 | 99 | # quality metric : mess detector 100 | md : 101 | enable: true 102 | rules: 103 | cleancode: true 104 | codesize: true 105 | controversial: true 106 | design: true 107 | naming: true 108 | unusedcode: true 109 | 110 | # generate phpdoc 111 | docs : true 112 | 113 | # testing 114 | test : 115 | enable: false 116 | lib : phpunit # phpunit || atoum 117 | phpunitTestSuite : ppa 118 | # atoumPath : /home/smith/www/projectX/vendor/bin/atoum 119 | # atoumTestDir : /absolute/path/to/your/test/dir 120 | 121 | # score 122 | score: 123 | enable: true 124 | csWeight: 100 # between 0 and 100, weighting of code sniffer 125 | testWeight: 100 # between 0 and 100, weighting of testing 126 | locWeight: 100 # between 0 and 100, weighting of code coverage 127 | 128 | ``` 129 | 130 | 131 | - Set assets 132 | ```bash 133 | php app/console assets:install 134 | ``` 135 | 136 | - Set right for ppa directory in the web directory 137 | ```bash 138 | sudo php app/console ppa:init 139 | ``` 140 | 141 | - Add web/ppa in your .gitignore 142 | 143 | ### Use 144 | - Call http://127.0.0.1:8000/en/ppa with your nav. 145 | - Click on 'Start Scan' 146 | 147 | 148 | ### update your phar 149 | 150 | ```bash 151 | cd Resources/_phar 152 | chmod +x update.sh 153 | ./update.sh 154 | ``` 155 | 156 | ### Commands available 157 | 158 | ppa:analyse:launch ==> launch analysis without web interface 159 | ppa:analyse:read ==> read analysis without web interface. The result is in json 160 | 161 | ### Need contributions 162 | 163 | Examples : 164 | * avoid phar files for dependencies symfony 165 | * refacto code 166 | * unit tests 167 | * download security checker at each scan 168 | * behat 169 | 170 | Just make a pull request on master 171 | 172 | ##### Check style 173 | ```bash 174 | bin/phpcs --standard=PSR2 --extensions=php Entities Manager Command Controller DependencyInjection Traits 175 | ``` 176 | 177 | ##### Unit Tests 178 | ```bash 179 | bin/simple-phpunit -c phpunit.xml 180 | ``` 181 | 182 | ##### Tip for local project 183 | Put in your composer.json 184 | 185 | ```json 186 | "minimum-stability": "dev", 187 | "prefer-stable": true, 188 | "repositories": [ 189 | { 190 | "type": "path", 191 | "url": "/path/to/your/project/dir/jdlabails-php-project-analyzer-bundle/" 192 | } 193 | ], 194 | ``` 195 | -------------------------------------------------------------------------------- /Resources/_phar/CodeSniffer.conf: -------------------------------------------------------------------------------- 1 | '/home/jd/Projets/jdlabails-php-project-analyzer-bundle/Traits/../Resources/_phar/csStandard/', 4 | 'Symfony2' => '/csStandard/Symfony2/', 5 | ) 6 | ?> -------------------------------------------------------------------------------- /Resources/_phar/atoum.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/_phar/atoum.phar -------------------------------------------------------------------------------- /Resources/_phar/behat.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/_phar/behat.phar -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Arrays/MultiLineArrayCommaSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony2-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony2_Sniffs_WhiteSpace_MultiLineArrayCommaSniff. 17 | * 18 | * Throws warnings if the last item in a multi line array does not have a 19 | * trailing comma 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony2 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_Arrays_MultiLineArrayCommaSniff 28 | implements PHP_CodeSniffer_Sniff 29 | { 30 | /** 31 | * A list of tokenizers this sniff supports. 32 | * 33 | * @var array 34 | */ 35 | public $supportedTokenizers = array( 36 | 'PHP', 37 | ); 38 | 39 | /** 40 | * Returns an array of tokens this test wants to listen for. 41 | * 42 | * @return array 43 | */ 44 | public function register() 45 | { 46 | return array( 47 | T_ARRAY, 48 | T_OPEN_SHORT_ARRAY, 49 | ); 50 | 51 | }//end register() 52 | 53 | /** 54 | * Processes this test, when one of its tokens is encountered. 55 | * 56 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 57 | * @param int $stackPtr The position of the current token 58 | * in the stack passed in $tokens. 59 | * 60 | * @return void 61 | */ 62 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 63 | { 64 | $tokens = $phpcsFile->getTokens(); 65 | $open = $tokens[$stackPtr]; 66 | 67 | if ($open['code'] === T_ARRAY) { 68 | $closePtr = $open['parenthesis_closer']; 69 | } else { 70 | $closePtr = $open['bracket_closer']; 71 | } 72 | 73 | if ($open['line'] <> $tokens[$closePtr]['line']) { 74 | $lastComma = $phpcsFile->findPrevious(T_COMMA, $closePtr); 75 | 76 | while ($lastComma < $closePtr -1) { 77 | $lastComma++; 78 | 79 | if ($tokens[$lastComma]['code'] !== T_WHITESPACE 80 | && $tokens[$lastComma]['code'] !== T_COMMENT 81 | ) { 82 | $phpcsFile->addError( 83 | 'Add a comma after each item in a multi-line array', 84 | $stackPtr, 85 | 'Invalid' 86 | ); 87 | break; 88 | } 89 | } 90 | } 91 | 92 | }//end process() 93 | 94 | }//end class 95 | 96 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Classes/MultipleClassesOneFileSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_Classes_MultipleClassesOneFileSniff. 18 | * 19 | * Throws errors if multiple classes are defined in a single file. 20 | * 21 | * Symfony coding standard specifies: "Define one class per file;" 22 | * 23 | * @category PHP 24 | * @package PHP_CodeSniffer-Symfony2 25 | * @author Dave Hauenstein 26 | * @license http://spdx.org/licenses/MIT MIT License 27 | * @link https://github.com/escapestudios/Symfony2-coding-standard 28 | */ 29 | class Symfony2_Sniffs_Classes_MultipleClassesOneFileSniff implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * The number of times the T_CLASS token is encountered in the file. 33 | * 34 | * @var int 35 | */ 36 | protected $classCount = 0; 37 | 38 | /** 39 | * The current file this class is operating on. 40 | * 41 | * @var string 42 | */ 43 | protected $currentFile; 44 | 45 | /** 46 | * A list of tokenizers this sniff supports. 47 | * 48 | * @var array 49 | */ 50 | public $supportedTokenizers = array( 51 | 'PHP', 52 | ); 53 | 54 | /** 55 | * Returns an array of tokens this test wants to listen for. 56 | * 57 | * @return array 58 | */ 59 | public function register() 60 | { 61 | return array(T_CLASS); 62 | } 63 | 64 | /** 65 | * Processes this test, when one of its tokens is encountered. 66 | * 67 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 68 | * @param int $stackPtr The position of the current token in 69 | * the stack passed in $tokens. 70 | * 71 | * @return void 72 | */ 73 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 74 | { 75 | if ($this->currentFile !== $phpcsFile->getFilename()) { 76 | $this->classCount = 0; 77 | $this->currentFile = $phpcsFile->getFilename(); 78 | } 79 | 80 | $this->classCount++; 81 | 82 | if ($this->classCount > 1) { 83 | $phpcsFile->addError( 84 | 'Multiple classes defined in a single file', 85 | $stackPtr 86 | ); 87 | } 88 | 89 | return; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Classes/PropertyDeclarationSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_Classes_PropertyDeclarationSniff. 18 | * 19 | * Throws warnings if properties are declared after methods 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony2 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_Classes_PropertyDeclarationSniff implements PHP_CodeSniffer_Sniff 28 | { 29 | 30 | /** 31 | * A list of tokenizers this sniff supports. 32 | * 33 | * @var array 34 | */ 35 | public $supportedTokenizers = array( 36 | 'PHP', 37 | ); 38 | 39 | /** 40 | * Returns an array of tokens this test wants to listen for. 41 | * 42 | * @return array 43 | */ 44 | public function register() 45 | { 46 | return array( 47 | T_CLASS, 48 | ); 49 | }//end register() 50 | 51 | /** 52 | * Processes this test, when one of its tokens is encountered. 53 | * 54 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 55 | * @param int $stackPtr The position of the current token 56 | * in the stack passed in $tokens. 57 | * 58 | * @return void 59 | */ 60 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 61 | { 62 | $tokens = $phpcsFile->getTokens(); 63 | $scope = $phpcsFile->findNext(T_FUNCTION, $stackPtr, $tokens[$stackPtr]['scope_closer']); 64 | 65 | $wantedTokens = array( 66 | T_PUBLIC, 67 | T_PROTECTED, 68 | T_PRIVATE 69 | ); 70 | 71 | while ($scope) { 72 | $scope = $phpcsFile->findNext($wantedTokens, $scope + 1, $tokens[$stackPtr]['scope_closer']); 73 | 74 | if ($scope && $tokens[$scope + 2]['code'] === T_VARIABLE) { 75 | $phpcsFile->addError( 76 | 'Declare class properties before methods', 77 | $scope, 78 | 'Invalid' 79 | ); 80 | } 81 | } 82 | }//end process() 83 | 84 | }//end class 85 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Commenting/ClassCommentSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Marc McIntyre 11 | * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) 12 | * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence 13 | * @version CVS: $Id: ClassCommentSniff.php 301632 2010-07-28 01:57:56Z squiz $ 14 | * @link http://pear.php.net/package/PHP_CodeSniffer 15 | */ 16 | 17 | if (class_exists('PHP_CodeSniffer_Tokenizers_Comment', true) === false) { 18 | $error = 'Class PHP_CodeSniffer_Tokenizers_Comment not found'; 19 | throw new PHP_CodeSniffer_Exception($error); 20 | } 21 | 22 | if (class_exists('PEAR_Sniffs_Commenting_ClassCommentSniff', true) === false) { 23 | $error = 'Class PEAR_Sniffs_Commenting_ClassCommentSniff not found'; 24 | throw new PHP_CodeSniffer_Exception($error); 25 | } 26 | 27 | /** 28 | * Parses and verifies the doc comments for classes. 29 | * 30 | * Verifies that : 31 | *
    32 | *
  • A doc comment exists.
  • 33 | *
  • There is a blank newline after the short description.
  • 34 | *
  • There is a blank newline between the long and short description.
  • 35 | *
  • There is a blank newline between the long description and tags.
  • 36 | *
  • Check the order of the tags.
  • 37 | *
  • Check the indentation of each tag.
  • 38 | *
  • Check required and optional tags and the format of their content.
  • 39 | *
40 | * 41 | * @category PHP 42 | * @package PHP_CodeSniffer 43 | * @author Greg Sherwood 44 | * @author Marc McIntyre 45 | * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) 46 | * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence 47 | * @version Release: 1.3.0RC2 48 | * @link http://pear.php.net/package/PHP_CodeSniffer 49 | */ 50 | class Symfony2_Sniffs_Commenting_ClassCommentSniff extends PEAR_Sniffs_Commenting_ClassCommentSniff 51 | { 52 | /** 53 | * Tags in correct order and related info. 54 | * 55 | * @var array 56 | */ 57 | protected $tags = array( 58 | 'category' => array( 59 | 'required' => false, 60 | 'allow_multiple' => false, 61 | 'order_text' => 'precedes @package', 62 | ), 63 | 'package' => array( 64 | 'required' => false, 65 | 'allow_multiple' => false, 66 | 'order_text' => 'follows @category', 67 | ), 68 | 'subpackage' => array( 69 | 'required' => false, 70 | 'allow_multiple' => false, 71 | 'order_text' => 'follows @package', 72 | ), 73 | 'author' => array( 74 | 'required' => false, 75 | 'allow_multiple' => true, 76 | 'order_text' => 'follows @subpackage (if used) or @package', 77 | ), 78 | 'copyright' => array( 79 | 'required' => false, 80 | 'allow_multiple' => true, 81 | 'order_text' => 'follows @author', 82 | ), 83 | 'license' => array( 84 | 'required' => false, 85 | 'allow_multiple' => false, 86 | 'order_text' => 'follows @copyright (if used) or @author', 87 | ), 88 | 'version' => array( 89 | 'required' => false, 90 | 'allow_multiple' => false, 91 | 'order_text' => 'follows @license', 92 | ), 93 | 'link' => array( 94 | 'required' => false, 95 | 'allow_multiple' => true, 96 | 'order_text' => 'follows @version', 97 | ), 98 | 'see' => array( 99 | 'required' => false, 100 | 'allow_multiple' => true, 101 | 'order_text' => 'follows @link', 102 | ), 103 | 'since' => array( 104 | 'required' => false, 105 | 'allow_multiple' => false, 106 | 'order_text' => 'follows @see (if used) or @link', 107 | ), 108 | 'deprecated' => array( 109 | 'required' => false, 110 | 'allow_multiple' => false, 111 | 'order_text' => 'follows @since (if used) or @see (if used) or @link', 112 | ), 113 | ); 114 | } 115 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Commenting/FunctionCommentSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony2-coding-standard 13 | */ 14 | 15 | if (class_exists('PEAR_Sniffs_Commenting_FunctionCommentSniff', true) === false) { 16 | $error = 'Class PEAR_Sniffs_Commenting_FunctionCommentSniff not found'; 17 | throw new PHP_CodeSniffer_Exception($error); 18 | } 19 | 20 | /** 21 | * Symfony2 standard customization to PEARs FunctionCommentSniff. 22 | * 23 | * Verifies that : 24 | *
    25 | *
  • There is a @return tag if a return statement exists inside the method
  • 26 | *
27 | * 28 | * @category PHP 29 | * @package PHP_CodeSniffer 30 | * @author Felix Brandt 31 | * @license http://spdx.org/licenses/BSD-3-Clause BSD 3-clause "New" or "Revised" License 32 | * @link http://pear.php.net/package/PHP_CodeSniffer 33 | */ 34 | class Symfony2_Sniffs_Commenting_FunctionCommentSniff extends PEAR_Sniffs_Commenting_FunctionCommentSniff 35 | { 36 | 37 | /** 38 | * Processes this test, when one of its tokens is encountered. 39 | * 40 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 41 | * @param int $stackPtr The position of the current token 42 | * in the stack passed in $tokens. 43 | * 44 | * @return void 45 | */ 46 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 47 | { 48 | if (false === $commentEnd = $phpcsFile->findPrevious(array(T_COMMENT, T_DOC_COMMENT, T_CLASS, T_FUNCTION, T_OPEN_TAG), ($stackPtr - 1))) { 49 | return; 50 | } 51 | 52 | $tokens = $phpcsFile->getTokens(); 53 | $code = $tokens[$commentEnd]['code']; 54 | 55 | // a comment is not required on protected/private methods 56 | $method = $phpcsFile->getMethodProperties($stackPtr); 57 | $commentRequired = 'public' == $method['scope']; 58 | 59 | if (($code === T_COMMENT && !$commentRequired) 60 | || ($code !== T_DOC_COMMENT && !$commentRequired) 61 | ) { 62 | return; 63 | } 64 | 65 | parent::process($phpcsFile, $stackPtr); 66 | } 67 | 68 | /** 69 | * Process the return comment of this function comment. 70 | * 71 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 72 | * @param int $stackPtr The position of the current token 73 | * in the stack passed in $tokens. 74 | * @param int $commentStart The position in the stack where the comment started. 75 | * 76 | * @return void 77 | */ 78 | protected function processReturn(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart) 79 | { 80 | 81 | if ($this->isInheritDoc($phpcsFile, $stackPtr)) { 82 | return; 83 | } 84 | 85 | $tokens = $phpcsFile->getTokens(); 86 | 87 | // Only check for a return comment if a non-void return statement exists 88 | if (isset($tokens[$stackPtr]['scope_opener'])) { 89 | $start = $tokens[$stackPtr]['scope_opener']; 90 | 91 | // iterate over all return statements of this function, 92 | // run the check on the first which is not only 'return;' 93 | while ($returnToken = $phpcsFile->findNext(T_RETURN, $start, $tokens[$stackPtr]['scope_closer'])) { 94 | if ($this->isMatchingReturn($tokens, $returnToken)) { 95 | parent::processReturn($phpcsFile, $stackPtr, $commentStart); 96 | break; 97 | } 98 | $start = $returnToken + 1; 99 | } 100 | } 101 | 102 | } /* end processReturn() */ 103 | 104 | /** 105 | * Is the comment an inheritdoc? 106 | * 107 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 108 | * @param int $stackPtr The position of the current token 109 | * in the stack passed in $tokens. 110 | * 111 | * @return boolean True if the comment is an inheritdoc 112 | */ 113 | protected function isInheritDoc(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 114 | { 115 | $tokens = $phpcsFile->getTokens(); 116 | 117 | $start = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr - 1); 118 | $end = $phpcsFile->findNext(T_DOC_COMMENT_CLOSE_TAG, $start); 119 | 120 | $content = $phpcsFile->getTokensAsString($start, ($end - $start)); 121 | 122 | return preg_match('#{@inheritdoc}#i', $content) === 1; 123 | } // end isInheritDoc() 124 | 125 | /** 126 | * Process the function parameter comments. 127 | * 128 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 129 | * @param int $stackPtr The position of the current token 130 | * in the stack passed in $tokens. 131 | * @param int $commentStart The position in the stack where the comment started. 132 | * 133 | * @return void 134 | */ 135 | protected function processParams(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart) 136 | { 137 | $tokens = $phpcsFile->getTokens(); 138 | 139 | if ($this->isInheritDoc($phpcsFile, $stackPtr)) { 140 | return; 141 | } 142 | 143 | parent::processParams($phpcsFile, $stackPtr, $commentStart); 144 | } // end processParams() 145 | 146 | /** 147 | * Is the return statement matching? 148 | * 149 | * @param array $tokens Array of tokens 150 | * @param int $returnPos Stack position of the T_RETURN token to process 151 | * 152 | * @return boolean True if the return does not return anything 153 | */ 154 | protected function isMatchingReturn($tokens, $returnPos) 155 | { 156 | do { 157 | $returnPos++; 158 | } while ($tokens[$returnPos]['code'] === T_WHITESPACE); 159 | 160 | return $tokens[$returnPos]['code'] !== T_SEMICOLON; 161 | } 162 | 163 | }//end class 164 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Formatting/BlankLineBeforeReturnSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_Formatting_BlankLineBeforeReturnSniff. 18 | * 19 | * Throws errors if there's no blank line before return statements. Symfony 20 | * coding standard specifies: "Add a blank line before return statements, 21 | * unless the return is alone inside a statement-group (like an if statement);" 22 | * 23 | * @category PHP 24 | * @package PHP_CodeSniffer-Symfony2 25 | * @author Dave Hauenstein 26 | * @license http://spdx.org/licenses/MIT MIT License 27 | * @link https://github.com/escapestudios/Symfony2-coding-standard 28 | */ 29 | class Symfony2_Sniffs_Formatting_BlankLineBeforeReturnSniff implements PHP_CodeSniffer_Sniff 30 | { 31 | /** 32 | * A list of tokenizers this sniff supports. 33 | * 34 | * @var array 35 | */ 36 | public $supportedTokenizers = array( 37 | 'PHP', 38 | 'JS', 39 | ); 40 | 41 | /** 42 | * Returns an array of tokens this test wants to listen for. 43 | * 44 | * @return array 45 | */ 46 | public function register() 47 | { 48 | return array(T_RETURN); 49 | } 50 | 51 | /** 52 | * Processes this test, when one of its tokens is encountered. 53 | * 54 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 55 | * @param int $stackPtr The position of the current token in 56 | * the stack passed in $tokens. 57 | * 58 | * @return void 59 | */ 60 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 61 | { 62 | $tokens = $phpcsFile->getTokens(); 63 | $current = $stackPtr; 64 | $previousLine = $tokens[$stackPtr]['line'] - 1; 65 | $prevLineTokens = array(); 66 | 67 | while ($current >= 0 && $tokens[$current]['line'] >= $previousLine) { 68 | if ($tokens[$current]['line'] == $previousLine 69 | && $tokens[$current]['type'] !== 'T_WHITESPACE' 70 | && $tokens[$current]['type'] !== 'T_COMMENT' 71 | && $tokens[$current]['type'] !== 'T_DOC_COMMENT_CLOSE_TAG' 72 | && $tokens[$current]['type'] !== 'T_DOC_COMMENT_WHITESPACE' 73 | ) { 74 | $prevLineTokens[] = $tokens[$current]['type']; 75 | } 76 | $current--; 77 | } 78 | 79 | if (isset($prevLineTokens[0]) 80 | && ($prevLineTokens[0] === 'T_OPEN_CURLY_BRACKET' 81 | || $prevLineTokens[0] === 'T_COLON') 82 | ) { 83 | return; 84 | } else if (count($prevLineTokens) > 0) { 85 | $phpcsFile->addError( 86 | 'Missing blank line before return statement', 87 | $stackPtr 88 | ); 89 | } 90 | 91 | return; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Functions/ScopeOrderSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_Functions_ScopeOrderSniff. 18 | * 19 | * Throws warnings if properties are declared after methods 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony2 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_Functions_ScopeOrderSniff implements PHP_CodeSniffer_Sniff 28 | { 29 | 30 | /** 31 | * A list of tokenizers this sniff supports. 32 | * 33 | * @var array 34 | */ 35 | public $supportedTokenizers = array( 36 | 'PHP', 37 | ); 38 | 39 | /** 40 | * Returns an array of tokens this test wants to listen for. 41 | * 42 | * @return array 43 | */ 44 | public function register() 45 | { 46 | return array( 47 | T_CLASS, 48 | T_INTERFACE, 49 | ); 50 | }//end register() 51 | 52 | /** 53 | * Processes this test, when one of its tokens is encountered. 54 | * 55 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 56 | * @param int $stackPtr The position of the current token 57 | * in the stack passed in $tokens. 58 | * 59 | * @return void 60 | */ 61 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 62 | { 63 | $tokens = $phpcsFile->getTokens(); 64 | $function = $stackPtr; 65 | 66 | $scopes = array( 67 | 0 => T_PUBLIC, 68 | 1 => T_PROTECTED, 69 | 2 => T_PRIVATE, 70 | ); 71 | 72 | $whitelisted = array( 73 | '__construct', 74 | 'setUp', 75 | 'tearDown', 76 | ); 77 | 78 | while ($function) { 79 | $function = $phpcsFile->findNext(T_FUNCTION, $function + 1, $tokens[$stackPtr]['scope_closer']); 80 | 81 | if (isset($tokens[$function]['parenthesis_opener'])) { 82 | $scope = $phpcsFile->findPrevious($scopes, $function -1, $stackPtr); 83 | $name = $phpcsFile->findNext(T_STRING, $function + 1, $tokens[$function]['parenthesis_opener']); 84 | 85 | if ($scope && $name && !in_array($tokens[$name]['content'], $whitelisted)) { 86 | $current = array_keys($scopes, $tokens[$scope]['code']); 87 | $current = $current[0]; 88 | 89 | if (isset($previous) && $current < $previous) { 90 | $phpcsFile->addError( 91 | 'Declare public methods first, then protected ones and finally private ones', 92 | $scope, 93 | 'Invalid' 94 | ); 95 | } 96 | 97 | $previous = $current; 98 | } 99 | } 100 | } 101 | }//end process() 102 | 103 | }//end class 104 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/NamingConventions/ValidClassNameSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony2-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony2_Sniffs_NamingConventions_ValidClassNameSniff. 17 | * 18 | * Throws errors if symfony's naming conventions are not met. 19 | * 20 | * @category PHP 21 | * @package PHP_CodeSniffer-Symfony2 22 | * @author Dave Hauenstein 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_NamingConventions_ValidClassNameSniff implements PHP_CodeSniffer_Sniff 28 | { 29 | /** 30 | * A list of tokenizers this sniff supports. 31 | * 32 | * @var array 33 | */ 34 | public $supportedTokenizers = array( 35 | 'PHP', 36 | ); 37 | 38 | /** 39 | * Returns an array of tokens this test wants to listen for. 40 | * 41 | * @return array 42 | */ 43 | public function register() 44 | { 45 | return array( 46 | T_INTERFACE, 47 | T_TRAIT, 48 | T_EXTENDS, 49 | T_ABSTRACT 50 | ); 51 | } 52 | 53 | /** 54 | * Processes this test, when one of its tokens is encountered. 55 | * 56 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 57 | * @param int $stackPtr The position of the current token in 58 | * the stack passed in $tokens. 59 | * 60 | * @return void 61 | */ 62 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 63 | { 64 | $tokens = $phpcsFile->getTokens(); 65 | $line = $tokens[$stackPtr]['line']; 66 | 67 | while ($tokens[$stackPtr]['line'] == $line) { 68 | 69 | /* 70 | * Suffix interfaces with Interface; 71 | */ 72 | if ('T_INTERFACE' == $tokens[$stackPtr]['type']) { 73 | $name = $phpcsFile->findNext(T_STRING, $stackPtr); 74 | 75 | if ($name && substr($tokens[$name]['content'], -9) != 'Interface') { 76 | $phpcsFile->addError( 77 | 'Interface name is not suffixed with "Interface"', 78 | $stackPtr, 79 | 'Invalid' 80 | ); 81 | } 82 | break; 83 | } 84 | 85 | /* 86 | * Suffix traits with Trait; 87 | */ 88 | if ('T_TRAIT' == $tokens[$stackPtr]['type']) { 89 | $name = $phpcsFile->findNext(T_STRING, $stackPtr); 90 | 91 | if ($name && substr($tokens[$name]['content'], -5) != 'Trait') { 92 | $phpcsFile->addError( 93 | 'Trait name is not suffixed with "Trait"', 94 | $stackPtr, 95 | 'Invalid' 96 | ); 97 | } 98 | break; 99 | } 100 | 101 | /* 102 | * Suffix exceptions with Exception; 103 | */ 104 | if ('T_EXTENDS' == $tokens[$stackPtr]['type']) { 105 | $extend = $phpcsFile->findNext(T_STRING, $stackPtr); 106 | 107 | if ($extend && substr($tokens[$extend]['content'], -9) == 'Exception') { 108 | $class = $phpcsFile->findPrevious(T_CLASS, $stackPtr); 109 | $name = $phpcsFile->findNext(T_STRING, $class); 110 | 111 | if ($name && substr($tokens[$name]['content'], -9) != 'Exception') { 112 | $phpcsFile->addError( 113 | 'Exception name is not suffixed with "Exception"', 114 | $stackPtr, 115 | 'Invalid' 116 | ); 117 | } 118 | } 119 | break; 120 | } 121 | 122 | /* 123 | * Prefix abstract classes with Abstract. 124 | */ 125 | if ('T_ABSTRACT' == $tokens[$stackPtr]['type']) { 126 | $name = $phpcsFile->findNext(T_STRING, $stackPtr); 127 | $function = $phpcsFile->findNext(T_FUNCTION, $stackPtr); 128 | 129 | // making sure we're not dealing with an abstract function 130 | if ($name && (is_null($function) || $name < $function) && substr($tokens[$name]['content'], 0, 8) != 'Abstract') { 131 | $phpcsFile->addError( 132 | 'Abstract class name is not prefixed with "Abstract"', 133 | $stackPtr, 134 | 'Invalid' 135 | ); 136 | } 137 | break; 138 | } 139 | 140 | $stackPtr++; 141 | } 142 | 143 | return; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Objects/ObjectInstantiationSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_Objects_ObjectInstantiationSniff. 18 | * 19 | * Throws a warning if an object isn't instantiated using parenthesis. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony2 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_Objects_ObjectInstantiationSniff implements PHP_CodeSniffer_Sniff 28 | { 29 | /** 30 | * A list of tokenizers this sniff supports. 31 | * 32 | * @var array 33 | */ 34 | public $supportedTokenizers = array( 35 | 'PHP', 36 | ); 37 | 38 | 39 | /** 40 | * Returns an array of tokens this test wants to listen for. 41 | * 42 | * @return array 43 | */ 44 | public function register() 45 | { 46 | return array( 47 | T_NEW, 48 | ); 49 | 50 | }//end register() 51 | 52 | /** 53 | * Processes this test, when one of its tokens is encountered. 54 | * 55 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 56 | * @param int $stackPtr The position of the current token 57 | * in the stack passed in $tokens. 58 | * 59 | * @return void 60 | */ 61 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 62 | { 63 | $tokens = $phpcsFile->getTokens(); 64 | $allowed = array( 65 | T_STRING, 66 | T_NS_SEPARATOR, 67 | T_VARIABLE, 68 | ); 69 | 70 | $object = $stackPtr; 71 | $line = $tokens[$object]['line']; 72 | 73 | while ($object && $tokens[$object]['line'] === $line) { 74 | $object = $phpcsFile->findNext($allowed, $object + 1); 75 | 76 | if ($tokens[$object]['line'] === $line && !in_array($tokens[$object + 1]['code'], $allowed)) { 77 | if ($tokens[$object + 1]['code'] !== T_OPEN_PARENTHESIS) { 78 | $phpcsFile->addError( 79 | 'Use parentheses when instantiating classes', 80 | $stackPtr, 81 | 'Invalid' 82 | ); 83 | } 84 | 85 | break; 86 | } 87 | } 88 | 89 | }//end process() 90 | 91 | }//end class 92 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/Scope/MethodScopeSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Marc McIntyre 11 | * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) 12 | * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence 13 | * @version CVS: $Id: MethodScopeSniff.php 301632 2010-07-28 01:57:56Z squiz $ 14 | * @link http://pear.php.net/package/PHP_CodeSniffer 15 | */ 16 | 17 | if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { 18 | throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); 19 | } 20 | 21 | /** 22 | * Verifies that class members have scope modifiers. 23 | * 24 | * @category PHP 25 | * @package PHP_CodeSniffer 26 | * @author Greg Sherwood 27 | * @author Marc McIntyre 28 | * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) 29 | * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence 30 | * @version Release: 1.3.0 31 | * @link http://pear.php.net/package/PHP_CodeSniffer 32 | */ 33 | class Symfony2_Sniffs_Scope_MethodScopeSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff 34 | { 35 | /** 36 | * Constructs a Symfony2_Sniffs_Scope_MethodScopeSniff. 37 | */ 38 | public function __construct() 39 | { 40 | parent::__construct(array(T_CLASS), array(T_FUNCTION)); 41 | 42 | }//end __construct() 43 | 44 | /** 45 | * Processes the function tokens within the class. 46 | * 47 | * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. 48 | * @param int $stackPtr The position where the token was found. 49 | * @param int $currScope The current scope opener token. 50 | * 51 | * @return void 52 | */ 53 | protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) 54 | { 55 | $tokens = $phpcsFile->getTokens(); 56 | 57 | $methodName = $phpcsFile->getDeclarationName($stackPtr); 58 | if ($methodName === null) { 59 | // Ignore closures. 60 | return; 61 | } 62 | 63 | $modifier = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$scopeModifiers, $stackPtr); 64 | if (($modifier === false) || ($tokens[$modifier]['line'] !== $tokens[$stackPtr]['line'])) { 65 | $error = 'No scope modifier specified for function "%s"'; 66 | $data = array($methodName); 67 | $phpcsFile->addError($error, $stackPtr, 'Missing', $data); 68 | } 69 | 70 | }//end processTokenWithinScope() 71 | }//end class 72 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/WhiteSpace/AssignmentSpacingSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_WhiteSpace_AssignmentSpacingSniff. 18 | * 19 | * Throws warnings if an assignement operator isn't surrounded with whitespace. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony2 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_WhiteSpace_AssignmentSpacingSniff implements PHP_CodeSniffer_Sniff 28 | { 29 | /** 30 | * A list of tokenizers this sniff supports. 31 | * 32 | * @var array 33 | */ 34 | public $supportedTokenizers = array( 35 | 'PHP', 36 | ); 37 | 38 | /** 39 | * Returns an array of tokens this test wants to listen for. 40 | * 41 | * @return array 42 | */ 43 | public function register() 44 | { 45 | return PHP_CodeSniffer_Tokens::$assignmentTokens; 46 | 47 | }//end register() 48 | 49 | /** 50 | * Processes this test, when one of its tokens is encountered. 51 | * 52 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 53 | * @param int $stackPtr The position of the current token 54 | * in the stack passed in $tokens. 55 | * 56 | * @return void 57 | */ 58 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 59 | { 60 | $tokens = $phpcsFile->getTokens(); 61 | 62 | if ($tokens[$stackPtr -1]['code'] !== T_WHITESPACE || $tokens[$stackPtr +1]['code'] !== T_WHITESPACE) { 63 | $phpcsFile->addError( 64 | 'Add a single space around assignement operators', 65 | $stackPtr, 66 | 'Invalid' 67 | ); 68 | } 69 | }//end process() 70 | 71 | }//end class 72 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/WhiteSpace/BinaryOperatorSpacingSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_WhiteSpace_BinaryOperatorSpacingSniff. 18 | * 19 | * Throws warnings if a binary operator isn't surrounded with whitespace. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony2 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_WhiteSpace_BinaryOperatorSpacingSniff 28 | { 29 | /** 30 | * A list of tokenizers this sniff supports. 31 | * 32 | * @var array 33 | */ 34 | public $supportedTokenizers = array( 35 | 'PHP', 36 | ); 37 | 38 | /** 39 | * Returns an array of tokens this test wants to listen for. 40 | * 41 | * @return array 42 | */ 43 | public function register() 44 | { 45 | return PHP_CodeSniffer_Tokens::$comparisonTokens; 46 | 47 | }//end register() 48 | 49 | /** 50 | * Processes this test, when one of its tokens is encountered. 51 | * 52 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 53 | * @param int $stackPtr The position of the current token 54 | * in the stack passed in $tokens. 55 | * 56 | * @return void 57 | */ 58 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 59 | { 60 | $tokens = $phpcsFile->getTokens(); 61 | 62 | if ($tokens[$stackPtr -1]['code'] !== T_WHITESPACE || $tokens[$stackPtr +1]['code'] !== T_WHITESPACE) { 63 | $phpcsFile->addError( 64 | 'Add a single space around binary operators', 65 | $stackPtr, 66 | 'Invalid' 67 | ); 68 | } 69 | }//end process() 70 | 71 | }//end class 72 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/WhiteSpace/CommaSpacingSniff.php: -------------------------------------------------------------------------------- 1 | 11 | * @license http://spdx.org/licenses/MIT MIT License 12 | * @version GIT: master 13 | * @link https://github.com/escapestudios/Symfony2-coding-standard 14 | */ 15 | 16 | /** 17 | * Symfony2_Sniffs_WhiteSpace_CommaSpacingSniff. 18 | * 19 | * Throws warnings if comma isn't followed by a whitespace. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer-Symfony2 23 | * @author wicliff wolda 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Sniffs_WhiteSpace_CommaSpacingSniff implements PHP_CodeSniffer_Sniff 28 | { 29 | /** 30 | * A list of tokenizers this sniff supports. 31 | * 32 | * @var array 33 | */ 34 | public $supportedTokenizers = array( 35 | 'PHP', 36 | ); 37 | 38 | 39 | /** 40 | * Returns an array of tokens this test wants to listen for. 41 | * 42 | * @return array 43 | */ 44 | public function register() 45 | { 46 | return array( 47 | T_COMMA, 48 | ); 49 | 50 | }//end register() 51 | 52 | /** 53 | * Processes this test, when one of its tokens is encountered. 54 | * 55 | * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 56 | * @param int $stackPtr The position of the current token 57 | * in the stack passed in $tokens. 58 | * 59 | * @return void 60 | */ 61 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 62 | { 63 | $tokens = $phpcsFile->getTokens(); 64 | $line = $tokens[$stackPtr]['line']; 65 | 66 | if ($tokens[$stackPtr + 1]['line'] === $line && $tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) { 67 | $phpcsFile->addError( 68 | 'Add a single space after each comma delimiter', 69 | $stackPtr, 70 | 'Invalid' 71 | ); 72 | } 73 | 74 | }//end process() 75 | 76 | }//end class 77 | 78 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Sniffs/WhiteSpace/DiscourageFitzinatorSniff.php: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony2-coding-standard 13 | */ 14 | 15 | /** 16 | * Symfony2_Sniffs_WhiteSpace_DiscourageFitzinatorSniff. 17 | * 18 | * Throws warnings if a file contains trailing whitespace. 19 | * 20 | * @category PHP 21 | * @package PHP_CodeSniffer-Symfony2 22 | * @author Justin Hileman 23 | * @license http://spdx.org/licenses/MIT MIT License 24 | * @link https://github.com/escapestudios/Symfony2-coding-standard 25 | */ 26 | class Symfony2_Sniffs_WhiteSpace_DiscourageFitzinatorSniff implements PHP_CodeSniffer_Sniff 27 | { 28 | 29 | /** 30 | * A list of tokenizers this sniff supports. 31 | * 32 | * @var array 33 | */ 34 | public $supportedTokenizers = array( 35 | 'PHP', 36 | 'JS', 37 | 'CSS', 38 | ); 39 | 40 | 41 | /** 42 | * Returns an array of tokens this test wants to listen for. 43 | * 44 | * @return array 45 | */ 46 | public function register() 47 | { 48 | return array(T_WHITESPACE); 49 | 50 | } 51 | 52 | 53 | /** 54 | * Processes this test, when one of its tokens is encountered. 55 | * 56 | * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 57 | * @param int $stackPtr The position of the current token in 58 | * the stack passed in $tokens. 59 | * 60 | * @return void 61 | */ 62 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 63 | { 64 | $tokens = $phpcsFile->getTokens(); 65 | 66 | // Make sure this is trailing whitespace. 67 | $line = $tokens[$stackPtr]['line']; 68 | if (($stackPtr < count($tokens) - 1) && $tokens[($stackPtr + 1)]['line'] === $line) { 69 | return; 70 | } 71 | 72 | if (strpos($tokens[$stackPtr]['content'], "\n") > 0 || strpos($tokens[$stackPtr]['content'], "\r") > 0) { 73 | $warning = 'Please trim any trailing whitespace'; 74 | $phpcsFile->addWarning($warning, $stackPtr); 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Tests/Arrays/MultiLineArrayCommaUnitTest.inc: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony2-coding-standard 13 | */ 14 | 15 | /** 16 | * Unit test class for the MultiLineArrayComma sniff. 17 | * 18 | * A sniff unit test checks a .inc file for expected violations of a single 19 | * coding standard. Expected errors and warnings are stored in this class. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer 23 | * @author Craige leeder 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | class Symfony2_Tests_Arrays_MultiLineArrayCommaUnitTest extends AbstractSniffUnitTest 28 | { 29 | /** 30 | * Returns the lines where errors should occur. 31 | * 32 | * The key of the array should represent the line number and the value 33 | * should represent the number of errors that should occur on that line. 34 | * 35 | * @return array 36 | */ 37 | public function getErrorList() 38 | { 39 | return array( 40 | 11 => 1, 41 | 24 => 1, 42 | 37 => 1, 43 | 47 => 1, 44 | 60 => 1, 45 | 70 => 1, 46 | ); 47 | } 48 | 49 | /** 50 | * Returns the lines where warnings should occur. 51 | * 52 | * The key of the array should represent the line number and the value 53 | * should represent the number of errors that should occur on that line. 54 | * 55 | * @return array(int => int) 56 | */ 57 | public function getWarningList() 58 | { 59 | return array(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Tests/Formatting/BlankLineBeforeReturnUnitTest.inc: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony2-coding-standard 13 | */ 14 | 15 | /** 16 | * Unit test class for the BlankLineBeforeReturn sniff. 17 | * 18 | * A sniff unit test checks a .inc file for expected violations of a single 19 | * coding standard. Expected errors and warnings are stored in this class. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer 23 | * @author Tom Klingenberg 24 | * @copyright 2012 Tom Klingenberg, some rights reserved. 25 | * @license http://spdx.org/licenses/MIT MIT License 26 | * @link https://github.com/escapestudios/Symfony2-coding-standard 27 | */ 28 | class Symfony2_Tests_Formatting_BlankLineBeforeReturnUnitTest extends AbstractSniffUnitTest 29 | { 30 | /** 31 | * Returns the lines where errors should occur. 32 | * 33 | * The key of the array should represent the line number and the value 34 | * should represent the number of errors that should occur on that line. 35 | * 36 | * @return array(int => int) 37 | */ 38 | public function getErrorList() 39 | { 40 | return array( 41 | 37 => 1 42 | ); 43 | } 44 | 45 | /** 46 | * Returns the lines where warnings should occur. 47 | * 48 | * The key of the array should represent the line number and the value 49 | * should represent the number of errors that should occur on that line. 50 | * 51 | * @return array(int => int) 52 | */ 53 | public function getWarningList() 54 | { 55 | return array(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Tests/Objects/ObjectInstantiationUnitTest.inc: -------------------------------------------------------------------------------- 1 | foo); 15 | new Foo\Bar(); 16 | new Foo\Bar(true); 17 | new Foo\Bar($this->foo); 18 | new \Foo\Bar(); 19 | new \Foo\Bar(true); 20 | new \Foo\Bar($this->foo); 21 | new $foo(); 22 | new $foo(true); 23 | new $foo($this->foo); 24 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/Tests/Objects/ObjectInstantiationUnitTest.php: -------------------------------------------------------------------------------- 1 | 10 | * @license http://spdx.org/licenses/MIT MIT License 11 | * @version GIT: master 12 | * @link https://github.com/escapestudios/Symfony2-coding-standard 13 | */ 14 | 15 | /** 16 | * Unit test class for the ObjectInstantiation sniff. 17 | * 18 | * A sniff unit test checks a .inc file for expected violations of a single 19 | * coding standard. Expected errors and warnings are stored in this class. 20 | * 21 | * @category PHP 22 | * @package PHP_CodeSniffer 23 | * @author Roman Weich 24 | * @license http://spdx.org/licenses/MIT MIT License 25 | * @link https://github.com/escapestudios/Symfony2-coding-standard 26 | */ 27 | 28 | class Symfony2_Tests_Objects_ObjectInstantiationUnitTest extends AbstractSniffUnitTest 29 | { 30 | /** 31 | * Returns the lines where errors should occur. 32 | * 33 | * The key of the array should represent the line number and the value 34 | * should represent the number of errors that should occur on that line. 35 | * 36 | * @return array 37 | */ 38 | public function getErrorList() 39 | { 40 | return array( 41 | 4 => 1, 42 | 5 => 1, 43 | 6 => 1, 44 | 7 => 1, 45 | 8 => 1, 46 | ); 47 | } 48 | 49 | /** 50 | * Returns the lines where warnings should occur. 51 | * 52 | * The key of the array should represent the line number and the value 53 | * should represent the number of errors that should occur on that line. 54 | * 55 | * @return array(int => int) 56 | */ 57 | public function getWarningList() 58 | { 59 | return array(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Resources/_phar/csStandard/Symfony2/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | The Symfony2 coding standard. 4 | 5 | 6 | */Resources/* 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 0 69 | 70 | 71 | 72 | 73 | 0 74 | 75 | 76 | 77 | 78 | 0 79 | 80 | 81 | 0 82 | 83 | 84 | 0 85 | 86 | 87 | 88 | 0 89 | 90 | 91 | 92 | 0 93 | 94 | 95 | 96 | There should always be a description, followed by a blank line, before the tags of a class comment. 97 | 98 | 99 | -------------------------------------------------------------------------------- /Resources/_phar/phpunit.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/_phar/phpunit.phar -------------------------------------------------------------------------------- /Resources/_phar/security-checker.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/_phar/security-checker.phar -------------------------------------------------------------------------------- /Resources/_phar/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm phpDocumentor.phar 4 | wget http://www.phpdoc.org/phpDocumentor.phar 5 | 6 | rm phpmd.phar 7 | wget http://static.phpmd.org/php/latest/phpmd.phar 8 | 9 | #si php >= 5.6 telecharge la 5.2 sinon la 4.8 10 | rm phpunit.phar 11 | wget https://phar.phpunit.de/phpunit.phar 12 | 13 | #wget https://phar.phpunit.de/phpunit-old.phar 14 | 15 | rm behat.phar 16 | wget https://github.com/downloads/Behat/Behat/behat.phar 17 | 18 | rm security-checker.phar 19 | wget http://get.sensiolabs.org/security-checker.phar 20 | 21 | rm atoum.phar 22 | wget https://github.com/atoum/atoum/releases/download/3.2.0/atoum.phar 23 | -------------------------------------------------------------------------------- /Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | jd_php_project_analyzer_homepage: 2 | path: /{_locale}/ppa 3 | defaults: { _controller: JDPhpProjectAnalyzerBundle:Main:index } 4 | requirements: 5 | _locale: en|fr 6 | 7 | jd_php_project_analyzer_phpinfo: 8 | path: /ppa/phpinfo 9 | defaults: { _controller: JDPhpProjectAnalyzerBundle:Main:phpinfo } 10 | 11 | jd_php_project_analyzer_analyze: 12 | path: /ppa/analyze 13 | defaults: { _controller: JDPhpProjectAnalyzerBundle:Main:analyze } 14 | -------------------------------------------------------------------------------- /Resources/config/services.yml: -------------------------------------------------------------------------------- 1 | services: 2 | jd_ppa.projectAnalyzer: 3 | class: JD\PhpProjectAnalyzerBundle\Manager\ProjectAnalyzer 4 | arguments: [%jd.ppa.global%, "@translator", %kernel.root_dir%/../] 5 | 6 | jd_ppa.scriptManager: 7 | class: JD\PhpProjectAnalyzerBundle\Manager\ScriptManager 8 | arguments: [%jd.ppa.global%, %kernel.root_dir%/../] 9 | -------------------------------------------------------------------------------- /Resources/doc/index.rst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/doc/index.rst -------------------------------------------------------------------------------- /Resources/public/css/pa.css: -------------------------------------------------------------------------------- 1 | body{ 2 | font-size: 13px 3 | } 4 | 5 | h3{ 6 | margin-top: 0; 7 | } 8 | 9 | #encartResultat{ 10 | border-radius: 0.25em; 11 | color: #fff; 12 | font-size: 75%; 13 | font-weight: 700; 14 | line-height: 1.5; 15 | white-space: nowrap; 16 | padding:10px 30px 17 | } 18 | 19 | #encartResultat table{ 20 | width: 100%; 21 | border-collapse: collapse; 22 | } 23 | 24 | ul.metricDetail { 25 | margin-top: 9px; 26 | padding-left: 20px; 27 | display: none; 28 | } 29 | 30 | #encartResultat table td{ 31 | padding: 2px; 32 | } 33 | 34 | .popover { 35 | color:grey; 36 | max-width: 350px; 37 | width:350px 38 | } 39 | 40 | .popover-title{ 41 | font-size: 18px; 42 | } 43 | 44 | .popover-content{ 45 | font-weight: normal; 46 | } 47 | 48 | ul.metrics .list-group-item > .badge { 49 | padding: 6px 7px; 50 | float: none; 51 | width: 12%; 52 | } 53 | 54 | ul.metrics .list-group-item label { 55 | width:75%; 56 | font-weight: normal 57 | } 58 | 59 | ul.metrics .list-group-item .optionsTool { 60 | border: medium none; 61 | margin: 0 0 5px 2px; 62 | padding: 0; 63 | width: 18px; 64 | } 65 | 66 | ul.metrics .list-group-item{ 67 | padding-right: 3px; 68 | } 69 | 70 | .optionsTool .dropdown-menu .glyphicon{ 71 | margin-right: 10px 72 | } 73 | 74 | ul.metrics .list-group-item span.value { 75 | width:12%; 76 | float: none 77 | } 78 | 79 | #detailTest span.badge{ 80 | width:19%; 81 | float: none 82 | } 83 | 84 | .badge.outil{ 85 | float: right; 86 | cursor: pointer; 87 | } 88 | 89 | .detail{ 90 | display: none; 91 | } 92 | 93 | .panel-heading{ 94 | height: 75px; 95 | } 96 | 97 | .panel-heading .baseline{ 98 | font-size: 75%; 99 | color: #777; 100 | } 101 | 102 | .panel-heading img{ 103 | float: right; 104 | height: 58px; 105 | } 106 | -------------------------------------------------------------------------------- /Resources/public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Resources/public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Resources/public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Resources/public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /Resources/public/img/Shield_Green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/img/Shield_Green.png -------------------------------------------------------------------------------- /Resources/public/img/Shield_Red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/img/Shield_Red.png -------------------------------------------------------------------------------- /Resources/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/img/favicon.ico -------------------------------------------------------------------------------- /Resources/public/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/img/loading.gif -------------------------------------------------------------------------------- /Resources/public/img/question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/public/img/question.png -------------------------------------------------------------------------------- /Resources/public/js/histo.js: -------------------------------------------------------------------------------- 1 | 2 | $('document').ready(function () { 3 | 4 | 5 | $('#successAnalysis').highcharts({ 6 | chart: { 7 | type: 'spline' 8 | }, 9 | title: { 10 | text: 'Success analysis' 11 | }, 12 | subtitle: { 13 | text: 'Life timeline of the project' 14 | }, 15 | xAxis: { 16 | type: 'datetime', 17 | dateTimeLabelFormats: {// don't display the dummy year 18 | month: '%e. %b', 19 | year: '%b' 20 | }, 21 | title: { 22 | text: 'Date' 23 | } 24 | }, 25 | yAxis: [{ 26 | title: { 27 | text: 'LOC' 28 | } 29 | }, {//--- Secondary yAxis 30 | title: { 31 | text: 'Score' 32 | }, 33 | min: 0, 34 | opposite: true 35 | }], 36 | tooltip: { 37 | headerFormat: '{series.name}
', 38 | pointFormat: '{point.x:%e. %b}: {point.y:.2f} m' 39 | }, 40 | series: [{ 41 | yAxis: 0, 42 | name: 'LOC', 43 | // Define the data points. All series have a dummy year 44 | // of 1970/71 in order to be compared on the same x axis. Note 45 | // that in JavaScript, months start at 0 for January, 1 for February etc. 46 | data: dataLoc 47 | }, { 48 | yAxis: 1, 49 | name: 'Note', 50 | data: dataNote 51 | }, { 52 | yAxis: 1, 53 | name: 'Code coverage', 54 | data: dataCov 55 | } 56 | ] 57 | }); 58 | 59 | 60 | $('#quantite').highcharts({ 61 | chart: { 62 | type: 'spline' 63 | }, 64 | title: { 65 | text: 'Quantité' 66 | }, 67 | subtitle: { 68 | text: 'Growth of the project' 69 | }, 70 | xAxis: { 71 | type: 'datetime', 72 | dateTimeLabelFormats: {// don't display the dummy year 73 | month: '%e. %b', 74 | year: '%b' 75 | }, 76 | title: { 77 | text: 'Date' 78 | } 79 | }, 80 | yAxis: { 81 | title: { 82 | text: 'Nb' 83 | } 84 | }, 85 | tooltip: { 86 | headerFormat: '{series.name}
', 87 | pointFormat: '{point.x:%e. %b}: {point.y:.2f} m' 88 | }, 89 | series: [{ 90 | name: 'Nb File', 91 | // Define the data points. All series have a dummy year 92 | // of 1970/71 in order to be compared on the same x axis. Note 93 | // that in JavaScript, months start at 0 for January, 1 for February etc. 94 | data: dataFile 95 | }, { 96 | name: 'Nb JS File', 97 | data: dataJS 98 | }, { 99 | name: 'Nb CSS File', 100 | data: dataCSS 101 | }, { 102 | name: 'Nb classes', 103 | data: dataClasse 104 | }] 105 | }); 106 | 107 | 108 | // Radialize the colors 109 | Highcharts.getOptions().colors = Highcharts.map(Highcharts.getOptions().colors, function (color) { 110 | return { 111 | radialGradient: {cx: 0.5, cy: 0.3, r: 0.7}, 112 | stops: [ 113 | [0, color], 114 | [1, Highcharts.Color(color).brighten(-0.3).get('rgb')] // darken 115 | ] 116 | }; 117 | }); 118 | 119 | // Build the chart 120 | $('#successFail').highcharts({ 121 | chart: { 122 | plotBackgroundColor: null, 123 | plotBorderWidth: null, 124 | plotShadow: false 125 | }, 126 | title: { 127 | text: 'Success and Fail' 128 | }, 129 | subtitle: { 130 | text: 'Used as debug tool' 131 | }, 132 | tooltip: { 133 | pointFormat: '{series.name}: {point.percentage:.1f}%' 134 | }, 135 | plotOptions: { 136 | pie: { 137 | allowPointSelect: true, 138 | cursor: 'pointer', 139 | dataLabels: { 140 | enabled: true, 141 | format: '{point.name}: {point.percentage:.1f} %', 142 | style: { 143 | color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black' 144 | }, 145 | connectorColor: 'silver' 146 | } 147 | } 148 | }, 149 | series: [{ 150 | type: 'pie', 151 | name: '% success', 152 | data: [{ 153 | name: 'Fail', 154 | y: (100 - successPart), 155 | color: Highcharts.getOptions().colors[3] // Jane's color 156 | }, { 157 | name: 'Success', 158 | y: successPart, 159 | color: Highcharts.getOptions().colors[2] // John's color 160 | }], 161 | center: [200, 100], 162 | size: 200, 163 | showInLegend: false, 164 | dataLabels: { 165 | enabled: true 166 | } 167 | }] 168 | }); 169 | 170 | 171 | 172 | }); -------------------------------------------------------------------------------- /Resources/public/js/pa.js: -------------------------------------------------------------------------------- 1 | $('document').ready(function () { 2 | $(".help").popover({placement: 'left', html: true}); 3 | }); 4 | 5 | function lancerUneAnalyse(one) { 6 | $('#formLanceur').hide(); 7 | $('#refreshLanceur').show(); 8 | $.ajax({ 9 | url: urlLanceur, 10 | data: { 11 | 'one' : one 12 | }, 13 | method: 'post' 14 | }).done(function (data) { 15 | setTimeout(refreshLanceur, 3000); 16 | }); 17 | 18 | return false; 19 | } 20 | 21 | function lancerAnalyse() { 22 | $('#formLanceur').hide(); 23 | $('#refreshLanceur').show(); 24 | 25 | var genDoc = false; 26 | if (document.getElementById('genCC') && document.getElementById('genDoc').checked) { 27 | genDoc = 1; 28 | } 29 | var genCC = false; 30 | if (document.getElementById('genCC') && document.getElementById('genCC').checked) { 31 | genCC = 1; 32 | } 33 | 34 | $.ajax({ 35 | url: urlLanceur, 36 | data: { 37 | genDoc: genDoc, 38 | genCC: genCC 39 | }, 40 | method: 'post' 41 | }).done(function (data) { 42 | setTimeout(refreshLanceur, 3000); 43 | }); 44 | 45 | return false; 46 | } 47 | 48 | function refreshLanceur() { 49 | $('#formLanceur').hide(); 50 | $('#refreshLanceur').show(); 51 | $.ajax({ 52 | url: urlLanceur+"?statut=1" 53 | }).done(function (data) { 54 | if (data.trim() == 'ok') { 55 | $('#rechargePage').show(); 56 | $('#refreshLanceur').hide(); 57 | } else { 58 | setTimeout(refreshLanceur, 3000); 59 | } 60 | }); 61 | } 62 | -------------------------------------------------------------------------------- /Resources/public/js/tooltip.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: tooltip.js v3.3.0 3 | * http://getbootstrap.com/javascript/#tooltip 4 | * Inspired by the original jQuery.tipsy by Jason Frame 5 | * ======================================================================== 6 | * Copyright 2011-2014 Twitter, Inc. 7 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 8 | * ======================================================================== */ 9 | 10 | 11 | +function ($) { 12 | 'use strict'; 13 | 14 | // TOOLTIP PUBLIC CLASS DEFINITION 15 | // =============================== 16 | 17 | var Tooltip = function (element, options) { 18 | this.type = 19 | this.options = 20 | this.enabled = 21 | this.timeout = 22 | this.hoverState = 23 | this.$element = null 24 | 25 | this.init('tooltip', element, options) 26 | } 27 | 28 | Tooltip.VERSION = '3.3.0' 29 | 30 | Tooltip.TRANSITION_DURATION = 150 31 | 32 | Tooltip.DEFAULTS = { 33 | animation: true, 34 | placement: 'top', 35 | selector: false, 36 | template: '', 37 | trigger: 'hover focus', 38 | title: '', 39 | delay: 0, 40 | html: false, 41 | container: false, 42 | viewport: { 43 | selector: 'body', 44 | padding: 0 45 | } 46 | } 47 | 48 | Tooltip.prototype.init = function (type, element, options) { 49 | this.enabled = true 50 | this.type = type 51 | this.$element = $(element) 52 | this.options = this.getOptions(options) 53 | this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 54 | 55 | var triggers = this.options.trigger.split(' ') 56 | 57 | for (var i = triggers.length; i--;) { 58 | var trigger = triggers[i] 59 | 60 | if (trigger == 'click') { 61 | this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 62 | } else if (trigger != 'manual') { 63 | var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 64 | var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 65 | 66 | this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 67 | this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 68 | } 69 | } 70 | 71 | this.options.selector ? 72 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 73 | this.fixTitle() 74 | } 75 | 76 | Tooltip.prototype.getDefaults = function () { 77 | return Tooltip.DEFAULTS 78 | } 79 | 80 | Tooltip.prototype.getOptions = function (options) { 81 | options = $.extend({}, this.getDefaults(), this.$element.data(), options) 82 | 83 | if (options.delay && typeof options.delay == 'number') { 84 | options.delay = { 85 | show: options.delay, 86 | hide: options.delay 87 | } 88 | } 89 | 90 | return options 91 | } 92 | 93 | Tooltip.prototype.getDelegateOptions = function () { 94 | var options = {} 95 | var defaults = this.getDefaults() 96 | 97 | this._options && $.each(this._options, function (key, value) { 98 | if (defaults[key] != value) options[key] = value 99 | }) 100 | 101 | return options 102 | } 103 | 104 | Tooltip.prototype.enter = function (obj) { 105 | var self = obj instanceof this.constructor ? 106 | obj : $(obj.currentTarget).data('bs.' + this.type) 107 | 108 | if (self && self.$tip && self.$tip.is(':visible')) { 109 | self.hoverState = 'in' 110 | return 111 | } 112 | 113 | if (!self) { 114 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 115 | $(obj.currentTarget).data('bs.' + this.type, self) 116 | } 117 | 118 | clearTimeout(self.timeout) 119 | 120 | self.hoverState = 'in' 121 | 122 | if (!self.options.delay || !self.options.delay.show) return self.show() 123 | 124 | self.timeout = setTimeout(function () { 125 | if (self.hoverState == 'in') self.show() 126 | }, self.options.delay.show) 127 | } 128 | 129 | Tooltip.prototype.leave = function (obj) { 130 | var self = obj instanceof this.constructor ? 131 | obj : $(obj.currentTarget).data('bs.' + this.type) 132 | 133 | if (!self) { 134 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 135 | $(obj.currentTarget).data('bs.' + this.type, self) 136 | } 137 | 138 | clearTimeout(self.timeout) 139 | 140 | self.hoverState = 'out' 141 | 142 | if (!self.options.delay || !self.options.delay.hide) return self.hide() 143 | 144 | self.timeout = setTimeout(function () { 145 | if (self.hoverState == 'out') self.hide() 146 | }, self.options.delay.hide) 147 | } 148 | 149 | Tooltip.prototype.show = function () { 150 | var e = $.Event('show.bs.' + this.type) 151 | 152 | if (this.hasContent() && this.enabled) { 153 | this.$element.trigger(e) 154 | 155 | var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) 156 | if (e.isDefaultPrevented() || !inDom) return 157 | var that = this 158 | 159 | var $tip = this.tip() 160 | 161 | var tipId = this.getUID(this.type) 162 | 163 | this.setContent() 164 | $tip.attr('id', tipId) 165 | this.$element.attr('aria-describedby', tipId) 166 | 167 | if (this.options.animation) $tip.addClass('fade') 168 | 169 | var placement = typeof this.options.placement == 'function' ? 170 | this.options.placement.call(this, $tip[0], this.$element[0]) : 171 | this.options.placement 172 | 173 | var autoToken = /\s?auto?\s?/i 174 | var autoPlace = autoToken.test(placement) 175 | if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 176 | 177 | $tip 178 | .detach() 179 | .css({ top: 0, left: 0, display: 'block' }) 180 | .addClass(placement) 181 | .data('bs.' + this.type, this) 182 | 183 | this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 184 | 185 | var pos = this.getPosition() 186 | var actualWidth = $tip[0].offsetWidth 187 | var actualHeight = $tip[0].offsetHeight 188 | 189 | if (autoPlace) { 190 | var orgPlacement = placement 191 | var $container = this.options.container ? $(this.options.container) : this.$element.parent() 192 | var containerDim = this.getPosition($container) 193 | 194 | placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' : 195 | placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' : 196 | placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' : 197 | placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' : 198 | placement 199 | 200 | $tip 201 | .removeClass(orgPlacement) 202 | .addClass(placement) 203 | } 204 | 205 | var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 206 | 207 | this.applyPlacement(calculatedOffset, placement) 208 | 209 | var complete = function () { 210 | var prevHoverState = that.hoverState 211 | that.$element.trigger('shown.bs.' + that.type) 212 | that.hoverState = null 213 | 214 | if (prevHoverState == 'out') that.leave(that) 215 | } 216 | 217 | $.support.transition && this.$tip.hasClass('fade') ? 218 | $tip 219 | .one('bsTransitionEnd', complete) 220 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 221 | complete() 222 | } 223 | } 224 | 225 | Tooltip.prototype.applyPlacement = function (offset, placement) { 226 | var $tip = this.tip() 227 | var width = $tip[0].offsetWidth 228 | var height = $tip[0].offsetHeight 229 | 230 | // manually read margins because getBoundingClientRect includes difference 231 | var marginTop = parseInt($tip.css('margin-top'), 10) 232 | var marginLeft = parseInt($tip.css('margin-left'), 10) 233 | 234 | // we must check for NaN for ie 8/9 235 | if (isNaN(marginTop)) marginTop = 0 236 | if (isNaN(marginLeft)) marginLeft = 0 237 | 238 | offset.top = offset.top + marginTop 239 | offset.left = offset.left + marginLeft 240 | 241 | // $.fn.offset doesn't round pixel values 242 | // so we use setOffset directly with our own function B-0 243 | $.offset.setOffset($tip[0], $.extend({ 244 | using: function (props) { 245 | $tip.css({ 246 | top: Math.round(props.top), 247 | left: Math.round(props.left) 248 | }) 249 | } 250 | }, offset), 0) 251 | 252 | $tip.addClass('in') 253 | 254 | // check to see if placing tip in new offset caused the tip to resize itself 255 | var actualWidth = $tip[0].offsetWidth 256 | var actualHeight = $tip[0].offsetHeight 257 | 258 | if (placement == 'top' && actualHeight != height) { 259 | offset.top = offset.top + height - actualHeight 260 | } 261 | 262 | var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 263 | 264 | if (delta.left) offset.left += delta.left 265 | else offset.top += delta.top 266 | 267 | var isVertical = /top|bottom/.test(placement) 268 | var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 269 | var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' 270 | 271 | $tip.offset(offset) 272 | this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) 273 | } 274 | 275 | Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) { 276 | this.arrow() 277 | .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') 278 | .css(isHorizontal ? 'top' : 'left', '') 279 | } 280 | 281 | Tooltip.prototype.setContent = function () { 282 | var $tip = this.tip() 283 | var title = this.getTitle() 284 | 285 | $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 286 | $tip.removeClass('fade in top bottom left right') 287 | } 288 | 289 | Tooltip.prototype.hide = function (callback) { 290 | var that = this 291 | var $tip = this.tip() 292 | var e = $.Event('hide.bs.' + this.type) 293 | 294 | function complete() { 295 | if (that.hoverState != 'in') $tip.detach() 296 | that.$element 297 | .removeAttr('aria-describedby') 298 | .trigger('hidden.bs.' + that.type) 299 | callback && callback() 300 | } 301 | 302 | this.$element.trigger(e) 303 | 304 | if (e.isDefaultPrevented()) return 305 | 306 | $tip.removeClass('in') 307 | 308 | $.support.transition && this.$tip.hasClass('fade') ? 309 | $tip 310 | .one('bsTransitionEnd', complete) 311 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 312 | complete() 313 | 314 | this.hoverState = null 315 | 316 | return this 317 | } 318 | 319 | Tooltip.prototype.fixTitle = function () { 320 | var $e = this.$element 321 | if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') { 322 | $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 323 | } 324 | } 325 | 326 | Tooltip.prototype.hasContent = function () { 327 | return this.getTitle() 328 | } 329 | 330 | Tooltip.prototype.getPosition = function ($element) { 331 | $element = $element || this.$element 332 | 333 | var el = $element[0] 334 | var isBody = el.tagName == 'BODY' 335 | 336 | var elRect = el.getBoundingClientRect() 337 | if (elRect.width == null) { 338 | // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 339 | elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) 340 | } 341 | var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() 342 | var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } 343 | var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null 344 | 345 | return $.extend({}, elRect, scroll, outerDims, elOffset) 346 | } 347 | 348 | Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 349 | return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 350 | placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 351 | placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 352 | /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 353 | 354 | } 355 | 356 | Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 357 | var delta = { top: 0, left: 0 } 358 | if (!this.$viewport) return delta 359 | 360 | var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 361 | var viewportDimensions = this.getPosition(this.$viewport) 362 | 363 | if (/right|left/.test(placement)) { 364 | var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 365 | var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 366 | if (topEdgeOffset < viewportDimensions.top) { // top overflow 367 | delta.top = viewportDimensions.top - topEdgeOffset 368 | } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 369 | delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset 370 | } 371 | } else { 372 | var leftEdgeOffset = pos.left - viewportPadding 373 | var rightEdgeOffset = pos.left + viewportPadding + actualWidth 374 | if (leftEdgeOffset < viewportDimensions.left) { // left overflow 375 | delta.left = viewportDimensions.left - leftEdgeOffset 376 | } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 377 | delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 378 | } 379 | } 380 | 381 | return delta 382 | } 383 | 384 | Tooltip.prototype.getTitle = function () { 385 | var title 386 | var $e = this.$element 387 | var o = this.options 388 | 389 | title = $e.attr('data-original-title') 390 | || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 391 | 392 | return title 393 | } 394 | 395 | Tooltip.prototype.getUID = function (prefix) { 396 | do prefix += ~~(Math.random() * 1000000) 397 | while (document.getElementById(prefix)) 398 | return prefix 399 | } 400 | 401 | Tooltip.prototype.tip = function () { 402 | return (this.$tip = this.$tip || $(this.options.template)) 403 | } 404 | 405 | Tooltip.prototype.arrow = function () { 406 | return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) 407 | } 408 | 409 | Tooltip.prototype.enable = function () { 410 | this.enabled = true 411 | } 412 | 413 | Tooltip.prototype.disable = function () { 414 | this.enabled = false 415 | } 416 | 417 | Tooltip.prototype.toggleEnabled = function () { 418 | this.enabled = !this.enabled 419 | } 420 | 421 | Tooltip.prototype.toggle = function (e) { 422 | var self = this 423 | if (e) { 424 | self = $(e.currentTarget).data('bs.' + this.type) 425 | if (!self) { 426 | self = new this.constructor(e.currentTarget, this.getDelegateOptions()) 427 | $(e.currentTarget).data('bs.' + this.type, self) 428 | } 429 | } 430 | 431 | self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 432 | } 433 | 434 | Tooltip.prototype.destroy = function () { 435 | var that = this 436 | clearTimeout(this.timeout) 437 | this.hide(function () { 438 | that.$element.off('.' + that.type).removeData('bs.' + that.type) 439 | }) 440 | } 441 | 442 | 443 | // TOOLTIP PLUGIN DEFINITION 444 | // ========================= 445 | 446 | function Plugin(option) { 447 | return this.each(function () { 448 | var $this = $(this) 449 | var data = $this.data('bs.tooltip') 450 | var options = typeof option == 'object' && option 451 | var selector = options && options.selector 452 | 453 | if (!data && option == 'destroy') return 454 | if (selector) { 455 | if (!data) $this.data('bs.tooltip', (data = {})) 456 | if (!data[selector]) data[selector] = new Tooltip(this, options) 457 | } else { 458 | if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 459 | } 460 | if (typeof option == 'string') data[option]() 461 | }) 462 | } 463 | 464 | var old = $.fn.tooltip 465 | 466 | $.fn.tooltip = Plugin 467 | $.fn.tooltip.Constructor = Tooltip 468 | 469 | 470 | // TOOLTIP NO CONFLICT 471 | // =================== 472 | 473 | $.fn.tooltip.noConflict = function () { 474 | $.fn.tooltip = old 475 | return this 476 | } 477 | 478 | }(jQuery); 479 | -------------------------------------------------------------------------------- /Resources/sh/cbf.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | echo "Réparation code sniffer" 3 | #rm -f ${DIR_REPORT}/CS/*.txt 4 | echo "php ${DIR_BIN}/phpcbf --extensions=php --standard=%%%standard%%% ${DIR_SRC} --no-patch" > ${DIR_REPORT}/CS/cbf_cmd.txt 5 | php ${DIR_BIN}/phpcbf --extensions=php --standard=%%%standard%%% ${DIR_SRC} --no-patch > ${DIR_REPORT}/CS/cbf_summary.txt 2>&1 6 | -------------------------------------------------------------------------------- /Resources/sh/count.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | echo "Comptage" 3 | rm -f ${DIR_REPORT}/COUNT/*.txt 4 | find ${DIR_SRC}/ -type d | wc -l > ${DIR_REPORT}/COUNT/nbDossier.txt 5 | find ${DIR_SRC}/ -type f | wc -l > ${DIR_REPORT}/COUNT/nbFichier.txt 6 | find ${DIR_SRC}/ -type f -name "*.php" | wc -l > ${DIR_REPORT}/COUNT/nbPHP.txt 7 | find ${DIR_SRC}/ -type f -name "*.css" | wc -l > ${DIR_REPORT}/COUNT/nbCSS.txt 8 | find ${DIR_SRC}/ -type f -name "*.js" | wc -l > ${DIR_REPORT}/COUNT/nbJS.txt 9 | find ${DIR_SRC}/ -type f -name "*.min.css" | wc -l > ${DIR_REPORT}/COUNT/nbLibCSS.txt 10 | find ${DIR_SRC}/ -type f -name "*.min.js" | wc -l > ${DIR_REPORT}/COUNT/nbLibJS.txt 11 | find ${DIR_SRC}/ -type f -name "*.twig" | wc -l > ${DIR_REPORT}/COUNT/nbTwig.txt 12 | find ${DIR_SRC}/ -type d -name "*Bundle" | wc -l > ${DIR_REPORT}/COUNT/nbBundle.txt 13 | 14 | -------------------------------------------------------------------------------- /Resources/sh/cpd.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -f ${DIR_REPORT}/CPD/*.txt 3 | 4 | echo "Analyse Copy-Paste" 5 | echo "php ${DIR_BIN}/phpcpd ${DIR_SRC}" > ${DIR_REPORT}/CPD/cmd.txt 6 | echo "php ${DIR_BIN}/phpcpd ${DIR_SRC}" > ${DIR_REPORT}/CPD/cmdManuelle.txt 7 | 8 | php ${DIR_BIN}/phpcpd ${DIR_SRC} > ${DIR_REPORT}/CPD/report.txt 2>&1 9 | -------------------------------------------------------------------------------- /Resources/sh/cs.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -f ${DIR_REPORT}/CS/*.txt 3 | 4 | echo "Analyse code sniffer" 5 | echo "${DIR_BIN}/phpcs --report-file=${DIR_REPORT}/CS/report.txt --extensions=php --standard=%%%standard%%% ${DIR_SRC}" > ${DIR_REPORT}/CS/cmd.txt 6 | echo "${DIR_BIN}/phpcs --extensions=php --standard=%%%standard%%% ${DIR_SRC}" > ${DIR_REPORT}/CS/cmdManuelle.txt 7 | echo "${DIR_BIN}/phpcs --extensions=php --standard=%%%standard%%% --no-patch ${DIR_SRC}" > ${DIR_REPORT}/CS/cmdRep.txt 8 | 9 | ${DIR_BIN}/phpcs --config-set installed_paths ${DIR_PHAR}/csStandard/ 10 | ${DIR_BIN}/phpcs --report-file=${DIR_REPORT}/CS/report.txt --extensions=php --standard=%%%standard%%% ${DIR_SRC} > ${DIR_REPORT}/CS/summary.txt 2>&1 11 | -------------------------------------------------------------------------------- /Resources/sh/depend.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -f ${DIR_REPORT}/DEPEND/*.txt 3 | 4 | echo "Calcul de metriques par PhpDepend" 5 | echo "${DIR_BIN}/pdepend --summary-xml=${DIR_REPORT}/DEPEND/summary.xml --jdepend-chart=${DIR_REPORT}/DEPEND/jdepend.svg --overview-pyramid=${DIR_REPORT}/DEPEND/pyramid.svg ${DIR_SRC}" > ${DIR_REPORT}/DEPEND/cmd.txt 6 | echo "${DIR_BIN}/pdepend ${DIR_SRC}" > ${DIR_REPORT}/DEPEND/cmdManuelle.txt 7 | 8 | ${DIR_BIN}/pdepend --summary-xml=${DIR_REPORT}/DEPEND/summary.xml --jdepend-chart=${DIR_REPORT}/DEPEND/jdepend.svg --overview-pyramid=${DIR_REPORT}/DEPEND/pyramid.svg ${DIR_SRC} > ${DIR_REPORT}/DEPEND/report.txt 2>&1 9 | -------------------------------------------------------------------------------- /Resources/sh/docs.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | if [ ${DOC} -eq 1 ] 3 | then 4 | rm -rf ${DIR_REPORT}/DOCS/* 5 | echo "Rédaction de la documentation" 6 | echo "${DIR_BIN}/phpDocumentor -d ${DIR_SRC} -t ${DIR_REPORT}/DOCS" > ${DIR_REPORT}/DOCS/cmd.txt 7 | ${DIR_BIN}/phpDocumentor -d ${DIR_SRC} -t ${DIR_REPORT}/DOCS > ${DIR_REPORT}/DOCS/report.txt 2>&1 8 | fi 9 | -------------------------------------------------------------------------------- /Resources/sh/footer.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -f ${DIR_JETON}/jetonAnalyse 3 | 4 | END=`date +%s` 5 | 6 | echo $((END-START)) > ${DIR_JETON}/timeAnalyse 7 | 8 | 9 | exit 0; 10 | -------------------------------------------------------------------------------- /Resources/sh/header.tpl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################################ 3 | # 4 | # Script Project Analyzer 5 | # 6 | # Date Auteur : Contenu 7 | # 2014-09-15 Jean-David Labails : creation du script 8 | # 9 | ################################################################################ 10 | 11 | 12 | #set -e # fail on first error 13 | 14 | #Parametres generaux 15 | DIR_SRC=%%%dir_src%%% #Repertoire des sources à analyser 16 | DIR_PA=%%%dir_pa%%% 17 | DIR_BIN=%%%dir_bin%%% 18 | DIR_REPORT=${DIR_PA}/reports 19 | DIR_PHAR=%%%dir_phar%%% 20 | DIR_JETON=${DIR_PA}/jetons 21 | LOCK_PATH=%%%lock_path%%% 22 | 23 | #chmod -R 777 ${DIR_REPORT} 24 | 25 | touch ${DIR_JETON}/jetonAnalyse 26 | 27 | START=`date +%s` 28 | 29 | # Reset all variables that might be set 30 | CODE_COVERAGE=0 31 | DOC=0 32 | 33 | 34 | while getopts cd opt 35 | do 36 | case $opt in 37 | c) 38 | CODE_COVERAGE=1 39 | ;; 40 | d) 41 | DOC=1 42 | ;; 43 | esac 44 | done 45 | 46 | 47 | echo "Lecture de la version de symfony" 48 | 49 | ${DIR_BIN}/console --version > ${DIR_REPORT}/SYMFONY/report.txt 50 | -------------------------------------------------------------------------------- /Resources/sh/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################################ 3 | # 4 | # Initialisation des repertoires des reports qui seront générés 5 | # 6 | ################################################################################ 7 | 8 | # on sort des qu'il y a une erreur 9 | set -e 10 | 11 | # Parametres generaux 12 | DIR_GEN=${2} 13 | DIR_PHP=${DIR_GEN}/php 14 | DIR_REPORT=${DIR_GEN}/reports 15 | DIR_JETON=${DIR_GEN}/jetons 16 | DIR_SH=${DIR_GEN}/sh 17 | 18 | WEB_USER=${1} 19 | 20 | if [ ${WEB_USER} == "" ] 21 | then 22 | WEB_USER=www-data:www-data 23 | fi 24 | 25 | echo 'Web server : '${WEB_USER} 26 | 27 | function createDir4Web { 28 | if [ ! -d $1 ] 29 | then 30 | echo 'Dir creation of '$1 31 | mkdir $1 32 | fi 33 | 34 | echo 'Change owner & rights of dir '$1 35 | chown -R ${WEB_USER} $1 36 | chmod -R 755 $1 37 | } 38 | 39 | # on cree les rep de report 40 | createDir4Web ${DIR_GEN} 41 | createDir4Web ${DIR_SH} 42 | createDir4Web ${DIR_REPORT} 43 | createDir4Web ${DIR_REPORT}/COUNT 44 | createDir4Web ${DIR_REPORT}/CPD 45 | createDir4Web ${DIR_REPORT}/CS 46 | createDir4Web ${DIR_REPORT}/LOC 47 | createDir4Web ${DIR_REPORT}/DEPEND 48 | createDir4Web ${DIR_REPORT}/DOCS 49 | createDir4Web ${DIR_REPORT}/MD 50 | createDir4Web ${DIR_REPORT}/SYMFONY 51 | createDir4Web ${DIR_REPORT}/TEST 52 | createDir4Web ${DIR_REPORT}/HISTORIQUE 53 | createDir4Web ${DIR_REPORT}/SECURITY 54 | 55 | createDir4Web ${DIR_SH}/one 56 | 57 | createDir4Web ${DIR_JETON} 58 | 59 | echo 'Change owner & rights of file '${DIR_SH}/pa.sh 60 | touch ${DIR_SH}/pa.sh 61 | chown ${WEB_USER} ${DIR_SH}/pa.sh 62 | chmod 755 ${DIR_SH}/pa.sh 63 | -------------------------------------------------------------------------------- /Resources/sh/loc.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -f ${DIR_REPORT}/LOC/*.txt 3 | 4 | echo "Mesures des sources par PhpLoc" 5 | echo "php ${DIR_BIN}/phploc --log-xml ${DIR_REPORT}/LOC/phploc.xml ${DIR_SRC}" > ${DIR_REPORT}/LOC/cmd.txt 6 | echo "php ${DIR_BIN}/phploc ${DIR_SRC}" > ${DIR_REPORT}/LOC/cmdManuelle.txt 7 | 8 | php ${DIR_BIN}/phploc --log-xml ${DIR_REPORT}/LOC/phploc.xml ${DIR_SRC} > ${DIR_REPORT}/LOC/report.txt 2>&1 9 | -------------------------------------------------------------------------------- /Resources/sh/md.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -f ${DIR_REPORT}/MD/*.txt 3 | 4 | echo "Analyse Mess Detector" 5 | echo "${DIR_BIN}/phpmd ${DIR_SRC} text %%%rule_set%%% --reportfile ${DIR_REPORT}/MD/report.txt" > ${DIR_REPORT}/MD/cmd.txt 6 | echo "${DIR_BIN}/phpmd ${DIR_SRC} text %%%rule_set%%%" > ${DIR_REPORT}/MD/cmdManuelle.txt 7 | 8 | ${DIR_BIN}/phpmd ${DIR_SRC} text %%%rule_set%%% --reportfile ${DIR_REPORT}/MD/report.txt 9 | -------------------------------------------------------------------------------- /Resources/sh/security.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -f ${DIR_REPORT}/SECURITY/*.txt 3 | 4 | echo "Security checker" 5 | echo "php ${DIR_PHAR}/security-checker.phar security:check ${LOCK_PATH} --format=simple" > ${DIR_REPORT}/SECURITY/cmd.txt 6 | 7 | php ${DIR_PHAR}/security-checker.phar security:check ${LOCK_PATH} --format=simple > ${DIR_REPORT}/SECURITY/report.txt 8 | -------------------------------------------------------------------------------- /Resources/sh/test.tpl.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/Resources/sh/test.tpl.sh -------------------------------------------------------------------------------- /Resources/sh/testAtoum.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | rm -f ${DIR_REPORT}/TEST/cmd.txt ${DIR_REPORT}/TEST/report.txt ${DIR_REPORT}/TEST/cmdManuelle.txt 4 | 5 | echo "cd ${DIR_SRC}/../" > ${DIR_REPORT}/TEST/cmd.txt 6 | echo "%%%pathAtoum%%% -d %%%dirTestAtoum%%% " > ${DIR_REPORT}/TEST/cmdManuelle.txt 7 | 8 | if [ ${CODE_COVERAGE} -eq 1 ] 9 | then 10 | echo "Lancement des tests unitaires atoum AVEC code-coverage" 11 | echo "%%%pathAtoum%%% -d %%%dirTestAtoum%%% -c ${DIR_PA}assets/php/atoum.cc.php" >> ${DIR_REPORT}/TEST/cmd.txt 12 | 13 | cd ${DIR_SRC}/../ 14 | 15 | %%%pathAtoum%%% -d %%%dirTestAtoum%%% -c ${DIR_PA}assets/php/atoum.cc.php > ${DIR_REPORT}/TEST/report.txt 2>&1 16 | else 17 | echo "Lancement des tests unitaires atoum SANS code-coverage" 18 | echo "%%%pathAtoum%%% -d %%%dirTestAtoum%%%" >> ${DIR_REPORT}/TEST/cmd.txt 19 | 20 | cd ${DIR_SRC}/../ 21 | %%%pathAtoum%%% -d %%%dirTestAtoum%%% > ${DIR_REPORT}/TEST/report.txt 2>&1 22 | fi 23 | -------------------------------------------------------------------------------- /Resources/sh/testPhpUnit.tpl.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | rm -f ${DIR_REPORT}/TEST/cmd.txt ${DIR_REPORT}/TEST/report.txt ${DIR_REPORT}/TEST/cmdManuelle.txt 4 | 5 | echo "cd ${DIR_SRC}/../" > ${DIR_REPORT}/TEST/cmd.txt 6 | echo "php ${DIR_PHAR}/phpunit.phar -c %%%testconfig%%% --testsuite '%%%testsuite%%%' " > ${DIR_REPORT}/TEST/cmdManuelle.txt 7 | 8 | if [ ${CODE_COVERAGE} -eq 1 ] 9 | then 10 | echo "Lancement des tests unitaires AVEC code-coverage" 11 | echo "php ${DIR_PHAR}/phpunit.phar -c %%%testconfig%%% --testsuite '%%%testsuite%%%' --coverage-text=${DIR_REPORT}/TEST/coverage.txt --coverage-html ${DIR_REPORT}/TEST/phpUnitReport/ " >> ${DIR_REPORT}/TEST/cmd.txt 12 | 13 | if [ -d ${DIR_REPORT}/TEST/phpUnitReport ];then 14 | rm -rf ${DIR_REPORT}/TEST/phpUnitReport 15 | fi 16 | mkdir ${DIR_REPORT}/TEST/phpUnitReport 17 | 18 | rm -f ${DIR_REPORT}/TEST/coverage.txt 19 | cd ${DIR_SRC}/../ 20 | php ${DIR_PHAR}/phpunit.phar -c %%%testconfig%%% --testsuite "%%%testsuite%%%" --coverage-text=${DIR_REPORT}/TEST/coverage.txt --coverage-html ${DIR_REPORT}/TEST/phpUnitReport/ > ${DIR_REPORT}/TEST/report.txt 2>&1 21 | else 22 | echo "Lancement des tests unitaires SANS code-coverage" 23 | echo "php ${DIR_PHAR}/phpunit.phar -c %%%testconfig%%% --testsuite '%%%testsuite%%%' " >> ${DIR_REPORT}/TEST/cmd.txt 24 | 25 | cd ${DIR_SRC}/../ 26 | php ${DIR_PHAR}/phpunit.phar -c %%%testconfig%%% --testsuite "%%%testsuite%%%" > ${DIR_REPORT}/TEST/report.txt 2>&1 27 | fi 28 | -------------------------------------------------------------------------------- /Resources/translations/messages.en.yml: -------------------------------------------------------------------------------- 1 | 2 | # header 3 | lastAnalyze: Last analysis 4 | duration: Duration 5 | seconds: seconds 6 | a: at 7 | 8 | # score 9 | score.note: Score 10 | score.popTitle: How score is calculated ? 11 | score.popContent.begin: "This score is based on quantitative and qualitative elements:" 12 | score.popContent.sizeProject: Project Size 13 | score.popContent.fitWeighting: You can adjust the weighting of these elements in the param.yml. 14 | score.popContent.currentSet: "You are currently set as:" 15 | score.popContent.weight: weight 16 | score.popContent.csWeight: Code sniffer weight 17 | score.popContent.cpWeight: Copy paste weight 18 | score.popContent.scWeight: Security checker weight 19 | score.popContent.testWeight: Tests weight 20 | score.popContent.sizeWeight: Size weight 21 | score.popContent.scale: Project scale 22 | 23 | # quantite 24 | quantity.quantity: Quantity 25 | quantity.srcContent: src directory content only 26 | quantity.bundles: Bundles 27 | quantity.directories: Directories 28 | quantity.files: Files 29 | quantity.PHP: PHP 30 | quantity.CSS: CSS (excluding lib) 31 | quantity.libCSS: Lib CSS 32 | quantity.JS: JS (excluding lib) 33 | quantity.libJS: Lib JS 34 | quantity.twig: TWIG 35 | quantity.namespaces: Namespaces 36 | quantity.classes: Classes 37 | quantity.methods: Methods 38 | quantity.codeLines: Lines of Code 39 | 40 | # qualite 41 | quality.quality: Quality 42 | quality.baseline: Robustness and maintainability 43 | quality.testsTitle: Unit and functional tests 44 | quality.tests: Tests 45 | quality.assertions: Assertions 46 | quality.coverage: Coverage 47 | quality.messDetector: Mess Detector 48 | quality.cc10: Nb methods with CC* > 10 49 | quality.ccMethod: CC* / Nb Methods 50 | quality.copyPaste: Copy-Paste 51 | quality.codeSniffer: Code Sniffer 52 | quality.defineCC: "*CC : Cyclomatic Complexity" 53 | 54 | # lien 55 | link.link: Links 56 | link.tools: Associated and generated tools 57 | link.coverageReport: Code coverage report 58 | link.phpDoc: Generated documentation 59 | link.gitRepositoryAccess: Git Repository Access 60 | link.phpinfo: Php Info 61 | link.histo: History 62 | 63 | # lanceur 64 | launcher.launcher: Scan 65 | launcher.baseline: Scan your code 66 | launcher.generateDoc: Generate doc 67 | launcher.generateCoverage: Generate code coverage 68 | launcher.launch: Start Scan 69 | launcher.analyzeInProgress: Analysis in progress. Please wait... 70 | launcher.analyzeFinished: Analysis is complete, refresh the page. 71 | launcher.refresh: Refresh the page 72 | 73 | # details 74 | details.see: See detailed reports 75 | details.generatedOn: Generated on 76 | details.notGenerated: Not generated 77 | details.emptyReport: Empty report 78 | details.noReport: No generated report 79 | details.libelle.test: Unit & functionnal tests 80 | details.libelle.phpmd: "PhpMD : Mess Detector" 81 | details.libelle.phpcpd: "CPD : Copy-Paste Detector" 82 | details.libelle.cs: "CS : Code Sniffer" 83 | details.libelle.phploc: "PhpLoc : Statistic" 84 | details.libelle.phpdoc: "PhpDoc : Documentation" 85 | details.libelle.phpdepend: "PhpDepend : Various Metrics" 86 | details.libelle.security: "Symfony security-cheker" 87 | details.libelle.behat: "Behat : functionnal tests" 88 | 89 | #outil 90 | outil.detail: See report 91 | outil.reparer: Fix 92 | outil.cmd.lancee: Launched command 93 | outil.cmd.manuelle: Manual Launch Command 94 | outil.relancer: Re-scan 95 | outil.close: Close 96 | -------------------------------------------------------------------------------- /Resources/translations/messages.fr.yml: -------------------------------------------------------------------------------- 1 | 2 | # header 3 | lastAnalyze: Dernière analyse 4 | duration: Durée 5 | seconds: secondes 6 | a: à 7 | 8 | # score 9 | score.note: Note 10 | score.popTitle: Comment la note est-elle calculée ? 11 | score.popContent.begin: "Ce score est basé sur des éléments quantitatifs et qualitatifs :" 12 | score.popContent.sizeProject: Taille du projet 13 | score.popContent.fitWeighting: Vous pouvez adapter la pondération de ces éléments dans le param.yml. 14 | score.popContent.currentSet: "Vous êtes paramétrés comme suit :" 15 | score.popContent.csWeight: Pondération de code sniffer 16 | score.popContent.cpWeight: Pondération de copy paste 17 | score.popContent.scWeight: Pondération de security checker 18 | score.popContent.testWeight: Pondération des tests 19 | score.popContent.sizeWeight: Pondération de la taille 20 | score.popContent.scale: Echelle du projet 21 | 22 | # quantite 23 | quantity.quantity: Quantité 24 | quantity.srcContent: Contenu du dossier src uniquement 25 | quantity.bundles: Bundles 26 | quantity.directories: Dossiers 27 | quantity.files: Fichiers 28 | quantity.PHP: PHP 29 | quantity.CSS: CSS (hors lib) 30 | quantity.libCSS: Lib CSS 31 | quantity.JS: JS (hors lib) 32 | quantity.libJS: Lib JS 33 | quantity.twig: TWIG 34 | quantity.namespaces: Namespaces 35 | quantity.classes: Classes 36 | quantity.methods: Méthodes 37 | quantity.codeLines: Lignes de code 38 | 39 | # qualite 40 | quality.quality: Qualité 41 | quality.baseline: Robustesse et maintenabilité 42 | quality.testsTitle: Tests unitaires et fonctionnels 43 | quality.tests: Tests 44 | quality.assertions: Assertions 45 | quality.coverage: Couverture 46 | quality.messDetector: Mess Detector 47 | quality.cc10: Nb méthode avec CC* > 10 48 | quality.ccMethod: CC* / Nb Méthodes 49 | quality.copyPaste: Copy-Paste 50 | quality.codeSniffer: Code Sniffer 51 | quality.defineCC: "*CC : Complexité Cyclomatique" 52 | 53 | # lien 54 | link.link: Liens 55 | link.tools: Outils associés ou générés 56 | link.coverageReport: Rapport de code coverage 57 | link.phpDoc: Documentation générée 58 | link.gitRepositoryAccess: Accès Git Repository 59 | link.phpinfo: Php Info 60 | link.histo: Historique 61 | 62 | # lanceur 63 | launcher.launcher: Lanceur 64 | launcher.baseline: Analyser votre code 65 | launcher.generateDoc: Générer la doc 66 | launcher.generateCoverage: Générer le code coverage 67 | launcher.launch: Lancer l'analyse 68 | launcher.analyzeInProgress: Analyse en cours. Veuillez patienter... 69 | launcher.analyzeFinished: Analyse terminée, rafraîchissez la page. 70 | launcher.refresh: Rafraîchir la page 71 | 72 | # details 73 | details.see: Voir tous les rapports 74 | details.generatedOn: Généré le 75 | details.notGenerated: Non généré 76 | details.emptyReport: Rapport vide 77 | details.noReport: Aucun report généré 78 | details.libelle.test: Tests fonctionnels et unitaires 79 | details.libelle.phpmd: "PhpMD : Mess Detector" 80 | details.libelle.phpcpd: "CPD : Copy-Paste Detector" 81 | details.libelle.cs: "CS : Code Sniffer" 82 | details.libelle.phploc: "PhpLoc : Statistic" 83 | details.libelle.phpdoc: "PhpDoc : Documentation" 84 | details.libelle.phpdepend: "PhpDepend : Métriques d'analyse" 85 | details.libelle.security: "Symfony security-cheker" 86 | details.libelle.behat: "Behat : test fonctionnel" 87 | 88 | #outil 89 | outil.detail: Voir le rapport 90 | outil.reparer: Réparer 91 | outil.cmd.lancee: Commande lancée 92 | outil.cmd.manuelle: Commande de lancement manuel 93 | outil.relancer: Relancer 94 | outil.close: Fermer 95 | -------------------------------------------------------------------------------- /Resources/views/Main/Modal/cmd.html.twig: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /Resources/views/Main/Modal/cmdManuelle.html.twig: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /Resources/views/Main/Modal/cmdRep.html.twig: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /Resources/views/Main/Modal/rapport.html.twig: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /Resources/views/Main/blockReportDetail.html.twig: -------------------------------------------------------------------------------- 1 | {% if idAnalyse == 'depend' %} 2 | 3 |
4 |
5 |
6 |

PhpDepend : Métriques d'analyse

7 | {{ projectAnalyzer.reportInfo['DEPEND']['date'] }} 8 |
9 |
10 |
{{ projectAnalyzer.reportInfo['DEPEND']['report'] }}
11 | 42 |
43 |
44 |
45 | {% else %} 46 | 47 |
48 |
49 |
50 |

{{title|trans}}

51 | {{report['date']}} 52 |
53 |
54 |
{{report['report']}}
55 |
56 |
57 |
58 | 59 | {% endif %} 60 | -------------------------------------------------------------------------------- /Resources/views/Main/btnDetail.html.twig: -------------------------------------------------------------------------------- 1 |
4 | {% trans %}details.see{% endtrans %} 5 |
6 | -------------------------------------------------------------------------------- /Resources/views/Main/detail.html.twig: -------------------------------------------------------------------------------- 1 | {% for idAnalyse, title in projectAnalyzer.tabAvailableAnalysis %} 2 | {% if projectAnalyzer.isEnable(idAnalyse, true) %} 3 | {% if idAnalyse == 'test' %} 4 | {% set report = projectAnalyzer.testInfo %} 5 | {% else %} 6 | {% set report = projectAnalyzer.reportInfo[idAnalyse|upper] %} 7 | {% endif %} 8 | 9 | {% include 'JDPhpProjectAnalyzerBundle:Main:blockReportDetail.html.twig' %} 10 | 11 | {% include 'JDPhpProjectAnalyzerBundle:Main:Modal/rapport.html.twig' %} 12 | {% include 'JDPhpProjectAnalyzerBundle:Main:Modal/cmd.html.twig' %} 13 | {% include 'JDPhpProjectAnalyzerBundle:Main:Modal/cmdManuelle.html.twig' %} 14 | 15 | {% if idAnalyse == 'cs' %} 16 | {% include 'JDPhpProjectAnalyzerBundle:Main:Modal/cmdRep.html.twig' %} 17 | {% endif %} 18 | {% endif %} 19 | {% endfor %} 20 | -------------------------------------------------------------------------------- /Resources/views/Main/header.html.twig: -------------------------------------------------------------------------------- 1 |
2 |

3 | Project Analyzer : {{ params['title'] }} 4 |
5 | {{ params['description'] }} 6 |

7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {% if projectAnalyzer.isScoreEnable %} 20 | 21 | 22 | 74 | 75 | {% endif %} 76 | 77 | 78 | 79 | 80 | 81 |
{% trans %}lastAnalyze{% endtrans %}{{ projectAnalyzer.analyze.readableDateTime }}
{% trans %}duration{% endtrans %}{{ projectAnalyzer.analyze.readableExecTime }}
{% trans %}score.note{% endtrans %} 23 | {{ projectAnalyzer.analyze.score }} / 20 24 | 73 |
Symfony{{ projectAnalyzer.analyze.symfonyVersion }}
82 |
83 |
84 | -------------------------------------------------------------------------------- /Resources/views/Main/index.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Php Project Analyzer 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
{% include 'JDPhpProjectAnalyzerBundle:Main:header.html.twig' %}
23 |
24 |
25 |
{% include 'JDPhpProjectAnalyzerBundle:Main:quantite.html.twig' %}
26 | 27 |
{% include 'JDPhpProjectAnalyzerBundle:Main:qualite.html.twig' %}
28 | 29 |
30 | {% include 'JDPhpProjectAnalyzerBundle:Main:lanceur.html.twig' %} 31 | {% include 'JDPhpProjectAnalyzerBundle:Main:btnDetail.html.twig' %} 32 |
33 |
34 | {% include 'JDPhpProjectAnalyzerBundle:Main:lien.html.twig' %} 35 |
36 |
37 | 38 |
39 | {% include 'JDPhpProjectAnalyzerBundle:Main:detail.html.twig' %} 40 |
41 |
42 | 43 | 44 | {% if projectAnalyzer.analyzeInProgress %} 45 | 51 | {% endif %} 52 | 53 | 56 | 57 | -------------------------------------------------------------------------------- /Resources/views/Main/lanceur.html.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | {% trans %}launcher.launcher{% endtrans %} 6 |

7 |
8 | {% trans %}launcher.baseline{% endtrans %} 9 |
10 |
11 |
12 |
13 |
14 | {% if projectAnalyzer.isEnable('docs') and false %} 15 |
16 | 20 |
21 | {% endif %} 22 | 23 | {% if params.test.lib != 'atoum' %} 24 |
25 | 29 |
30 | {% endif %} 31 | 32 | 35 |
36 |
37 |
38 |
39 |
40 | {% trans %}launcher.analyzeInProgress{% endtrans %} 41 |
42 | 43 |
44 | 51 |
52 |
53 | -------------------------------------------------------------------------------- /Resources/views/Main/lien.html.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | {% trans %}link.link{%endtrans%} 6 |

7 |
8 | {% trans %}link.tools{%endtrans%} 9 |
10 |
11 |
12 | {% if params.test.lib != 'atoum' %} 13 | 14 | {% trans %}link.coverageReport{%endtrans%} 15 | 16 |
17 | {% endif %} 18 | 19 | {% if projectAnalyzer.isEnable('docs') and false %} 20 | 21 | {% trans %}link.phpDoc{%endtrans%} 22 | 23 | {% endif %} 24 | 25 | {% if projectAnalyzer.isEnable('histo', true) %} 26 |
27 | 28 | {% trans %}link.histo{%endtrans%} 29 | 30 | {% endif %} 31 | 32 |
33 | 34 | {% trans %}link.phpinfo{%endtrans%} 35 | 36 |
37 | 38 | {% trans %}link.gitRepositoryAccess{%endtrans%} 39 | 40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /Resources/views/Main/options.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 5 | 34 | 35 | -------------------------------------------------------------------------------- /Resources/views/Main/qualite.html.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

5 | 6 | {% trans %}quality.quality{% endtrans %} 7 |

8 |
9 | {% trans %}quality.baseline{% endtrans %} 10 |
11 |
12 |
13 | {% if projectAnalyzer.isEnable('security', true) %} 14 | {% if projectAnalyzer.analyze.securitySuccess %} 15 | Security checker symfony OK 18 | {% else %} 19 | Security checker symfony KO 22 | {% endif %} 23 | {% endif %} 24 |
25 |
26 |
27 |
    28 | 29 | {% if projectAnalyzer.isEnable('test', true) %} 30 |
  • 31 | 37 | 38 | {% if projectAnalyzer.testInfo['ok'] == false %} 39 | KO 40 | {% else %} 41 | OK 42 | {% endif %} 43 | 44 | {% set idAnalyse = 'test' %} 45 | {% include 'JDPhpProjectAnalyzerBundle:Main:options.html.twig' %} 46 | 47 |
      48 |
    • 49 | 50 | {{ projectAnalyzer.testInfo['nbTest'] }} 51 |
    • 52 |
    • 53 | 54 | {{ projectAnalyzer.testInfo['nbAssertions'] }} 55 |
    • 56 |
    • 57 | 58 | {{ projectAnalyzer.testInfo['ccLine'] }} 59 | {% if projectAnalyzer.testInfo['dateTimeCC'] != projectAnalyzer.analyze.readableDateTime %} 60 |
      61 |
      62 | {{ projectAnalyzer.testInfo['dateTimeCC'] }} 63 |
      64 | {% endif %} 65 |
    • 66 |
    67 |
  • 68 | {% endif %} 69 | 70 | 71 | {% if projectAnalyzer.isEnable('cs', true) %} 72 |
  • 73 | 77 | {{ projectAnalyzer.viewSummary(projectAnalyzer.qualityInfo['CS']['summary'])|raw }} 78 | {% set idAnalyse = 'cs' %} 79 | {% include 'JDPhpProjectAnalyzerBundle:Main:options.html.twig' %} 80 |
  • 81 | {% endif %} 82 | 83 | 84 | {% if projectAnalyzer.isEnable('cpd') %} 85 |
  • 86 | 87 | {{ projectAnalyzer.viewSummary(projectAnalyzer.qualityInfo['CPD']['summary'])|raw }} 88 | {% set idAnalyse = 'cpd' %} 89 | {% include 'JDPhpProjectAnalyzerBundle:Main:options.html.twig' %} 90 |
  • 91 | {% endif %} 92 | 93 | 94 | {% if projectAnalyzer.isEnable('md', true) %} 95 |
  • 96 | 97 | {{ projectAnalyzer.viewSummary(projectAnalyzer.qualityInfo['MD']['summary'])|raw }} 98 | {% set idAnalyse = 'md' %} 99 | {% include 'JDPhpProjectAnalyzerBundle:Main:options.html.twig' %} 100 |
  • 101 |
  • 102 | 103 | {{ projectAnalyzer.qualityInfo['cc10'] }} 104 | 105 |
  • 106 |
  • 107 | 108 | {{ projectAnalyzer.qualityInfo['ccMethod'] }} 109 | 110 |
  • 111 | {% endif %} 112 | 113 |
114 | {% trans %}quality.defineCC{% endtrans %} 115 |
116 |
117 | -------------------------------------------------------------------------------- /Resources/views/Main/quantite.html.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | {% trans %}quantity.quantity{%endtrans %} 6 | 23 |

24 |
25 | {% trans %}quantity.srcContent{%endtrans %} 26 |
27 |
28 |
29 |
    30 | 31 | {% if projectAnalyzer.isEnable('loc') %} 32 | 33 |
  • 34 | {{ projectAnalyzer.analyze.loc}} 35 | {% trans %}quantity.codeLines{%endtrans %} 36 |
  • 37 | 38 |
  • 39 | {{projectAnalyzer.analyze.nbClasses}} 40 | {% trans %}quantity.classes{%endtrans %} 41 |
  • 42 | 43 |
  • 44 | {{projectAnalyzer.analyze.nbMethod}} 45 | {% trans %}quantity.methods{%endtrans %} 46 |
  • 47 | 48 |
  • 49 | {{projectAnalyzer.analyze.nbNamespace}} 50 | {% trans %}quantity.namespaces{%endtrans %} 51 |
  • 52 | 53 | {% endif %} 54 | 55 | {% if projectAnalyzer.isEnable('count') %} 56 | 57 |
  • 58 | {{projectAnalyzer.analyze.nbBundles}} 59 | {% trans %}quantity.bundles{%endtrans %} 60 |
  • 61 |
  • 62 | {{projectAnalyzer.analyze.nbDir}} 63 | {% trans %}quantity.directories{%endtrans %} 64 |
  • 65 |
  • 66 | {{projectAnalyzer.analyze.nbfile}} 67 | {% trans %}quantity.files{%endtrans %} 68 | 69 | 70 | 71 |
      72 |
    • 73 | {{projectAnalyzer.analyze.nbPhpFile}} 74 | {% trans %}quantity.PHP{%endtrans %} 75 |
    • 76 |
    • 77 | {{projectAnalyzer.analyze.nbCSSFile}} 78 | {% trans %}quantity.CSS{%endtrans %} 79 |
    • 80 |
    • 81 | {{projectAnalyzer.analyze.nbCSSLib}} 82 | {% trans %}quantity.libCSS{%endtrans %} 83 |
    • 84 |
    • 85 | {{projectAnalyzer.analyze.nbJSFile}} 86 | {% trans %}quantity.JS{%endtrans %} 87 |
    • 88 |
    • 89 | {{projectAnalyzer.analyze.nbJSLib}} 90 | {% trans %}quantity.libJS{%endtrans %} 91 |
    • 92 |
    • 93 | {{projectAnalyzer.analyze.nbTwig}} 94 | {% trans %}quantity.twig{%endtrans %} 95 |
    • 96 |
    97 |
  • 98 | 99 | {% endif %} 100 | 101 |
102 |
103 |
104 | -------------------------------------------------------------------------------- /Resources/views/Main/res.html.twig: -------------------------------------------------------------------------------- 1 | {{res}} 2 | -------------------------------------------------------------------------------- /Tests/Fixtures/Traits/visualizer.txt: -------------------------------------------------------------------------------- 1 | [30;42m[37;41m[31;1m[41;37m[0m -------------------------------------------------------------------------------- /Tests/Traits/ScoreCalculatorTest.php: -------------------------------------------------------------------------------- 1 | parameters['score']['enable'] = 'true'; 24 | $this->isTrue($this->isScoreEnable()); 25 | } 26 | 27 | /** 28 | * Test la lecture des parametres de poids du score 29 | */ 30 | public function testGetScoreWeightParam() 31 | { 32 | // un bon parametrage 33 | $this->parameters['score']['csWeight'] = 80; 34 | $this->assertEquals($this->getScoreWeightParam('csWeight'), 80); 35 | 36 | // parametrage hors limite 37 | $this->parameters['score']['testWeight'] = 8650; 38 | $this->assertEquals($this->getScoreWeightParam('testWeight'), 100); 39 | $this->parameters['score']['testWeight'] = -8650; 40 | $this->assertEquals($this->getScoreWeightParam('testWeight'), 100); 41 | 42 | // parametrage non numerique 43 | $this->parameters['score']['locWeight'] = 'nimpa'; 44 | $this->assertEquals($this->getScoreWeightParam('locWeight'), 100); 45 | } 46 | 47 | public function testCalculateScore() 48 | { 49 | // resultats de l'analyse 50 | $this->oAnalyze = new Analyze(); 51 | $this->oAnalyze 52 | ->setCov(100) 53 | ->setCpSuccess(false) 54 | ->setCsSuccess(true) 55 | ->setSecuritySuccess(false) 56 | ->setLoc(8564) 57 | ->setTuSuccess(true) 58 | ; 59 | 60 | // si le scoring n'est pas enable 61 | $this->parameters['score']['enable'] = 'false'; 62 | $this->calculateScore(); 63 | $this->assertEquals($this->oAnalyze->getScore(), 0); 64 | 65 | // scoring enable 66 | $this->parameters['score'] = [ 67 | 'enable' => true, 68 | 'testWeight' => '20', 69 | 'cpWeight' => '30', 70 | 'scWeight' => '40', 71 | 'locWeight' => '50', 72 | 'csWeight' => '60', 73 | ]; 74 | 75 | $note = 76 | 60 + // cs 77 | 20 + // test 78 | 8564 * 50 / 10000; // loc 79 | $divide = (20 + 30 + 40 + 50 + 60) / 20; 80 | $score = round(($note / $divide), 2); 81 | 82 | $this->calculateScore(); 83 | $this->assertEquals($this->oAnalyze->getScore(), $score); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Tests/Traits/ViewHelperTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(self::viewSummary('ok'), 'OK'); 23 | $this->assertEquals(self::viewSummary('ko'), 'KO'); 24 | $this->assertEquals(self::viewSummary('nimp'), 'NC'); 25 | } 26 | 27 | /** 28 | * Test de la transformation htmk des rapports générés 29 | */ 30 | public function testAdaptPhpUnitReport() 31 | { 32 | $reflClass = new \ReflectionClass(get_class($this)); 33 | $file = dirname($reflClass->getFileName()).'/../Fixtures/Traits/visualizer.txt'; 34 | $this->assertEquals(self::adaptPhpUnitReport($file), ''); 35 | } 36 | 37 | /** 38 | * Test du formatage des dates 39 | */ 40 | public function testGetReadableDateTime() 41 | { 42 | $this->translator = $this 43 | ->getMockBuilder(Translator::class) 44 | ->disableOriginalConstructor() 45 | ->getMock(); 46 | 47 | $date = strtotime('10 sept 2015 12:00'); 48 | 49 | $this->translator->expects($this->any()) 50 | ->method('getLocale') 51 | ->will($this->returnValue('fr')); 52 | $this->assertEquals($this->getReadableDateTime($date), '10/09/2015 à 12:00'); 53 | 54 | $this->translator = $this 55 | ->getMockBuilder(Translator::class) 56 | ->disableOriginalConstructor() 57 | ->getMock(); 58 | $this->translator->expects($this->any()) 59 | ->method('getLocale') 60 | ->will($this->returnValue('en')); 61 | $this->assertEquals($this->getReadableDateTime($date), '2015-09-10 12:00'); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Traits/ParamReader.php: -------------------------------------------------------------------------------- 1 | parameters[$name])) { 16 | if ($attr != '' && isset($this->parameters[$name][$attr])) { 17 | return $this->parameters[$name][$attr]; 18 | } 19 | 20 | return $this->parameters[$name]; 21 | } 22 | 23 | return ''; 24 | } 25 | 26 | /** 27 | * Renvoi vrai si la param est à true dans le yml 28 | * @param type $paramName 29 | * @return boolean 30 | */ 31 | public function isEnable($paramName) 32 | { 33 | if (isset($this->parameters[$paramName])) { 34 | if (is_array($this->parameters[$paramName])) { 35 | return $this->parameters[$paramName]['enable']; 36 | } 37 | 38 | return $this->parameters[$paramName]; 39 | } 40 | 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Traits/ScoreCalculator.php: -------------------------------------------------------------------------------- 1 | getParam('score', 'enable') == 'true'; 23 | } 24 | 25 | /** 26 | * Calcule le score en fonction des analyses et du parametrage, puis set l'objet analyse 27 | * 28 | * 20/20 serait donné à un projet de 100kLoc tester à 100% avec CS ok 29 | */ 30 | protected function calculateScore() 31 | { 32 | if (!$this->isScoreEnable()) { 33 | return 0; 34 | } 35 | 36 | $loc = (int) $this->oAnalyze->getLoc(); 37 | $cs = (int) ($this->oAnalyze->getCsSuccess() === true); 38 | $cp = (int) ($this->oAnalyze->getCpSuccess() === true); 39 | $sc = (int) ($this->oAnalyze->getSecuritySuccess() === true); 40 | $test = (int) ($this->oAnalyze->getTuSuccess() === true); 41 | $cc = (float) $this->oAnalyze->getCov(); 42 | 43 | $csWeight = $this->getScoreWeightParam('csWeight'); 44 | $cpWeight = $this->getScoreWeightParam('cpWeight'); 45 | $scWeight = $this->getScoreWeightParam('scWeight'); 46 | $testWeight = $this->getScoreWeightParam('testWeight'); 47 | $locWeight = $this->getScoreWeightParam('locWeight'); 48 | 49 | // define size category of the project 50 | $maxSize = 10000; // small, default 51 | if ($loc >= 10000) { 52 | // medium 53 | $maxSize = 50000; 54 | } 55 | if ($loc >= 50000) { 56 | // big 57 | $maxSize = 100000; 58 | } 59 | 60 | $note = 61 | $cp * $cpWeight + 62 | $sc * $scWeight + 63 | $cs * $csWeight + 64 | $test * $testWeight * ($cc / 100) + 65 | $loc * $locWeight / $maxSize; 66 | $divide = ($csWeight + $scWeight + $cpWeight + $testWeight + $locWeight) / 20; 67 | $score = round(($note / $divide), 2); 68 | 69 | $this->oAnalyze->setScore($score); 70 | } 71 | 72 | /** 73 | * Return weight of the given parameter 74 | * @param string $name 75 | * @return int 76 | */ 77 | public function getScoreWeightParam($name) 78 | { 79 | $weight = $this->getParam('score', $name); 80 | if (!is_numeric($weight)) { 81 | return 100; 82 | } 83 | 84 | if ($weight < 0 || $weight > 100) { 85 | return 100; 86 | } 87 | 88 | return $weight; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Traits/ScriptBuilder.php: -------------------------------------------------------------------------------- 1 | getHeader(); 23 | 24 | foreach ($this->parameters as $idAnalyse => $param) { 25 | if ($this->isEnable($idAnalyse) && file_exists($this->tplShDirPath . '/' . $idAnalyse . '.tpl.sh')) { 26 | $contentSh = ''; 27 | switch ($idAnalyse) { 28 | case 'md': 29 | $contentSh = file_get_contents($this->tplShDirPath . '/md.tpl.sh'); 30 | $contentSh = str_replace('%%%rule_set%%%', $this->getMDRuleSet(), $contentSh); 31 | break; 32 | case 'test': 33 | if ($param['lib'] == 'phpunit') { 34 | $contentSh = file_get_contents($this->tplShDirPath . '/testPhpUnit.tpl.sh'); 35 | $contentSh = str_replace('%%%testsuite%%%', $param['phpunitTestSuite'], $contentSh); 36 | $contentSh = str_replace('%%%testconfig%%%', $param['phpunitTestConfig'], $contentSh); 37 | } 38 | if ($param['lib'] == 'atoum') { 39 | $contentSh = file_get_contents($this->tplShDirPath . '/testAtoum.tpl.sh'); 40 | $contentSh = str_replace('%%%pathAtoum%%%', $param['atoumPath'], $contentSh); 41 | $contentSh = str_replace('%%%dirTestAtoum%%%', $param['atoumTestDir'], $contentSh); 42 | } 43 | break; 44 | case 'cs': 45 | $contentSh = file_get_contents($this->tplShDirPath . '/cs.tpl.sh'); 46 | $cbfContent = file_get_contents($this->tplShDirPath . '/cbf.tpl.sh'); 47 | $std = 'PSR2'; 48 | if (strpos($param['standard'], 'PSR') !== null && 49 | strlen($param['standard']) < 10 50 | ) { 51 | $std = $this->parameters['cs']['standard']; 52 | } 53 | 54 | $cbfContent = str_replace('%%%standard%%%', $std, $cbfContent); 55 | $contentSh = str_replace('%%%standard%%%', $std, $contentSh); 56 | 57 | $contentCbfSh .= $cbfContent; 58 | $contentCbfSh .= file_get_contents($this->tplShDirPath . '/footer.tpl.sh'); 59 | file_put_contents($this->shDirPath . '/one/cbf.sh', $contentCbfSh); 60 | break; 61 | default: 62 | $contentSh = file_get_contents($this->tplShDirPath . '/' . $idAnalyse . '.tpl.sh'); 63 | break; 64 | } 65 | 66 | $contentGlobalSh .= $contentSh; 67 | 68 | $content = $this->getHeader(); 69 | $content .= $contentSh; 70 | $content .= file_get_contents($this->tplShDirPath . '/footer.tpl.sh'); 71 | 72 | $this->command = $content; 73 | file_put_contents($this->shDirPath . '/one/' . $idAnalyse . '.sh', $content); 74 | } 75 | } 76 | 77 | $contentGlobalSh .= file_get_contents($this->tplShDirPath . '/footer.tpl.sh'); 78 | file_put_contents($this->paShPath, $contentGlobalSh); 79 | } 80 | 81 | private function getMDRuleSet() 82 | { 83 | $availableRule = ['cleancode', 'codesize', 'controversial', 'design', 'naming', 'unusedcode']; 84 | $tabRule = []; 85 | 86 | foreach ($availableRule as $r) { 87 | if ($this->parameters['md']['rules'][$r] == 'true') { 88 | $tabRule[] = $r; 89 | } 90 | } 91 | 92 | return implode(',', $tabRule); 93 | } 94 | 95 | private function getHeader() 96 | { 97 | if ($this->header == '') { 98 | $this->header = file_get_contents($this->tplShDirPath . '/header.tpl.sh'); 99 | $this->header = str_replace('%%%dir_src%%%', $this->parameters['srcPath'], $this->header); 100 | $this->header = str_replace('%%%dir_pa%%%', $this->dirRoot, $this->header); 101 | $this->header = str_replace('%%%dir_bin%%%', $this->dirBin, $this->header); 102 | $this->header = str_replace('%%%dir_phar%%%', __DIR__ . '/../Resources/_phar', $this->header); 103 | $this->header = str_replace('%%%lock_path%%%', $this->dirRoot . '/../../composer.lock', $this->header); 104 | } 105 | 106 | return $this->header; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Traits/ViewHelper.php: -------------------------------------------------------------------------------- 1 | OK'; 26 | break; 27 | case 'ko': 28 | $txt = 'KO'; 29 | break; 30 | default: 31 | $txt = 'NC'; 32 | break; 33 | } 34 | 35 | return $txt; 36 | } 37 | 38 | /** 39 | * Adapt the phpunit report to html 40 | * 41 | * @param string $file path to the phpunit report 42 | * 43 | * @return string 44 | */ 45 | static public function adaptPhpUnitReport($file) 46 | { 47 | $txt = file_get_contents($file); 48 | $txt = str_replace('[30;42m', '', $txt); 49 | $txt = str_replace('[37;41m', '', $txt); 50 | $txt = str_replace('[31;1m', '', $txt); 51 | $txt = str_replace('[41;37m', '', $txt); 52 | $txt = str_replace('[0m', '', $txt); 53 | 54 | return $txt; 55 | } 56 | 57 | /** 58 | * Return a formated date 59 | * 60 | * @param int $dt 61 | * 62 | * @return string 63 | */ 64 | public function getReadableDateTime($dt) 65 | { 66 | if ($this->translator->getLocale() == 'fr') { 67 | return date('d/m/Y à H:i', $dt); 68 | } 69 | 70 | return date('Y-m-d H:i', $dt); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jdlabails/php-project-analyzer-bundle", 3 | "description": "Symfony Bundle for PhpProjectAnalyzer", 4 | "type": "symfony-bundle", 5 | "homepage": "https://github.com/jdlabails/PhpProjectAnalyzerBundle", 6 | "license": [ 7 | "MIT" 8 | ], 9 | "keywords": [ 10 | "Php Project Analyzer Symfony" 11 | ], 12 | "authors": [ 13 | { 14 | "name": "Jean-David Labails", 15 | "email": "jd.labails@gmail.com" 16 | } 17 | ], 18 | "autoload": { 19 | "psr-4": { 20 | "JD\\PhpProjectAnalyzerBundle\\": "" 21 | } 22 | }, 23 | "config": { 24 | "bin-dir": "bin/" 25 | }, 26 | "require": { 27 | "php": ">=5.6.", 28 | "symfony/symfony": ">=2.3", 29 | "doctrine/doctrine-bundle": "*", 30 | "doctrine/orm": "*", 31 | "symfony/translation": ">=2.3", 32 | "sebastian/phpcpd": "*", 33 | "phploc/phploc": "*", 34 | "symfony/phpunit-bridge": "*", 35 | "squizlabs/php_codesniffer": "*", 36 | "pdepend/pdepend": "*", 37 | "phpmd/phpmd": "*" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | Tests 13 | 14 | 15 | 16 | 17 | 18 | ../PhpProjectAnalyzerBundle 19 | 20 | Resources 21 | Tests 22 | vendor 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ppaIndex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlabails/PhpProjectAnalyzerBundle/3060ae13c35ed39196a6f0cb9217b9975da18ec6/ppaIndex.png --------------------------------------------------------------------------------