Skip to content

Add Syntax Error callback #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,24 @@ This is a fork of [original project](https://github.com/JakubOnderka/PHP-Paralle

## Options for run

- `-p <php>` 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 <ext>` 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 <num>` Run <num> 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 <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 <php>` 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 <ext>` 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 <num>` Run <num> 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 <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
Expand Down
31 changes: 31 additions & 0 deletions doc/syntax-error-callback.md
Original file line number Diff line number Diff line change
@@ -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 .`.<br>
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()
);
}
}
```
39 changes: 20 additions & 19 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,26 @@ private function showOptions()
{
echo <<<HELP
Options:
-p <php> 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 <ext> 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 <num> Run <num> 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 <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 <php> 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 <ext> 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 <num> Run <num> 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 <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;
}
Expand Down
13 changes: 13 additions & 0 deletions src/Contracts/SyntaxErrorCallback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
namespace JakubOnderka\PhpParallelLint\Contracts;

use JakubOnderka\PhpParallelLint\SyntaxError;

interface SyntaxErrorCallback
{
/**
* @param SyntaxError $error
* @return SyntaxError
*/
public function errorFound(SyntaxError $error);
}
29 changes: 29 additions & 0 deletions src/Manager.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace JakubOnderka\PhpParallelLint;

use JakubOnderka\PhpParallelLint\Contracts\SyntaxErrorCallback;
use JakubOnderka\PhpParallelLint\Process\GitBlameProcess;
use JakubOnderka\PhpParallelLint\Process\PhpExecutable;

Expand Down Expand Up @@ -38,6 +39,7 @@ public function run(Settings $settings = null)
$parallelLint->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) {
Expand Down Expand Up @@ -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
Expand Down
28 changes: 26 additions & 2 deletions src/ParallelLint.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace JakubOnderka\PhpParallelLint;

use JakubOnderka\PhpParallelLint\Contracts\SyntaxErrorCallback;
use JakubOnderka\PhpParallelLint\Process\LintProcess;
use JakubOnderka\PhpParallelLint\Process\PhpExecutable;
use JakubOnderka\PhpParallelLint\Process\SkipLintProcess;
Expand Down Expand Up @@ -30,6 +31,9 @@ class ParallelLint
/** @var bool */
private $showDeprecated = false;

/** @var SyntaxErrorCallback|null */
private $syntaxErrorCallback = null;

public function __construct(PhpExecutable $phpExecutable, $parallelJobs = 10)
{
$this->phpExecutable = $phpExecutable;
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
}
10 changes: 10 additions & 0 deletions src/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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);
}
Expand Down
39 changes: 39 additions & 0 deletions src/exceptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
14 changes: 14 additions & 0 deletions tests/Settings.parseArguments.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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()
Expand Down Expand Up @@ -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;
Expand Down