diff --git a/README.md b/README.md index 446428d..615b41e 100644 --- a/README.md +++ b/README.md @@ -48,23 +48,24 @@ This is a fork of [original project](https://github.com/JakubOnderka/PHP-Paralle ## Options for run -- `-p ` Specify PHP-CGI executable to run (default: 'php'). -- `-s, --short` Set short_open_tag to On (default: Off). -- `-a, --asp` Set asp_tags to On (default: Off). -- `-e ` Check only files with selected extensions separated by comma. (default: php,php3,php4,php5,phtml,phpt) -- `--exclude` Exclude a file or directory. If you want exclude multiple items, use multiple exclude parameters. -- `-j ` Run jobs in parallel (default: 10). -- `--colors` Force enable colors in console output. -- `--no-colors` Disable colors in console output. -- `--no-progress` Disable progress in console output. -- `--checkstyle` Output results as Checkstyle XML. -- `--json` Output results as JSON string (require PHP 5.4). -- `--blame` Try to show git blame for row with error. -- `--git ` Path to Git executable to show blame message (default: 'git'). -- `--stdin` Load files and folder to test from standard input. -- `--ignore-fails` Ignore failed tests. -- `-h, --help` Print this help. -- `-V, --version` Display this application version. +- `-p ` Specify PHP-CGI executable to run (default: 'php'). +- `-s, --short` Set short_open_tag to On (default: Off). +- `-a, --asp` Set asp_tags to On (default: Off). +- `-e ` Check only files with selected extensions separated by comma. (default: php,php3,php4,php5,phtml,phpt) +- `--exclude` Exclude a file or directory. If you want exclude multiple items, use multiple exclude parameters. +- `-j ` Run jobs in parallel (default: 10). +- `--colors` Force enable colors in console output. +- `--no-colors` Disable colors in console output. +- `--no-progress` Disable progress in console output. +- `--checkstyle` Output results as Checkstyle XML. +- `--json` Output results as JSON string (require PHP 5.4). +- `--blame` Try to show git blame for row with error. +- `--git ` Path to Git executable to show blame message (default: 'git'). +- `--stdin` Load files and folder to test from standard input. +- `--ignore-fails` Ignore failed tests. +- `--syntax-error-callback` File with syntax error callback for ability to modify error, see more in [example](doc/syntax-error-callback.md) +- `-h, --help` Print this help. +- `-V, --version` Display this application version. ## Recommended setting for usage with Symfony framework diff --git a/doc/syntax-error-callback.md b/doc/syntax-error-callback.md new file mode 100644 index 0000000..955f5ef --- /dev/null +++ b/doc/syntax-error-callback.md @@ -0,0 +1,31 @@ +# Syntax Error Callback + +1. Set a path to a file with custom error callback to `--syntax-error-callback` option. +1. Create a class implementing `JakubOnderka\PhpParallelLint\Contracts\SyntaxErrorCallback` interface. File with the class must have the same name as the class inside. +1. Modify error before it is printed to the output. + +## Example configuration + +File `MyCustomErrorHandler.php` will be passed as an argument like `./parallel-lint --syntax-error-callback ./path/to/MyCustomErrorHandler.php .`.
+The content should look like: + +```php + +use JakubOnderka\PhpParallelLint\Contracts\SyntaxErrorCallback; +use JakubOnderka\PhpParallelLint\SyntaxError; + +class MyCustomErrorHandler implements SyntaxErrorCallback { + /** + * @param SyntaxError $error + * @return SyntaxError + */ + public function errorFound(SyntaxError $error){ + // Return new SyntaxError with custom modification to FilePath or Message + // Or return custom implementation of SyntaxError extending the original one... + return new SyntaxError( + $error->getFilePath(), + $error->getMessage() + ); + } +} +``` diff --git a/src/Application.php b/src/Application.php index 4517083..f4002e0 100644 --- a/src/Application.php +++ b/src/Application.php @@ -75,25 +75,26 @@ private function showOptions() { echo << Specify PHP-CGI executable to run (default: 'php'). - -s, --short Set short_open_tag to On (default: Off). - -a, -asp Set asp_tags to On (default: Off). - -e Check only files with selected extensions separated by comma. - (default: php,php3,php4,php5,phtml,phpt) - --exclude Exclude a file or directory. If you want exclude multiple items, - use multiple exclude parameters. - -j Run jobs in parallel (default: 10). - --colors Enable colors in console output. (disables auto detection of color support) - --no-colors Disable colors in console output. - --no-progress Disable progress in console output. - --json Output results as JSON string. - --checkstyle Output results as Checkstyle XML. - --blame Try to show git blame for row with error. - --git Path to Git executable to show blame message (default: 'git'). - --stdin Load files and folder to test from standard input. - --ignore-fails Ignore failed tests. - -h, --help Print this help. - -V, --version Display this application version + -p Specify PHP-CGI executable to run (default: 'php'). + -s, --short Set short_open_tag to On (default: Off). + -a, -asp Set asp_tags to On (default: Off). + -e Check only files with selected extensions separated by comma. + (default: php,php3,php4,php5,phtml,phpt) + --exclude Exclude a file or directory. If you want exclude multiple items, + use multiple exclude parameters. + -j Run jobs in parallel (default: 10). + --colors Enable colors in console output. (disables auto detection of color support) + --no-colors Disable colors in console output. + --no-progress Disable progress in console output. + --json Output results as JSON string. + --checkstyle Output results as Checkstyle XML. + --blame Try to show git blame for row with error. + --git Path to Git executable to show blame message (default: 'git'). + --stdin Load files and folder to test from standard input. + --ignore-fails Ignore failed tests. + --syntax-error-callback File with syntax error callback for ability to modify error + -h, --help Print this help. + -V, --version Display this application version HELP; } diff --git a/src/Contracts/SyntaxErrorCallback.php b/src/Contracts/SyntaxErrorCallback.php new file mode 100644 index 0000000..0db055f --- /dev/null +++ b/src/Contracts/SyntaxErrorCallback.php @@ -0,0 +1,13 @@ +setAspTagsEnabled($settings->aspTags); $parallelLint->setShortTagEnabled($settings->shortTag); $parallelLint->setShowDeprecated($settings->showDeprecated); + $parallelLint->setSyntaxErrorCallback($this->createSyntaxErrorCallback($settings)); $parallelLint->setProcessCallback(function ($status, $file) use ($output) { if ($status === ParallelLint::STATUS_OK) { @@ -167,6 +169,33 @@ protected function getFilesFromPaths(array $paths, array $extensions, array $exc return $files; } + + protected function createSyntaxErrorCallback(Settings $settings) + { + if ($settings->syntaxErrorCallbackFile === null) { + return null; + } + + $fullFilePath = realpath($settings->syntaxErrorCallbackFile); + if ($fullFilePath === false) { + throw new NotExistsPathException($settings->syntaxErrorCallbackFile); + } + + require_once $fullFilePath; + + $expectedClassName = basename($fullFilePath, '.php'); + if (!class_exists($expectedClassName)) { + throw new NotExistsClassException($expectedClassName, $settings->syntaxErrorCallbackFile); + } + + $callbackInstance = new $expectedClassName; + + if (!($callbackInstance instanceof SyntaxErrorCallback)) { + throw new NotImplementCallbackException($expectedClassName); + } + + return $callbackInstance; + } } class RecursiveDirectoryFilterIterator extends \RecursiveFilterIterator diff --git a/src/ParallelLint.php b/src/ParallelLint.php index 8c12a73..8137020 100644 --- a/src/ParallelLint.php +++ b/src/ParallelLint.php @@ -1,6 +1,7 @@ phpExecutable = $phpExecutable; @@ -92,7 +96,7 @@ public function lint(array $files) } else if ($process->containsError()) { $checkedFiles[] = $file; - $errors[] = new SyntaxError($file, $process->getSyntaxError()); + $errors[] = $this->triggerSyntaxErrorCallback(new SyntaxError($file, $process->getSyntaxError())); $processCallback(self::STATUS_ERROR, $file); } else if ($process->isSuccess()) { @@ -131,7 +135,7 @@ public function lint(array $files) } else if ($process->containsError()) { $checkedFiles[] = $file; - $errors[] = new SyntaxError($file, $process->getSyntaxError()); + $errors[] = $this->triggerSyntaxErrorCallback(new SyntaxError($file, $process->getSyntaxError())); $processCallback(self::STATUS_ERROR, $file); } else { @@ -259,4 +263,24 @@ public function setShowDeprecated($showDeprecated) return $this; } + + public function triggerSyntaxErrorCallback($syntaxError) + { + if ($this->syntaxErrorCallback === null) { + return $syntaxError; + } + + return $this->syntaxErrorCallback->errorFound($syntaxError); + } + + /** + * @param SyntaxErrorCallback|null $syntaxErrorCallback + * @return ParallelLint + */ + public function setSyntaxErrorCallback($syntaxErrorCallback) + { + $this->syntaxErrorCallback = $syntaxErrorCallback; + + return $this; + } } diff --git a/src/Settings.php b/src/Settings.php index 24071af..3e03a71 100644 --- a/src/Settings.php +++ b/src/Settings.php @@ -103,6 +103,12 @@ class Settings */ public $showDeprecated = false; + /** + * Path to a file with syntax error callback + * @var string|null + */ + public $syntaxErrorCallbackFile = null; + /** * @param array $paths */ @@ -197,6 +203,10 @@ public static function parseArguments(array $arguments) $settings->showDeprecated = true; break; + case '--syntax-error-callback': + $settings->syntaxErrorCallbackFile = $arguments->getNext(); + break; + default: throw new InvalidArgumentException($argument); } diff --git a/src/exceptions.php b/src/exceptions.php index fd47ddc..3893b83 100644 --- a/src/exceptions.php +++ b/src/exceptions.php @@ -49,3 +49,42 @@ public function getPath() return $this->path; } } + +class NotExistsClassException extends Exception +{ + protected $className; + protected $fileName; + + public function __construct($className, $fileName) + { + $this->className = $className; + $this->fileName = $fileName; + $this->message = "Class with name '$className' does not exists in file '$fileName'"; + } + + public function getClassName() + { + return $this->className; + } + + public function getFileName() + { + return $this->fileName; + } +} + +class NotImplementCallbackException extends Exception +{ + protected $className; + + public function __construct($className) + { + $this->className = $className; + $this->message = "Class '$className' does not implement SyntaxErrorCallback interface."; + } + + public function getClassName() + { + return $this->className; + } +} diff --git a/tests/Settings.parseArguments.phpt b/tests/Settings.parseArguments.phpt index 76c19e8..0a83673 100644 --- a/tests/Settings.parseArguments.phpt +++ b/tests/Settings.parseArguments.phpt @@ -27,6 +27,7 @@ class SettingsParseArgumentsTest extends Tester\TestCase $expectedSettings->colors = Settings::AUTODETECT; $expectedSettings->showProgress = true; $expectedSettings->format = Settings::FORMAT_TEXT; + $expectedSettings->syntaxErrorCallbackFile = null; Assert::equal($expectedSettings->shortTag, $settings->shortTag); Assert::equal($expectedSettings->aspTags, $settings->aspTags); @@ -37,6 +38,7 @@ class SettingsParseArgumentsTest extends Tester\TestCase Assert::equal($expectedSettings->colors, $settings->colors); Assert::equal($expectedSettings->showProgress, $settings->showProgress); Assert::equal($expectedSettings->format, $settings->format); + Assert::equal($expectedSettings->syntaxErrorCallbackFile, $settings->syntaxErrorCallbackFile); } public function testMoreArguments() @@ -120,6 +122,18 @@ class SettingsParseArgumentsTest extends Tester\TestCase Assert::equal($expectedSettings->extensions, $settings->extensions); } + + public function testFailCallaback() + { + $commandLine = "./parallel-lint --syntax-error-callback ./path/to/my_custom_callback_file.php ."; + $argv = explode(" ", $commandLine); + $settings = Settings::parseArguments($argv); + + $expectedSettings = new Settings(); + $expectedSettings->syntaxErrorCallbackFile = "./path/to/my_custom_callback_file.php"; + + Assert::equal($expectedSettings->syntaxErrorCallbackFile, $settings->syntaxErrorCallbackFile); + } } $testCase = new SettingsParseArgumentsTest;