Skip to content

Commit

Permalink
Merge pull request #86 from sasezaki/context-type-rule-introduce
Browse files Browse the repository at this point in the history
Introduce ContextTypeRule & LogMethodLevelRule to to support  several context type
  • Loading branch information
sasezaki authored Jan 19, 2025
2 parents 92a1d2c + fb80b3f commit 17bb014
Show file tree
Hide file tree
Showing 32 changed files with 1,479 additions and 49 deletions.
29 changes: 25 additions & 4 deletions .laminas-ci.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
{
"additional_checks": [
{
"name": "phpstan",
"name": "phpstan-lowest",
"job": {
"php": "@lowest",
"command": "./vendor/bin/phpstan analyse --no-progress"
}
},
{
"name": "psalm",
"name": "phpstan-latest",
"job": {
"php": "@latest",
"command": "./vendor/bin/phpstan analyse --no-progress"
}
},
{
"name": "psalm",
"job": {
"php": "8.3",
"command": "./vendor/bin/psalm --shepherd --stats --output-format=github --no-cache -c psalm5.xml"
}
},
{
"name": "example",
"name": "example-default",
"job": {
"php": "@latest",
"command": "diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.default.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.default.output"
}
},
{
"name": "example-recommend",
"job": {
"php": "@latest",
"command": "diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.recommend.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.recommend.output"
}
},
{
"name": "example-enableContextTypeRule",
"job": {
"php": "@latest",
"command": "diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.output"
"command": "diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.enableContextTypeRule.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.enableContextTypeRule.output"
}
}
],
Expand Down
41 changes: 31 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,54 @@
[![License](https://poser.pugx.org/struggle-for-php/sfp-phpstan-psr-log/license)](https://packagist.org/packages/struggle-for-php/sfp-phpstan-psr-log)
[![Psalm coverage](https://shepherd.dev/github/struggle-for-php/sfp-phpstan-psr-log/coverage.svg)](https://shepherd.dev/github/struggle-for-php/sfp-phpstan-psr-log)

> [!IMPORTANT]
> The next version `0.25.0` will have a BC break. Please refer `Stubs` section.
`struggle-for-php/sfp-phpstan-psr-log` is extra strict and opinionated psr/log (psr-3) rules for PHPStan.

* [PHPStan](https://phpstan.org/)
* [PSR-3: Logger Interface - PHP-FIG](https://www.php-fig.org/psr/psr-3/)
* [PSR-3 Meta Document](https://www.php-fig.org/psr/psr-3/meta/)

> [!IMPORTANT]
> Since `0.20.0`, changed default rule settings.
## Recommendation Settings

* MessageStaticStringRule is enabled by default.
* ContextRequireExceptionKeyRule is disabled by default.
* [Recommendation] write these parameters to your project's `phpstan.neon`.
Write these parameters to your project's `phpstan.neon`.

```neon
parameters:
sfpPsrLog:
enableMessageStaticStringRule: true
enableMessageStaticStringRule: false # default:true
enableContextRequireExceptionKeyRule: true
reportContextExceptionLogLevel: 'info'
contextKeyOriginalPattern: '#\A[A-Za-z0-9-_]+\z#'
```

## Stubs

This extension depends on our psr/log stub to serve strictness.
> [!IMPORTANT]
> include psr/log stub be planned to dropped in next release.
To try out the changes in the next version,

DELETE `vendor/struggle-for-php/sfp-phpstan-psr-log/extension.neon` line from your `phpstan.neon`

```neon
includes:
- vendor/struggle-for-php/sfp-phpstan-psr-log/extension.neon
```

and, set parameters `enableLogLevelMethodRule` and `enableContextTypeRule`

```neon
parameters:
sfpPsrLog:
enableLogLevelMethodRule: true # default:false
enableContextTypeRule: true # default:false
```

### About stub

Currently, this extension depends on our psr/log stub to serve strictness.

* eg.
* `@param LogLevel::* $level` at `log()` method
Expand Down Expand Up @@ -221,11 +244,9 @@ To use this extension, require it in [Composer](https://getcomposer.org/):
composer require --dev struggle-for-php/sfp-phpstan-psr-log
```

If you also install [phpstan/extension-installer](https://github.com/phpstan/extension-installer) then you're all set.

### Manual installation

If you don't want to use `phpstan/extension-installer`, include extension.neon & rules.neon in your project's PHPStan config:
include extension.neon & rules.neon in your project's PHPStan config:

```neon
includes:
Expand Down
49 changes: 49 additions & 0 deletions bin/phpstan-type-mapping-from-bigquery
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

use PHPStan\DependencyInjection\ContainerFactory;
use Sfp\PHPStan\Psr\Log\TypeMapping\BigQuery\GenericTableFieldSchemaJsonPayloadTypeMapper;
use Sfp\PHPStan\Psr\Log\TypeProvider\BigQueryContextTypeProvider;

/**
* borrowed from doctrine/sql-formatter 's sql-formatter
*/

if ('cli' !== php_sapi_name()) {
echo "<p>Run this PHP script from the command line to see mapping BigQuery schema to PHPStan Type. It supports Unix pipes or command line argument style.</p>";
exit;
}

if (isset($argv[1])) {
$schema = $argv[1];
} else {
$schema = stream_get_contents(fopen('php://stdin', 'r'));
}

$autoloadFiles = [
2 => __DIR__ . '/../vendor/autoload.php',
3 => __DIR__ . '/../../../autoload.php',
];

$rootDir = false;
foreach ($autoloadFiles as $deps => $autoloadFile) {
if (file_exists($autoloadFile)) {
$rootDir = dirname($autoloadFile, $deps);
require_once $autoloadFile;
break;
}
}

// bootstrap ReflectionProvider
$containerFactory = new ContainerFactory($rootDir);
$containerFactory->create(sys_get_temp_dir() . DIRECTORY_SEPARATOR . __FILE__, [], []);

$converter = new GenericTableFieldSchemaJsonPayloadTypeMapper();
$provider = new BigQueryContextTypeProvider(
'data://,' . $schema,
$converter
);

echo $provider->getType()->toPhpDocNode();
10 changes: 9 additions & 1 deletion composer-require-checker.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
"PHPStan\\Type\\ArrayType",
"PHPStan\\Type\\Constant\\ConstantStringType",
"PHPStan\\Type\\ObjectType",
"PHPStan\\Type\\Type"
"PHPStan\\Type\\Type",
"PHPStan\\Type\\Accessory\\AccessoryNumericStringType",
"PHPStan\\Type\\BooleanType",
"PHPStan\\Type\\Constant\\ConstantArrayType",
"PHPStan\\Type\\Constant\\ConstantArrayTypeBuilder",
"PHPStan\\Type\\FloatType",
"PHPStan\\Type\\IntegerType",
"PHPStan\\Type\\StringType",
"PHPStan\\Type\\TypeCombinator"
]
}
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
],
"require": {
"php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"ext-json": "*",
"phpstan/phpstan": "^1.12 || ^2.0",
"struggle-for-php/sfp-stubs-psr-log": "^1.0.1 || ^2 || ^3.0.1"
},
Expand Down Expand Up @@ -40,6 +41,7 @@
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"bin": ["bin/phpstan-type-mapping-from-bigquery"],
"extra": {
"phpstan": {
"includes": [
Expand Down
22 changes: 22 additions & 0 deletions example/phpstan.default.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# usage.
# ./vendor/bin/phpstan analyse -c ./example/phpstan.default.neon
#
# docker run -v $(realpath .):/github/workspace -w=/github/workspace ghcr.io/laminas/laminas-continuous-integration:1 \
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"./vendor/bin/phpstan analyse -c ./example/phpstan.default.neon --no-progress --error-format=junit | xmllint --format -"}'
# docker run -v $(realpath .):/github/workspace -w=/github/workspace ghcr.io/laminas/laminas-continuous-integration:1 \
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.default.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.output"}'

parameters:
level: 5
bootstrapFiles:
- %currentWorkingDirectory%/vendor/autoload.php
paths:
- %currentWorkingDirectory%/example/src
stubFiles:
# relative path can not work
- ../vendor/struggle-for-php/sfp-stubs-psr-log/stubs-for-throwable/LoggerInterface.phpstub

includes:
# relative path can not work
# - %currentWorkingDirectory%/extension.neon
- %currentWorkingDirectory%/rules.neon
26 changes: 26 additions & 0 deletions example/phpstan.enableContextTypeRule.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# usage.
# ./vendor/bin/phpstan analyse -c ./example/phpstan.enableContextTypeRule.neon
#
# docker run -v $(realpath .):/github/workspace -w=/github/workspace ghcr.io/laminas/laminas-continuous-integration:1 \
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"./vendor/bin/phpstan analyse -c ./example/phpstan.enableContextTypeRule.neon --no-progress --error-format=junit | xmllint --format -"}'
# docker run -v $(realpath .):/github/workspace -w=/github/workspace ghcr.io/laminas/laminas-continuous-integration:1 \
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.enableContextTypeRule.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.output"}'

parameters:
level: 5
bootstrapFiles:
- %currentWorkingDirectory%/vendor/autoload.php
paths:
- %currentWorkingDirectory%/example/src
sfpPsrLog:
enableLogLevelMethodRule: true
enableContextTypeRule: true

# services:
# sfpPsrLogContextTypeProvider :
# class: Sfp\PHPStan\Psr\Log\TypeProvider\Psr3ContextTypeProvider
# arguments:
# exceptionClass: '\Exception'

includes:
- %currentWorkingDirectory%/rules.neon
9 changes: 5 additions & 4 deletions example/phpstan.neon → example/phpstan.recommend.neon
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# usage.
# ./vendor/bin/phpstan analyse -c ./example/phpstan.neon
# ./vendor/bin/phpstan analyse -c ./example/phpstan.recommend.neon
#
# docker run -v $(realpath .):/github/workspace -w=/github/workspace ghcr.io/laminas/laminas-continuous-integration:1 \
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"./vendor/bin/phpstan analyse -c ./example/phpstan.neon --no-progress --error-format=junit | xmllint --format -"}'
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"./vendor/bin/phpstan analyse -c ./example/phpstan.recommend.neon --no-progress --error-format=junit | xmllint --format -"}'
# docker run -v $(realpath .):/github/workspace -w=/github/workspace ghcr.io/laminas/laminas-continuous-integration:1 \
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.output"}'
# '{"php":"8.2","dependencies":"latest","extensions":[],"ini":["memory_limit=-1"],"command":"diff <(./vendor/bin/phpstan analyse -c ./example/phpstan.recommend.neon --no-progress --error-format=junit | xmllint --format -) ./test/example.output"}'

parameters:
level: 5
Expand All @@ -17,10 +17,11 @@ parameters:
enableMessageStaticStringRule: true
reportContextExceptionLogLevel: 'notice'
contextKeyOriginalPattern: '#\A[A-Za-z0-9-]+\z#'
enableContextTypeRule: false
stubFiles:
- ../vendor/struggle-for-php/sfp-stubs-psr-log/stubs-for-throwable/LoggerInterface.phpstub

includes:
# relative path can not work
# - %currentWorkingDirectory%/extension.neon
# - %currentWorkingDirectory%/extension.neon
- %currentWorkingDirectory%/rules.neon
21 changes: 13 additions & 8 deletions example/src/Example.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace src;

use Psr\Log\LoggerInterface;
use Throwable;

use function sprintf;

Expand All @@ -19,8 +18,10 @@ public function __construct(LoggerInterface $logger)
$this->logger = $logger;
}

public function exceptionKeyOnlyAllowThrowable(Throwable $throwable): void
{
public function exceptionKeyOnlyAllowThrowable(
// phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
\Throwable $throwable
): void {
// invalid
$this->logger->notice('foo', ['exception' => $throwable->getMessage()]);
$this->logger->log('panic', 'foo', ['exception' => $throwable]);
Expand All @@ -29,17 +30,21 @@ public function exceptionKeyOnlyAllowThrowable(Throwable $throwable): void
$this->logger->log('notice', 'foo', ['exception' => $throwable]);
}

public function mustIncludesCurrentScopeThrowableIntoContext(Throwable $throwable): void
{
public function mustIncludesCurrentScopeThrowableIntoContext(
// phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
\Throwable $throwable
): void {
// Parameter $context of logger method Psr\Log\LoggerInterface::info() requires 'exception' key. Current scope has Throwable variable - $throwable
$this->logger->notice('foo');

$this->logger->notice('foo', ['user' => 1]);
}

public function reportContextExceptionLogLevel(Throwable $throwable): void
{
// phpstan.neon sfpPsrLog.reportContextExceptionLogLevel is 'notice'
public function reportContextExceptionLogLevel(
// phpcs:ignore SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
\Throwable $throwable
): void {
// phpstan.enableContextTypeRule.neon sfpPsrLog.reportContextExceptionLogLevel is 'notice'
// so bellow would not report.
$this->logger->debug('foo');
}
Expand Down
4 changes: 3 additions & 1 deletion phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
<file>src</file>
<file>test</file>

<exclude-pattern>test/TypeProvider/data/*</exclude-pattern>

<!-- Include all rules from Laminas Coding Standard -->
<rule ref="LaminasCodingStandard"/>

<rule ref="PSR12">
<exclude name="Generic.Files.LineLength"/>
<exclude name="WebimpressCodingStandard.Formatting.StringClassReference" />
</rule>
</ruleset>
</ruleset>
Loading

0 comments on commit 17bb014

Please sign in to comment.