From 015799c859b8493d8dcef63a18ce8bd603774846 Mon Sep 17 00:00:00 2001 From: Mark Shust Date: Wed, 27 May 2026 09:37:36 -0400 Subject: [PATCH] refactor(view): drop mutual conflict; align with multi-driver pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #88 added Composer `conflict` declarations between view-latte and view-twig. This is duplication — Marko's DI already catches double-bindings via BindingConflictException at boot. The conflict forced view-twig into "autoload-dev only" mode in the monorepo, making view asymmetric with database/cache/queue (where both drivers sit in `require` together). Drops the Composer conflict blocks. view-twig becomes a regular monorepo package: in `repositories[]`, in `require`, full autoload via its own composer.json (no more manual src namespace in root autoload-dev). twig/twig is no longer needed in root require-dev — it's pulled in transitively now that view-twig is in require. Trade-off: failure point moves from `composer install` time to boot time. The boot-time error ("Two modules bind ViewInterface: X and Y") is more actionable than Composer's dependency-resolution noise, and fires immediately on the next request. This pattern aligns with how Magento handles module conflicts (DI-level, not composer-level) and how every other Marko multi-driver family already works today. Co-Authored-By: Claude Opus 4.7 (1M context) --- composer.json | 10 ++++++---- packages/framework/tests/RootComposerJsonTest.php | 6 +++--- packages/view-latte/composer.json | 3 --- packages/view-latte/tests/ComposerConflictTest.php | 12 ------------ packages/view-twig/composer.json | 3 --- packages/view-twig/tests/PackageTest.php | 8 -------- 6 files changed, 9 insertions(+), 33 deletions(-) delete mode 100644 packages/view-latte/tests/ComposerConflictTest.php diff --git a/composer.json b/composer.json index 2fd0ea3d..c704c1f6 100644 --- a/composer.json +++ b/composer.json @@ -320,6 +320,10 @@ "type": "path", "url": "packages/view-latte" }, + { + "type": "path", + "url": "packages/view-twig" + }, { "type": "path", "url": "packages/vite" @@ -412,6 +416,7 @@ "marko/validation": "self.version", "marko/view": "self.version", "marko/view-latte": "self.version", + "marko/view-twig": "self.version", "marko/vite": "self.version", "marko/webhook": "self.version" }, @@ -421,15 +426,13 @@ "aws/aws-sdk-php": "^3.0", "friendsofphp/php-cs-fixer": "^3.92", "guzzlehttp/guzzle": "^7.0", - "latte/latte": "^3.0", "marko/debugbar": "self.version", "pestphp/pest": "^4.3", "php-amqplib/php-amqplib": "^3.0", "predis/predis": "^2.0", "rector/rector": "^2.3", "slevomat/coding-standard": "^8.26", - "squizlabs/php_codesniffer": "^4.0", - "twig/twig": "^3.0" + "squizlabs/php_codesniffer": "^4.0" }, "scripts": { "test": "pest -c phpunit.xml --parallel --exclude-group=integration-destructive", @@ -530,7 +533,6 @@ "Marko\\Validation\\Tests\\": "packages/validation/tests/", "Marko\\View\\Tests\\": "packages/view/tests/", "Marko\\View\\Latte\\Tests\\": "packages/view-latte/tests/", - "Marko\\View\\Twig\\": "packages/view-twig/src/", "Marko\\View\\Twig\\Tests\\": "packages/view-twig/tests/", "Marko\\Vite\\Tests\\": "packages/vite/tests/", "Marko\\Webhook\\Tests\\": "packages/webhook/tests/" diff --git a/packages/framework/tests/RootComposerJsonTest.php b/packages/framework/tests/RootComposerJsonTest.php index 14efb66a..7e068b46 100644 --- a/packages/framework/tests/RootComposerJsonTest.php +++ b/packages/framework/tests/RootComposerJsonTest.php @@ -75,10 +75,11 @@ 'marko/validation', 'marko/view', 'marko/view-latte', + 'marko/view-twig', 'marko/webhook', ]; -it('adds a require section entry for all 70 marko packages set to self.version', function () use ($rootComposer, $allPackages): void { +it('adds a require section entry for all 71 marko packages set to self.version', function () use ($rootComposer, $allPackages): void { expect($rootComposer)->toHaveKey('require'); foreach ($allPackages as $package) { @@ -91,7 +92,7 @@ expect($rootComposer)->not->toHaveKey('replace'); }); -it('adds repositories section with path repos for all 70 packages', function () use ($rootComposer, $allPackages): void { +it('adds repositories section with path repos for all 71 packages', function () use ($rootComposer, $allPackages): void { expect($rootComposer)->toHaveKey('repositories'); $repoUrls = array_column($rootComposer['repositories'], 'url'); @@ -153,7 +154,6 @@ 'aws/aws-sdk-php', 'friendsofphp/php-cs-fixer', 'guzzlehttp/guzzle', - 'latte/latte', 'pestphp/pest', 'php-amqplib/php-amqplib', 'predis/predis', diff --git a/packages/view-latte/composer.json b/packages/view-latte/composer.json index 2857611f..f863571e 100644 --- a/packages/view-latte/composer.json +++ b/packages/view-latte/composer.json @@ -11,9 +11,6 @@ "require-dev": { "pestphp/pest": "^4.0" }, - "conflict": { - "marko/view-twig": "*" - }, "autoload": { "psr-4": { "Marko\\View\\Latte\\": "src/" diff --git a/packages/view-latte/tests/ComposerConflictTest.php b/packages/view-latte/tests/ComposerConflictTest.php deleted file mode 100644 index f29fca37..00000000 --- a/packages/view-latte/tests/ComposerConflictTest.php +++ /dev/null @@ -1,12 +0,0 @@ -toHaveKey('conflict') - ->and($composer['conflict'])->toHaveKey('marko/view-twig') - ->and($composer['conflict']['marko/view-twig'])->toBe('*'); -}); diff --git a/packages/view-twig/composer.json b/packages/view-twig/composer.json index ace5eaa7..af569990 100644 --- a/packages/view-twig/composer.json +++ b/packages/view-twig/composer.json @@ -11,9 +11,6 @@ "require-dev": { "pestphp/pest": "^4.0" }, - "conflict": { - "marko/view-latte": "*" - }, "autoload": { "psr-4": { "Marko\\View\\Twig\\": "src/" diff --git a/packages/view-twig/tests/PackageTest.php b/packages/view-twig/tests/PackageTest.php index 9de44eee..17abaf1d 100644 --- a/packages/view-twig/tests/PackageTest.php +++ b/packages/view-twig/tests/PackageTest.php @@ -37,14 +37,6 @@ ->and($composer['require']['twig/twig'])->toBe('^3.0'); }); - test('it declares a Composer conflict with marko/view-latte', function (): void { - $composerPath = dirname(__DIR__) . '/composer.json'; - $composer = json_decode(file_get_contents($composerPath), true); - - expect($composer['conflict'])->toHaveKey('marko/view-latte') - ->and($composer['conflict']['marko/view-latte'])->toBe('*'); - }); - test('it autoloads Marko\\View\\Twig namespace from src/', function (): void { $composerPath = dirname(__DIR__) . '/composer.json'; $composer = json_decode(file_get_contents($composerPath), true);