Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on Keep a Changelog.

### Changed
- The `DemoWeb` and `Toolkit` module templates redirect back with `back()` instead of `redirect(get_referrer() ?? base_url())` and `redirectWith(get_referrer() ?? base_url(), $data)`, so generated code gets the same-origin check. Modules generated before keep their code (#541)
- Twig is a required dependency again: `twig/twig` `^3.27` is in `require` and no longer only suggested, which reverses the 3.0.3 change that made it optional while the framework supported PHP 8.0 (#532). Twig `^3.27` needs PHP 8.1, the minimum since 3.1.0. An application that pins an older Twig must allow `^3.27`. Removed `RendererException::twigNotInstalled()` and the check in `TwigAdapter` that threw it when Twig was missing, and the Twig tests no longer skip (#626)

## [3.1.0] - 2026-10-24

Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"ezyang/htmlpurifier": "^4.18",
"povils/figlet": "^0.1.0",
"ramsey/uuid": "^4.2",
"dragonmantank/cron-expression": "^3.0"
"dragonmantank/cron-expression": "^3.0",
"twig/twig": "^3.27"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
Expand All @@ -66,8 +67,7 @@
"ext-dom": "Required for XML/HTML processing",
"ext-zip": "Required for ZIP file handling",
"ext-memcached": "Required for Memcached support",
"ext-redis": "Required for Redis support",
"twig/twig": "Required for the optional Twig renderer; secure Twig ^3.27 releases require PHP 8.1 or later"
"ext-redis": "Required for Redis support"
},
"autoload": {
"psr-4": {
Expand Down
3 changes: 0 additions & 3 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ parameters:
phpVersion: 80100
level: 8

scanFiles:
- stubs/Twig.stub

paths:
- src

Expand Down
4 changes: 0 additions & 4 deletions src/Renderer/Adapters/TwigAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ class TwigAdapter implements TemplateRendererInterface
*/
public function __construct(?array $configs = [])
{
if (!class_exists(Environment::class)) {
throw RendererException::twigNotInstalled();
}

$this->configs = $configs;

$this->fs = FileSystemFactory::get();
Expand Down
8 changes: 0 additions & 8 deletions src/Renderer/Exceptions/RendererException.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,4 @@
*/
class RendererException extends BaseException
{
public static function twigNotInstalled(): self
{
return new self(
'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`.'
);
}
}
58 changes: 0 additions & 58 deletions stubs/Twig.stub

This file was deleted.

21 changes: 0 additions & 21 deletions tests/Unit/Renderer/Adapters/TwigAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Quantum\Tests\Unit\Renderer\Adapters;

use Quantum\Renderer\Adapters\TwigAdapter;
use Quantum\Renderer\Exceptions\RendererException;
use Quantum\Tests\Unit\AppTestCase;
use Quantum\Router\MatchedRoute;
use Quantum\Router\Route;
Expand All @@ -30,10 +29,6 @@ public function setUp(): void

public function testTwigAdapterRenderView(): void
{
if (!class_exists('Twig\Environment')) {
$this->markTestSkipped('The optional twig/twig package is not installed.');
}

$adapter = new TwigAdapter();

$output = $adapter->render('index.twig', ['name' => 'Tester']);
Expand All @@ -42,20 +37,4 @@ public function testTwigAdapterRenderView(): void

$this->assertSame('<p>Hello Tester, this is rendered twig view</p>', $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();
}
}
4 changes: 0 additions & 4 deletions tests/Unit/Renderer/Factories/RendererFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ 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());
Expand Down
4 changes: 0 additions & 4 deletions tests/Unit/Renderer/RendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ 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());
Expand Down
4 changes: 0 additions & 4 deletions tests/Unit/View/ViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,6 @@ 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);

Expand Down
Loading