From a1d2127c16e95a1aa3ced52ed432b5205642bea9 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:04:59 +0400 Subject: [PATCH 1/3] [#532] Make Twig renderer optional on PHP 8.0 --- CHANGELOG.md | 2 + README.md | 13 +++++ composer.json | 11 +--- phpstan.neon.dist | 3 + src/Renderer/Adapters/TwigAdapter.php | 4 ++ src/Renderer/Exceptions/RendererException.php | 8 +++ stubs/Twig.stub | 58 +++++++++++++++++++ .../Renderer/Adapters/TwigAdapterTest.php | 22 ++++++- .../Factories/RendererFactoryTest.php | 4 ++ tests/Unit/Renderer/RendererTest.php | 4 ++ tests/Unit/View/ViewTest.php | 4 ++ 11 files changed, 124 insertions(+), 9 deletions(-) create mode 100644 stubs/Twig.stub diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d3fb019..87f9550c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ - Raised the static analysis baseline to PHPStan level `8` with PHP `8.0` target settings (#532) - Kept Rector aligned to the PHP 8 baseline and applied bounded PHP 8-safe modernization updates (#532) - Simplified the standard framework file banner across core sources, templates, and affected tests (#532) +- Made Twig an optional renderer dependency so the framework can retain PHP 8.0 support without requiring vulnerable Twig releases (#532) ### Notes - OpenAPI metadata remains on Doctrine-style annotations for now because the currently used `swagger-php` attribute scanning path requires PHP `8.1+`; `doctrine/annotations` is intentionally retained on the PHP `8.0` baseline (#532) +- Twig rendering requires a separately installed, security-supported Twig release; Twig `^3.27` requires PHP 8.1 or later, while the default HTML renderer remains available on PHP 8.0 (#532) ## [3.0.0] - 2026-05-28 diff --git a/README.md b/README.md index 5e5283b5..73d58fee 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,19 @@
+Hello Tester, this is rendered twig view
', $output); } + public function testTwigAdapterThrowsActionableExceptionWhenTwigIsMissing(): void + { + if (class_exists('Twig\Environment')) { + $this->markTestSkipped('The optional twig/twig package is installed.'); + } + + $this->expectException(RendererException::class); + $this->expectExceptionMessage( + 'The Twig renderer requires the optional `twig/twig` package. ' . + 'Install a security-supported release separately; Twig ^3.27 requires PHP 8.1 or later: ' . + '`composer require twig/twig:^3.27`.' + ); + + new TwigAdapter(); + } } diff --git a/tests/Unit/Renderer/Factories/RendererFactoryTest.php b/tests/Unit/Renderer/Factories/RendererFactoryTest.php index 3e825118..19b1d7da 100644 --- a/tests/Unit/Renderer/Factories/RendererFactoryTest.php +++ b/tests/Unit/Renderer/Factories/RendererFactoryTest.php @@ -48,6 +48,10 @@ public function testRendererFactoryGetHtmlAdapter(): void public function testRendererFactoryTwigAdapter(): void { + if (!class_exists('Twig\Environment')) { + $this->markTestSkipped('The optional twig/twig package is not installed.'); + } + $renderer = RendererFactory::get(RendererType::TWIG); $this->assertInstanceOf(TemplateRendererInterface::class, $renderer->getAdapter()); diff --git a/tests/Unit/Renderer/RendererTest.php b/tests/Unit/Renderer/RendererTest.php index f0dee936..6b21186b 100644 --- a/tests/Unit/Renderer/RendererTest.php +++ b/tests/Unit/Renderer/RendererTest.php @@ -42,6 +42,10 @@ public function testRendererGetHtmlAdapter(): void public function testRendererGetTwigAdapter(): void { + if (!class_exists('Twig\Environment')) { + $this->markTestSkipped('The optional twig/twig package is not installed.'); + } + $renderer = new Renderer(new TwigAdapter()); $this->assertInstanceOf(TwigAdapter::class, $renderer->getAdapter()); diff --git a/tests/Unit/View/ViewTest.php b/tests/Unit/View/ViewTest.php index ff06859b..b252e2cb 100644 --- a/tests/Unit/View/ViewTest.php +++ b/tests/Unit/View/ViewTest.php @@ -170,6 +170,10 @@ public function testRenderPartial(): void public function testRenderViewWithTwig(): void { + if (!class_exists('Twig\Environment')) { + $this->markTestSkipped('The optional twig/twig package is not installed.'); + } + $factory = Di::get(ViewFactory::class); $this->setPrivateProperty($factory, 'instance', null); From 98f571ac313fdb8852b9640803ec61267e086cca Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:21:13 +0400 Subject: [PATCH 2/3] [#532] Raise PHP 8.0-compatible runtime deps --- CHANGELOG.md | 1 + composer.json | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87f9550c..dd250c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Kept Rector aligned to the PHP 8 baseline and applied bounded PHP 8-safe modernization updates (#532) - Simplified the standard framework file banner across core sources, templates, and affected tests (#532) - Made Twig an optional renderer dependency so the framework can retain PHP 8.0 support without requiring vulnerable Twig releases (#532) +- Upgraded the PHP 8.0-compatible runtime lines for `psr/log`, `php-curl-class`, `php-debugbar`, `phpmailer`, `voku/html-min`, `swagger-ui`, and `swagger-php` (#532) ### Notes - OpenAPI metadata remains on Doctrine-style annotations for now because the currently used `swagger-php` attribute scanning path requires PHP `8.1+`; `doctrine/annotations` is intentionally retained on the PHP `8.0` baseline (#532) diff --git a/composer.json b/composer.json index be995665..4a848833 100644 --- a/composer.json +++ b/composer.json @@ -39,17 +39,17 @@ "symfony/console": "^5.4", "vlucas/phpdotenv": "^5.0", "dflydev/dot-access-data": "^3.0", - "php-debugbar/php-debugbar": "^1.8", - "phpmailer/phpmailer": "^6.0", - "php-curl-class/php-curl-class": "^11.0", - "psr/log": "^1.1", + "php-debugbar/php-debugbar": "^2.2", + "phpmailer/phpmailer": "^7.1", + "php-curl-class/php-curl-class": "^13.0", + "psr/log": "^2.0", "rakibtg/sleekdb": "^2.13", - "swagger-api/swagger-ui": "^4.14", - "zircote/swagger-php": "~4.4", + "swagger-api/swagger-ui": "^5.32", + "zircote/swagger-php": "^5.8", "psr/simple-cache": "^1.0", "vaibhavpandeyvpz/phemail": "^1.1", "doctrine/annotations": "^2.0", - "voku/html-min": "^4.5", + "voku/html-min": "^5.0", "league/commonmark": "^2.0", "ezyang/htmlpurifier": "^4.18", "povils/figlet": "^0.1.0", From 31662538d1ec7ef6653b08de706e1ccccb8d8293 Mon Sep 17 00:00:00 2001 From: Arman <407448+armanist@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:37:14 +0400 Subject: [PATCH 3/3] [#532] Widen logger message contract --- src/Logger/Adapters/MessageAdapter.php | 3 ++- src/Logger/Contracts/ReportableInterface.php | 4 +++- src/Logger/Traits/LoggerTrait.php | 7 ++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Logger/Adapters/MessageAdapter.php b/src/Logger/Adapters/MessageAdapter.php index 53ca913c..6c22da04 100644 --- a/src/Logger/Adapters/MessageAdapter.php +++ b/src/Logger/Adapters/MessageAdapter.php @@ -12,6 +12,7 @@ use Quantum\Logger\Contracts\ReportableInterface; use Quantum\Debugger\Debugger; +use Stringable; /** * Class MessageAdapter @@ -19,7 +20,7 @@ */ class MessageAdapter implements ReportableInterface { - public function report(string $level, string $message, ?array $context = []): void + public function report(string $level, string|Stringable $message, ?array $context = []): void { $tab = $context['tab'] ?? Debugger::MESSAGES; diff --git a/src/Logger/Contracts/ReportableInterface.php b/src/Logger/Contracts/ReportableInterface.php index a63661a2..e8ab942a 100644 --- a/src/Logger/Contracts/ReportableInterface.php +++ b/src/Logger/Contracts/ReportableInterface.php @@ -10,6 +10,8 @@ namespace Quantum\Logger\Contracts; +use Stringable; + /** * Interface ReportableInterface * @package Quantum\Logger @@ -20,6 +22,6 @@ interface ReportableInterface * Reports a message * @param array