2016-06-06 07:07:50 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace CodeInspector;
|
|
|
|
|
2016-06-10 00:08:25 +02:00
|
|
|
use CodeInspector\Config\FileFilter;
|
|
|
|
use SimpleXMLElement;
|
|
|
|
|
2016-06-06 07:07:50 +02:00
|
|
|
class Config
|
|
|
|
{
|
2016-06-10 00:08:25 +02:00
|
|
|
protected static $_config;
|
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
public $stop_on_error = true;
|
|
|
|
public $use_docblock_return_type = false;
|
2016-06-10 00:08:25 +02:00
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
protected $inspect_files;
|
2016-06-10 00:08:25 +02:00
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
protected $base_dir;
|
2016-06-06 07:07:50 +02:00
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
protected $file_extensions = ['php'];
|
|
|
|
|
2016-06-20 06:38:13 +02:00
|
|
|
protected $filetype_handlers = [];
|
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
protected $issue_handlers = [];
|
|
|
|
|
|
|
|
protected $mock_classes = [];
|
2016-06-06 07:07:50 +02:00
|
|
|
|
2016-06-18 20:45:55 +02:00
|
|
|
/**
|
|
|
|
* CodeInspector plugins
|
|
|
|
* @var array<Plugin>
|
|
|
|
*/
|
|
|
|
protected $plugins = [];
|
|
|
|
|
2016-06-06 07:07:50 +02:00
|
|
|
private function __construct()
|
|
|
|
{
|
|
|
|
self::$_config = $this;
|
|
|
|
}
|
|
|
|
|
2016-06-20 06:38:13 +02:00
|
|
|
public function loadFromXML($file_name)
|
2016-06-10 00:08:25 +02:00
|
|
|
{
|
2016-06-10 20:47:44 +02:00
|
|
|
$file_contents = file_get_contents($file_name);
|
|
|
|
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->base_dir = dirname($file_name) . '/';
|
2016-06-10 20:47:44 +02:00
|
|
|
|
2016-06-10 00:08:25 +02:00
|
|
|
$config_xml = new SimpleXMLElement($file_contents);
|
|
|
|
|
|
|
|
if (isset($config_xml['stopOnError'])) {
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->stop_on_error = $config_xml['stopOnError'] === 'true' || $config_xml['stopOnError'] === '1';
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($config_xml['useDocblockReturnType'])) {
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->use_docblock_return_type = (bool) $config_xml['useDocblockReturnType'];
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($config_xml->inspectFiles)) {
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->inspect_files = FileFilter::loadFromXML($config_xml->inspectFiles, true);
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($config_xml->fileExtensions)) {
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->file_extensions = [];
|
2016-06-10 20:47:44 +02:00
|
|
|
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->loadFileExtensions($config_xml->fileExtensions->extension);
|
2016-06-10 20:47:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($config_xml->mockClasses) && isset($config_xml->mockClasses->class)) {
|
|
|
|
foreach ($config_xml->mockClasses->class as $mock_class) {
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->mock_classes[] = $mock_class['name'];
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
2016-06-10 20:47:44 +02:00
|
|
|
}
|
|
|
|
|
2016-06-18 20:45:55 +02:00
|
|
|
// this plugin loading system borrows heavily from etsy/phan
|
|
|
|
if (isset($config_xml->plugins) && isset($config_xml->plugins->plugin)) {
|
|
|
|
foreach ($config_xml->plugins->plugin as $plugin) {
|
|
|
|
$plugin_file_name = $plugin['filename'];
|
2016-06-20 06:38:13 +02:00
|
|
|
|
|
|
|
$path = $this->base_dir . $plugin_file_name;
|
|
|
|
|
|
|
|
if (!file_exists($path)) {
|
|
|
|
throw new \InvalidArgumentException('Cannot find file ' . $path);
|
|
|
|
}
|
|
|
|
|
|
|
|
$loaded_plugin = require($path);
|
2016-06-18 20:45:55 +02:00
|
|
|
|
|
|
|
if (!$loaded_plugin) {
|
|
|
|
throw new \InvalidArgumentException('Plugins must return an instance of that plugin at the end of the file - ' . $plugin_file_name . ' does not');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!($loaded_plugin instanceof Plugin)) {
|
|
|
|
throw new \InvalidArgumentException('Plugins must extend \CodeInspector\Plugin - ' . $plugin_file_name . ' does not');
|
|
|
|
}
|
|
|
|
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->plugins[] = $loaded_plugin;
|
2016-06-18 20:45:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
if (isset($config_xml->issueHandler)) {
|
|
|
|
foreach ($config_xml->issueHandler->children() as $key => $issue_handler) {
|
|
|
|
if (isset($issue_handler->excludeFiles)) {
|
2016-06-20 06:38:13 +02:00
|
|
|
$this->issue_handlers[$key] = FileFilter::loadFromXML($issue_handler->excludeFiles, false);
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return $this
|
|
|
|
*/
|
2016-06-06 07:07:50 +02:00
|
|
|
public static function getInstance()
|
|
|
|
{
|
|
|
|
if (self::$_config) {
|
|
|
|
return self::$_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new self();
|
|
|
|
}
|
|
|
|
|
2016-06-20 06:38:13 +02:00
|
|
|
protected function loadFileExtensions($extensions)
|
|
|
|
{
|
|
|
|
foreach ($extensions as $extension) {
|
|
|
|
$extension_name = preg_replace('/^\.?/', '', $extension['name']);
|
|
|
|
$this->file_extensions[] = $extension_name;
|
|
|
|
|
|
|
|
if (isset($extension['filetypeHandler'])) {
|
|
|
|
$path = $this->base_dir . $extension['filetypeHandler'];
|
|
|
|
|
|
|
|
if (!file_exists($path)) {
|
2016-06-20 07:05:44 +02:00
|
|
|
throw new Exception\ConfigException('Error parsing config: cannot find file ' . $path);
|
2016-06-20 06:38:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$declared_classes = FileChecker::getDeclaredClassesInFile($path);
|
|
|
|
|
|
|
|
if (count($declared_classes) !== 1) {
|
|
|
|
throw new \InvalidArgumentException('Filetype handlers must have exactly one class in the file - ' . $path . ' has ' . count($declared_classes));
|
|
|
|
}
|
|
|
|
|
|
|
|
require_once($path);
|
|
|
|
|
|
|
|
if (!is_subclass_of($declared_classes[0], 'CodeInspector\\FileChecker')) {
|
|
|
|
throw new \InvalidArgumentException('Filetype handlers must extend \CodeInspector\FileChecker - ' . $path . ' does not');
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->filetype_handlers[$extension_name] = $declared_classes[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-10 23:20:04 +02:00
|
|
|
public function shortenFileName($file_name)
|
|
|
|
{
|
|
|
|
return preg_replace('/^' . preg_quote($this->base_dir, '/') . '/', '', $file_name);
|
|
|
|
}
|
|
|
|
|
2016-06-10 00:08:25 +02:00
|
|
|
public function excludeIssueInFile($issue_type, $file_name)
|
|
|
|
{
|
2016-06-10 20:47:44 +02:00
|
|
|
$issue_type = array_pop(explode('\\', $issue_type));
|
2016-06-10 23:20:04 +02:00
|
|
|
$file_name = $this->shortenFileName($file_name);
|
2016-06-10 20:47:44 +02:00
|
|
|
|
|
|
|
if (!isset($this->issue_handlers[$issue_type])) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-10 00:08:25 +02:00
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
return !$this->issue_handlers[$issue_type]->allows($file_name);
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
|
|
|
|
2016-06-06 07:07:50 +02:00
|
|
|
public function doesInheritVariables($file_name)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-10 00:08:25 +02:00
|
|
|
|
2016-06-13 21:33:18 +02:00
|
|
|
public function getIncludeDirs()
|
2016-06-10 00:08:25 +02:00
|
|
|
{
|
2016-06-13 21:33:18 +02:00
|
|
|
return $this->inspect_files->getIncludeDirs();
|
|
|
|
}
|
2016-06-10 00:08:25 +02:00
|
|
|
|
2016-06-13 21:33:18 +02:00
|
|
|
public function getBaseDir()
|
|
|
|
{
|
|
|
|
return $this->base_dir;
|
|
|
|
}
|
2016-06-10 00:08:25 +02:00
|
|
|
|
2016-06-13 21:33:18 +02:00
|
|
|
public function getFileExtensions()
|
|
|
|
{
|
|
|
|
return $this->file_extensions;
|
2016-06-10 00:08:25 +02:00
|
|
|
}
|
2016-06-10 20:47:44 +02:00
|
|
|
|
2016-06-20 06:38:13 +02:00
|
|
|
public function getFiletypeHandlers()
|
|
|
|
{
|
|
|
|
return $this->filetype_handlers;
|
|
|
|
}
|
|
|
|
|
2016-06-10 20:47:44 +02:00
|
|
|
public function getMockClasses()
|
|
|
|
{
|
|
|
|
return $this->mock_classes;
|
|
|
|
}
|
2016-06-18 20:45:55 +02:00
|
|
|
|
|
|
|
public function getPlugins()
|
|
|
|
{
|
|
|
|
return $this->plugins;
|
|
|
|
}
|
2016-06-20 22:18:31 +02:00
|
|
|
|
|
|
|
public function setIssueHandler($issue_name, FileFilter $filter = null)
|
|
|
|
{
|
|
|
|
$this->issue_handlers[$issue_name] = $filter;
|
|
|
|
}
|
2016-06-06 07:07:50 +02:00
|
|
|
}
|