From 95c0584ffa121994615ee2184e16c398318fced0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20L=C3=B8vgaard?= Date: Tue, 14 May 2024 12:01:18 +0200 Subject: [PATCH] Remove PHP 7.4 and PHP 8.0 support --- .editorconfig | 30 ---------- .github/workflows/build.yaml | 57 +++++++++---------- .gitignore | 2 +- LICENSE | 2 +- composer.json | 6 +- ecs.php | 7 +-- psalm-baseline.xml | 9 --- psalm.xml | 5 +- rector.php | 21 +++++++ src/Event/PreTagAddedEvent.php | 5 +- src/Event/TagAddedEvent.php | 14 ++--- src/Exception/UnsupportedTagException.php | 2 +- .../ValueBasedFingerprintGenerator.php | 2 +- src/Renderer/ElementRenderer.php | 2 +- src/Tag/ElementTag.php | 34 ++--------- src/Tag/RenderedTag.php | 34 +++-------- src/Tag/Tag.php | 36 +++--------- src/Tag/TemplateTag.php | 23 ++------ src/TagBag.php | 17 ++---- tests/Renderer/ElementRendererTest.php | 10 ++-- tests/TagBagTest.php | 6 +- 21 files changed, 107 insertions(+), 217 deletions(-) delete mode 100644 psalm-baseline.xml create mode 100644 rector.php diff --git a/.editorconfig b/.editorconfig index e716f26..779f99a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,42 +1,12 @@ root = true [*] -# Change these settings to your own preference indent_style = space indent_size = 4 - -# We recommend you to keep these unchanged end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true - -[*.json] -indent_style = space -indent_size = 2 - [*.md] -indent_style = space -indent_size = 4 trim_trailing_whitespace = false - -[*.neon] -indent_style = tab -indent_size = 4 - -[*.php] -indent_style = space -indent_size = 4 - -[composer.json] -indent_style = space -indent_size = 4 - -[phpstan.neon] -indent_style = tab -indent_size = 4 - -[phpunit.xml{,.dist}] -indent_style = space -indent_size = 4 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4c7c290..f7cf9c0 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -15,14 +15,14 @@ jobs: strategy: matrix: php-version: - - "7.4" + - "8.1" dependencies: - "highest" steps: - name: "Checkout" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -32,7 +32,7 @@ jobs: coverage: "none" - name: "Install composer dependencies" - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: dependency-versions: "${{ matrix.dependencies }}" @@ -45,6 +45,9 @@ jobs: - name: "Check style" run: "composer check-style" + - name: "Rector" + run: "vendor/bin/rector process --dry-run" + dependency-analysis: name: "Dependency Analysis" @@ -53,17 +56,17 @@ jobs: strategy: matrix: php-version: - - "7.4" - - "8.0" - "8.1" - "8.2" + - "8.3" dependencies: + - "lowest" - "highest" steps: - name: "Checkout" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -74,7 +77,7 @@ jobs: tools: "composer-require-checker, composer-unused" - name: "Install composer dependencies" - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: dependency-versions: "${{ matrix.dependencies }}" @@ -82,7 +85,7 @@ jobs: run: "composer-require-checker check" - name: "Run composer-unused/composer-unused" - run: "composer-unused || true" # TODO Remove when https://github.com/shivammathur/setup-php/issues/703 is fixed + run: "composer-unused" static-code-analysis: name: "Static Code Analysis" @@ -92,17 +95,17 @@ jobs: strategy: matrix: php-version: - - "7.4" - - "8.0" - "8.1" - "8.2" + - "8.3" dependencies: + - "lowest" - "highest" steps: - name: "Checkout" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -112,7 +115,7 @@ jobs: coverage: "none" - name: "Install composer dependencies" - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: dependency-versions: "${{ matrix.dependencies }}" @@ -127,10 +130,9 @@ jobs: strategy: matrix: php-version: - - "7.4" - - "8.0" - "8.1" - "8.2" + - "8.3" dependencies: - "lowest" @@ -138,7 +140,7 @@ jobs: steps: - name: "Checkout" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -148,12 +150,12 @@ jobs: coverage: "none" - name: "Install composer dependencies" - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: dependency-versions: "${{ matrix.dependencies }}" - name: "Run phpunit" - run: "vendor/bin/phpunit --no-coverage" + run: "vendor/bin/phpunit" code-coverage: name: "Code Coverage" @@ -163,14 +165,14 @@ jobs: strategy: matrix: php-version: - - "8.2" + - "8.3" dependencies: - "highest" steps: - name: "Checkout" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -179,11 +181,8 @@ jobs: extensions: "${{ env.PHP_EXTENSIONS }}" php-version: "${{ matrix.php-version }}" - - name: "Set up problem matchers for phpunit/phpunit" - run: "echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"" - - name: "Install composer dependencies" - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: dependency-versions: "${{ matrix.dependencies }}" @@ -191,9 +190,9 @@ jobs: run: "vendor/bin/phpunit --coverage-clover=.build/logs/clover.xml" - name: "Send code coverage report to Codecov.io" - env: - CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" - run: "bash <(curl -s https://codecov.io/bash)" + uses: "codecov/codecov-action@v4" + with: + token: "${{ secrets.CODECOV_TOKEN }}" mutation-tests: name: "Mutation tests" @@ -203,14 +202,14 @@ jobs: strategy: matrix: php-version: - - "8.2" + - "8.3" dependencies: - "highest" steps: - name: "Checkout" - uses: "actions/checkout@v3" + uses: "actions/checkout@v4" - name: "Setup PHP, with composer and extensions" uses: "shivammathur/setup-php@v2" @@ -220,7 +219,7 @@ jobs: php-version: "${{ matrix.php-version }}" - name: "Install composer dependencies" - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: dependency-versions: "${{ matrix.dependencies }}" diff --git a/.gitignore b/.gitignore index 39a92f2..f99cb76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /vendor/ /composer.lock /.phpunit.result.cache -/build/ +/.build/ diff --git a/LICENSE b/LICENSE index dc9924d..ddee45d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Setono +Copyright (c) 2024 Setono Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/composer.json b/composer.json index e05001c..30b1a5a 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": ">=7.4", + "php": ">=8.1", "ext-hash": "*", "psr/event-dispatcher": "^1.0", "psr/log": "^1.1 || ^2.0 || ^3.0", @@ -20,7 +20,7 @@ "infection/infection": "^0.26", "phpunit/phpunit": "^9.6", "psalm/plugin-phpunit": "^0.18", - "setono/code-quality-pack": "^2.4" + "setono/code-quality-pack": "^2.7" }, "prefer-stable": true, "autoload": { @@ -35,8 +35,8 @@ }, "config": { "allow-plugins": { - "ergebnis/composer-normalize": true, "dealerdirect/phpcodesniffer-composer-installer": false, + "ergebnis/composer-normalize": true, "infection/extension-installer": true }, "sort-packages": true diff --git a/ecs.php b/ecs.php index 716ed1f..d463917 100644 --- a/ecs.php +++ b/ecs.php @@ -2,12 +2,11 @@ declare(strict_types=1); -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; -use Symplify\EasyCodingStandard\ValueObject\Option; +use Symplify\EasyCodingStandard\Config\ECSConfig; -return static function (ContainerConfigurator $config): void { +return static function (ECSConfig $config): void { $config->import('vendor/sylius-labs/coding-standard/ecs.php'); - $config->parameters()->set(Option::PATHS, [ + $config->paths([ 'src', 'tests' ]); }; diff --git a/psalm-baseline.xml b/psalm-baseline.xml deleted file mode 100644 index c02c553..0000000 --- a/psalm-baseline.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - $prevErrorHandler - $prevErrorHandler - - - diff --git a/psalm.xml b/psalm.xml index d374c43..8c4c0ed 100644 --- a/psalm.xml +++ b/psalm.xml @@ -3,9 +3,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" + findUnusedBaselineEntry="false" + findUnusedCode="false" + findUnusedPsalmSuppress="true" + findUnusedVariablesAndParams="false" errorLevel="1" phpVersion="8.1" - errorBaseline="psalm-baseline.xml" > diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..ed2056c --- /dev/null +++ b/rector.php @@ -0,0 +1,21 @@ +cacheClass(FileCacheStorage::class); + $rectorConfig->cacheDirectory('./.build/rector'); + + $rectorConfig->paths([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]); + + $rectorConfig->sets([ + LevelSetList::UP_TO_PHP_81 + ]); +}; diff --git a/src/Event/PreTagAddedEvent.php b/src/Event/PreTagAddedEvent.php index 366a2fc..8ceebbb 100644 --- a/src/Event/PreTagAddedEvent.php +++ b/src/Event/PreTagAddedEvent.php @@ -11,10 +11,7 @@ */ final class PreTagAddedEvent { - public TagInterface $tag; - - public function __construct(TagInterface $tag) + public function __construct(public readonly TagInterface $tag) { - $this->tag = $tag; } } diff --git a/src/Event/TagAddedEvent.php b/src/Event/TagAddedEvent.php index 08f64c3..cedba95 100644 --- a/src/Event/TagAddedEvent.php +++ b/src/Event/TagAddedEvent.php @@ -12,15 +12,9 @@ */ final class TagAddedEvent { - /** @readonly */ - public RenderedTag $tag; - - /** @readonly */ - public TagBagInterface $tagBag; - - public function __construct(RenderedTag $tag, TagBagInterface $tagBag) - { - $this->tag = $tag; - $this->tagBag = $tagBag; + public function __construct( + public readonly RenderedTag $tag, + public readonly TagBagInterface $tagBag, + ) { } } diff --git a/src/Exception/UnsupportedTagException.php b/src/Exception/UnsupportedTagException.php index f671605..de8447b 100644 --- a/src/Exception/UnsupportedTagException.php +++ b/src/Exception/UnsupportedTagException.php @@ -11,6 +11,6 @@ final class UnsupportedTagException extends InvalidArgumentException { public function __construct(TagInterface $tag) { - parent::__construct(sprintf('The tag %s is not supported', get_class($tag))); + parent::__construct(sprintf('The tag %s is not supported', $tag::class)); } } diff --git a/src/Generator/ValueBasedFingerprintGenerator.php b/src/Generator/ValueBasedFingerprintGenerator.php index 25f15eb..3d2b33f 100644 --- a/src/Generator/ValueBasedFingerprintGenerator.php +++ b/src/Generator/ValueBasedFingerprintGenerator.php @@ -9,7 +9,7 @@ final class ValueBasedFingerprintGenerator implements FingerprintGeneratorInterface { - private string $hashAlgorithm; + private readonly string $hashAlgorithm; public function __construct(string $hashAlgorithm = 'md5') { diff --git a/src/Renderer/ElementRenderer.php b/src/Renderer/ElementRenderer.php index 3824560..b1e1a8a 100644 --- a/src/Renderer/ElementRenderer.php +++ b/src/Renderer/ElementRenderer.php @@ -33,7 +33,7 @@ public function render(TagInterface $tag): string $tag->getElement(), $this->renderAttributes($tag), $tag->getContent(), - $tag->getElement() + $tag->getElement(), ); } diff --git a/src/Tag/ElementTag.php b/src/Tag/ElementTag.php index 64fda14..f0f5760 100644 --- a/src/Tag/ElementTag.php +++ b/src/Tag/ElementTag.php @@ -10,32 +10,19 @@ class ElementTag extends Tag implements AttributesAwareInterface, ContentAwareInterface { use AttributesAwareTrait; - use ContentAwareTrait; - protected string $element; - - protected bool $closingElement; - - final private function __construct(string $element, string $content, bool $hasClosingElement) + final private function __construct(protected string $element, string $content, protected bool $closingElement) { $this->content = $content; - $this->element = $element; - $this->closingElement = $hasClosingElement; } - /** - * @return static - */ - public static function createWithContent(string $element, string $content): self + public static function createWithContent(string $element, string $content): static { return new static($element, $content, true); } - /** - * @return static - */ - public static function createWithoutContent(string $element, bool $hasClosingElement = true): self + public static function createWithoutContent(string $element, bool $hasClosingElement = true): static { return new static($element, '', $hasClosingElement); } @@ -45,10 +32,7 @@ public function getElement(): string return $this->element; } - /** - * @return static - */ - public function withElement(string $element): self + public function withElement(string $element): static { return $this->with('element', $element); } @@ -58,18 +42,12 @@ public function hasClosingElement(): bool return $this->closingElement; } - /** - * @return static - */ - public function withClosingElement(bool $closingElement): self + public function withClosingElement(bool $closingElement): static { return $this->with('closingElement', $closingElement); } - /** - * @return static - */ - public function noClosingElement(): self + public function noClosingElement(): static { return $this->withClosingElement(false); } diff --git a/src/Tag/RenderedTag.php b/src/Tag/RenderedTag.php index c72ec57..a55d6a5 100644 --- a/src/Tag/RenderedTag.php +++ b/src/Tag/RenderedTag.php @@ -12,35 +12,15 @@ * * @internal */ -final class RenderedTag +final class RenderedTag implements \Stringable { - /** @readonly */ - public string $value; - - /** @readonly */ - public string $section; - - /** @readonly */ - public int $priority; - - /** @readonly */ - public bool $unique; - - /** @readonly */ - public string $fingerprint; - private function __construct( - string $value, - string $section, - int $priority, - bool $unique, - string $fingerprint + public readonly string $value, + public readonly string $section, + public readonly int $priority, + public readonly bool $unique, + public readonly string $fingerprint, ) { - $this->value = $value; - $this->section = $section; - $this->priority = $priority; - $this->unique = $unique; - $this->fingerprint = $fingerprint; } public static function createFromTag(TagInterface $tag, string $value, string $fingerprint): self @@ -50,7 +30,7 @@ public static function createFromTag(TagInterface $tag, string $value, string $f $tag->getSection(), $tag->getPriority(), $tag->isUnique(), - $fingerprint + $fingerprint, ); } diff --git a/src/Tag/Tag.php b/src/Tag/Tag.php index 3bded68..cb2b20a 100644 --- a/src/Tag/Tag.php +++ b/src/Tag/Tag.php @@ -19,10 +19,7 @@ public function getSection(): string return $this->section; } - /** - * @return static - */ - public function withSection(string $section): self + public function withSection(string $section): static { return $this->with('section', $section); } @@ -32,10 +29,7 @@ public function getPriority(): int return $this->priority; } - /** - * @return static - */ - public function withPriority(int $priority): self + public function withPriority(int $priority): static { return $this->with('priority', $priority); } @@ -45,26 +39,17 @@ public function isUnique(): bool return $this->unique; } - /** - * @return static - */ - public function unique(): self + public function unique(): static { return $this->withUnique(true); } - /** - * @return static - */ - public function notUnique(): self + public function notUnique(): static { return $this->withUnique(false); } - /** - * @return static - */ - public function withUnique(bool $unique): self + public function withUnique(bool $unique): static { return $this->with('unique', $unique); } @@ -74,22 +59,15 @@ public function getFingerprint(): ?string return $this->fingerprint; } - /** - * @return static - */ - public function withFingerprint(string $fingerprint): self + public function withFingerprint(string $fingerprint): static { return $this->with('fingerprint', $fingerprint); } /** * This is a helper method for immutable withers - * - * @param mixed $val - * - * @return static */ - protected function with(string $property, $val): self + protected function with(string $property, mixed $val): static { $obj = clone $this; $obj->{$property} = $val; diff --git a/src/Tag/TemplateTag.php b/src/Tag/TemplateTag.php index 0460260..01d586a 100644 --- a/src/Tag/TemplateTag.php +++ b/src/Tag/TemplateTag.php @@ -8,20 +8,11 @@ final class TemplateTag extends Tag { - protected string $template; - - protected array $data; - - private function __construct(string $template, array $data = []) + private function __construct(protected string $template, protected array $data = []) { - $this->template = $template; - $this->data = $data; } - /** - * @return static - */ - public static function create(string $template, array $data = []): self + public static function create(string $template, array $data = []): static { return new self($template, $data); } @@ -34,10 +25,7 @@ public function getTemplate(): string return $this->template; } - /** - * @return static - */ - public function withTemplate(string $template): self + public function withTemplate(string $template): static { return $this->with('template', $template); } @@ -50,10 +38,7 @@ public function getData(): array return $this->data; } - /** - * @return static - */ - public function withData(array $data): self + public function withData(array $data): static { return $this->with('data', $data); } diff --git a/src/TagBag.php b/src/TagBag.php index d4b5acd..0542af2 100644 --- a/src/TagBag.php +++ b/src/TagBag.php @@ -34,14 +34,11 @@ final class TagBag implements TagBagInterface, LoggerAwareInterface private ?EventDispatcherInterface $eventDispatcher = null; - private RendererInterface $renderer; + private readonly FingerprintGeneratorInterface $fingerprintGenerator; - private FingerprintGeneratorInterface $fingerprintGenerator; - - public function __construct(RendererInterface $renderer, FingerprintGeneratorInterface $fingerprintGenerator = null) + public function __construct(private readonly RendererInterface $renderer, FingerprintGeneratorInterface $fingerprintGenerator = null) { $this->logger = new NullLogger(); - $this->renderer = $renderer; $this->fingerprintGenerator = $fingerprintGenerator ?? new ValueBasedFingerprintGenerator(); } @@ -156,9 +153,7 @@ private static function renderTags(array $tags): string */ private static function sort(array &$tags): void { - usort($tags, static function (RenderedTag $tag1, RenderedTag $tag2): int { - return $tag2->priority <=> $tag1->priority; - }); + usort($tags, static fn (RenderedTag $tag1, RenderedTag $tag2): int => $tag2->priority <=> $tag1->priority); } public function store(): void @@ -261,7 +256,6 @@ private function unserialize(string $data): array $serializationException = new SerializationException(sprintf('Could not unserialize data: %s.', $data)); $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class . '::handleUnserializeCallback'); - /** @psalm-suppress MixedArgumentTypeCoercion */ $prevErrorHandler = set_error_handler(static function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $serializationException) { if (__FILE__ === $file) { throw $serializationException; @@ -285,10 +279,9 @@ private function unserialize(string $data): array /** @psalm-suppress RedundantConditionGivenDocblockType */ Assert::isArray($tags); - /** @psalm-suppress DocblockTypeContradiction */ Assert::allIsInstanceOf($tags, RenderedTag::class); } - } catch (InvalidArgumentException $e) { + } catch (InvalidArgumentException) { throw new SerializationException(sprintf('The unserialized data was incorrect. Here is the original data: %s', $data)); } finally { restore_error_handler(); @@ -301,7 +294,7 @@ private function unserialize(string $data): array /** * @internal */ - public static function handleUnserializeCallback(string $class): void + public static function handleUnserializeCallback(string $class): never { throw new SerializationException(sprintf('Message class "%s" not found during decoding.', $class)); } diff --git a/tests/Renderer/ElementRendererTest.php b/tests/Renderer/ElementRendererTest.php index 5c277d6..7b66c7f 100644 --- a/tests/Renderer/ElementRendererTest.php +++ b/tests/Renderer/ElementRendererTest.php @@ -46,7 +46,7 @@ public function it_renders_with_type(): void { self::assertRenderedContent( '', - InlineScriptTag::create('content')->withType('application/ld+json') + InlineScriptTag::create('content')->withType('application/ld+json'), ); } @@ -58,7 +58,7 @@ public function it_renders_with_single_attribute(): void self::assertRenderedContent( '', InlineScriptTag::create('content') - ->withAttribute('data-attribute') + ->withAttribute('data-attribute'), ); } @@ -70,7 +70,7 @@ public function it_renders_with_single_attribute_and_value(): void self::assertRenderedContent( '', InlineScriptTag::create('content') - ->withAttribute('data-attribute', 'attribute-value') + ->withAttribute('data-attribute', 'attribute-value'), ); } @@ -84,7 +84,7 @@ public function it_renders_with_multiple_attributes(): void InlineScriptTag::create('content') ->withType('application/ld+json') ->withAttribute('data-attribute1') - ->withAttribute('data-attribute2', 'attribute2-value') + ->withAttribute('data-attribute2', 'attribute2-value'), ); } @@ -95,7 +95,7 @@ public function it_renders_tags_with_no_closing_element(): void { self::assertRenderedContent( '', - LinkTag::create('stylesheet', 'https://example.com/style.css') + LinkTag::create('stylesheet', 'https://example.com/style.css'), ); } diff --git a/tests/TagBagTest.php b/tests/TagBagTest.php index a80e1c5..36fa284 100644 --- a/tests/TagBagTest.php +++ b/tests/TagBagTest.php @@ -299,7 +299,7 @@ public function remove(): void private function getTag( string $content = 'content', string $section = null, - bool $unique = true + bool $unique = true, ): ContentTag { $tag = ContentTag::create($content); @@ -352,10 +352,12 @@ final class TestLogger extends AbstractLogger public function log($level, $message, array $context = []): void { - /** @psalm-suppress RedundantCastGivenDocblockType */ $this->messages[] = (string) $message; } + /** + * @param non-empty-string $regexp + */ public function hasMessageMatching(string $regexp): bool { foreach ($this->messages as $message) {