Skip to content

Commit

Permalink
phpstan installation (#2249)
Browse files Browse the repository at this point in the history
* phpstan installation

* remove old symfony 4.2 code

* deprecate unused property

* remove symfony 5.3 BC layer

* remove bleedingEdge

* remove phpstan/extension-installer

* add phpstan-strict-rules

* rename to phpstan.dist.neon

* add phpstan job

* add phpstan-symfony application loader

* remove phpVersion

* source code fixes PHPStan level 1

* test code fixes PHPStan level 1

* fix strings used for int Asserts

* revert util change for PHP < 8.1

* remove mixed type usage

* remove __callStatic

* add baseline command

* PHPStan level 2

* cleanup ControllerReflector class

* remove bitwise operator usage

* PHPStan level 3

* PHPStan level 4

* PHPStan level 5

* bump deprecation version

Co-authored-by: Dominic Luidold <DominicLuidold@users.noreply.github.com>

* Create dependabot.yml

* Bump actions/cache from 3 to 4

Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](actions/cache@v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* drop sensio/framework-extra-bundle (#2256)

* add phpstan-baseline description

* remove config section

* move PropertyDescriberInterface errors to baseline

* add phpstan.neon to gitignore

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Dominic Luidold <DominicLuidold@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Apr 6, 2024
1 parent 8aa0ca0 commit fc5d60d
Show file tree
Hide file tree
Showing 74 changed files with 819 additions and 658 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/continuous-integration.yml
Expand Up @@ -101,3 +101,29 @@ jobs:

- name: Run PHP-CS-Fixer
run: vendor/bin/php-cs-fixer check -v --diff

phpstan:
name: PHPStan
runs-on: ubuntu-22.04

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Install PHP without coverage
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
tools: composer, flex
coverage: pcov

- name: Setup dependencies
uses: ./.github/workflows/common/composer-install
with:
symfony-version: "7.0.*"
install-doctrine-annotations: false

- name: Run PHPStan
run: vendor/bin/phpstan analyse --memory-limit=2G --no-progress --no-interaction
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -8,6 +8,7 @@
/Tests/Functional/cache
/Tests/Functional/logs
.idea
/phpstan.neon

###> friendsofphp/php-cs-fixer ###
/.php-cs-fixer.php
Expand Down
19 changes: 15 additions & 4 deletions composer.json
Expand Up @@ -53,9 +53,16 @@
"jms/serializer": "^1.14|^3.0",
"composer/package-versions-deprecated": "1.11.99.1",

"phpunit/phpunit": "^8.5|^9.6",
"doctrine/annotations": "^2.0",
"friendsofphp/php-cs-fixer": "^3.52"

"phpunit/phpunit": "^8.5|^9.6",

"friendsofphp/php-cs-fixer": "^3.52",

"phpstan/phpstan": "^1.10",
"phpstan/phpstan-symfony": "^1.3",
"phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan-strict-rules": "^1.5"
},
"conflict": {
"zircote/swagger-php": "4.8.7"
Expand Down Expand Up @@ -93,11 +100,15 @@
"scripts-descriptions": {
"phpcs-check": "Run PHP-CS-Fixer in dry-run mode",
"phpcs-fix": "Run PHP-CS-Fixer",
"phpunit": "Run phpunit"
"phpunit": "Run phpunit",
"phpstan": "Run phpstan",
"phpstan-baseline": "Generate a baseline for phpstan"
},
"scripts": {
"phpcs-check": "vendor/bin/php-cs-fixer check -v --diff",
"phpcs-fix": "vendor/bin/php-cs-fixer fix -v",
"phpunit": "phpunit"
"phpunit": "phpunit",
"phpstan": "phpstan --memory-limit=2G",
"phpstan-baseline": "phpstan --memory-limit=2G --generate-baseline"
}
}
126 changes: 126 additions & 0 deletions phpstan-baseline.neon
@@ -0,0 +1,126 @@
parameters:
ignoreErrors:
-
message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#"
count: 1
path: src/PropertyDescriber/ArrayPropertyDescriber.php

-
message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#"
count: 1
path: src/PropertyDescriber/CompoundPropertyDescriber.php

-
message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#"
count: 1
path: src/PropertyDescriber/DictionaryPropertyDescriber.php

-
message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#"
count: 1
path: src/PropertyDescriber/NullablePropertyDescriber.php

-
message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#"
count: 1
path: src/PropertyDescriber/PropertyDescriber.php

-
message: "#^PHPDoc tag @param references unknown parameter\\: \\$context$#"
count: 1
path: src/PropertyDescriber/PropertyDescriberInterface.php

-
message: "#^PHPDoc tag @param references unknown parameter\\: \\$schema$#"
count: 1
path: src/PropertyDescriber/PropertyDescriberInterface.php

-
message: "#^Method Nelmio\\\\ApiDocBundle\\\\PropertyDescriber\\\\PropertyDescriberInterface\\:\\:describe\\(\\) invoked with 5 parameters, 2\\-3 required\\.$#"
count: 1
path: src/PropertyDescriber/RequiredPropertyDescriber.php

-
message: "#^Call to method render\\(\\) on an unknown class Twig_Environment\\.$#"
count: 2
path: src/Render/Html/HtmlOpenApiRenderer.php

-
message: "#^Class Twig_Environment not found\\.$#"
count: 1
path: src/Render/Html/HtmlOpenApiRenderer.php

-
message: "#^Property Nelmio\\\\ApiDocBundle\\\\Render\\\\Html\\\\HtmlOpenApiRenderer\\:\\:\\$twig has unknown class Twig_Environment as its type\\.$#"
count: 1
path: src/Render/Html/HtmlOpenApiRenderer.php

-
message: "#^Access to property \\$allowBlank on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$description on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$key on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$key on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$map on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#"
count: 2
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$nullable on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#"
count: 2
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$nullable on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$strict on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Access to property \\$strict on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Call to method getName\\(\\) on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Call to method getName\\(\\) on an unknown class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam\\.$#"
count: 1
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\QueryParam not found\\.$#"
count: 3
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Class FOS\\\\RestBundle\\\\Controller\\\\Annotations\\\\RequestParam not found\\.$#"
count: 2
path: src/RouteDescriber/FosRestDescriber.php

-
message: "#^Call to function method_exists\\(\\) with 'Hateoas\\\\\\\\Configuration\\\\\\\\Embedded' and 'getType' will always evaluate to true\\.$#"
count: 1
path: tests/Functional/BazingaFunctionalTest.php
30 changes: 30 additions & 0 deletions phpstan.dist.neon
@@ -0,0 +1,30 @@
includes:
- phpstan-baseline.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-symfony/extension.neon
- vendor/phpstan/phpstan-symfony/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon

parameters:
level: 5
paths:
- src
- tests
excludePaths:
- tests/Functional/Entity/*
- tests/Functional/EntityExcluded/*
- tests/Functional/Controller/*
dynamicConstantNames:
- Symfony\Component\HttpKernel\Kernel::VERSION
- Symfony\Component\HttpKernel\Kernel::VERSION_ID
- Symfony\Component\HttpKernel\Kernel::MAJOR_VERSION
- Symfony\Component\HttpKernel\Kernel::MINOR_VERSION
- Symfony\Component\HttpKernel\Kernel::RELEASE_VERSION
symfony:
consoleApplicationLoader: tests/console-application.php
strictRules:
noVariableVariables: false # Neccessary for swagger-php integration
universalObjectCratesClasses:
- OpenApi\Context
treatPhpDocTypesAsCertain: false
9 changes: 4 additions & 5 deletions src/Annotation/Areas.php
Expand Up @@ -20,6 +20,9 @@ final class Areas
/** @var string[] */
private $areas;

/**
* @param string[]|array{value: string[]} $properties
*/
public function __construct(array $properties)
{
if (!array_key_exists('value', $properties) || !is_array($properties['value'])) {
Expand All @@ -36,15 +39,11 @@ public function __construct(array $properties)
throw new \InvalidArgumentException('An area must be given as a string');
}

if (!in_array($area, $areas)) {
if (!in_array($area, $areas, true)) {
$areas[] = $area;
}
}

if (0 === count($areas)) {
throw new \LogicException('At least one area is expected');
}

$this->areas = $areas;
}

Expand Down
4 changes: 2 additions & 2 deletions src/ApiDocGenerator.php
Expand Up @@ -90,14 +90,14 @@ public function generate(): OpenApi
return $this->openApi;
}

if ($this->cacheItemPool) {
if (null !== $this->cacheItemPool) {
$item = $this->cacheItemPool->getItem($this->cacheItemId);
if ($item->isHit()) {
return $this->openApi = $item->get();
}
}

if ($this->openApiVersion) {
if (null !== $this->openApiVersion) {
$this->generator->setVersion($this->openApiVersion);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Command/DumpCommand.php
Expand Up @@ -77,7 +77,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
];
}

if ($input->getOption('server-url')) {
if (null !== $input->getOption('server-url')) {
$options['server_url'] = $input->getOption('server-url');
}

Expand Down
7 changes: 1 addition & 6 deletions src/DependencyInjection/Configuration.php
Expand Up @@ -20,12 +20,7 @@ public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('nelmio_api_doc');

if (method_exists($treeBuilder, 'getRootNode')) {
$rootNode = $treeBuilder->getRootNode();
} else {
// symfony < 4.2 support
$rootNode = $treeBuilder->root('nelmio_api_doc');
}
$rootNode = $treeBuilder->getRootNode();

$rootNode
->children()
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyInjection/NelmioApiDocExtension.php
Expand Up @@ -284,7 +284,7 @@ public function load(array $configs, ContainerBuilder $container): void
private function findNameAliases(array $names, string $area): array
{
$nameAliases = array_filter($names, function (array $aliasInfo) use ($area) {
return empty($aliasInfo['areas']) || in_array($area, $aliasInfo['areas'], true);
return [] === $aliasInfo['areas'] || in_array($area, $aliasInfo['areas'], true);
});

$aliases = [];
Expand Down
4 changes: 2 additions & 2 deletions src/Describer/ApiPlatformDescriber.php
Expand Up @@ -21,11 +21,11 @@ final class ApiPlatformDescriber extends ExternalDocDescriber
public function __construct(object $documentation, NormalizerInterface $normalizer)
{
if (!$documentation instanceof DocumentationInterface && !$documentation instanceof OpenApi) {
throw new \InvalidArgumentException(sprintf('Argument 1 passed to %s() must be an instance of %s or %s. The documentation provided is an instance of %s.', __METHOD__, Documentation::class, OpenApi::class, get_class($documentation)));
throw new \InvalidArgumentException(sprintf('Argument 1 passed to %s() must be an instance of %s or %s. The documentation provided is an instance of %s.', __METHOD__, DocumentationInterface::class, OpenApi::class, get_class($documentation)));
}

if (!$normalizer->supportsNormalization($documentation, 'json')) {
throw new \InvalidArgumentException(sprintf('Argument 2 passed to %s() must implement %s and support normalization of %s. The normalizer provided is an instance of %s.', __METHOD__, NormalizerInterface::class, Documentation::class, get_class($normalizer)));
throw new \InvalidArgumentException(sprintf('Argument 2 passed to %s() must implement %s and support normalization of %s. The normalizer provided is an instance of %s.', __METHOD__, NormalizerInterface::class, DocumentationInterface::class, get_class($normalizer)));
}

parent::__construct(function () use ($documentation, $normalizer) {
Expand Down
2 changes: 1 addition & 1 deletion src/Describer/DefaultDescriber.php
Expand Up @@ -42,7 +42,7 @@ public function describe(OA\OpenApi $api)
foreach (Util::OPERATIONS as $method) {
/** @var OA\Operation $operation */
$operation = $path->{$method};
if (Generator::UNDEFINED !== $operation && null !== $operation && (Generator::UNDEFINED === $operation->responses || empty($operation->responses))) {
if (Generator::UNDEFINED !== $operation && null !== $operation && (Generator::UNDEFINED === $operation->responses || [] === $operation->responses)) {
/** @var OA\Response $response */
$response = Util::getIndexedCollectionItem($operation, OA\Response::class, 'default');
$response->description = '';
Expand Down
2 changes: 1 addition & 1 deletion src/Describer/ExternalDocDescriber.php
Expand Up @@ -33,7 +33,7 @@ public function describe(OA\OpenApi $api)
{
$externalDoc = $this->getExternalDoc();

if (!empty($externalDoc)) {
if ($externalDoc) {
Util::merge($api, $externalDoc, $this->overwrite);
}
}
Expand Down
17 changes: 12 additions & 5 deletions src/Describer/OpenApiPhpDescriber.php
Expand Up @@ -39,15 +39,17 @@ final class OpenApiPhpDescriber
*/
private $annotationReader;
private $logger;
private $overwrite;

public function __construct(RouteCollection $routeCollection, ControllerReflector $controllerReflector, ?Reader $annotationReader, LoggerInterface $logger, bool $overwrite = false)
{
if ($overwrite || func_num_args() > 4) {
trigger_deprecation('nelmio/api-doc-bundle', '4.25.2', 'The "$overwrite" argument of "%s" is unused and therefore deprecated.', __METHOD__);
}

$this->routeCollection = $routeCollection;
$this->controllerReflector = $controllerReflector;
$this->annotationReader = $annotationReader;
$this->logger = $logger;
$this->overwrite = $overwrite;
}

public function describe(OA\OpenApi $api)
Expand Down Expand Up @@ -155,7 +157,7 @@ public function describe(OA\OpenApi $api)
$implicitAnnotations[] = $annotation;
}

if (empty($implicitAnnotations) && empty(get_object_vars($mergeProperties))) {
if ([] === $implicitAnnotations && [] === get_object_vars($mergeProperties)) {
continue;
}

Expand Down Expand Up @@ -187,7 +189,7 @@ private function getMethodsToParse(): \Generator
}
$path = $this->normalizePath($route->getPath());
$supportedHttpMethods = $this->getSupportedHttpMethods($route);
if (empty($supportedHttpMethods)) {
if ([] === $supportedHttpMethods) {
$this->logger->warning('None of the HTTP methods specified for path {path} are supported by swagger-ui, skipping this path', [
'path' => $path,
]);
Expand All @@ -203,7 +205,12 @@ private function getSupportedHttpMethods(Route $route): array
$allMethods = Util::OPERATIONS;
$methods = array_map('strtolower', $route->getMethods());

return array_intersect($methods ?: $allMethods, $allMethods);
// an empty array means that any method is allowed
if ([] === $methods) {
return $allMethods;
}

return array_intersect($methods, $allMethods);
}

private function normalizePath(string $path): string
Expand Down

0 comments on commit fc5d60d

Please sign in to comment.