diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fe594210..a2033873 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,10 +1,11 @@ name: 'CI' on: + workflow_dispatch: ~ push: branches: - master - pull_request: + pull_request: ~ jobs: @@ -54,7 +55,9 @@ jobs: - name: 'PHP CS Fixer' if: always() && steps.deps.outcome == 'success' - run: vendor/bin/php-cs-fixer fix --dry-run --diff + run: | + make php-cs-fixer.phar + ./php-cs-fixer.phar fix --dry-run --diff - name: 'PhpStan' if: always() && steps.deps.outcome == 'success' @@ -76,7 +79,38 @@ jobs: strategy: fail-fast: false # don't cancel other matrix jobs on failure matrix: - php: [ '7.4', '8.0' ] + include: + # Previous Symfony versions + - name: 'Test Symfony 5.3 [Linux, PHP 8.0]' + os: 'ubuntu-latest' + php: '8.0' + symfony: '5.3.*' + + # Previous PHP versions + - name: 'Test Symfony 5.4 [Linux, PHP 7.4]' + os: 'ubuntu-latest' + php: '7.4' + symfony: '5.4.*@dev' + allow-unstable: true + + # Most recent versions + - name: 'Test Symfony 5.4 [Linux, PHP 8.1]' + os: 'ubuntu-latest' + php: '8.1' + symfony: '5.4.*@dev' + allow-unstable: true + + - name: 'Test Symfony 5.4 [Windows, PHP 8.0]' + os: 'windows-latest' + php: '8.0' + symfony: '5.4.*@dev' + allow-unstable: true + + - name: 'Test Symfony 6.0 [Linux, PHP 8.1]' + os: 'ubuntu-latest' + php: '8.1' + symfony: '6.0.*@dev' + allow-unstable: true steps: - name: 'Checkout' @@ -84,39 +118,40 @@ jobs: - name: 'Setup PHP' uses: shivammathur/setup-php@v2 + with: - coverage: "none" - extensions: "json" - ini-values: "memory_limit=-1" - php-version: "${{ matrix.php }}" + php-version: ${{ matrix.php }} + coverage: none + extensions: json + ini-values: 'memory_limit=-1' + tools: 'composer:v2,flex' - - name: 'Determine composer cache directory' + - name: 'Get composer cache directory' id: composer-cache - run: echo "::set-output name=directory::$(composer config cache-dir)" + run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - name: 'Cache composer dependencies' + - name: 'Cache dependencies' uses: actions/cache@v2 with: - path: ${{ steps.composer-cache.outputs.directory }} - key: ${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ matrix.php }}-composer- + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-${{ hashFiles('**/composer.json') }}-flags-${{ matrix.composer-flags }} + restore-keys: ${{ runner.os }}-composer- - - name: 'Fixup Composer' - if: matrix.php == 8.0 - run: | - echo "::group::Fixup Composer platform config for third-parties deps not PHP 8 ready yet" - composer config platform.php 7.4.99 - echo "::endgroup::" + - name: 'Allow unstable packages' + run: composer config minimum-stability dev + if: ${{ matrix.allow-unstable }} - name: 'Install dependencies' run: | echo "::group::composer update" - composer update --no-progress --ansi + composer update --prefer-dist --no-progress ${{ matrix.composer-flags }} --ansi echo "::endgroup::" echo "::group::install phpunit" vendor/bin/simple-phpunit install echo "::endgroup::" + env: + SYMFONY_REQUIRE: "${{ matrix.symfony }}" - name: 'Run tests' run: vendor/bin/simple-phpunit --testdox @@ -126,9 +161,6 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 - strategy: - fail-fast: false # don't cancel other matrix jobs on failure - steps: - name: 'Checkout' uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 868b1c50..26067f75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /vendor /composer.lock -/.php_cs.cache +/.php-cs-fixer.cache /.phpunit.result.cache /node_modules +/php-cs-fixer.phar diff --git a/.php_cs b/.php-cs-fixer.php similarity index 86% rename from .php_cs rename to .php-cs-fixer.php index 2eaddb54..27bae6fb 100644 --- a/.php_cs +++ b/.php-cs-fixer.php @@ -13,27 +13,29 @@ ->exclude('tests/fixtures/app/build') ; -return PhpCsFixer\Config::create() +return (new PhpCsFixer\Config) ->setUsingCache(true) ->setRiskyAllowed(true) ->setFinder($finder) ->setRules([ '@Symfony' => true, - 'php_unit_namespaced' => true, - 'psr0' => false, + 'array_syntax' => ['syntax' => 'short'], 'concat_space' => ['spacing' => 'one'], - 'phpdoc_summary' => false, + 'header_comment' => ['header' => $header], + 'native_function_invocation' => ['include' => ['@compiler_optimized']], + 'ordered_imports' => true, + 'php_unit_namespaced' => true, + 'php_unit_method_casing' => false, 'phpdoc_annotation_without_dot' => false, + 'phpdoc_summary' => false, 'phpdoc_order' => true, - 'array_syntax' => ['syntax' => 'short'], - 'ordered_imports' => true, + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'psr_autoloading' => true, + 'single_line_throw' => false, 'simplified_null_return' => false, - 'header_comment' => ['header' => $header], - 'yoda_style' => [], - 'no_superfluous_phpdoc_tags' => true, - 'native_function_invocation' => ['include' => ['@compiler_optimized']], 'void_return' => true, - 'single_line_throw' => false, + 'yoda_style' => [], + // @see https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/5495 'binary_operator_spaces' => ['operators' => ['|' => null]] ]) diff --git a/Makefile b/Makefile index a0d638f1..60fb421c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ .PHONY: dist +PHP_CS_FIXER_VERSION=v3.3.2 + ########## # Colors # ########## @@ -25,8 +27,30 @@ php8: # Install # ########### +setup: + composer global require --no-progress --no-scripts --no-plugins symfony/flex + +install: setup install: + rm -f composer.lock + composer config minimum-stability --unset + composer update --prefer-dist + +install-54: setup +install-54: export SYMFONY_REQUIRE = 5.4.*@dev +install-54: + rm -f composer.lock + composer config minimum-stability dev + composer update + composer config minimum-stability --unset + +install-60: setup +install-60: export SYMFONY_REQUIRE = 6.0.*@dev +install-60: + rm -f composer.lock + composer config minimum-stability dev composer update + composer config minimum-stability --unset ######## # Lint # @@ -34,16 +58,26 @@ install: lint: lint-phpcsfixer lint-phpstan lint-twig lint-yaml lint-composer -fix-phpcsfixer: php8 -fix-phpcsfixer: - vendor/bin/php-cs-fixer fix - lint-composer: composer validate --strict +php-cs-fixer.phar: + wget --no-verbose https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/${PHP_CS_FIXER_VERSION}/php-cs-fixer.phar + chmod +x php-cs-fixer.phar + +update-php-cs-fixer.phar: + rm -f php-cs-fixer.phar + make php-cs-fixer.phar + lint-phpcsfixer: php8 +lint-phpcsfixer: php-cs-fixer.phar lint-phpcsfixer: - vendor/bin/php-cs-fixer fix --dry-run --diff + ./php-cs-fixer.phar fix --dry-run --diff + +fix-phpcsfixer: php8 +fix-phpcsfixer: php-cs-fixer.phar +fix-phpcsfixer: + ./php-cs-fixer.phar fix lint-phpstan: vendor/bin/phpstan analyse --memory-limit=-1 diff --git a/composer.json b/composer.json index f575a7df..08245173 100644 --- a/composer.json +++ b/composer.json @@ -32,43 +32,44 @@ } }, "prefer-stable": true, - "minimum-stability": "dev", "require": { "php": ">=7.4", "ext-dom": "*", "erusev/parsedown": "^1.7.4", - "symfony/asset": "^5.1", - "symfony/config": "^5.1", - "symfony/console": "^5.1", - "symfony/css-selector": "^5.1", - "symfony/dependency-injection": "^5.1", - "symfony/dom-crawler": "^5.1", - "symfony/event-dispatcher": "^5.1", - "symfony/filesystem": "^5.1", - "symfony/finder": "^5.1", - "symfony/http-foundation": "^5.1", - "symfony/http-kernel": "^5.1", - "symfony/mime": "^5.1", - "symfony/process": "^5.1", - "symfony/property-access": "^5.1", - "symfony/routing": "^5.1", - "symfony/serializer": "^5.1", - "symfony/string": "^5.1", - "symfony/yaml": "^5.1", + "symfony/asset": "^5.1|^6.0", + "symfony/config": "^5.1|^6.0", + "symfony/console": "^5.1|^6.0", + "symfony/css-selector": "^5.1|^6.0", + "symfony/dependency-injection": "^5.1|^6.0", + "symfony/dom-crawler": "^5.1|^6.0", + "symfony/event-dispatcher": "^5.1|^6.0", + "symfony/filesystem": "^5.1|^6.0", + "symfony/finder": "^5.1|^6.0", + "symfony/http-foundation": "^5.1|^6.0", + "symfony/http-kernel": "^5.1|^6.0", + "symfony/mime": "^5.1|^6.0", + "symfony/process": "^5.1|^6.0", + "symfony/property-access": "^5.1|^6.0", + "symfony/routing": "^5.1|^6.0", + "symfony/serializer": "^5.1|^6.0", + "symfony/string": "^5.1|^6.0", + "symfony/yaml": "^5.1|^6.0", "twig/twig": "^2.12|^3.0" }, "require-dev": { + "doctrine/annotations": "^1.9", "ekino/phpstan-banned-code": "^0.4", - "friendsofphp/php-cs-fixer": "^2.16", "phpspec/prophecy-phpunit": "^2.0", "phpstan/phpstan": "^0.12.32", - "symfony/browser-kit": "^5.1", - "symfony/expression-language": "^5.1", - "symfony/framework-bundle": "^5.1", + "psr/log": "^1", + "symfony/browser-kit": "^5.1|^6.0", + "symfony/expression-language": "^5.1|^6.0", + "symfony/framework-bundle": "^5.1|^6.0", "symfony/monolog-bundle": "^3.7", - "symfony/phpunit-bridge": "^5.1", - "symfony/twig-bridge": "^5.1", - "symfony/twig-bundle": "^5.1" + "symfony/phpunit-bridge": "^5.3|^6.0", + "symfony/stopwatch": "^5.1|^6.0", + "symfony/twig-bridge": "^5.1|^6.0", + "symfony/twig-bundle": "^5.1|^6.0" }, "extra": { "branch-alias": { @@ -76,6 +77,9 @@ } }, "config": { + "preferred-install": { + "*": "dist" + }, "sort-packages": true } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e4e48938..5fd906ef 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,9 +13,9 @@ - - + + diff --git a/src/Builder/Sitemap.php b/src/Builder/Sitemap.php index 6a2f4674..e6f7d17e 100644 --- a/src/Builder/Sitemap.php +++ b/src/Builder/Sitemap.php @@ -9,7 +9,8 @@ namespace Stenope\Bundle\Builder; /** - * Sitemap + * @phpstan-implements \Iterator + * @final */ class Sitemap implements \Iterator, \Countable { @@ -21,8 +22,6 @@ class Sitemap implements \Iterator, \Countable private $urls = []; /** - * Position - * * @var int */ private $position = 0; @@ -30,10 +29,10 @@ class Sitemap implements \Iterator, \Countable /** * Add location * - * @param string $location The URL - * @param DateTime $lastModified Date of last modification - * @param int $priority Location priority - * @param string $frequency + * @param string $location The URL + * @param \DateTime $lastModified Date of last modification + * @param int $priority Location priority + * @param string $frequency */ public function add(string $location, \DateTime $lastModified = null, int $priority = null, string $frequency = null): void { @@ -68,7 +67,10 @@ public function rewind(): void /** * {@inheritdoc} + * + * @return mixed */ + #[\ReturnTypeWillChange] public function current() { return $this->urls[array_keys($this->urls)[$this->position]]; @@ -76,7 +78,10 @@ public function current() /** * {@inheritdoc} + * + * @return mixed */ + #[\ReturnTypeWillChange] public function key() { return array_keys($this->urls)[$this->position]; @@ -93,7 +98,7 @@ public function next(): void /** * {@inheritdoc} */ - public function valid() + public function valid(): bool { return isset(array_keys($this->urls)[$this->position]); } @@ -101,7 +106,7 @@ public function valid() /** * {@inheritdoc} */ - public function count() + public function count(): int { return \count($this->urls); } diff --git a/src/Command/DebugCommand.php b/src/Command/DebugCommand.php index 0b139d36..9b71d02b 100644 --- a/src/Command/DebugCommand.php +++ b/src/Command/DebugCommand.php @@ -190,11 +190,11 @@ private function getOrders(array $rawOrders): array { $orders = []; foreach ($rawOrders ?? [] as $field) { - if (\str_starts_with($field, 'desc:')) { + if (str_starts_with($field, 'desc:')) { $orders[substr($field, 5)] = false; continue; } - if (\str_starts_with($field, '-')) { + if (str_starts_with($field, '-')) { $orders[substr($field, 1)] = false; continue; } diff --git a/src/Command/StopwatchHelperTrait.php b/src/Command/StopwatchHelperTrait.php index 4df07286..a57a45fa 100644 --- a/src/Command/StopwatchHelperTrait.php +++ b/src/Command/StopwatchHelperTrait.php @@ -11,15 +11,18 @@ use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Stopwatch\StopwatchEvent; +/** + * @internal + */ trait StopwatchHelperTrait { private static function formatEvent(StopwatchEvent $event): string { return sprintf( 'Start time: %s — End time: %s — Duration: %s — Memory used: %s', - date('H:i:s', ($event->getOrigin() + $event->getStartTime()) / 1000), - date('H:i:s', ($event->getOrigin() + $event->getEndTime()) / 1000), - static::formatTimePrecision($event->getDuration() / 1000), + date('H:i:s', (int) (($event->getOrigin() + $event->getStartTime()) / 1000)), + date('H:i:s', (int) (($event->getOrigin() + $event->getEndTime()) / 1000)), + static::formatTimePrecision((int) $event->getDuration() / 1000), Helper::formatMemory($event->getMemory()) ); } diff --git a/src/ContentManager.php b/src/ContentManager.php index 2ee57689..7881d364 100644 --- a/src/ContentManager.php +++ b/src/ContentManager.php @@ -122,13 +122,13 @@ private function filterBy(array &$contents, $filterBy = null): void private function sortBy(array &$contents, $sortBy = null): void { if ($sorter = $this->getSortFunction($sortBy)) { - \set_error_handler(static function (int $severity, string $message, ?string $file, ?int $line): void { + set_error_handler(static function (int $severity, string $message, ?string $file, ?int $line): void { throw new \ErrorException($message, $severity, $severity, $file, $line); }); uasort($contents, $sorter); - \restore_error_handler(); + restore_error_handler(); } } diff --git a/src/Decoder/HtmlDecoder.php b/src/Decoder/HtmlDecoder.php index 7f788ff1..d604b8e6 100644 --- a/src/Decoder/HtmlDecoder.php +++ b/src/Decoder/HtmlDecoder.php @@ -13,6 +13,8 @@ /** * Parse Html data + * + * @final */ class HtmlDecoder implements DecoderInterface { @@ -24,7 +26,7 @@ class HtmlDecoder implements DecoderInterface /** * {@inheritdoc} */ - public function decode($data, $format, array $context = []) + public function decode($data, $format, array $context = []): array { $crawler = new Crawler($data); @@ -46,7 +48,7 @@ public function decode($data, $format, array $context = []) /** * {@inheritdoc} */ - public function supportsDecoding($format) + public function supportsDecoding($format): bool { return self::FORMAT === $format; } diff --git a/src/Decoder/MarkdownDecoder.php b/src/Decoder/MarkdownDecoder.php index 2e7bb446..7a09685f 100644 --- a/src/Decoder/MarkdownDecoder.php +++ b/src/Decoder/MarkdownDecoder.php @@ -14,6 +14,8 @@ /** * Parse Markdown data + * + * @final */ class MarkdownDecoder implements DecoderInterface { @@ -36,7 +38,7 @@ public function __construct(Parsedown $parser) /** * {@inheritdoc} */ - public function decode($data, $format, array $context = []) + public function decode($data, $format, array $context = []): array { $content = trim($data); $separator = static::HEAD_SEPARATOR; @@ -57,7 +59,7 @@ public function decode($data, $format, array $context = []) /** * {@inheritdoc} */ - public function supportsDecoding($format) + public function supportsDecoding($format): bool { return self::FORMAT === $format; } diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 06c97c80..21e6ef94 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -13,13 +13,16 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; +/** + * @final + */ class Configuration implements ConfigurationInterface { private const NATIVE_PROVIDERS_TYPES = [ LocalFilesystemProviderFactory::TYPE, ]; - public function getConfigTreeBuilder() + public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('stenope'); $rootNode = method_exists(TreeBuilder::class, 'getRootNode') ? $treeBuilder->getRootNode() : $treeBuilder->root('stenope'); diff --git a/src/DependencyInjection/StenopeExtension.php b/src/DependencyInjection/StenopeExtension.php index 3a58449d..aeac4d22 100644 --- a/src/DependencyInjection/StenopeExtension.php +++ b/src/DependencyInjection/StenopeExtension.php @@ -26,6 +26,9 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +/** + * @final + */ class StenopeExtension extends Extension { public function load(array $configs, ContainerBuilder $container): void @@ -60,12 +63,12 @@ public function load(array $configs, ContainerBuilder $container): void } } - public function getNamespace() + public function getNamespace(): string { return 'http://stenope.com/schema/dic/stenope'; } - public function getXsdValidationBasePath() + public function getXsdValidationBasePath(): string { return __DIR__ . '/../../config/schema'; } diff --git a/src/EventListener/Informator.php b/src/EventListener/Informator.php index b1caed57..6fd89eaa 100644 --- a/src/EventListener/Informator.php +++ b/src/EventListener/Informator.php @@ -15,11 +15,12 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Twig\Environment; +/** + * @final + */ class Informator implements EventSubscriberInterface { /** - * Url Generator - * * @var UrlGeneratorInterface */ private $urlGenerator; @@ -31,9 +32,6 @@ class Informator implements EventSubscriberInterface */ private $twig; - /** - * Injecting dependencies - */ public function __construct(UrlGeneratorInterface $urlGenerator, Environment $twig) { $this->urlGenerator = $urlGenerator; @@ -43,14 +41,11 @@ public function __construct(UrlGeneratorInterface $urlGenerator, Environment $tw /** * {@inheritdoc} */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [KernelEvents::REQUEST => 'onRequest']; } - /** - * Before request - */ public function onRequest(RequestEvent $event): void { $request = $event->getRequest(); @@ -66,12 +61,7 @@ public function onRequest(RequestEvent $event): void } } - /** - * Get canonical URL - * - * @return string - */ - private function getCanonicalUrl(Request $request) + private function getCanonicalUrl(Request $request): string { if (!$request->attributes->get('_route')) { return ''; @@ -84,12 +74,7 @@ private function getCanonicalUrl(Request $request) ); } - /** - * Get root URL - * - * @return string - */ - private function getRootUrl(Request $request) + private function getRootUrl(Request $request): string { return sprintf('%s://%s', $request->getScheme(), $request->getHost()); } diff --git a/src/EventListener/SitemapListener.php b/src/EventListener/SitemapListener.php index 51ff64c4..8d1a7baa 100644 --- a/src/EventListener/SitemapListener.php +++ b/src/EventListener/SitemapListener.php @@ -16,6 +16,8 @@ /** * Map all routes into a Sitemap + * + * @final */ class SitemapListener implements EventSubscriberInterface { @@ -42,7 +44,7 @@ public function onKernelResponse(ResponseEvent $event): void if ($route && $route->isMapped() && $request->attributes->get('_canonical')) { $this->sitemap->add( $request->attributes->get('_canonical'), - new \DateTime($response->headers->get('Last-Modified')) + new \DateTime($response->headers->get('Last-Modified') ?? 'now') ); } } @@ -50,7 +52,7 @@ public function onKernelResponse(ResponseEvent $event): void /** * {@inheritdoc} */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [KernelEvents::RESPONSE => 'onKernelResponse']; } diff --git a/src/ExpressionLanguage/ExpressionLanguageProvider.php b/src/ExpressionLanguage/ExpressionLanguageProvider.php index f5de43ab..690446f8 100644 --- a/src/ExpressionLanguage/ExpressionLanguageProvider.php +++ b/src/ExpressionLanguage/ExpressionLanguageProvider.php @@ -24,7 +24,7 @@ public function __construct(iterable $providers = []) $this->providers = $providers; } - public function getFunctions() + public function getFunctions(): iterable { // prepend the default functions to let users override these easily: yield from [ diff --git a/src/HttpKernel/Controller/ArgumentResolver/ContentArgumentResolver.php b/src/HttpKernel/Controller/ArgumentResolver/ContentArgumentResolver.php index 12e92231..aec9ec76 100644 --- a/src/HttpKernel/Controller/ArgumentResolver/ContentArgumentResolver.php +++ b/src/HttpKernel/Controller/ArgumentResolver/ContentArgumentResolver.php @@ -13,6 +13,9 @@ use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; +/** + * @final + */ class ContentArgumentResolver implements ArgumentValueResolverInterface { private ContentManagerInterface $contentManager; @@ -22,7 +25,7 @@ public function __construct(ContentManagerInterface $contentManager) $this->contentManager = $contentManager; } - public function resolve(Request $request, ArgumentMetadata $argument) + public function resolve(Request $request, ArgumentMetadata $argument): iterable { $slug = $request->attributes->get($argument->getName()); @@ -33,7 +36,7 @@ public function resolve(Request $request, ArgumentMetadata $argument) yield $this->contentManager->getContent($argument->getType(), $slug); } - public function supports(Request $request, ArgumentMetadata $argument) + public function supports(Request $request, ArgumentMetadata $argument): bool { if (null === $argument->getType() || !$this->contentManager->supports($argument->getType())) { return false; diff --git a/src/Processor/HtmlIdProcessor.php b/src/Processor/HtmlIdProcessor.php index facfbbf3..4fd0c0d1 100644 --- a/src/Processor/HtmlIdProcessor.php +++ b/src/Processor/HtmlIdProcessor.php @@ -77,7 +77,7 @@ private function setIdFromHashedContent(\DOMElement $element): void private function setIdForImage(\DOMElement $element): void { if (!$id = $element->getAttribute('id')) { - $name = $element->getAttribute('alt') ?: \basename($element->getAttribute('src')); + $name = $element->getAttribute('alt') ?: basename($element->getAttribute('src')); $element->setAttribute('id', $this->slugify($name)); } } diff --git a/src/Routing/RouteInfoCollection.php b/src/Routing/RouteInfoCollection.php index 9bbf3182..f8a96bfc 100644 --- a/src/Routing/RouteInfoCollection.php +++ b/src/Routing/RouteInfoCollection.php @@ -11,7 +11,8 @@ use Symfony\Component\Routing\RouterInterface; /** - * @phpstan-implements IteratorAggregate + * @phpstan-implements \IteratorAggregate + * @final */ class RouteInfoCollection implements \IteratorAggregate, \ArrayAccess, \Countable { @@ -37,20 +38,17 @@ private function getInfos(): array return $this->routeInfos; } - public function getIterator() + public function getIterator(): \Traversable { return new \ArrayIterator($this->getInfos()); } - public function offsetExists($offset) + public function offsetExists($offset): bool { return isset($this->getInfos()[$offset]); } - /** - * @return RouteInfo|null - */ - public function offsetGet($offset) + public function offsetGet($offset): ?RouteInfo { return $this->getInfos()[$offset] ?? null; } @@ -65,7 +63,7 @@ public function offsetUnset($offset): void throw new \BadMethodCallException(sprintf('Unexpected call to "%s()"', __METHOD__)); } - public function count() + public function count(): int { return \count($this->getInfos()); } diff --git a/src/Routing/UrlGenerator.php b/src/Routing/UrlGenerator.php index e5742682..9de874cc 100644 --- a/src/Routing/UrlGenerator.php +++ b/src/Routing/UrlGenerator.php @@ -14,6 +14,8 @@ /** * A wrapper for UrlGenerator that register every generated url in the PageList. + * + * @final */ class UrlGenerator implements UrlGeneratorInterface { @@ -28,7 +30,7 @@ public function __construct(RouteInfoCollection $routesInfo, UrlGeneratorInterfa $this->routesInfo = $routesInfo; } - public function generate($name, $parameters = [], $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH) + public function generate($name, $parameters = [], $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string { if (($routeInfo = $this->routesInfo[$name] ?? null) && !$routeInfo->isIgnored()) { $this->pageList->add( @@ -44,7 +46,7 @@ public function setContext(RequestContext $context): void $this->urlGenerator->setContext($context); } - public function getContext() + public function getContext(): RequestContext { return $this->urlGenerator->getContext(); } diff --git a/src/Serializer/Normalizer/SkippingInstantiatedObjectDenormalizer.php b/src/Serializer/Normalizer/SkippingInstantiatedObjectDenormalizer.php index 3b3c8526..0c1a0eca 100644 --- a/src/Serializer/Normalizer/SkippingInstantiatedObjectDenormalizer.php +++ b/src/Serializer/Normalizer/SkippingInstantiatedObjectDenormalizer.php @@ -12,12 +12,14 @@ /** * Avoiding double-denormalization for already instantiated objects inside $data. + * + * @final */ class SkippingInstantiatedObjectDenormalizer implements ContextAwareDenormalizerInterface { public const SKIP = 'skip_instantiated_object'; - public function denormalize($data, string $type, string $format = null, array $context = []) + public function denormalize($data, string $type, string $format = null, array $context = []): object { return $data; } diff --git a/src/StenopeBundle.php b/src/StenopeBundle.php index 457ab392..c53bb067 100644 --- a/src/StenopeBundle.php +++ b/src/StenopeBundle.php @@ -12,6 +12,9 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; +/** + * @final + */ class StenopeBundle extends Bundle { public function build(ContainerBuilder $container): void @@ -21,7 +24,7 @@ public function build(ContainerBuilder $container): void $container->addCompilerPass(new TwigExtensionFixerCompilerPass()); } - public function getPath() + public function getPath(): string { return \dirname(__DIR__); } diff --git a/src/Twig/ContentExtension.php b/src/Twig/ContentExtension.php index 9d0e7e79..b7a71864 100644 --- a/src/Twig/ContentExtension.php +++ b/src/Twig/ContentExtension.php @@ -11,9 +11,12 @@ use Twig\Extension\AbstractExtension; use Twig\TwigFunction; +/** + * @final + */ class ContentExtension extends AbstractExtension { - public function getFunctions() + public function getFunctions(): array { return [ new TwigFunction('content_get', [ContentRuntime::class, 'getContent']), diff --git a/tests/Integration/BuildTest.php b/tests/Integration/BuildTest.php index 1d6e5aed..0c4fc741 100644 --- a/tests/Integration/BuildTest.php +++ b/tests/Integration/BuildTest.php @@ -64,7 +64,7 @@ public function testBuildApp(): void $this->assertStringContainsString('[OK] Built 17 pages.', $output); /** @var TestLogger $logger */ - $logger = static::$container->get('logger'); + $logger = static::getContainer()->get('logger'); $logger->hasWarningThatContains('Url "http://localhost/without-noindex" contains a "x-robots-tag: noindex" header that will be lost by going static.'); } diff --git a/tests/Unit/DependencyInjection/StenopeExtensionTest.php b/tests/Unit/DependencyInjection/StenopeExtensionTest.php index 667da95d..b8f2df92 100644 --- a/tests/Unit/DependencyInjection/StenopeExtensionTest.php +++ b/tests/Unit/DependencyInjection/StenopeExtensionTest.php @@ -19,7 +19,7 @@ abstract class StenopeExtensionTest extends TestCase { - const FIXTURES_PATH = __DIR__ . '/../../fixtures/Unit/DependencyInjection/StenopeExtension'; + public const FIXTURES_PATH = __DIR__ . '/../../fixtures/Unit/DependencyInjection/StenopeExtension'; public function testDefaults(): void { diff --git a/tests/Unit/Service/Git/LastModifiedFetcherTest.php b/tests/Unit/Service/Git/LastModifiedFetcherTest.php index 14eac68a..6dfa2073 100644 --- a/tests/Unit/Service/Git/LastModifiedFetcherTest.php +++ b/tests/Unit/Service/Git/LastModifiedFetcherTest.php @@ -44,13 +44,12 @@ public function testUnavailable(): void self::assertCount(1, $logger->records); self::assertNull($fetcher->__invoke('some-fake-path')); - self::assertCount(1, $logger->records, 'Do not attempt to check git avaiulability twice'); + self::assertCount(1, $logger->records, 'Do not attempt to check git availability twice'); } public function testSuccess(): void { - $logger = new TestLogger(); - $fetcher = new LastModifiedFetcher(self::$executable, $logger); + $fetcher = new LastModifiedFetcher(self::$executable); $fetcher->reset(); self::assertInstanceOf(\DateTimeImmutable::class, $date = $fetcher->__invoke('some-fake-path')); @@ -59,8 +58,7 @@ public function testSuccess(): void public function testEmpty(): void { - $logger = new TestLogger(); - $fetcher = new LastModifiedFetcher(self::$executable, $logger); + $fetcher = new LastModifiedFetcher(self::$executable); $fetcher->reset(); self::assertNull($fetcher->__invoke('empty')); @@ -68,8 +66,7 @@ public function testEmpty(): void public function testFailure(): void { - $logger = new TestLogger(); - $fetcher = new LastModifiedFetcher(self::$executable, $logger); + $fetcher = new LastModifiedFetcher(self::$executable); $fetcher->reset(); $this->expectException(ProcessFailedException::class); diff --git a/tests/Unit/TableOfContent/CrawlerTableOfContentGeneratorTest.php b/tests/Unit/TableOfContent/CrawlerTableOfContentGeneratorTest.php index efb9b9d7..ad7a5c7d 100644 --- a/tests/Unit/TableOfContent/CrawlerTableOfContentGeneratorTest.php +++ b/tests/Unit/TableOfContent/CrawlerTableOfContentGeneratorTest.php @@ -6,7 +6,7 @@ * @author Thomas Jarrand */ -namespace Stenope\Bundle\Tests\Unit\Service; +namespace Stenope\Bundle\Tests\Unit\TableOfContent; use PHPUnit\Framework\TestCase; use Stenope\Bundle\TableOfContent\CrawlerTableOfContentGenerator; diff --git a/tests/fixtures/app/src/Controller/AuthorsController.php b/tests/fixtures/app/src/Controller/AuthorsController.php index 4bcc17a8..6deb15b4 100644 --- a/tests/fixtures/app/src/Controller/AuthorsController.php +++ b/tests/fixtures/app/src/Controller/AuthorsController.php @@ -13,12 +13,12 @@ use Symfony\Component\Routing\Annotation\Route; /** - * @Route("/authors") + * @Route(path="/authors") */ class AuthorsController extends AbstractController { /** - * @Route("/{author<[\w.]+>}.json", name="author_json", options={ + * @Route(path="/{author<[\w.]+>}.json", name="author_json", options={ * "stenope": { * "sitemap": false, * }, @@ -36,7 +36,7 @@ public function showAsJson(Author $author) } /** - * @Route("/{author}", name="author") + * @Route(path="/{author}", name="author") */ public function show(Author $author) { diff --git a/tests/fixtures/app/src/Controller/DefaultController.php b/tests/fixtures/app/src/Controller/DefaultController.php index a95836b7..90ae9564 100644 --- a/tests/fixtures/app/src/Controller/DefaultController.php +++ b/tests/fixtures/app/src/Controller/DefaultController.php @@ -15,7 +15,7 @@ class DefaultController extends AbstractController { /** - * @Route("/", name="homepage") + * @Route(path="/", name="homepage") */ public function index() { @@ -27,7 +27,7 @@ public function index() } /** - * @Route("/foo.html", name="foo_html") + * @Route(path="/foo.html", name="foo_html") */ public function foo() { diff --git a/tests/fixtures/app/src/Controller/NoIndexController.php b/tests/fixtures/app/src/Controller/NoIndexController.php index 016da506..f18f0175 100644 --- a/tests/fixtures/app/src/Controller/NoIndexController.php +++ b/tests/fixtures/app/src/Controller/NoIndexController.php @@ -14,7 +14,7 @@ class NoIndexController extends AbstractController { /** - * @Route("/with-noindex", name="with_noindex") + * @Route(path="/with-noindex", name="with_noindex") */ public function withNoIndex() { @@ -26,7 +26,7 @@ public function withNoIndex() } /** - * @Route("/without-noindex", name="without_noindex") + * @Route(path="/without-noindex", name="without_noindex") */ public function withoutNoIndex() { diff --git a/tests/fixtures/app/src/Controller/RecipesController.php b/tests/fixtures/app/src/Controller/RecipesController.php index 44ff03e0..e2c63942 100644 --- a/tests/fixtures/app/src/Controller/RecipesController.php +++ b/tests/fixtures/app/src/Controller/RecipesController.php @@ -16,7 +16,7 @@ use Symfony\Component\Routing\Annotation\Route; /** - * @Route("/recipes") + * @Route(path="/recipes") */ class RecipesController extends AbstractController { @@ -28,7 +28,7 @@ public function __construct(ContentManager $manager) } /** - * @Route("/", name="recipes") + * @Route(path="/", name="recipes") */ public function index() { @@ -43,7 +43,7 @@ public function index() /** * Ensure {@link ContentArgumentResolver} handles nullable arguments properly. * - * @Route("/optional-recipe", name="optional-recipe", options={ + * @Route(path="/optional-recipe", name="optional-recipe", options={ * "stenope": { * "ignore": true, * }, @@ -55,7 +55,7 @@ public function optionalRecipe(?Recipe $recipe) } /** - * @Route("/{recipe}.pdf", name="recipe_pdf", options={ + * @Route(path="/{recipe}.pdf", name="recipe_pdf", options={ * "stenope": { * "sitemap": false, * }, @@ -71,7 +71,7 @@ public function downloadAsPdf(Recipe $recipe) } /** - * @Route("/{recipe}", name="recipe") + * @Route(path="/{recipe}", name="recipe") */ public function show(Recipe $recipe) { diff --git a/tests/fixtures/app/src/Kernel.php b/tests/fixtures/app/src/Kernel.php index a731ac61..f52cc247 100644 --- a/tests/fixtures/app/src/Kernel.php +++ b/tests/fixtures/app/src/Kernel.php @@ -13,11 +13,14 @@ use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; +/** + * @final + */ class Kernel extends BaseKernel { use MicroKernelTrait; - public function getProjectDir() + public function getProjectDir(): string { return __DIR__ . '/..'; }